github-issues-wiki

github issues viewer

当前为 2023-08-06 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name       github-issues-wiki
// @namespace  npm/vite-plugin-monkey
// @version    0.0.0
// @description github issues viewer
// @author     monkey
// @icon       https://vitejs.dev/logo.svg
// @match      https://github.com/*
// @require    https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js
// @license MIT
// ==/UserScript==

(t=>{const e=document.createElement("style");e.dataset.source="vite-plugin-monkey",e.textContent=t,document.head.append(e)})(" :root.issue-active{padding-left:250px}#app{width:250px;height:100%;text-align:center;position:fixed;left:0;top:0;z-index:999;display:none}#app.active{display:block}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{border-radius:3px;background:rgba(0,0,0,.06);-webkit-box-shadow:inset 0 0 5px rgba(0,0,0,.08)}::-webkit-scrollbar-thumb{border-radius:3px;background:rgba(0,0,0,.12);-webkit-box-shadow:inset 0 0 10px rgba(0,0,0,.2)}.item-inner[data-v-ab6148b8]{text-align:left;border-top:1px solid gray;padding:10px 0}.item-inner .head[data-v-ab6148b8]{font-weight:500;display:flex;flex-direction:row}.item-inner .index[data-v-ab6148b8]{margin-right:3px}.item-inner .name[data-v-ab6148b8]{margin-left:5px;word-break:break-all;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}.item-inner .desc[data-v-ab6148b8]{padding-top:.5em;text-align:justify}.item-inner[data-v-ab6148b8]:hover{background-color:#dcffff;cursor:default}.list-infinite[data-v-8e8d3fd2]{width:100%;height:100%;border:2px solid;border-radius:3px;overflow-y:scroll;max-height:100%;border-color:#696969;position:relative;background-color:#fff;padding-left:5px;padding-right:5px}.list-infinite .list-item-infinite[data-v-8e8d3fd2]{display:flex;align-items:center;padding:1em;border-bottom:1px solid;border-color:#d3d3d3}.list-infinite .loader[data-v-8e8d3fd2]{margin-top:5px;letter-spacing:3px} ");

(function (vue) {
  'use strict';

  function ownKeys(object, enumerableOnly) {
    var keys = Object.keys(object);
    if (Object.getOwnPropertySymbols) {
      var symbols = Object.getOwnPropertySymbols(object);
      if (enumerableOnly) {
        symbols = symbols.filter(function(sym) {
          return Object.getOwnPropertyDescriptor(object, sym).enumerable;
        });
      }
      keys.push.apply(keys, symbols);
    }
    return keys;
  }
  function _objectSpread2(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i] != null ? arguments[i] : {};
      if (i % 2) {
        ownKeys(Object(source), true).forEach(function(key) {
          _defineProperty(target, key, source[key]);
        });
      } else if (Object.getOwnPropertyDescriptors) {
        Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
      } else {
        ownKeys(Object(source)).forEach(function(key) {
          Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
        });
      }
    }
    return target;
  }
  function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
      throw new TypeError("Cannot call a class as a function");
    }
  }
  function _defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor)
        descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }
  function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps)
      _defineProperties(Constructor.prototype, protoProps);
    if (staticProps)
      _defineProperties(Constructor, staticProps);
    return Constructor;
  }
  function _defineProperty(obj, key, value) {
    if (key in obj) {
      Object.defineProperty(obj, key, {
        value,
        enumerable: true,
        configurable: true,
        writable: true
      });
    } else {
      obj[key] = value;
    }
    return obj;
  }
  function _toConsumableArray(arr) {
    return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
  }
  function _arrayWithoutHoles(arr) {
    if (Array.isArray(arr))
      return _arrayLikeToArray(arr);
  }
  function _iterableToArray(iter) {
    if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null)
      return Array.from(iter);
  }
  function _unsupportedIterableToArray(o, minLen) {
    if (!o)
      return;
    if (typeof o === "string")
      return _arrayLikeToArray(o, minLen);
    var n = Object.prototype.toString.call(o).slice(8, -1);
    if (n === "Object" && o.constructor)
      n = o.constructor.name;
    if (n === "Map" || n === "Set")
      return Array.from(o);
    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
      return _arrayLikeToArray(o, minLen);
  }
  function _arrayLikeToArray(arr, len) {
    if (len == null || len > arr.length)
      len = arr.length;
    for (var i = 0, arr2 = new Array(len); i < len; i++)
      arr2[i] = arr[i];
    return arr2;
  }
  function _nonIterableSpread() {
    throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  }
  var DIRECTION_TYPE = {
    FRONT: "FRONT",
    // scroll up or left
    BEHIND: "BEHIND"
    // scroll down or right
  };
  var CALC_TYPE = {
    INIT: "INIT",
    FIXED: "FIXED",
    DYNAMIC: "DYNAMIC"
  };
  var LEADING_BUFFER = 2;
  var Virtual = /* @__PURE__ */ function() {
    function Virtual2(param, callUpdate) {
      _classCallCheck(this, Virtual2);
      this.init(param, callUpdate);
    }
    _createClass(Virtual2, [{
      key: "init",
      value: function init(param, callUpdate) {
        this.param = param;
        this.callUpdate = callUpdate;
        this.sizes = /* @__PURE__ */ new Map();
        this.firstRangeTotalSize = 0;
        this.firstRangeAverageSize = 0;
        this.lastCalcIndex = 0;
        this.fixedSizeValue = 0;
        this.calcType = CALC_TYPE.INIT;
        this.offset = 0;
        this.direction = "";
        this.range = /* @__PURE__ */ Object.create(null);
        if (param) {
          this.checkRange(0, param.keeps - 1);
        }
      }
    }, {
      key: "destroy",
      value: function destroy() {
        this.init(null, null);
      }
      // return current render range
    }, {
      key: "getRange",
      value: function getRange() {
        var range = /* @__PURE__ */ Object.create(null);
        range.start = this.range.start;
        range.end = this.range.end;
        range.padFront = this.range.padFront;
        range.padBehind = this.range.padBehind;
        return range;
      }
    }, {
      key: "isBehind",
      value: function isBehind() {
        return this.direction === DIRECTION_TYPE.BEHIND;
      }
    }, {
      key: "isFront",
      value: function isFront() {
        return this.direction === DIRECTION_TYPE.FRONT;
      }
      // return start index offset
    }, {
      key: "getOffset",
      value: function getOffset(start) {
        return (start < 1 ? 0 : this.getIndexOffset(start)) + this.param.slotHeaderSize;
      }
    }, {
      key: "updateParam",
      value: function updateParam(key, value) {
        var _this = this;
        if (this.param && key in this.param) {
          if (key === "uniqueIds") {
            this.sizes.forEach(function(v, key2) {
              if (!value.includes(key2)) {
                _this.sizes["delete"](key2);
              }
            });
          }
          this.param[key] = value;
        }
      }
      // save each size map by id
    }, {
      key: "saveSize",
      value: function saveSize(id, size) {
        this.sizes.set(id, size);
        if (this.calcType === CALC_TYPE.INIT) {
          this.fixedSizeValue = size;
          this.calcType = CALC_TYPE.FIXED;
        } else if (this.calcType === CALC_TYPE.FIXED && this.fixedSizeValue !== size) {
          this.calcType = CALC_TYPE.DYNAMIC;
          delete this.fixedSizeValue;
        }
        if (this.calcType !== CALC_TYPE.FIXED && typeof this.firstRangeTotalSize !== "undefined") {
          if (this.sizes.size < Math.min(this.param.keeps, this.param.uniqueIds.length)) {
            this.firstRangeTotalSize = _toConsumableArray(this.sizes.values()).reduce(function(acc, val) {
              return acc + val;
            }, 0);
            this.firstRangeAverageSize = Math.round(this.firstRangeTotalSize / this.sizes.size);
          } else {
            delete this.firstRangeTotalSize;
          }
        }
      }
      // in some special situation (e.g. length change) we need to update in a row
      // try goiong to render next range by a leading buffer according to current direction
    }, {
      key: "handleDataSourcesChange",
      value: function handleDataSourcesChange() {
        var start = this.range.start;
        if (this.isFront()) {
          start = start - LEADING_BUFFER;
        } else if (this.isBehind()) {
          start = start + LEADING_BUFFER;
        }
        start = Math.max(start, 0);
        this.updateRange(this.range.start, this.getEndByStart(start));
      }
      // when slot size change, we also need force update
    }, {
      key: "handleSlotSizeChange",
      value: function handleSlotSizeChange() {
        this.handleDataSourcesChange();
      }
      // calculating range on scroll
    }, {
      key: "handleScroll",
      value: function handleScroll(offset) {
        this.direction = offset < this.offset ? DIRECTION_TYPE.FRONT : DIRECTION_TYPE.BEHIND;
        this.offset = offset;
        if (!this.param) {
          return;
        }
        if (this.direction === DIRECTION_TYPE.FRONT) {
          this.handleFront();
        } else if (this.direction === DIRECTION_TYPE.BEHIND) {
          this.handleBehind();
        }
      }
      // ----------- public method end -----------
    }, {
      key: "handleFront",
      value: function handleFront() {
        var overs = this.getScrollOvers();
        if (overs > this.range.start) {
          return;
        }
        var start = Math.max(overs - this.param.buffer, 0);
        this.checkRange(start, this.getEndByStart(start));
      }
    }, {
      key: "handleBehind",
      value: function handleBehind() {
        var overs = this.getScrollOvers();
        if (overs < this.range.start + this.param.buffer) {
          return;
        }
        this.checkRange(overs, this.getEndByStart(overs));
      }
      // return the pass overs according to current scroll offset
    }, {
      key: "getScrollOvers",
      value: function getScrollOvers() {
        var offset = this.offset - this.param.slotHeaderSize;
        if (offset <= 0) {
          return 0;
        }
        if (this.isFixedType()) {
          return Math.floor(offset / this.fixedSizeValue);
        }
        var low = 0;
        var middle = 0;
        var middleOffset = 0;
        var high = this.param.uniqueIds.length;
        while (low <= high) {
          middle = low + Math.floor((high - low) / 2);
          middleOffset = this.getIndexOffset(middle);
          if (middleOffset === offset) {
            return middle;
          } else if (middleOffset < offset) {
            low = middle + 1;
          } else if (middleOffset > offset) {
            high = middle - 1;
          }
        }
        return low > 0 ? --low : 0;
      }
      // return a scroll offset from given index, can efficiency be improved more here?
      // although the call frequency is very high, its only a superposition of numbers
    }, {
      key: "getIndexOffset",
      value: function getIndexOffset(givenIndex) {
        if (!givenIndex) {
          return 0;
        }
        var offset = 0;
        var indexSize = 0;
        for (var index = 0; index < givenIndex; index++) {
          indexSize = this.sizes.get(this.param.uniqueIds[index]);
          offset = offset + (typeof indexSize === "number" ? indexSize : this.getEstimateSize());
        }
        this.lastCalcIndex = Math.max(this.lastCalcIndex, givenIndex - 1);
        this.lastCalcIndex = Math.min(this.lastCalcIndex, this.getLastIndex());
        return offset;
      }
      // is fixed size type
    }, {
      key: "isFixedType",
      value: function isFixedType() {
        return this.calcType === CALC_TYPE.FIXED;
      }
      // return the real last index
    }, {
      key: "getLastIndex",
      value: function getLastIndex() {
        return this.param.uniqueIds.length - 1;
      }
      // in some conditions range is broke, we need correct it
      // and then decide whether need update to next range
    }, {
      key: "checkRange",
      value: function checkRange(start, end) {
        var keeps = this.param.keeps;
        var total = this.param.uniqueIds.length;
        if (total <= keeps) {
          start = 0;
          end = this.getLastIndex();
        } else if (end - start < keeps - 1) {
          start = end - keeps + 1;
        }
        if (this.range.start !== start) {
          this.updateRange(start, end);
        }
      }
      // setting to a new range and rerender
    }, {
      key: "updateRange",
      value: function updateRange(start, end) {
        this.range.start = start;
        this.range.end = end;
        this.range.padFront = this.getPadFront();
        this.range.padBehind = this.getPadBehind();
        this.callUpdate(this.getRange());
      }
      // return end base on start
    }, {
      key: "getEndByStart",
      value: function getEndByStart(start) {
        var theoryEnd = start + this.param.keeps - 1;
        var truelyEnd = Math.min(theoryEnd, this.getLastIndex());
        return truelyEnd;
      }
      // return total front offset
    }, {
      key: "getPadFront",
      value: function getPadFront() {
        if (this.isFixedType()) {
          return this.fixedSizeValue * this.range.start;
        } else {
          return this.getIndexOffset(this.range.start);
        }
      }
      // return total behind offset
    }, {
      key: "getPadBehind",
      value: function getPadBehind() {
        var end = this.range.end;
        var lastIndex = this.getLastIndex();
        if (this.isFixedType()) {
          return (lastIndex - end) * this.fixedSizeValue;
        }
        if (this.lastCalcIndex === lastIndex) {
          return this.getIndexOffset(lastIndex) - this.getIndexOffset(end);
        } else {
          return (lastIndex - end) * this.getEstimateSize();
        }
      }
      // get the item estimate size
    }, {
      key: "getEstimateSize",
      value: function getEstimateSize() {
        return this.isFixedType() ? this.fixedSizeValue : this.firstRangeAverageSize || this.param.estimateSize;
      }
    }]);
    return Virtual2;
  }();
  var VirtualProps = {
    dataKey: {
      type: [String, Function],
      required: true
    },
    dataSources: {
      type: Array,
      required: true,
      "default": function _default() {
        return [];
      }
    },
    dataComponent: {
      type: [Object, Function],
      required: true
    },
    keeps: {
      type: Number,
      "default": 30
    },
    extraProps: {
      type: Object
    },
    estimateSize: {
      type: Number,
      "default": 50
    },
    direction: {
      type: String,
      "default": "vertical"
      // the other value is horizontal
    },
    start: {
      type: Number,
      "default": 0
    },
    offset: {
      type: Number,
      "default": 0
    },
    topThreshold: {
      type: Number,
      "default": 0
    },
    bottomThreshold: {
      type: Number,
      "default": 0
    },
    pageMode: {
      type: Boolean,
      "default": false
    },
    rootTag: {
      type: String,
      "default": "div"
    },
    wrapTag: {
      type: String,
      "default": "div"
    },
    wrapClass: {
      type: String,
      "default": "wrap"
    },
    wrapStyle: {
      type: Object
    },
    itemTag: {
      type: String,
      "default": "div"
    },
    itemClass: {
      type: String,
      "default": ""
    },
    itemClassAdd: {
      type: Function
    },
    itemStyle: {
      type: Object
    },
    headerTag: {
      type: String,
      "default": "div"
    },
    headerClass: {
      type: String,
      "default": ""
    },
    headerStyle: {
      type: Object
    },
    footerTag: {
      type: String,
      "default": "div"
    },
    footerClass: {
      type: String,
      "default": ""
    },
    footerStyle: {
      type: Object
    },
    itemScopedSlots: {
      type: Object
    }
  };
  var ItemProps = {
    index: {
      type: Number
    },
    event: {
      type: String
    },
    tag: {
      type: String
    },
    horizontal: {
      type: Boolean
    },
    source: {
      type: Object
    },
    component: {
      type: [Object, Function]
    },
    uniqueKey: {
      type: [String, Number]
    },
    extraProps: {
      type: Object
    },
    scopedSlots: {
      type: Object
    }
  };
  var SlotProps = {
    event: {
      type: String
    },
    uniqueKey: {
      type: String
    },
    tag: {
      type: String
    },
    horizontal: {
      type: Boolean
    }
  };
  var useResizeChange = function useResizeChange2(props, rootRef, emit) {
    var resizeObserver = null;
    var shapeKey = vue.computed(function() {
      return props.horizontal ? "offsetWidth" : "offsetHeight";
    });
    var getCurrentSize = function getCurrentSize2() {
      return rootRef.value ? rootRef.value[shapeKey.value] : 0;
    };
    var dispatchSizeChange = function dispatchSizeChange2() {
      var event = props.event, uniqueKey = props.uniqueKey, hasInitial = props.hasInitial;
      emit(event, uniqueKey, getCurrentSize(), hasInitial);
    };
    vue.onMounted(function() {
      if (typeof ResizeObserver !== "undefined") {
        resizeObserver = new ResizeObserver(function() {
          dispatchSizeChange();
        });
        rootRef.value && resizeObserver.observe(rootRef.value);
      }
    });
    vue.onUpdated(function() {
      dispatchSizeChange();
    });
    vue.onUnmounted(function() {
      if (resizeObserver) {
        resizeObserver.disconnect();
        resizeObserver = null;
      }
    });
  };
  var Item$1 = vue.defineComponent({
    name: "VirtualListItem",
    props: ItemProps,
    emits: ["itemResize"],
    setup: function setup(props, _ref) {
      var emit = _ref.emit;
      var rootRef = vue.ref(null);
      useResizeChange(props, rootRef, emit);
      return function() {
        var Tag = props.tag, Comp = props.component, _props$extraProps = props.extraProps, extraProps = _props$extraProps === void 0 ? {} : _props$extraProps, index = props.index, source = props.source, _props$scopedSlots = props.scopedSlots, scopedSlots = _props$scopedSlots === void 0 ? {} : _props$scopedSlots, uniqueKey = props.uniqueKey;
        var mergedProps = _objectSpread2(_objectSpread2({}, extraProps), {}, {
          source,
          index
        });
        return vue.createVNode(Tag, {
          "key": uniqueKey,
          "ref": rootRef
        }, {
          "default": function _default2() {
            return [vue.createVNode(Comp, _objectSpread2(_objectSpread2({}, mergedProps), {}, {
              "scopedSlots": scopedSlots
            }), null)];
          }
        });
      };
    }
  });
  var Slot = vue.defineComponent({
    name: "VirtualListSlot",
    props: SlotProps,
    emits: ["slotResize"],
    setup: function setup2(props, _ref2) {
      var slots = _ref2.slots, emit = _ref2.emit;
      var rootRef = vue.ref(null);
      useResizeChange(props, rootRef, emit);
      return function() {
        var _slots$default;
        var Tag = props.tag, uniqueKey = props.uniqueKey;
        return vue.createVNode(Tag, {
          "ref": rootRef,
          "key": uniqueKey
        }, {
          "default": function _default2() {
            return [(_slots$default = slots["default"]) === null || _slots$default === void 0 ? void 0 : _slots$default.call(slots)];
          }
        });
      };
    }
  });
  var EVENT_TYPE;
  (function(EVENT_TYPE2) {
    EVENT_TYPE2["ITEM"] = "itemResize";
    EVENT_TYPE2["SLOT"] = "slotResize";
  })(EVENT_TYPE || (EVENT_TYPE = {}));
  var SLOT_TYPE;
  (function(SLOT_TYPE2) {
    SLOT_TYPE2["HEADER"] = "thead";
    SLOT_TYPE2["FOOTER"] = "tfoot";
  })(SLOT_TYPE || (SLOT_TYPE = {}));
  var VirtualList = vue.defineComponent({
    name: "VirtualList",
    props: VirtualProps,
    setup: function setup3(props, _ref) {
      var emit = _ref.emit, slots = _ref.slots, expose = _ref.expose;
      var isHorizontal = props.direction === "horizontal";
      var directionKey = isHorizontal ? "scrollLeft" : "scrollTop";
      var range = vue.ref(null);
      var root = vue.ref();
      var shepherd = vue.ref(null);
      var virtual;
      vue.watch(function() {
        return props.dataSources.length;
      }, function() {
        virtual.updateParam("uniqueIds", getUniqueIdFromDataSources());
        virtual.handleDataSourcesChange();
      });
      vue.watch(function() {
        return props.keeps;
      }, function(newValue) {
        virtual.updateParam("keeps", newValue);
        virtual.handleSlotSizeChange();
      });
      vue.watch(function() {
        return props.start;
      }, function(newValue) {
        scrollToIndex(newValue);
      });
      vue.watch(function() {
        return props.offset;
      }, function(newValue) {
        return scrollToOffset(newValue);
      });
      var getSize = function getSize2(id) {
        return virtual.sizes.get(id);
      };
      var getOffset = function getOffset2() {
        if (props.pageMode) {
          return document.documentElement[directionKey] || document.body[directionKey];
        } else {
          return root.value ? Math.ceil(root.value[directionKey]) : 0;
        }
      };
      var getClientSize = function getClientSize2() {
        var key = isHorizontal ? "clientWidth" : "clientHeight";
        if (props.pageMode) {
          return document.documentElement[key] || document.body[key];
        } else {
          return root.value ? Math.ceil(root.value[key]) : 0;
        }
      };
      var getScrollSize = function getScrollSize2() {
        var key = isHorizontal ? "scrollWidth" : "scrollHeight";
        if (props.pageMode) {
          return document.documentElement[key] || document.body[key];
        } else {
          return root.value ? Math.ceil(root.value[key]) : 0;
        }
      };
      var emitEvent = function emitEvent2(offset, clientSize, scrollSize, evt) {
        emit("scroll", evt, virtual.getRange());
        if (virtual.isFront() && !!props.dataSources.length && offset - props.topThreshold <= 0) {
          emit("totop");
        } else if (virtual.isBehind() && offset + clientSize + props.bottomThreshold >= scrollSize) {
          emit("tobottom");
        }
      };
      var onScroll = function onScroll2(evt) {
        var offset = getOffset();
        var clientSize = getClientSize();
        var scrollSize = getScrollSize();
        if (offset < 0 || offset + clientSize > scrollSize + 1 || !scrollSize) {
          return;
        }
        virtual.handleScroll(offset);
        emitEvent(offset, clientSize, scrollSize, evt);
      };
      var getUniqueIdFromDataSources = function getUniqueIdFromDataSources2() {
        var dataKey = props.dataKey, _props$dataSources = props.dataSources, dataSources = _props$dataSources === void 0 ? [] : _props$dataSources;
        return dataSources.map(function(dataSource) {
          return typeof dataKey === "function" ? dataKey(dataSource) : dataSource[dataKey];
        });
      };
      var onRangeChanged = function onRangeChanged2(newRange) {
        range.value = newRange;
      };
      var installVirtual = function installVirtual2() {
        virtual = new Virtual({
          slotHeaderSize: 0,
          slotFooterSize: 0,
          keeps: props.keeps,
          estimateSize: props.estimateSize,
          buffer: Math.round(props.keeps / 3),
          // recommend for a third of keeps
          uniqueIds: getUniqueIdFromDataSources()
        }, onRangeChanged);
        range.value = virtual.getRange();
      };
      var scrollToIndex = function scrollToIndex2(index) {
        if (index >= props.dataSources.length - 1) {
          scrollToBottom();
        } else {
          var offset = virtual.getOffset(index);
          scrollToOffset(offset);
        }
      };
      var scrollToOffset = function scrollToOffset2(offset) {
        if (props.pageMode) {
          document.body[directionKey] = offset;
          document.documentElement[directionKey] = offset;
        } else {
          if (root.value) {
            root.value[directionKey] = offset;
          }
        }
      };
      var getRenderSlots = function getRenderSlots2() {
        var slots2 = [];
        var _range$value = range.value, start = _range$value.start, end = _range$value.end;
        var dataSources = props.dataSources, dataKey = props.dataKey, itemClass = props.itemClass, itemTag = props.itemTag, itemStyle = props.itemStyle, extraProps = props.extraProps, dataComponent = props.dataComponent, itemScopedSlots = props.itemScopedSlots;
        for (var index = start; index <= end; index++) {
          var dataSource = dataSources[index];
          if (dataSource) {
            var uniqueKey = typeof dataKey === "function" ? dataKey(dataSource) : dataSource[dataKey];
            if (typeof uniqueKey === "string" || typeof uniqueKey === "number") {
              slots2.push(vue.createVNode(Item$1, {
                "index": index,
                "tag": itemTag,
                "event": EVENT_TYPE.ITEM,
                "horizontal": isHorizontal,
                "uniqueKey": uniqueKey,
                "source": dataSource,
                "extraProps": extraProps,
                "component": dataComponent,
                "scopedSlots": itemScopedSlots,
                "style": itemStyle,
                "class": "".concat(itemClass).concat(props.itemClassAdd ? " " + props.itemClassAdd(index) : ""),
                "onItemResize": onItemResized
              }, null));
            } else {
              console.warn("Cannot get the data-key '".concat(dataKey, "' from data-sources."));
            }
          } else {
            console.warn("Cannot get the index '".concat(index, "' from data-sources."));
          }
        }
        return slots2;
      };
      var onItemResized = function onItemResized2(id, size) {
        virtual.saveSize(id, size);
        emit("resized", id, size);
      };
      var onSlotResized = function onSlotResized2(type, size, hasInit) {
        if (type === SLOT_TYPE.HEADER) {
          virtual.updateParam("slotHeaderSize", size);
        } else if (type === SLOT_TYPE.FOOTER) {
          virtual.updateParam("slotFooterSize", size);
        }
        if (hasInit) {
          virtual.handleSlotSizeChange();
        }
      };
      var scrollToBottom = function scrollToBottom2() {
        if (shepherd.value) {
          var offset = shepherd.value[isHorizontal ? "offsetLeft" : "offsetTop"];
          scrollToOffset(offset);
          setTimeout(function() {
            if (getOffset() + getClientSize() < getScrollSize()) {
              scrollToBottom2();
            }
          }, 3);
        }
      };
      var updatePageModeFront = function updatePageModeFront2() {
        if (root.value) {
          var rect = root.value.getBoundingClientRect();
          var defaultView = root.value.ownerDocument.defaultView;
          var offsetFront = isHorizontal ? rect.left + defaultView.pageXOffset : rect.top + defaultView.pageYOffset;
          virtual.updateParam("slotHeaderSize", offsetFront);
        }
      };
      var getSizes = function getSizes2() {
        return virtual.sizes.size;
      };
      vue.onBeforeMount(function() {
        installVirtual();
      });
      vue.onActivated(function() {
        scrollToOffset(virtual.offset);
      });
      vue.onMounted(function() {
        if (props.start) {
          scrollToIndex(props.start);
        } else if (props.offset) {
          scrollToOffset(props.offset);
        }
        if (props.pageMode) {
          updatePageModeFront();
          document.addEventListener("scroll", onScroll, {
            passive: false
          });
        }
      });
      vue.onUnmounted(function() {
        virtual.destroy();
        if (props.pageMode) {
          document.removeEventListener("scroll", onScroll);
        }
      });
      expose({
        scrollToBottom,
        getSizes,
        getSize,
        getOffset,
        getScrollSize,
        getClientSize,
        scrollToOffset,
        scrollToIndex
      });
      return function() {
        var pageMode = props.pageMode, RootTag = props.rootTag, WrapTag = props.wrapTag, wrapClass = props.wrapClass, wrapStyle = props.wrapStyle, headerTag = props.headerTag, headerClass = props.headerClass, headerStyle = props.headerStyle, footerTag = props.footerTag, footerClass = props.footerClass, footerStyle = props.footerStyle;
        var _ref2 = range.value, padFront = _ref2.padFront, padBehind = _ref2.padBehind;
        var paddingStyle = {
          padding: isHorizontal ? "0px ".concat(padBehind, "px 0px ").concat(padFront, "px") : "".concat(padFront, "px 0px ").concat(padBehind, "px")
        };
        var wrapperStyle = wrapStyle ? Object.assign({}, wrapStyle, paddingStyle) : paddingStyle;
        var header = slots.header, footer = slots.footer;
        return vue.createVNode(RootTag, {
          "ref": root,
          "onScroll": !pageMode && onScroll
        }, {
          "default": function _default2() {
            return [header && vue.createVNode(Slot, {
              "class": headerClass,
              "style": headerStyle,
              "tag": headerTag,
              "event": EVENT_TYPE.SLOT,
              "uniqueKey": SLOT_TYPE.HEADER,
              "onSlotResize": onSlotResized
            }, {
              "default": function _default3() {
                return [header()];
              }
            }), vue.createVNode(WrapTag, {
              "class": wrapClass,
              "style": wrapperStyle
            }, {
              "default": function _default3() {
                return [getRenderSlots()];
              }
            }), footer && vue.createVNode(Slot, {
              "class": footerClass,
              "style": footerStyle,
              "tag": footerTag,
              "event": EVENT_TYPE.SLOT,
              "uniqueKey": SLOT_TYPE.FOOTER,
              "onSlotResize": onSlotResized
            }, {
              "default": function _default3() {
                return [footer()];
              }
            }), vue.createVNode("div", {
              "ref": shepherd,
              "style": {
                width: isHorizontal ? "0px" : "100%",
                height: isHorizontal ? "100%" : "0px"
              }
            }, null)];
          }
        });
      };
    }
  });
  const _export_sfc = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
      target[key] = val;
    }
    return target;
  };
  const _hoisted_1$1 = { class: "head" };
  const _hoisted_2 = { class: "index" };
  const _hoisted_3 = { class: "name" };
  const _sfc_main$2 = {
    __name: "Item",
    props: {
      source: {
        type: Object,
        default: () => ({})
      }
    },
    setup(__props) {
      const props = __props;
      const handleClick = () => {
        const url = props.source.url;
        const parser = new DOMParser();
        const oldTopo = document.getElementsByClassName("list-infinite")[0].scrollTop;
        fetch(url).then(function(response) {
          return response.text();
        }).then(function(html) {
          const doc = parser.parseFromString(html, "text/html");
          const app = document.getElementById("app");
          document.body = doc.body;
          document.body.appendChild(app);
          document.getElementsByClassName("list-infinite")[0].scrollTop = oldTopo;
        }).catch(function(error) {
          console.error("Failed to load issue:", error);
        });
        history.pushState({}, "", url);
      };
      return (_ctx, _cache) => {
        return vue.openBlock(), vue.createElementBlock("div", {
          class: "item-inner",
          onClick: handleClick
        }, [
          vue.createElementVNode("div", _hoisted_1$1, [
            vue.createElementVNode("div", _hoisted_2, vue.toDisplayString(__props.source.index), 1),
            vue.createElementVNode("div", _hoisted_3, vue.toDisplayString(__props.source.text), 1)
          ])
        ]);
      };
    }
  };
  const Item = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-ab6148b8"]]);
  const _withScopeId = (n) => (vue.pushScopeId("data-v-8e8d3fd2"), n = n(), vue.popScopeId(), n);
  const _hoisted_1 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "loader" }, "已经到底了", -1));
  const _sfc_main$1 = {
    __name: "IssueSidebar",
    setup(__props) {
      let currentPage = 1;
      let hasFinished = vue.ref(false);
      const listData = vue.ref([]);
      const onScrollToTop = () => {
        console.log("at top");
      };
      const onScrollToBottom = () => {
        console.log("at bottom");
        requestData();
      };
      vue.onMounted(() => {
        requestData();
      });
      function requestData() {
        const url = `https://github.com${window.location.pathname.replace(/\/issues\/.*/, "/issues")}?page=${currentPage}&q=is%3Aissue`;
        fetch(url).then(function(response) {
          return response.text();
        }).then(function(html) {
          const parser = new DOMParser();
          const doc = parser.parseFromString(html, "text/html");
          const issueLinks = doc.querySelectorAll(".js-navigation-open");
          const len = listData.value.length;
          if (!issueLinks.length) {
            hasFinished.value = true;
          } else {
            listData.value = listData.value.concat(Array.from(issueLinks).map((v, i) => {
              return {
                index: len + i + 1,
                text: v.innerText,
                url: v.href
              };
            }));
            currentPage++;
          }
        }).catch(function(error) {
          console.error("Failed to load issues:", error);
        });
      }
      return (_ctx, _cache) => {
        return vue.openBlock(), vue.createBlock(vue.unref(VirtualList), {
          class: "list-infinite",
          "data-key": "index",
          "data-sources": listData.value,
          "data-component": Item,
          "estimate-size": 70,
          "item-class": "list-item-infinite",
          "footer-class": "loader-wrapper",
          onTotop: onScrollToTop,
          onTobottom: onScrollToBottom
        }, vue.createSlots({ _: 2 }, [
          vue.unref(hasFinished) ? {
            name: "footer",
            fn: vue.withCtx(() => [
              _hoisted_1
            ]),
            key: "0"
          } : void 0
        ]), 1032, ["data-sources"]);
      };
    }
  };
  const IssueSidebar = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-8e8d3fd2"]]);
  const _sfc_main = {
    __name: "App",
    setup(__props) {
      let tamp = null;
      let currentUrl = "";
      const showIssueTab = vue.ref(false);
      const reg = /\/issues/;
      vue.onMounted(() => {
        tamp = setInterval(function() {
          if (window.location.href !== currentUrl) {
            console.log("URL发生变化");
            if (reg.test(window.location.href)) {
              showIssueTab.value = true;
              document.documentElement.classList.add("issue-active");
              document.getElementById("app").classList.add("active");
            } else {
              showIssueTab.value = false;
              document.documentElement.classList.remove("issue-active");
              document.getElementById("app").classList.remove("active");
            }
            currentUrl = window.location.href;
          }
        }, 500);
      });
      vue.onUnmounted(() => {
        clearInterval(tamp);
      });
      return (_ctx, _cache) => {
        return showIssueTab.value ? (vue.openBlock(), vue.createBlock(IssueSidebar, { key: 0 })) : vue.createCommentVNode("", true);
      };
    }
  };
  vue.createApp(_sfc_main).mount(
    (() => {
      const app = document.createElement("div");
      app.id = "app";
      document.body.append(app);
      return app;
    })()
  );

})(Vue);