github-issues-wiki

github issues viewer

目前為 2023-08-06 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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);