Greasy Fork

Kbin Usability Pack

A collection of usability enhancements for Kbin

目前为 2023-06-29 提交的版本。查看 最新版本

// ==UserScript==
// @name         Kbin Usability Pack
// @namespace    https://perry.dev
// @license      MIT
// @version      0.2.1
// @description  A collection of usability enhancements for Kbin
// @author       Daniel Pervan
// @match        https://kbin.social/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=kbin.social
// @run-at       document-end
// ==/UserScript==

(function () {
    'use strict';
(() => {
  // src/Classes/User/User.js
  var User = class {
    username;
    avatar;
    constructor(username, avatar = null) {
      this.username = username;
      this.avatar = avatar;
    }
  };
  var User_default = User;

  // style-helper:index.js
  function inject_style(text) {
    if (typeof document !== "undefined") {
      var style = document.createElement("style");
      var node = document.createTextNode(text);
      style.appendChild(node);
      document.head.appendChild(style);
    }
  }

  // src/Classes/Article/Article.scss
  inject_style('body:not(.kup-show-article-preview) .show-article-preview{display:none!important}#content article.entry aside.meta.entry__meta{line-height:3.5em}#content article.entry aside.meta.entry__meta img{margin-right:.25em;margin-left:.25em}#content article.entry .magazine-inline{white-space:nowrap}#content article.entry.no-image{grid-template-areas:"vote title" "vote shortDesc" "vote meta" "vote footer" "body body" "preview preview"}#content article.entry:not(.no-image){grid-template-areas:"vote image title" "vote image shortDesc" "vote image meta" "vote image footer" "body body body" "preview preview preview"!important;grid-template-columns:min-content min-content auto}#content article.entry.selected{border:var(--kbin-meta-border)}#content article.entry>figure{margin:0 1rem 0 0;align-self:center}#content article.entry>figure img{max-width:180px;max-height:100%;width:auto;height:auto;object-fit:contain}#content article.entry aside.vote{place-content:center}#content article.entry button.show-preview,#content article.entry button.preview-button{border:1px solid var(--kbin-section-text-color);padding:.5em;background:var(--kbin-bg)}main#main.view-compact article.entry{grid-template-areas:"vote image title" "vote image meta" "vote image footer" "body body body" "preview preview preview"!important}main#main.view-compact article.entry.no-image{grid-template-areas:"vote title" "vote meta" "vote footer" "body body" "preview preview"!important}main#main.view-compact article.entry figure{margin-right:1rem}main#main.view-compact article.entry figure img{max-height:100px;max-width:120px}@media (max-width: 689.98px){main#main.view-compact article.entry{grid-template-areas:"image vote" "title vote" "meta vote" "footer vote" "body body" "preview preview"!important;grid-template-columns:auto min-content}main#main.view-compact article.entry figure img{object-fit:contain}main#main.view-compact article.entry.no-image{grid-template-areas:"title vote" "meta vote" "footer vote" "body body" "preview preview"!important;grid-template-columns:auto min-content}}@media (max-width: 991.98px){#content article.entry:not(.no-image){grid-template-areas:"vote image image" "vote title title" "vote shortDesc shortDesc" "vote meta meta" "vote footer footer" "body body body" "preview preview preview"!important}}@media (max-width: 689.98px){#content article.entry:not(.no-image){grid-template-areas:"vote image" "title title" "shortDesc shortDesc" "meta meta" "footer footer" "body body" "preview preview"!important;grid-template-columns:min-content auto}#content article.entry.no-image{grid-template-areas:"vote title" "vote shortDesc" "vote meta" "vote footer" "body body" "preview preview"!important;grid-template-columns:min-content auto}#content article.entry>figure{margin:0}#content article.entry aside.vote{place-self:center}}.preview-outer{grid-area:preview}.preview-outer .preview-inner{position:relative;display:none;border-top:var(--kbin-meta-border);padding:1em}.preview-outer .preview-inner.show{display:block}.preview-outer .preview-inner .loading{position:relative;height:3em;z-index:1;display:flex;justify-content:center;align-items:center;animation:showPreviewLoading .25s ease-in-out}.preview-outer .preview-inner .article-preview-content{position:relative}.preview-outer .preview-inner .article-preview-content.loaded{animation:articlePreviewFadeIn .5s ease-in-out}.preview-outer .preview-inner .media-preview-content{position:relative}.preview-outer .preview-inner .media-preview-content img{max-width:100%;max-height:100%;min-width:100px;object-fit:contain}.preview-outer .preview-inner .media-preview-content img.animateMinResize{animation:animateMinResize .25s ease-out;transform-origin:left top}@keyframes animateMinResize{0%{opacity:1;transform:scale(1)}33%{opacity:.8;transform:scale(.95)}66%{opacity:1;transform:scale(1.01)}to{opacity:1;transform:scale(1)}}.preview-outer .preview-inner .media-preview-content.oembed-embed{position:relative;overflow:hidden;max-width:100%;height:100vh;margin:0 auto}.preview-outer .preview-inner .media-preview-content.oembed-embed iframe{position:absolute;top:0;left:0;overflow:hidden;width:100%;height:100%;border:none}.preview-outer .preview-inner .media-preview-content.youtube-embed{position:relative;overflow:hidden;max-width:100%;max-height:100vh;margin:0 auto;aspect-ratio:16/9}.preview-outer .preview-inner .media-preview-content.youtube-embed iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:none}.preview-outer .preview-inner .media-preview-content.loaded{animation:articlePreviewFadeIn .5s ease-in-out}@keyframes showPreviewLoading{0%{opacity:0;transform:scale(.8)}50%{opacity:1;transform:scale(1.15)}80%{transform:scale(.9)}to{transform:scale(1)}}@keyframes articlePreviewFadeIn{0%{opacity:0;transform:translateY(-.5em)}to{opacity:1}}');

  // src/Classes/Settings.js
  var Settings = class {
    constructor() {
    }
    get(key) {
      const settings = this.getAll();
      if (settings[key] === void 0) {
        return null;
      }
      return settings[key];
    }
    getAll() {
      const data = localStorage.getItem("kup-settings");
      let settings = {};
      if (data) {
        settings = JSON.parse(data);
      }
      if (settings.showUrlSubheader === void 0) {
        settings.showUrlSubheader = true;
      }
      if (settings.removeCommentAnchor === void 0) {
        settings.removeCommentAnchor = true;
      }
      if (settings.showArticlePreview === void 0) {
        settings.showArticlePreview = true;
      }
      return settings;
    }
    replace(settings) {
      localStorage.setItem("kup-settings", JSON.stringify(settings));
      window.dispatchEvent(new CustomEvent("kup-settings-changed"));
    }
    save(key, value) {
      const settings = this.getAll();
      settings[key] = value;
      this.replace(settings);
    }
    reset() {
      localStorage.removeItem("kup-settings");
    }
  };
  var Settings_default = Settings;

  // src/Classes/Article/Article.js
  var Article = class _Article {
    feedElement = null;
    subject = null;
    author = null;
    date = null;
    articleUrl = null;
    mediaUrl = null;
    magazine = null;
    linkUrl = null;
    hasMedia = false;
    articlePreviewOpen = false;
    mediaPreviewOpen = false;
    TYPES = {
      ARTICLE: "article",
      LINK: "link",
      IMAGE: "image"
    };
    #content;
    #articleLoaded;
    articlePageElement;
    enableArticlePreview = true;
    constructor() {
    }
    static fromFeedElement(element) {
      let article = new _Article();
      article.feedElement = element;
      article.subject = element.querySelector("header h2").innerText;
      article.author = new User_default(element.querySelector(".meta .user-inline").innerText, element.querySelector(".meta .user-inline img")?.src);
      article.date = new Date(element.querySelector(".meta.entry__meta time")?.innerText);
      article.articleUrl = element.querySelector("header h2 a")?.href;
      article.thumbUrl = element.querySelector("figure a img")?.src;
      article.mediaUrl = element.querySelector("button.show-preview")?.dataset?.previewUrlParam;
      article.magazine = element.querySelector(".meta.entry__meta .magazine-inline")?.innerText;
      article.shortDescription = element.querySelector(".content.short-desc")?.innerText?.trim();
      const upvoteElement = element.querySelector("aside.vote .vote__up");
      const downvoteElement = element.querySelector("aside.vote .vote__down");
      article.upvotes = parseInt(upvoteElement?.querySelector("span")?.innerText) || 0;
      article.downvotes = parseInt(downvoteElement?.querySelector("span")?.innerText) || 0;
      if (article.feedElement.querySelector("li.meta-link")) {
        article.type = article.TYPES.ARTICLE;
      } else if (article.feedElement.querySelector("li>button.show-preview")) {
        article.type = article.TYPES.IMAGE;
      } else {
        article.type = article.TYPES.LINK;
      }
      return article;
    }
    upvote() {
      const element = this.feedElement ?? this.articlePageElement;
      if (!element) {
        return;
      }
      const voteElement = element.querySelector("aside.vote .vote__up button");
      if (voteElement) {
        voteElement.click();
        this.upvotes++;
      }
    }
    downvote() {
      const element = this.feedElement ?? this.articlePageElement;
      if (!element) {
        return;
      }
      const voteElement = element.querySelector("aside.vote .vote__down button");
      if (voteElement) {
        voteElement.click();
        this.upvotes--;
      }
    }
    boost() {
      const element = this.feedElement ?? this.articlePageElement;
      if (!element) {
        return;
      }
      const boostElement = element.querySelector("footer menu li form button");
      if (boostElement && boostElement.dataset.action === "subject#favourite") {
        boostElement.click();
      }
    }
    loadArticle() {
      if (this.#articleLoaded) {
        return Promise.resolve(this);
      }
      const fetchOptions = {
        method: "GET",
        headers: {
          "Accept": "text/html"
        }
      };
      return fetch(this.articleUrl, fetchOptions).then((response) => {
        return response.text();
      }).then((text) => {
        const parser = new DOMParser();
        const htmlDocument = parser.parseFromString(text, "text/html");
        const contentElement = htmlDocument.querySelector("article .entry__body .content");
        this.#content = contentElement?.innerHTML ?? null;
        const linkElement = htmlDocument.querySelector("article header h1 a");
        if (linkElement) {
          this.linkUrl = linkElement.href;
        } else {
          this.linkUrl = null;
        }
        this.#articleLoaded = true;
        return this;
      });
    }
    static fromArticlePage(articleElement) {
      let article = new _Article();
      article.subject = articleElement.querySelector("header h1")?.childNodes[0]?.innerText?.trim();
      article.author = new User_default(articleElement.querySelector(".meta .user-inline").innerText, articleElement.querySelector(".meta .user-inline img")?.src);
      article.date = new Date(articleElement.querySelector(".meta.entry__meta time")?.innerText);
      article.linkUrl = articleElement.querySelector("header h1>a")?.href;
      article.thumbUrl = articleElement.querySelector("figure a img")?.src;
      article.mediaUrl = articleElement.querySelector("button.show-preview")?.dataset?.previewUrlParam;
      article.magazine = articleElement.querySelector(".meta.entry__meta .magazine-inline")?.innerText;
      article.#content = articleElement.querySelector(".entry__body .content")?.innerHTML ?? null;
      const upvoteElement = articleElement.querySelector("aside.vote .vote__up");
      const downvoteElement = articleElement.querySelector("aside.vote .vote__down");
      article.upvotes = parseInt(upvoteElement?.querySelector("span")?.innerText) || 0;
      article.downvotes = parseInt(downvoteElement?.querySelector("span")?.innerText) || 0;
      article.enableArticlePreview = false;
      article.#articleLoaded = true;
      article.articlePageElement = articleElement;
      if (articleElement.querySelector("li.meta-link")) {
        article.type = article.TYPES.ARTICLE;
      } else if (articleElement.querySelector("li>button.show-preview")) {
        article.type = article.TYPES.IMAGE;
      } else {
        article.type = article.TYPES.LINK;
      }
      return article;
    }
    getContent() {
      if (!this.shortDescription) {
        this.#content = null;
        return Promise.resolve(this.#content);
      }
      return this.loadArticle().then(() => {
        return this.#content;
      });
    }
    hasContent() {
      return !!this.shortDescription || !!this.#content;
    }
    enrichFeedElement() {
      if (!this.feedElement) {
        return;
      }
      const settings = new Settings_default();
      const footer = this.feedElement.querySelector("footer");
      const footerMenu = footer.querySelector("menu");
      const previewOuter = Object.assign(document.createElement("div"), {
        className: "preview-outer"
      });
      this.feedElement.append(previewOuter);
      const thumbnail = this.feedElement.querySelector("figure a img");
      if (thumbnail) {
        thumbnail.style.objectFit = null;
      }
      this.replaceMediaPreview(this.feedElement);
      if (this.hasContent()) {
        if (this.type === this.TYPES.ARTICLE) {
          footer.querySelector("li.meta-link i")?.remove();
        }
        const previewButton = document.createElement("button");
        previewButton.classList.add("show-article-preview", "preview-button");
        previewButton.innerHTML = '<i class="fas fa-newspaper"></i>';
        previewButton.addEventListener("click", (event) => {
          event.preventDefault();
          this.toggleArticlePreview();
        });
        let metaLinkElement = footer.querySelector("li.meta-link");
        if (!metaLinkElement) {
          metaLinkElement = document.createElement("li");
          metaLinkElement.classList.add("meta-link");
          footerMenu.insertBefore(metaLinkElement, footerMenu.firstChild);
        }
        metaLinkElement.append(previewButton);
        let previewElement = this.feedElement.querySelector(".article-preview");
        let previewContentElement;
        if (!previewElement) {
          previewElement = document.createElement("div");
          previewElement.classList.add("article-preview", "preview-inner");
          previewContentElement = document.createElement("div");
          previewContentElement.classList.add("article-preview-content", "content");
          previewElement.append(previewContentElement);
          previewOuter.append(previewElement);
        }
      }
      if (settings.get("removeCommentAnchor")) {
        const commentsLinkElements = footer.querySelectorAll("menu li > a.stretched-link");
        commentsLinkElements.forEach((commentsLinkElement) => {
          if (commentsLinkElement && commentsLinkElement.href.endsWith("#comments")) {
            const url = new URL(commentsLinkElement.href);
            commentsLinkElement.href = url.pathname;
          }
        });
      }
    }
    replaceMediaPreview(parent) {
      const footer = parent.querySelector("footer");
      const mediaPreviewButton = footer.querySelector("button.show-preview");
      const previewOuter = parent.querySelector(".preview-outer");
      const footerMenu = footer.querySelector("menu");
      if (mediaPreviewButton && mediaPreviewButton.dataset.action === "preview#show") {
        this.hasMedia = true;
        mediaPreviewButton.remove();
        const newMediaPreviewButton = document.createElement("button");
        newMediaPreviewButton.classList.add("show-media-preview", "preview-button");
        newMediaPreviewButton.innerHTML = '<i class="fas fa-photo-film"></i>';
        newMediaPreviewButton.addEventListener("click", (event) => {
          event.preventDefault();
          this.toggleMediaPreview();
        });
        const li = document.createElement("li");
        li.append(newMediaPreviewButton);
        footer.querySelector("menu").insertBefore(li, footerMenu.firstChild);
        let previewElement = parent.querySelector(".media-preview");
        if (!previewElement) {
          previewElement = document.createElement("div");
          previewElement.classList.add("media-preview", "preview-inner");
          const previewContentElement = document.createElement("div");
          previewContentElement.classList.add("media-preview-content");
          previewElement.append(previewContentElement);
          previewOuter.append(previewElement);
        }
      }
    }
    enrichArticlePage() {
      if (!this.articlePageElement) {
        return;
      }
      const previewOuter = Object.assign(document.createElement("div"), {
        className: "preview-outer"
      });
      this.articlePageElement.append(previewOuter);
      this.replaceMediaPreview(this.articlePageElement);
    }
    showArticlePreview() {
      if (!this.feedElement || !this.type === this.TYPES.ARTICLE || !this.hasContent()) {
        return;
      }
      this.articlePreviewOpen = true;
      let previewElement = this.feedElement.querySelector(".article-preview");
      let previewContentElement = previewElement.querySelector(".article-preview-content");
      previewElement.classList.add("show");
      previewContentElement.innerHTML = '<div class="loading"><i class="fas fa-spinner fa-spin"></i></div>';
      previewContentElement.classList.remove("loaded");
      this.getContent().then((content) => {
        if (content) {
          previewContentElement.innerHTML = content ?? "";
        } else {
          previewContentElement.innerHTML = '<div class="no-content"><i class="fas fa-exclamation-triangle"></i> No content</div>';
        }
        previewContentElement.classList.add("loaded");
      }).catch(() => {
        previewContentElement.innerHTML = '<div class="error"><i class="fas fa-exclamation-triangle"></i> Error loading content</div>';
        previewContentElement.classList.add("loaded");
      });
    }
    hideArticlePreview() {
      if (!this.feedElement || !this.type === this.TYPES.ARTICLE) {
        return;
      }
      this.articlePreviewOpen = false;
      let previewElement = this.feedElement.querySelector(".article-preview");
      if (previewElement) {
        previewElement.classList.remove("show");
      }
    }
    toggleArticlePreview() {
      if (this.articlePreviewOpen) {
        this.hideArticlePreview();
      } else {
        this.showArticlePreview();
      }
    }
    showMediaPreview() {
      let element = this.feedElement ?? this.articlePageElement;
      if (!element || !this.mediaUrl) {
        return;
      }
      this.mediaPreviewOpen = true;
      let previewElement = element.querySelector(".media-preview");
      let previewContentElement = previewElement.querySelector(".media-preview-content");
      previewElement.classList.add("show");
      previewContentElement.innerHTML = '<div class="loading"><i class="fas fa-spinner fa-spin"></i></div>';
      previewContentElement.classList.remove("loaded");
      const mediaURLObject = new URL(this.mediaUrl);
      if (this.mediaUrl.match(/\.(jpeg|jpg|gif|png|svg)$/) !== null) {
        const imageElement = document.createElement("img");
        imageElement.addEventListener("load", () => {
          previewContentElement.innerHTML = "";
          previewContentElement.append(imageElement);
          previewContentElement.classList.add("loaded");
        });
        imageElement.src = this.mediaUrl;
        imageElement.addEventListener("error", () => {
          previewContentElement.innerHTML = '<div class="error"><i class="fas fa-exclamation-triangle"></i> Error loading image</div>';
          previewContentElement.classList.add("loaded");
        });
        imageElement.addEventListener("dragstart", (event) => {
          event.preventDefault();
        });
        imageElement.addEventListener("mousedown", (event) => {
          this.handleMediaPreviewResizeDrag(event, imageElement, "start");
        });
        document.body.addEventListener("mouseup", (event) => {
          this.handleMediaPreviewResizeDrag(event, imageElement, "end");
        });
        element.addEventListener("mousemove", (event) => {
          this.handleMediaPreviewResizeDrag(event, imageElement, "move");
        });
      } else if (mediaURLObject.hostname === "www.youtube.com" || mediaURLObject.hostname === "youtube.com" || mediaURLObject.hostname === "youtu.be") {
        const videoElement = document.createElement("iframe");
        let videoSrc = "https://www.youtube.com/embed/";
        if (mediaURLObject.hostname === "youtu.be") {
          videoSrc += mediaURLObject.pathname.substring(1);
        } else {
          videoSrc += mediaURLObject.searchParams.get("v");
        }
        videoElement.src = videoSrc;
        videoElement.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture";
        videoElement.allowFullscreen = true;
        previewContentElement.innerHTML = "";
        previewContentElement.append(videoElement);
        previewContentElement.classList.add("youtube-embed");
        previewContentElement.classList.add("loaded");
      } else {
        let url = "/ajax/fetch_embed?url=" + encodeURIComponent(this.mediaUrl);
        fetch(url).then((response) => response.json().then((data) => {
          previewContentElement.innerHTML = "";
          previewContentElement.insertAdjacentHTML("beforeend", data.html);
          previewContentElement.classList.add("loaded");
        })).catch(() => {
          previewContentElement.innerHTML = '<div class="error"><i class="fas fa-exclamation-triangle"></i> Error loading media</div>';
          previewContentElement.classList.add("loaded");
        });
      }
    }
    hideMediaPreview() {
      const element = this.feedElement ?? this.articlePageElement;
      if (!element) {
        return;
      }
      this.mediaPreviewOpen = false;
      let previewElement = element.querySelector(".media-preview");
      if (previewElement) {
        previewElement.classList.remove("show");
        previewElement.querySelector(".media-preview-content").innerHTML = "";
      }
    }
    toggleMediaPreview() {
      if (this.mediaPreviewOpen) {
        this.hideMediaPreview();
      } else {
        this.showMediaPreview();
      }
    }
    select() {
      this.selected = true;
      this.feedElement.classList.add("selected");
    }
    unselect() {
      this.selected = false;
      this.feedElement.classList.remove("selected");
    }
    /** Resize media preview on drag */
    #isDraggingMediaPreview = false;
    handleMediaPreviewResizeDrag(event, imageElement) {
      if (event.type === "mousedown") {
        this.#isDraggingMediaPreview = true;
      } else if (event.type === "mouseup") {
        this.#isDraggingMediaPreview = false;
      } else if (event.type === "mousemove" && this.#isDraggingMediaPreview) {
        let imageRect = imageElement.getBoundingClientRect();
        imageElement.style.width = imageRect.width + event.movementX * 2 + "px";
        if (imageRect.width <= 100 && !imageElement.classList.contains("animateMinResize")) {
          imageElement.classList.add("animateMinResize");
        } else if (imageRect.width > 110) {
          imageElement.classList.remove("animateMinResize");
        }
      }
    }
    togglePreviews() {
      if (!this.articlePreviewOpen && this.enableArticlePreview && this.hasContent()) {
        this.showArticlePreview();
      } else if (!this.mediaPreviewOpen && this.hasMedia) {
        this.showMediaPreview();
      } else {
        this.hideArticlePreview();
        this.hideMediaPreview();
      }
    }
  };
  var Article_default = Article;

  // src/Classes/ArticlesHandler/ArticlesHandler.js
  var ArticlesHandler = class {
    #articles;
    currentArticle;
    constructor() {
      this.#articles = [];
    }
    init() {
      if (!document.querySelector("#content>div article.entry")) {
        return;
      }
      this.applySettings();
      window.addEventListener("kup-settings-changed", () => {
        this.applySettings();
      });
      this.parseArticles();
      const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          if (mutation.addedNodes.length > 0) {
            mutation.addedNodes.forEach((node) => {
              if (node.classList.contains("entry")) {
                this.parseArticle(node);
              }
            });
          }
        });
      });
      observer.observe(document.querySelector("#content>div"), {
        childList: true
      });
      document.addEventListener("keydown", (e) => {
        this.handleKeydown(e);
      });
    }
    parseArticle(element) {
      const article = Article_default.fromFeedElement(element);
      article.enrichFeedElement();
      element.addEventListener("click", () => {
        this.selectArticle(article);
      });
      this.#articles.push(article);
    }
    parseArticles() {
      document.querySelectorAll("#content>div>article.entry").forEach((el) => {
        this.parseArticle(el);
      });
    }
    selectArticle(article) {
      if (this.currentArticle) {
        this.currentArticle.unselect();
      }
      this.currentArticle = article;
      article.select();
    }
    unselectCurrentArticle() {
      if (this.currentArticle) {
        this.currentArticle.unselect();
        this.currentArticle = null;
      }
    }
    selectClosestArticle() {
      console.log("Selecting closest article");
      if (!this.currentArticle) {
        this.#articles.some((article) => {
          if (article.feedElement?.getBoundingClientRect().top > 0 && article.feedElement?.getBoundingClientRect().top < window.innerHeight) {
            this.selectArticle(article);
            return true;
          }
        });
      }
    }
    handleKeydown(event) {
      if (event.target.tagName !== "BODY") {
        return;
      }
      if (event.key === "Escape") {
        this.unselectCurrentArticle();
      } else if (event.key === "ArrowUp") {
        if (!this.currentArticle) {
          return;
        }
        event.preventDefault();
        const index = this.#articles.indexOf(this.currentArticle);
        if (index > 0) {
          this.selectArticle(this.#articles[index - 1]);
        }
        if (this.currentArticle.feedElement?.getBoundingClientRect().top < 0) {
          this.currentArticle.feedElement.scrollIntoView();
        }
      } else if (event.key === "ArrowDown") {
        if (!this.currentArticle) {
          return;
        }
        event.preventDefault();
        const index = this.#articles.indexOf(this.currentArticle);
        if (index < this.#articles.length - 1) {
          this.selectArticle(this.#articles[index + 1]);
        }
        if (this.currentArticle.feedElement?.getBoundingClientRect().top > window.innerHeight) {
          this.currentArticle.feedElement.scrollIntoView(false);
        }
      } else if (event.key === "Enter") {
        if (!this.currentArticle) {
          this.selectClosestArticle();
        } else {
          event.preventDefault();
          this.currentArticle.togglePreviews();
        }
      } else if (event.key === "a") {
        if (!this.currentArticle) {
          return;
        }
        event.preventDefault();
        this.currentArticle.upvote();
      } else if (event.key === "z") {
        if (!this.currentArticle) {
          return;
        }
        event.preventDefault();
        this.currentArticle.downvote();
      } else if (event.key === "b") {
        if (!this.currentArticle) {
          return;
        }
        event.preventDefault();
        this.currentArticle.boost();
      } else if (event.key === "o") {
        if (!this.currentArticle) {
          return;
        }
        event.preventDefault();
        window.location.href = this.currentArticle.articleUrl;
      }
    }
    applySettings() {
      const settings = new Settings_default();
      if (settings.get("showArticlePreview")) {
        document.body.classList.add("kup-show-article-preview");
      } else {
        document.body.classList.remove("kup-show-article-preview");
        this.#articles.forEach((article) => {
          article.hideArticlePreview();
        });
      }
    }
  };
  var ArticlesHandler_default = ArticlesHandler;

  // src/Classes/Navigator/Navigator.js
  var Navigator = class {
    constructor() {
    }
    init() {
      this.fixMobileLogoLink();
    }
    fixMobileLogoLink() {
      const nav = document.querySelector("nav.head-nav");
      const logo = document.querySelector("nav.head-nav .brand > a");
      const hamburger = document.querySelector("nav.head-nav .brand > div");
      const homeButton = document.querySelector("#sidebar .section.mobile-close a.btn");
      const action = nav.dataset.action;
      nav.dataset.action = "";
      hamburger.dataset.action = action;
      homeButton.href = logo.href;
    }
  };
  var Navigator_default = Navigator;

  // src/Classes/ArticlePage/ArticlePage.scss
  inject_style("body.kup-show-url-subheader article.entry header .url-subheader{display:block}article.entry header .url-subheader{display:none;font-size:.6rem;font-weight:600;flex-basis:100%}article.entry header .url-subheader .url-subheader__path{font-weight:200}");

  // src/Classes/ArticlePage/ArticlePage.js
  var ArticlePage = class {
    currentPage = 1;
    numberOfPages = 1;
    constructor() {
    }
    init() {
      const currentURL = new URL(window.location.href);
      if (!currentURL.pathname.match(/\/m\/.+?\/t\/.+?/)) {
        return;
      }
      this.url = currentURL;
      this.articleElement = document.querySelector("article.entry");
      this.article = Article_default.fromArticlePage(this.articleElement);
      this.article.enrichArticlePage();
      const paginationElement = document.querySelector("nav.pagination.section");
      let currentPage = this.url.searchParams.get("p");
      if (currentPage) {
        this.currentPage = parseInt(currentPage);
      } else {
        this.currentPage = 1;
      }
      let numberOfPages = paginationElement?.querySelectorAll(".pagination__item:not(.pagination__item--next-page):not(.pagination__item--previous-page)");
      if (numberOfPages && numberOfPages[numberOfPages.length - 1]) {
        this.numberOfPages = parseInt(numberOfPages[numberOfPages.length - 1].textContent);
      } else {
        this.numberOfPages = this.currentPage;
      }
      if (paginationElement) {
        paginationElement.innerHTML = "";
        const observer = new IntersectionObserver((entries) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
              this.handleInfiniteScroll();
            }
          });
        });
        observer.observe(paginationElement);
      }
      document.addEventListener("keydown", (e) => {
        this.handleKeydown(e);
      });
      if (this.article.linkUrl) {
        const subheader = document.createElement("h3");
        subheader.classList.add("url-subheader");
        let url = new URL(this.article.linkUrl);
        let subheaderText = '<i class="fa fa-link"></i> <span class="url-subheader__host">' + url.hostname + '</span><span class="url-subheader__path">' + url.pathname + url.search + "</span>";
        subheader.innerHTML = `<a href="${this.article.linkUrl}" target="_blank">${subheaderText}</a>`;
        this.articleElement.querySelector("header").appendChild(subheader);
      }
      this.applySettings();
      window.addEventListener("kup-settings-changed", () => {
        this.applySettings();
      });
    }
    handleInfiniteScroll() {
      if (this.numberOfPages > this.currentPage) {
        this.currentPage++;
        this.loadPage(this.currentPage).then((html) => {
          const dom = new DOMParser().parseFromString(html, "text/html");
          const comments = dom.querySelectorAll("#comments section.comments > .comment");
          const paginationElement = document.querySelector("nav.pagination.section");
          comments.forEach((comment) => {
            document.querySelector("#comments section.comments").insertBefore(comment, paginationElement);
          });
        });
      }
    }
    applySettings() {
      const settings = new Settings_default();
      if (settings.get("showUrlSubheader") === true) {
        document.body.classList.add("kup-show-url-subheader");
      } else {
        document.body.classList.remove("kup-show-url-subheader");
      }
    }
    handleKeydown(event) {
      if (event.target.tagName !== "BODY") {
        return;
      }
      if (event.key === "Enter") {
        event.preventDefault();
        this.article.togglePreviews();
      } else if (event.key === "a") {
        event.preventDefault();
        this.article.upvote();
      } else if (event.key === "z") {
        event.preventDefault();
        this.article.downvote();
      } else if (event.key === "b") {
        event.preventDefault();
        this.article.boost();
      } else if (event.key === "o") {
        if (this.article.linkUrl) {
          event.preventDefault();
          window.open(this.article.linkUrl, "_blank");
        }
      }
    }
    loadPage(page) {
      let url = this.url.pathname + "?p=" + page;
      return fetch(url).then((response) => {
        return response.text();
      });
    }
  };
  var ArticlePage_default = ArticlePage;

  // src/Classes/SettingsPanel/SettingsRow.js
  var SettingsRow = class _SettingsRow {
    element;
    name;
    description;
    value;
    type;
    options;
    static TYPES = {
      BOOLEAN: "boolean",
      STRING: "string",
      NUMBER: "number",
      ENUM: "enum",
      CUSTOM: "custom"
    };
    constructor(name, type, value, options = {}) {
      this.name = name;
      this.type = type;
      this.value = value;
      const { description } = options || {};
      this.description = description;
    }
    getElement() {
      if (this.element) {
        return this.element;
      }
      const element = Object.assign(document.createElement("div"), {
        className: "settings-row"
      });
      this.element = element;
      const name = Object.assign(document.createElement("span"), {
        className: "name",
        innerText: this.name
      });
      element.appendChild(name);
      if (this.description) {
        element.classList.add("has-description");
        const description = Object.assign(document.createElement("span"), {
          className: "description",
          innerText: this.description
        });
        element.appendChild(description);
      }
      return element;
    }
    static fromElement(element) {
      return new _SettingsRow(element.innerText, _SettingsRow.detectType(element), "", {});
    }
    static detectType(element) {
      const valueElement = element.querySelector(":scope > div");
      const booleanRegex = /Yes\s*\|\s*No/;
      const enumRegex = /(\w+)\s*\|\s*(\w+)/;
      if (valueElement.innerText.trim().match(booleanRegex)) {
        return _SettingsRow.TYPES.BOOLEAN;
      } else if (valueElement.innerText.trim().match(enumRegex)) {
        return _SettingsRow.TYPES.ENUM;
      } else {
        return _SettingsRow.TYPES.CUSTOM;
      }
    }
  };
  var SettingsRow_default = SettingsRow;

  // src/Classes/SettingsPanel/SettingsRowCustom.js
  var SettingsRowCustom = class _SettingsRowCustom extends SettingsRow_default {
    name;
    description;
    value;
    valueElement;
    constructor(name, value) {
      super(name, SettingsRow_default.TYPES.CUSTOM, value);
    }
    getElement() {
      if (this.element) {
        return this.element;
      }
      const element = Object.assign(document.createElement("div"), {
        className: "settings-row"
      });
      this.element = element;
      const name = Object.assign(document.createElement("span"), {
        className: "name",
        innerText: this.name
      });
      element.appendChild(name);
      if (this.description) {
        element.classList.add("has-description");
        const description = Object.assign(document.createElement("span"), {
          className: "description",
          innerText: this.description
        });
        element.appendChild(description);
      }
      const valueContainer = Object.assign(document.createElement("div"), {
        className: "value-container"
      });
      valueContainer.appendChild(this.valueElement);
      element.appendChild(valueContainer);
      return element;
    }
    static fromElement(element) {
      const settingsRow = new _SettingsRowCustom();
      settingsRow.name = element.querySelector(":scope > span")?.innerText.trim();
      settingsRow.name = settingsRow.name.endsWith(":") ? settingsRow.name.slice(0, -1) : settingsRow.name;
      settingsRow.description = element.querySelector(".description")?.innerText;
      settingsRow.value = element.querySelector("input")?.value;
      settingsRow.valueElement = element.querySelector(":scope > div");
      return settingsRow;
    }
  };
  var SettingsRowCustom_default = SettingsRowCustom;

  // src/Classes/SettingsPanel/SettingsSection.js
  var SettingsSection = class _SettingsSection {
    settingsRows = [];
    name;
    expanded = false;
    constructor(name) {
      this.name = name;
      this.settingsRows = [];
    }
    addSettingsRow(settingRow) {
      this.settingsRows.push(settingRow);
    }
    addSettingsRows(settingRows) {
      settingRows.forEach((row) => {
        this.addSettingsRow(row);
      });
    }
    static fromHeaderElement(headerElement) {
      return new _SettingsSection(headerElement.innerText);
    }
    expand() {
      this.expanded = true;
      this.element.classList.add("expanded");
    }
    collapse() {
      this.expanded = false;
      this.element.classList.remove("expanded");
    }
    toggle() {
      this.expanded ? this.collapse() : this.expand();
    }
    getElement() {
      if (this.element) {
        return this.element;
      }
      const element = Object.assign(document.createElement("div"), {
        className: "settings-section"
      });
      this.element = element;
      const header = Object.assign(document.createElement("h3"), {
        className: "settings-section-header",
        innerHTML: `<span>${this.name}</span><i class="fas fa-chevron-down icon-chevron"></i>`
      });
      header.addEventListener("click", (e) => {
        if (e.shiftKey) {
          window.dispatchEvent(new CustomEvent("kup-settings-expand-all-sections", {
            detail: {
              expand: !this.expanded
            }
          }));
        } else {
          this.toggle();
        }
      });
      element.appendChild(header);
      const settingsRows = Object.assign(document.createElement("div"), {
        className: "settings-rows"
      });
      element.appendChild(settingsRows);
      this.settingsRows.forEach((row) => {
        settingsRows.appendChild(row.getElement());
      });
      return element;
    }
  };
  var SettingsSection_default = SettingsSection;

  // src/Classes/SettingsPanel/SettingsPanel.scss
  inject_style('#settings .settings-list{display:none!important;visibility:hidden}#settings .settings-panel-footer{font-size:.8em;font-weight:100}#settings .settings-panel-footer span{margin-left:.25em}.settings-panel .settings-section{margin-bottom:2em}.settings-panel .settings-section .settings-section-header{font-weight:700;margin-bottom:1em;cursor:pointer}.settings-panel .settings-section .settings-section-header:hover{color:var(--kbin-primary)}.settings-panel .settings-section .settings-section-header .icon{margin-right:.5em}.settings-panel .settings-section .settings-section-header .icon-chevron{transition:transform .25s ease-in-out;transform:rotate(-90deg);margin-left:.5em}.settings-panel .settings-section.expanded .icon-chevron{transform:rotate(0)}.settings-panel .settings-section.expanded .settings-row{display:grid}.settings-panel .settings-section .settings-row{display:none;grid-template-areas:"name value" "description value";grid-template-columns:auto;align-items:center;margin-bottom:1em;animation:showSettingsRow .25s ease-in-out}@keyframes showSettingsRow{0%{opacity:0;transform:translateY(-1em)}to{opacity:1;transform:translateY(0)}}.settings-panel .settings-section .settings-row .name{margin-right:1em;grid-area:name}.settings-panel .settings-section .settings-row .description{grid-area:description;font-size:.8em;color:var(--kbin-secondary-text-color)}.settings-panel .settings-section .settings-row .value-container{flex-grow:1;text-align:right;grid-area:value;margin-left:1em}.settings-panel .settings-section .settings-row .value-container .link-muted.active{color:var(--kbin-primary);font-weight:800!important}.settings-panel .settings-section .settings-row .value-container.enum{border:var(--kbin-button-primary-border);border-radius:.5em;display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));align-items:center;text-align:center;background-color:var(--kbin-button-secondary-bg);overflow:hidden;font-size:.8em}.settings-panel .settings-section .settings-row .value-container.enum .value{padding:.5em .25em;font-weight:100;color:var(--kbin-button-secondary-text-color)}.settings-panel .settings-section .settings-row .value-container.enum .value:not(:last-child){border-right:var(--kbin-button-primary-border)}.settings-panel .settings-section .settings-row .value-container.enum .value.selected{background:var(--kbin-button-primary-bg);color:var(--kbin-button-primary-text-color);font-weight:800!important}.settings-panel .settings-section .settings-row .value-container .switch{position:relative;display:inline-block;width:3em;height:1.5em;border-radius:.75em;overflow:hidden;border:var(--kbin-button-primary-border)}.settings-panel .settings-section .settings-row .value-container .switch input{width:0;height:0;visibility:hidden}.settings-panel .settings-section .settings-row .value-container .switch:hover .slider{background-color:var(--kbin-button-secondary-text-hover-color)}.settings-panel .settings-section .settings-row .value-container .switch:hover .slider:before{background-color:var(--kbin-button-primary-text-hover-color);border:.5em solid var(--kbin-button-primary-text-hover-color)}.settings-panel .settings-section .settings-row .value-container .switch:hover input:checked+.slider{background-color:var(--kbin-button-primary-hover-bg)}.settings-panel .settings-section .settings-row .value-container .switch:hover input:checked+.slider:before{background:var(--kbin-button-primary-hover-bg)}.settings-panel .settings-section .settings-row .value-container .slider{position:absolute;cursor:pointer;inset:0;background-color:var(--kbin-button-secondary-text-color);transition:.25s}.settings-panel .settings-section .settings-row .value-container .slider:before{position:absolute;content:"";height:100%;aspect-ratio:1;left:0;bottom:0;background-color:var(--kbin-button-primary-text-color);transition:.25s;border-radius:.75em;border:.5em solid var(--kbin-button-primary-text-color)}.settings-panel .settings-section .settings-row .value-container input:checked+.slider{background-color:var(--kbin-button-primary-bg)}.settings-panel .settings-section .settings-row .value-container input:checked+.slider:before{transform:translate(1.5em);background:var(--kbin-button-primary-bg)}#settings-notification-container{position:fixed;bottom:0;left:0;right:0;z-index:1000;padding:1em;display:none;flex-direction:column;align-items:center;pointer-events:none}#settings-notification-container.visible{display:flex}#settings-notification-container .notification{pointer-events:initial;margin-bottom:1em;padding:1em;border-radius:.25rem;background-color:var(--kbin-bg);box-shadow:var(--kbin-shadow);border:var(--kbin-section-border);display:flex;flex-direction:row;align-items:center;justify-content:space-between;animation:showNotification .25s ease-in-out}@keyframes showNotification{0%{opacity:0;transform:translateY(1em)}to{opacity:1;transform:translateY(0)}}#settings-notification-container .notification .message,#settings-notification-container .notification .message-icon{margin-right:1em}');

  // src/Classes/SettingsPanel/SettingsRowBoolean.js
  var SettingsRowBoolean = class _SettingsRowBoolean extends SettingsRow_default {
    element;
    postAction;
    trueAction;
    falseAction;
    id;
    requireReload;
    constructor(name, defaultValue, options = {}) {
      super(name, SettingsRow_default.TYPES.BOOLEAN, defaultValue, options);
      const { id, requireReload, postAction } = options || {};
      if (id) {
        this.id = id;
        const settings = new Settings_default();
        const value = settings.get(id);
        if (value !== void 0) {
          this.value = value;
        }
      }
      if (requireReload) {
        this.requireReload = requireReload;
      }
      if (postAction) {
        this.postAction = postAction;
      }
      const action = (newValue) => {
        if (this.id) {
          const settings = new Settings_default();
          settings.save(this.id, newValue);
        }
        if (this.postAction) {
          this.postAction(newValue);
        }
        if (this.requireReload) {
          window.dispatchEvent(new CustomEvent("kup-settings-needs-reload"));
        }
      };
      this.bindTrueAction(() => {
        action(true);
      });
      this.bindFalseAction(() => {
        action(false);
      });
    }
    bindPostAction(action) {
      this.postAction = action;
    }
    setValue(value) {
      this.value = !!value;
      if (this.value) {
        this.trueAction();
      } else {
        this.falseAction();
      }
    }
    bindTrueAction(action) {
      this.trueAction = action;
    }
    bindFalseAction(action) {
      this.falseAction = action;
    }
    getElement() {
      if (this.element) {
        return this.element;
      }
      const element = Object.assign(document.createElement("div"), {
        className: "settings-row"
      });
      this.element = element;
      const name = Object.assign(document.createElement("span"), {
        className: "name",
        innerText: this.name
      });
      element.appendChild(name);
      if (this.description) {
        element.classList.add("has-description");
        const description = Object.assign(document.createElement("span"), {
          className: "description",
          innerText: this.description
        });
        element.appendChild(description);
      }
      const valueContainer = Object.assign(document.createElement("div"), {
        className: "value-container"
      });
      const label = Object.assign(document.createElement("label"), {
        className: "switch"
      });
      const input = Object.assign(document.createElement("input"), {
        type: "checkbox",
        checked: this.value
      });
      const slider = Object.assign(document.createElement("span"), {
        className: "slider"
      });
      input.addEventListener("change", () => {
        this.setValue(!this.value);
      });
      label.appendChild(input);
      label.appendChild(slider);
      valueContainer.appendChild(label);
      element.appendChild(valueContainer);
      return element;
    }
    static fromElement(element) {
      let name = element.querySelector(":scope > span")?.innerText.trim();
      name = name.endsWith(":") ? name.slice(0, -1) : name;
      const settingsRow = new _SettingsRowBoolean(name, element.querySelector(":scope > div a.active").innerText.trim() === "Yes");
      const valueElements = element.querySelectorAll(":scope > div a");
      valueElements.forEach((valueElement) => {
        if (valueElement.innerText.trim() === "Yes") {
          settingsRow.bindTrueAction(() => {
            if (valueElement.href?.trim().toLowerCase().startsWith("javascript:") || valueElement.href?.trim().startsWith("#")) {
              valueElement.click();
              return Promise.resolve();
            } else {
              return fetch(valueElement.href).then(() => {
                window.dispatchEvent(new CustomEvent("kup-settings-needs-reload"));
              });
            }
          });
        } else {
          settingsRow.bindFalseAction(() => {
            if (valueElement.href.startsWith("javascript:") || valueElement.href.startsWith("#")) {
              valueElement.click();
              return Promise.resolve();
            } else {
              return fetch(valueElement.href).then(() => {
                window.dispatchEvent(new CustomEvent("kup-settings-needs-reload"));
              });
            }
          });
        }
      });
      return settingsRow;
    }
  };
  var SettingsRowBoolean_default = SettingsRowBoolean;

  // src/Classes/SettingsPanel/SettingsRowEnum.js
  var SettingsRowEnum = class _SettingsRowEnum extends SettingsRow_default {
    selectedId;
    constructor(name, defaultValue, options = {}) {
      super(name, SettingsRow_default.TYPES.ENUM, "", options);
      const { id, values } = options || {};
      if (id) {
        this.id = id;
        const settings = new Settings_default();
        const value = settings.get(id);
        if (value !== void 0) {
          this.value = value;
        }
      } else {
        this.selectedId = defaultValue;
      }
      if (values) {
        this.values = values;
      } else {
        throw new Error("SettingsRowEnum requires values");
      }
    }
    getElement() {
      if (this.element) {
        return this.element;
      }
      const element = Object.assign(document.createElement("div"), {
        className: "settings-row"
      });
      this.element = element;
      const name = Object.assign(document.createElement("span"), {
        className: "name",
        innerText: this.name
      });
      element.appendChild(name);
      if (this.description) {
        element.classList.add("has-description");
        const description = Object.assign(document.createElement("span"), {
          className: "description",
          innerText: this.description
        });
        element.appendChild(description);
      }
      const valueContainer = Object.assign(document.createElement("div"), {
        className: "value-container enum"
      });
      this.values.forEach((value) => {
        const valueElement = Object.assign(document.createElement("a"), {
          className: "value",
          innerText: value.value,
          href: value.id
        });
        if (this.selectedId === value.id) {
          valueElement.classList.add("selected");
        }
        valueElement.addEventListener("click", (e) => {
          e.preventDefault();
          value.action();
          element.querySelectorAll(".value").forEach((valueElement2) => {
            valueElement2.classList.remove("selected");
          });
          valueElement.classList.add("selected");
        });
        valueContainer.appendChild(valueElement);
      });
      element.appendChild(valueContainer);
      return element;
    }
    static fromElement(element) {
      let name = element.querySelector(":scope > span")?.innerText.trim();
      name = name.endsWith(":") ? name.slice(0, -1) : name;
      const valueElements = element.querySelectorAll(":scope > div a");
      let values = [];
      let selectedId = null;
      valueElements.forEach((valueElement) => {
        let value = {};
        value.value = valueElement.innerText.trim();
        value.id = valueElement.href;
        value.action = () => {
          return fetch(valueElement.href).then(() => {
            window.dispatchEvent(new CustomEvent("kup-settings-needs-reload"));
          });
        };
        if (valueElement.classList.contains("active")) {
          selectedId = value.id;
        }
        values.push(value);
      });
      return new _SettingsRowEnum(name, selectedId, {
        values
      });
    }
  };
  var SettingsRowEnum_default = SettingsRowEnum;

  // src/Classes/SettingsPanel/SettingsPanel.js
  function settingsRowFromElement(element) {
    let settingsRow;
    switch (SettingsRow_default.detectType(element)) {
      case SettingsRow_default.TYPES.BOOLEAN:
        settingsRow = SettingsRowBoolean_default.fromElement(element);
        break;
      case SettingsRow_default.TYPES.ENUM:
        settingsRow = SettingsRowEnum_default.fromElement(element);
        break;
      default:
        settingsRow = SettingsRowCustom_default.fromElement(element);
        break;
    }
    return settingsRow;
  }
  var SettingsPanel = class {
    sections = [];
    constructor() {
    }
    init() {
      this.settingsPanelContainerElement = document.getElementById("settings");
      this.addSettingsNotificationElement();
      this.enrichSettingsPanel().then(() => {
        this.populateKUPSettings();
      });
      window.addEventListener("kup-settings-needs-reload", () => {
        this.showNotification("Settings updated. Some changes require a reload to take effect.");
      });
      window.addEventListener("kup-settings-expand-all-sections", (e) => {
        this.sections.forEach((section) => {
          e.detail.expand ? section.expand() : section.collapse();
        });
      });
    }
    addSection(section) {
      this.sections.push(section);
      this.settingsPanelElement.appendChild(section.getElement());
    }
    enrichSettingsPanel() {
      const settingsListElement = this.settingsPanelContainerElement.querySelector(".settings-list");
      const settingsList = settingsListElement.querySelectorAll(":scope > *");
      return new Promise((resolve) => {
        setTimeout(() => {
          let currentSection = null;
          let sections = [];
          settingsList.forEach((el) => {
            if (el.tagName === "STRONG") {
              if (currentSection) {
                sections.push(currentSection);
                currentSection = null;
              }
              currentSection = SettingsSection_default.fromHeaderElement(el);
            } else {
              if (!currentSection) {
                console.error("Found setting without section: ", el);
                currentSection = new SettingsSection_default("Other");
              }
              const settingsRow = settingsRowFromElement(el);
              currentSection.addSettingsRow(settingsRow);
            }
          });
          if (currentSection) {
            sections.push(currentSection);
          }
          const settingsPanel2 = document.createElement("div");
          settingsPanel2.classList.add("settings-panel");
          sections.forEach((section) => {
            settingsPanel2.appendChild(section.getElement());
          });
          this.settingsPanelElement = settingsPanel2;
          this.settingsPanelContainerElement.appendChild(settingsPanel2);
          settingsListElement.remove();
          this.sections = sections;
          this.settingsPanelContainerElement.appendChild(Object.assign(document.createElement("div"), {
            className: "settings-panel-footer",
            innerHTML: '<div><i class="fas fa-info-circle"></i> <span>Shift click to toggle all sections</span></div>'
          }));
          resolve();
        }, 500);
      });
    }
    addSettingsNotificationElement() {
      const settingsNotificationContainer = Object.assign(document.createElement("div"), {
        id: "settings-notification-container"
      });
      const settingsNotificationElement = document.createElement("div");
      settingsNotificationElement.classList.add("notification");
      settingsNotificationElement.innerHTML = `
            <span class="message-icon"><i class="fas fa-circle-info"></i></span>
            <span class="message"></span>
            <button class="btn btn-primary">Reload</button>
        `;
      settingsNotificationElement.querySelector("button").addEventListener("click", () => {
        window.location.reload();
      });
      settingsNotificationContainer.appendChild(settingsNotificationElement);
      document.body.appendChild(settingsNotificationContainer);
      this.notificationElement = settingsNotificationContainer;
    }
    showNotification(message) {
      this.notificationElement.classList.add("visible");
      this.notificationElement.querySelector(".message").innerText = message;
    }
    hideNotification() {
      this.notificationElement.classList.remove("visible");
    }
    populateKUPSettings() {
      const section = new SettingsSection_default("Kbin Usability Pack");
      section.addSettingsRows([
        new SettingsRowBoolean_default("Show URL subheader", true, {
          id: "showUrlSubheader",
          description: "Show the link URL beneath the title"
        }),
        new SettingsRowBoolean_default("Remove comment anchor", true, {
          id: "removeCommentAnchor",
          description: "Make the comment links go to the top of the article instead of the comments section.",
          requireReload: true
        }),
        new SettingsRowBoolean_default("Show article preview button", true, {
          id: "showArticlePreview"
        })
      ]);
      this.addSection(section);
    }
  };
  var SettingsPanel_default = SettingsPanel;

  // src/index.js
  var articlesHandler = new ArticlesHandler_default();
  var navigator = new Navigator_default();
  var articlePage = new ArticlePage_default();
  var settingsPanel = new SettingsPanel_default();
  articlesHandler.init();
  navigator.init();
  articlePage.init();
  settingsPanel.init();
})();
})();