▲V2EX Polish - 体验更现代化的 V2EX 🟢

一款专为 V2EX 用户设计的浏览器插件,提供了丰富的扩展功能,让原生页面焕然一新!✨

// ==UserScript==
// @name         ▲V2EX Polish - 体验更现代化的 V2EX 🟢
// @namespace    https://v2p.app
// @version      2.0.5
// @description  一款专为 V2EX 用户设计的浏览器插件,提供了丰富的扩展功能,让原生页面焕然一新!✨
// @author       LeoKu(https://leoku.dev)
// @match        https://*.v2ex.com/*
// @match        https://v2ex.com/*
// @icon         https://v2p.app/favicon.svg
// @run-at       document-start
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

"use strict";
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res) => function __init() {
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};

// src/contents/polyfill.ts
var init_polyfill = __esm({
  "src/contents/polyfill.ts"() {
    "use strict";
    {
      if (!window.requestIdleCallback) {
        window.requestIdleCallback = function(callback) {
          const start = Date.now();
          return setTimeout(function() {
            callback({
              didTimeout: false,
              timeRemaining: function() {
                return Math.max(0, 50 - (Date.now() - start));
              }
            });
          }, 1);
        };
      }
      if (!window.cancelIdleCallback) {
        window.cancelIdleCallback = function(id) {
          clearTimeout(id);
        };
      }
    }
  }
});

// src/constants.ts
var EXTENSION_NAME, emojiLinks, emoticons, READABLE_CONTENT_HEIGHT, MAX_CONTENT_HEIGHT, READING_CONTENT_LIMIT, dataExpiryTime, imgurClientIdPool, defaultOptions;
var init_constants = __esm({
  "src/constants.ts"() {
    "use strict";
    EXTENSION_NAME = "V2EX_Polish";
    emojiLinks = {
      // B 站表情。
      ["[\u8131\u5355doge]" /* 脱单doge */]: {
        ld: "https://i.imgur.com/L62ZP7V.png",
        hd: "https://i.imgur.com/3mPhudo.png"
      },
      ["[doge]" /* doge */]: {
        ld: "https://i.imgur.com/agAJ0Rd.png",
        hd: "https://i.imgur.com/HZL0hOa.png"
      },
      ["[\u8FA3\u773C\u775B]" /* 辣眼睛 */]: {
        ld: "https://i.imgur.com/n119Wvk.png",
        hd: "https://i.imgur.com/A5WXoZJ.png"
      },
      ["[\u7591\u60D1]" /* 疑惑 */]: {
        ld: "https://i.imgur.com/U3hKhrT.png",
        hd: "https://i.imgur.com/3gCygBS.png"
      },
      ["[\u6342\u8138]" /* 捂脸 */]: {
        ld: "https://i.imgur.com/14cwgsI.png",
        hd: "https://i.imgur.com/fLp3t8s.png"
      },
      ["[\u54E6\u547C]" /* 哦呼 */]: {
        ld: "https://i.imgur.com/km62MY2.png",
        hd: "https://i.imgur.com/CXXgF4E.png"
      },
      ["[\u50B2\u5A07]" /* 傲娇 */]: {
        ld: "https://i.imgur.com/TkdeN49.png",
        hd: "https://i.imgur.com/m7IlCrD.png"
      },
      ["[\u601D\u8003]" /* 思考 */]: {
        ld: "https://i.imgur.com/MAyk5GN.png",
        hd: "https://i.imgur.com/eRJTCx7.png"
      },
      ["[\u5403\u74DC]" /* 吃瓜 */]: {
        ld: "https://i.imgur.com/Ug1iMq4.png",
        hd: "https://i.imgur.com/Gy3nwkC.png"
      },
      ["[\u65E0\u8BED]" /* 无语 */]: {
        ld: "https://i.imgur.com/e1q9ScT.png",
        hd: "https://i.imgur.com/wMfcBqD.png"
      },
      ["[\u5927\u54ED]" /* 大哭 */]: {
        ld: "https://i.imgur.com/YGIx7lh.png",
        hd: "https://i.imgur.com/SNHJxtv.png"
      },
      ["[\u9178\u4E86]" /* 酸了 */]: {
        ld: "https://i.imgur.com/5FDsp6L.png",
        hd: "https://i.imgur.com/wnQBodT.png"
      },
      ["[\u6253call]" /* 打call */]: {
        ld: "https://i.imgur.com/pmNOo2w.png",
        hd: "https://i.imgur.com/4GfTlV0.png"
      },
      ["[\u6B6A\u5634]" /* 歪嘴 */]: {
        ld: "https://i.imgur.com/XzEYBoY.png",
        hd: "https://i.imgur.com/84ycU43.png"
      },
      ["[\u661F\u661F\u773C]" /* 星星眼 */]: {
        ld: "https://i.imgur.com/2spsghH.png",
        hd: "https://i.imgur.com/oEIJRru.png"
      },
      ["[OK]" /* OK */]: {
        ld: "https://i.imgur.com/6DMydmQ.png",
        hd: "https://i.imgur.com/PE2dyjY.png"
      },
      ["[\u8DEA\u4E86]" /* 跪了 */]: {
        ld: "https://i.imgur.com/TYtySHv.png",
        hd: "https://i.imgur.com/0pjsMf0.png"
      },
      ["[\u54CD\u6307]" /* 响指 */]: {
        ld: "https://i.imgur.com/Ac88cMm.png",
        hd: "https://i.imgur.com/nkoevMu.png"
      },
      ["[\u8C03\u76AE]" /* 调皮 */]: {
        ld: "https://i.imgur.com/O6ZZSLk.png",
        hd: "https://i.imgur.com/ggHTLzH.png"
      },
      ["[\u7B11\u54ED]" /* 笑哭 */]: {
        ld: "https://i.imgur.com/NIvxivj.png",
        hd: "https://i.imgur.com/h8edr5G.png"
      },
      ["[\u55D1\u74DC\u5B50]" /* 嗑瓜子 */]: {
        ld: "https://i.imgur.com/rjR4rdr.png",
        hd: "https://i.imgur.com/GMzq0tq.png"
      },
      ["[\u559C\u6781\u800C\u6CE3]" /* 喜极而泣 */]: {
        ld: "https://i.imgur.com/N9E3iZ2.png",
        hd: "https://i.imgur.com/L1N27tb.png"
      },
      ["[\u60CA\u8BB6]" /* 惊讶 */]: {
        ld: "https://i.imgur.com/aptfuiN.png",
        hd: "https://i.imgur.com/cuzxGOI.png"
      },
      ["[\u7ED9\u5FC3\u5FC3]" /* 给心心 */]: {
        ld: "https://i.imgur.com/4aXVwxJ.png",
        hd: "https://i.imgur.com/q663Mor.png"
      },
      ["[\u5446]" /* 呆 */]: {
        ld: "https://i.imgur.com/c1Q76Cd.png",
        hd: "https://i.imgur.com/xMXlmxm.png"
      },
      // 小红薯表情。
      ["[\u54ED\u60F9R]" /* 哭惹 */]: {
        ld: "https://i.imgur.com/HgxsUD2.png",
        hd: "https://i.imgur.com/0aOdQJd.png"
      },
      ["[\u54C7R]" /* 哇 */]: {
        ld: "https://i.imgur.com/OZySWIG.png",
        hd: "https://i.imgur.com/ngoi2I6.png"
      },
      ["[\u6C57\u989CR]" /* 汗颜 */]: {
        ld: "https://i.imgur.com/jrVZoLi.png",
        hd: "https://i.imgur.com/O8alqc1.png"
      },
      ["[\u5BB3\u7F9ER]" /* 害羞 */]: {
        ld: "https://i.imgur.com/OVQjxIr.png",
        hd: "https://i.imgur.com/1PeoVR5.png"
      },
      ["[\u840C\u840C\u54D2R]" /* 萌萌哒 */]: {
        ld: "https://i.imgur.com/Ue1kikn.png",
        hd: "https://i.imgur.com/vOHzwus.png"
      },
      ["[\u5077\u7B11R]" /* 偷笑 */]: {
        ld: "https://i.imgur.com/aF7QiE5.png",
        hd: "https://i.imgur.com/WneGpK9.png"
      },
      ["[\u4E70\u7206R]" /* 买爆 */]: {
        ld: "https://i.imgur.com/2JhZFtb.png",
        hd: "https://i.imgur.com/za9t585.png"
      },
      ["[\u8272\u8272R]" /* 色色 */]: {
        ld: "https://i.imgur.com/ZA1jRv1.png",
        hd: "https://i.imgur.com/mEGRKJy.png"
      },
      ["[\u62A0\u9F3BR]" /* 抠鼻 */]: {
        ld: "https://i.imgur.com/pYtTFnj.png",
        hd: "https://i.imgur.com/ErnQrMJ.png"
      },
      ["[\u9ED1\u85AF\u95EE\u53F7R]" /* 黑薯问号 */]: {
        ld: "https://i.imgur.com/aCjmFLD.png",
        hd: "https://i.imgur.com/i4Wgtyv.png"
      },
      ["[\u6276\u5899R]" /* 扶墙 */]: {
        ld: "https://i.imgur.com/RV7y6tR.png",
        hd: "https://i.imgur.com/PjhjZsJ.png"
      },
      ["[\u9119\u89C6R]" /* 鄙视 */]: {
        ld: "https://i.imgur.com/LaO5dh3.png",
        hd: "https://i.imgur.com/StrGaFx.png"
      },
      ["[\u8E72R]" /* 蹲 */]: {
        ld: "https://i.imgur.com/t876WSv.png",
        hd: "https://i.imgur.com/jdTq0YI.png"
      },
      ["[\u5E86\u795DR]" /* 庆祝 */]: {
        ld: "https://i.imgur.com/wQw2kD0.png",
        hd: "https://i.imgur.com/lx6jrkm.png"
      },
      ["[\u516DR]" /* 六 */]: {
        ld: "https://i.imgur.com/JqoC4L5.png",
        hd: "https://i.imgur.com/cUVWKc2.png"
      },
      ["[\u53EFR]" /* 可 */]: {
        ld: "https://i.imgur.com/I70yy88.png",
        hd: "https://i.imgur.com/nRgXwUT.png"
      },
      ["[\u52A0\u4E00R]" /* 加一 */]: {
        ld: "https://i.imgur.com/hpVvbVh.png",
        hd: "https://i.imgur.com/abBCCK9.png"
      }
    };
    emoticons = [
      {
        title: "\u6D41\u884C",
        list: [
          "[\u8131\u5355doge]" /* 脱单doge */,
          "[doge]" /* doge */,
          "[\u6253call]" /* 打call */,
          "[\u661F\u661F\u773C]" /* 星星眼 */,
          "[\u5403\u74DC]" /* 吃瓜 */,
          "[OK]" /* OK */,
          "[\u54E6\u547C]" /* 哦呼 */,
          "[\u601D\u8003]" /* 思考 */,
          "[\u7591\u60D1]" /* 疑惑 */,
          "[\u8FA3\u773C\u775B]" /* 辣眼睛 */,
          "[\u50B2\u5A07]" /* 傲娇 */,
          "[\u6342\u8138]" /* 捂脸 */,
          "[\u65E0\u8BED]" /* 无语 */,
          "[\u5927\u54ED]" /* 大哭 */,
          "[\u9178\u4E86]" /* 酸了 */,
          "[\u6B6A\u5634]" /* 歪嘴 */,
          "[\u8C03\u76AE]" /* 调皮 */,
          "[\u7B11\u54ED]" /* 笑哭 */,
          "[\u55D1\u74DC\u5B50]" /* 嗑瓜子 */,
          "[\u559C\u6781\u800C\u6CE3]" /* 喜极而泣 */,
          "[\u60CA\u8BB6]" /* 惊讶 */,
          "[\u7ED9\u5FC3\u5FC3]" /* 给心心 */,
          "[\u5446]" /* 呆 */,
          "[\u8DEA\u4E86]" /* 跪了 */,
          "[\u54CD\u6307]" /* 响指 */,
          "[\u54C7R]" /* 哇 */,
          "[\u840C\u840C\u54D2R]" /* 萌萌哒 */,
          "[\u5BB3\u7F9ER]" /* 害羞 */,
          "[\u5077\u7B11R]" /* 偷笑 */,
          "[\u54ED\u60F9R]" /* 哭惹 */,
          "[\u6C57\u989CR]" /* 汗颜 */,
          "[\u8272\u8272R]" /* 色色 */,
          "[\u62A0\u9F3BR]" /* 抠鼻 */,
          "[\u9119\u89C6R]" /* 鄙视 */,
          "[\u4E70\u7206R]" /* 买爆 */,
          "[\u9ED1\u85AF\u95EE\u53F7R]" /* 黑薯问号 */,
          "[\u6276\u5899R]" /* 扶墙 */,
          "[\u8E72R]" /* 蹲 */,
          "[\u53EFR]" /* 可 */,
          "[\u516DR]" /* 六 */,
          "[\u52A0\u4E00R]" /* 加一 */,
          "[\u5E86\u795DR]" /* 庆祝 */
        ]
      },
      {
        title: "\u5C0F\u9EC4\u8138",
        list: [
          "\u{1F600}",
          "\u{1F601}",
          "\u{1F602}",
          "\u{1F923}",
          "\u{1F605}",
          "\u{1F60A}",
          "\u{1F60B}",
          "\u{1F618}",
          "\u{1F970}",
          "\u{1F617}",
          "\u{1F929}",
          "\u{1F914}",
          "\u{1F928}",
          "\u{1F610}",
          "\u{1F611}",
          "\u{1F644}",
          "\u{1F60F}",
          "\u{1F62A}",
          "\u{1F62B}",
          "\u{1F971}",
          "\u{1F61C}",
          "\u{1F612}",
          "\u{1F614}",
          "\u{1F628}",
          "\u{1F630}",
          "\u{1F631}",
          "\u{1F975}",
          "\u{1F621}",
          "\u{1F973}",
          "\u{1F97A}",
          "\u{1F92D}",
          "\u{1F9D0}",
          "\u{1F60E}",
          "\u{1F913}",
          "\u{1F62D}",
          "\u{1F911}",
          "\u{1F92E}"
        ]
      },
      {
        title: "\u624B\u52BF",
        list: [
          "\u{1F64B}",
          "\u{1F64E}",
          "\u{1F645}",
          "\u{1F647}",
          "\u{1F937}",
          "\u{1F90F}",
          "\u{1F449}",
          "\u270C\uFE0F",
          "\u{1F918}",
          "\u{1F919}",
          "\u{1F44C}",
          "\u{1F90C}",
          "\u{1F44D}",
          "\u{1F44E}",
          "\u{1F44B}",
          "\u{1F91D}",
          "\u{1F64F}",
          "\u{1F44F}"
        ]
      },
      {
        title: "\u5E86\u795D",
        list: ["\u2728", "\u{1F389}", "\u{1F38A}"]
      },
      {
        title: "\u5176\u4ED6",
        list: ["\u{1F47B}", "\u{1F921}", "\u{1F414}", "\u{1F440}", "\u{1F4A9}", "\u{1F434}", "\u{1F984}", "\u{1F427}", "\u{1F436}", "\u{1F412}", "\u{1F648}", "\u{1F649}", "\u{1F64A}", "\u{1F435}"]
      }
    ];
    READABLE_CONTENT_HEIGHT = 250;
    MAX_CONTENT_HEIGHT = 550;
    READING_CONTENT_LIMIT = 150;
    dataExpiryTime = 60 * 60 * 1e3;
    imgurClientIdPool = [
      "3107b9ef8b316f3",
      // 以下 Client ID 来自「V2EX Plus」
      "442b04f26eefc8a",
      "59cfebe717c09e4",
      "60605aad4a62882",
      "6c65ab1d3f5452a",
      "83e123737849aa9",
      "9311f6be1c10160",
      "c4a4a563f698595",
      "81be04b9e4a08ce"
    ];
    defaultOptions = {
      openInNewTab: false,
      autoCheckIn: {
        enabled: true
      },
      theme: {
        autoSwitch: false
      },
      reply: {
        preload: "auto",
        layout: "vertical"
      },
      replyContent: {
        autoFold: true,
        hideReplyTime: true,
        hideRefName: true,
        showImgInPage: true
      },
      nestedReply: {
        display: "indent",
        multipleInsideOne: "nested"
      },
      userTag: {
        display: "inline"
      },
      contextMenu: {
        enabled: true
      }
    };
  }
});

// src/icons.ts
var iconLogo, iconGitHub;
var init_icons = __esm({
  "src/icons.ts"() {
    "use strict";
    iconLogo = `
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 88 88"><g style="mix-blend-mode:passthrough"><path d="M87.92 86.098v-.052a.592.592 0 0 0 0-.07L44.978.72l-.059-.105c-.16-.3-.415-.511-.705-.586a.961.961 0 0 0-.841.19 1.315 1.315 0 0 0-.336.378l-.058.115a2571.004 2571.004 0 0 1-8.695 17.172c-.59 1.024-.59 2.382 0 3.406 3.856 7.57 7.7 15.142 11.532 22.718.641 1.108.641 2.58 0 3.688C39.5 60.23 32.826 73.406 26.45 85.993c-.291.661-.086 1.482.46 1.84.16.104.341.158.525.158h18.52c.415.003.797-.272.992-.713l.635-1.285 8.585-17.023c.142-.317.383-.552.67-.653a.949.949 0 0 1 .855.116c.156.1.289.245.386.423l8.506 16.723.787 1.558c.199.433.575.702.985.704h.518c.087.009.175.009.263 0h17.74c.617 0 1.119-.601 1.123-1.347a1.615 1.615 0 0 0-.08-.396Z" fill="currentColor" style="mix-blend-mode:passthrough"/><path d="m38.551 48.541.62-1.232a3.095 3.095 0 0 0 0-3.02l-3.807-7.446-4.377-8.511c-.155-.308-.406-.527-.697-.61a.957.957 0 0 0-.85.17 1.252 1.252 0 0 0-.4.502L.132 86.002c-.29.658-.085 1.477.46 1.83.161.113.345.17.532.168h16.981c.41 0 .788-.27.985-.705l.65-1.302c.029-.048.055-.098.08-.15l.729-1.408c6.047-12.103 11.839-23.66 17.9-35.7.038-.062.072-.127.102-.194Z" fill="currentColor" style="mix-blend-mode:passthrough"/></g></svg>
`;
    iconGitHub = `
<svg viewBox="0 0 24 24" aria-hidden="true">
  <path fill="currentColor" clip-rule="evenodd" d="M12 2C6.477 2 2 6.463 2 11.97c0 4.404 2.865 8.14 6.839 9.458.5.092.682-.216.682-.48 0-.236-.008-.864-.013-1.695-2.782.602-3.369-1.337-3.369-1.337-.454-1.151-1.11-1.458-1.11-1.458-.908-.618.069-.606.069-.606 1.003.07 1.531 1.027 1.531 1.027.892 1.524 2.341 1.084 2.91.828.092-.643.35-1.083.636-1.332-2.22-.251-4.555-1.107-4.555-4.927 0-1.088.39-1.979 1.029-2.675-.103-.252-.446-1.266.098-2.638 0 0 .84-.268 2.75 1.022A9.607 9.607 0 0 1 12 6.82c.85.004 1.705.114 2.504.336 1.909-1.29 2.747-1.022 2.747-1.022.546 1.372.202 2.386.1 2.638.64.696 1.028 1.587 1.028 2.675 0 3.83-2.339 4.673-4.566 4.92.359.307.678.915.678 1.846 0 1.332-.012 2.407-.012 2.734 0 .267.18.577.688.48 3.97-1.32 6.833-5.054 6.833-9.458C22 6.463 17.522 2 12 2Z"></path>
</svg>
`;
  }
});

// src/utils.ts
function getOS() {
  const userAgent = window.navigator.userAgent.toLowerCase();
  const macosPlatforms = /(macintosh|macintel|macppc|mac68k|macos)/i;
  const windowsPlatforms = /(win32|win64|windows|wince)/i;
  const iosPlatforms = /(iphone|ipad|ipod)/i;
  let os = null;
  if (macosPlatforms.test(userAgent)) {
    os = "macos";
  } else if (iosPlatforms.test(userAgent)) {
    os = "ios";
  } else if (windowsPlatforms.test(userAgent)) {
    os = "windows";
  } else if (userAgent.includes("android")) {
    os = "android";
  } else if (userAgent.includes("linux")) {
    os = "linux";
  }
  return os;
}
function formatTimestamp(timestamp, { format = "YMD" } = {}) {
  const date = new Date(timestamp.toString().length === 10 ? timestamp * 1e3 : timestamp);
  const year = date.getFullYear().toString();
  const month = (date.getMonth() + 1).toString().padStart(2, "0");
  const day = date.getDate().toString().padStart(2, "0");
  const YMD = `${year}-${month}-${day}`;
  if (format === "YMDHM") {
    const hour = date.getHours().toString().padStart(2, "0");
    const minute = date.getMinutes().toString().padStart(2, "0");
    return `${YMD} ${hour}:${minute}`;
  }
  if (format === "YMDHMS") {
    const hour = date.getHours().toString().padStart(2, "0");
    const minute = date.getMinutes().toString().padStart(2, "0");
    const second = date.getSeconds().toString().padStart(2, "0");
    return `${YMD} ${hour}:${minute}:${second}`;
  }
  return YMD;
}
function isSameDay(timestamp1, timestamp2) {
  const date1 = new Date(timestamp1);
  const date2 = new Date(timestamp2);
  return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate();
}
function isObject(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
function deepMerge(target, source) {
  const result = {};
  for (const key in target) {
    const targetProp = target[key];
    const sourceProp = source[key];
    if (isObject(targetProp) && isObject(sourceProp)) {
      result[key] = deepMerge(targetProp, sourceProp);
    } else if (Reflect.has(source, key)) {
      result[key] = sourceProp;
    } else {
      result[key] = targetProp;
    }
  }
  for (const key in source) {
    if (!Reflect.has(target, key)) {
      result[key] = source[key];
    }
  }
  return result;
}
function getRunEnv() {
  if (typeof chrome === "object" && typeof chrome.extension !== "undefined") {
    return "chrome";
  }
  if (typeof browser === "object" && typeof browser.extension !== "undefined") {
    return "web-ext";
  }
  return null;
}
function isBrowserExtension() {
  const runEnv = getRunEnv();
  return runEnv === "chrome" || runEnv === "web-ext";
}
function escapeHTML(htmlString) {
  return htmlString.replace(/[<>&"'']/g, (match) => {
    switch (match) {
      case "<":
        return "&lt;";
      case ">":
        return "&gt;";
      case "&":
        return "&amp;";
      case '"':
        return "&quot;";
      case "'":
        return "&#39;";
      default:
        return match;
    }
  });
}
function injectScript(scriptSrc) {
  const script = document.createElement("script");
  script.setAttribute("type", "text/javascript");
  script.setAttribute("src", scriptSrc);
  document.body.appendChild(script);
}
function isValidSettings(settings) {
  return !!settings && typeof settings === "object" && "options" /* Options */ in settings;
}
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
async function getV2P_Settings() {
  let noteId;
  {
    const res = await fetch(`${V2EX_ORIGIN}/notes`);
    const htmlText = await res.text();
    const $page = $(htmlText);
    const $note = $page.find('.note_item > .note_item_title > a[href^="/notes"]');
    $note.each((_, dom) => {
      const $dom = $(dom);
      if ($dom.text().startsWith(mark)) {
        const href = $dom.attr("href");
        if (typeof href === "string") {
          const id = href.split("/").at(2);
          noteId = id;
        }
        return false;
      }
    });
  }
  if (noteId) {
    const res = await fetch(`${V2EX_ORIGIN}/notes/edit/${noteId}`);
    const htmlText = await res.text();
    const $editor = $(htmlText).find("#note_content.note_editor");
    const value = $editor.val();
    if (typeof value === "string") {
      const syncSettings = JSON.parse(value.replace(mark, ""));
      if (isValidSettings(syncSettings)) {
        return { noteId, config: syncSettings };
      }
    }
  }
}
async function setV2P_Settings(storageSettings, signal) {
  const data = await getV2P_Settings();
  const updating = !!data;
  const formData = new FormData();
  const syncVersion = updating ? data.config["settings-sync" /* SyncInfo */].version + 1 : 1;
  const syncInfo = {
    version: syncVersion,
    lastSyncTime: Date.now()
  };
  formData.append(
    "content",
    mark + JSON.stringify({ ...storageSettings, ["settings-sync" /* SyncInfo */]: syncInfo })
  );
  formData.append("syntax", "0");
  if (updating) {
    const { noteId } = data;
    await fetch(`${V2EX_ORIGIN}/notes/edit/${noteId}`, {
      method: "POST",
      body: formData,
      signal
    });
  } else {
    formData.append("parent_id", "0");
    await fetch(`${V2EX_ORIGIN}/notes/new`, {
      method: "POST",
      body: formData,
      signal
    });
  }
  await setStorage("settings-sync" /* SyncInfo */, syncInfo);
  return syncInfo;
}
function getStorage(useCache = true) {
  return new Promise((resolve, reject) => {
    if (useCache) {
      if (window.__V2P_StorageCache) {
        resolve(window.__V2P_StorageCache);
      }
    }
    if (!isBrowserExtension()) {
      const data = { ["options" /* Options */]: defaultOptions };
      if (typeof window !== "undefined") {
        window.__V2P_StorageCache = data;
      }
      resolve(data);
    } else {
      chrome.storage.sync.get().then((items) => {
        let data;
        const options = items["options" /* Options */];
        if (options) {
          data = { ...items, ["options" /* Options */]: deepMerge(defaultOptions, options) };
        } else {
          data = { ...items, ["options" /* Options */]: defaultOptions };
        }
        if (typeof window !== "undefined") {
          window.__V2P_StorageCache = data;
        }
        resolve(data);
      }).catch(() => {
        reject(new Error("\u83B7\u53D6\u6269\u5C55\u914D\u7F6E\u5931\u8D25\u3002"));
      });
    }
  });
}
function getStorageSync() {
  const storage = window.__V2P_StorageCache;
  if (!storage) {
    throw new Error(`${EXTENSION_NAME}: \u65E0\u53EF\u7528\u7684 Storage \u7F13\u5B58\u6570\u636E`);
  }
  return storage;
}
async function setStorage(storageKey, storageItem) {
  switch (storageKey) {
    case "options" /* Options */:
    case "api" /* API */:
    case "daily" /* Daily */:
    case "member-tag" /* MemberTag */:
    case "settings-sync" /* SyncInfo */:
    case "reading-list" /* ReadingList */:
      try {
        await chrome.storage.sync.set({ [storageKey]: storageItem });
        if (storageKey !== "api" /* API */ && storageKey !== "settings-sync" /* SyncInfo */ && typeof $ !== "undefined") {
          const settings = await getStorage(false);
          if (controller) {
            controller.abort();
          }
          controller = new AbortController();
          setV2P_Settings(settings, controller.signal);
        }
      } catch (err) {
        if (String(err).includes("QUOTA_BYTES_PER_ITEM quota exceeded")) {
          console.error(
            `${EXTENSION_NAME}: \u65E0\u6CD5\u8BBE\u7F6E ${storageKey}\uFF0C \u5355\u4E2A item \u4E0D\u80FD\u8D85\u51FA 8 KB\uFF0C\u8BE6\u60C5\u67E5\u770B\uFF1Ahttps://developer.chrome.com/docs/extensions/reference/storage/#storage-areas`
          );
        }
        console.error(err);
        throw new Error(`\u274C \u65E0\u6CD5\u8BBE\u7F6E\uFF1A${storageKey}`);
      }
      break;
    default:
      throw new Error(`\u672A\u77E5\u7684 storageKey\uFF1A ${storageKey}`);
  }
}
var V2EX_ORIGIN, mark, controller;
var init_utils = __esm({
  "src/utils.ts"() {
    "use strict";
    init_constants();
    V2EX_ORIGIN = typeof window !== "undefined" && window.location.origin.includes("v2ex.com") ? window.location.origin : "https://www.v2ex.com" /* Origin */;
    mark = `${EXTENSION_NAME}_settings`;
    controller = null;
  }
});

// src/contents/globals.ts
function updateCommentCells() {
  $commentCells = $commentBox.find('.cell[id^="r_"]');
  $commentTableRows = $commentCells.find("> table > tbody > tr");
}
var $body, $wrapper, $wrapperContent, $main, $topicList, $infoCard, $topicContentBox, $topicHeader, $commentBox, $commentCells, $commentTableRows, $replyBox, $replyForm, $replyTextArea, replyTextArea, loginName, topicOwnerName, pathTopicId;
var init_globals = __esm({
  "src/contents/globals.ts"() {
    "use strict";
    $body = $(document.body);
    $wrapper = $("#Wrapper");
    $wrapperContent = $wrapper.find("> .content");
    $main = $("#Main");
    $topicList = $(
      "#Main #Tabs ~ .cell.item, #Main #TopicsNode > .cell, #Main .cell.item:has(.item_title > .topic-link)"
    );
    $infoCard = $('#Rightbar > .box:has("#member-activity")');
    $topicContentBox = $("#Main .box:has(.topic_buttons)");
    $topicHeader = $topicContentBox.find(".header");
    $commentBox = $('#Main .box:has(.cell[id^="r_"])');
    $commentCells = $commentBox.find('.cell[id^="r_"]');
    $commentTableRows = $commentCells.find("> table > tbody > tr");
    $replyBox = $("#reply-box");
    $replyForm = $replyBox.find('form[action^="/t"]');
    $replyTextArea = $("#reply_content");
    replyTextArea = document.querySelector("#reply_content");
    loginName = $('#Top .tools > a[href^="/member"]').text();
    topicOwnerName = $topicHeader.find('> small > a[href^="/member"]').text();
    pathTopicId = window.location.pathname.match(/\/t\/(\d+)/)?.at(1);
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/createElement.js
var createElement, createElement$1;
var init_createElement = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/createElement.js"() {
    "use strict";
    createElement = (tag, attrs, children = []) => {
      const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
      Object.keys(attrs).forEach((name) => {
        element.setAttribute(name, String(attrs[name]));
      });
      if (children.length) {
        children.forEach((child) => {
          const childElement = createElement(...child);
          element.appendChild(childElement);
        });
      }
      return element;
    };
    createElement$1 = ([tag, attrs, children]) => createElement(tag, attrs, children);
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/replaceElement.js
var getAttrs, getClassNames, combineClassNames, toPascalCase, replaceElement;
var init_replaceElement = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/replaceElement.js"() {
    "use strict";
    init_createElement();
    getAttrs = (element) => Array.from(element.attributes).reduce((attrs, attr) => {
      attrs[attr.name] = attr.value;
      return attrs;
    }, {});
    getClassNames = (attrs) => {
      if (typeof attrs === "string")
        return attrs;
      if (!attrs || !attrs.class)
        return "";
      if (attrs.class && typeof attrs.class === "string") {
        return attrs.class.split(" ");
      }
      if (attrs.class && Array.isArray(attrs.class)) {
        return attrs.class;
      }
      return "";
    };
    combineClassNames = (arrayOfClassnames) => {
      const classNameArray = arrayOfClassnames.flatMap(getClassNames);
      return classNameArray.map((classItem) => classItem.trim()).filter(Boolean).filter((value, index, self) => self.indexOf(value) === index).join(" ");
    };
    toPascalCase = (string) => string.replace(/(\w)(\w*)(_|-|\s*)/g, (g0, g1, g2) => g1.toUpperCase() + g2.toLowerCase());
    replaceElement = (element, { nameAttr, icons, attrs }) => {
      const iconName = element.getAttribute(nameAttr);
      if (iconName == null)
        return;
      const ComponentName = toPascalCase(iconName);
      const iconNode = icons[ComponentName];
      if (!iconNode) {
        return console.warn(
          `${element.outerHTML} icon name was not found in the provided icons object.`
        );
      }
      const elementAttrs = getAttrs(element);
      const [tag, iconAttributes, children] = iconNode;
      const iconAttrs = {
        ...iconAttributes,
        "data-lucide": iconName,
        ...attrs,
        ...elementAttrs
      };
      const classNames = combineClassNames(["lucide", `lucide-${iconName}`, elementAttrs, attrs]);
      if (classNames) {
        Object.assign(iconAttrs, {
          class: classNames
        });
      }
      const svgElement = createElement$1([tag, iconAttrs, children]);
      return element.parentNode?.replaceChild(svgElement, element);
    };
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/defaultAttributes.js
var defaultAttributes;
var init_defaultAttributes = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/defaultAttributes.js"() {
    "use strict";
    defaultAttributes = {
      xmlns: "http://www.w3.org/2000/svg",
      width: 24,
      height: 24,
      viewBox: "0 0 24 24",
      fill: "none",
      stroke: "currentColor",
      "stroke-width": 2,
      "stroke-linecap": "round",
      "stroke-linejoin": "round"
    };
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/book-open-check.js
var BookOpenCheck;
var init_book_open_check = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/book-open-check.js"() {
    "use strict";
    init_defaultAttributes();
    BookOpenCheck = [
      "svg",
      defaultAttributes,
      [
        ["path", { d: "M12 21V7" }],
        ["path", { d: "m16 12 2 2 4-4" }],
        [
          "path",
          {
            d: "M22 6V4a1 1 0 0 0-1-1h-5a4 4 0 0 0-4 4 4 4 0 0 0-4-4H3a1 1 0 0 0-1 1v13a1 1 0 0 0 1 1h6a3 3 0 0 1 3 3 3 3 0 0 1 3-3h6a1 1 0 0 0 1-1v-1.3"
          }
        ]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/chevron-down.js
var ChevronDown;
var init_chevron_down = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/chevron-down.js"() {
    "use strict";
    init_defaultAttributes();
    ChevronDown = ["svg", defaultAttributes, [["path", { d: "m6 9 6 6 6-6" }]]];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/chevrons-up.js
var ChevronsUp;
var init_chevrons_up = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/chevrons-up.js"() {
    "use strict";
    init_defaultAttributes();
    ChevronsUp = [
      "svg",
      defaultAttributes,
      [
        ["path", { d: "m17 11-5-5-5 5" }],
        ["path", { d: "m17 18-5-5-5 5" }]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/eye-off.js
var EyeOff;
var init_eye_off = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/eye-off.js"() {
    "use strict";
    init_defaultAttributes();
    EyeOff = [
      "svg",
      defaultAttributes,
      [
        [
          "path",
          {
            d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"
          }
        ],
        ["path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }],
        [
          "path",
          {
            d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"
          }
        ],
        ["path", { d: "m2 2 20 20" }]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/heart.js
var Heart;
var init_heart = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/heart.js"() {
    "use strict";
    init_defaultAttributes();
    Heart = [
      "svg",
      defaultAttributes,
      [
        [
          "path",
          {
            d: "M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"
          }
        ]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/house.js
var House;
var init_house = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/house.js"() {
    "use strict";
    init_defaultAttributes();
    House = [
      "svg",
      defaultAttributes,
      [
        ["path", { d: "M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8" }],
        [
          "path",
          {
            d: "M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"
          }
        ]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/message-square-plus.js
var MessageSquarePlus;
var init_message_square_plus = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/message-square-plus.js"() {
    "use strict";
    init_defaultAttributes();
    MessageSquarePlus = [
      "svg",
      defaultAttributes,
      [
        ["path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }],
        ["path", { d: "M12 7v6" }],
        ["path", { d: "M9 10h6" }]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/message-square.js
var MessageSquare;
var init_message_square = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/message-square.js"() {
    "use strict";
    init_defaultAttributes();
    MessageSquare = [
      "svg",
      defaultAttributes,
      [["path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }]]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/moon.js
var Moon;
var init_moon = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/moon.js"() {
    "use strict";
    init_defaultAttributes();
    Moon = [
      "svg",
      defaultAttributes,
      [["path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" }]]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/package-plus.js
var PackagePlus;
var init_package_plus = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/package-plus.js"() {
    "use strict";
    init_defaultAttributes();
    PackagePlus = [
      "svg",
      defaultAttributes,
      [
        ["path", { d: "M16 16h6" }],
        ["path", { d: "M19 13v6" }],
        [
          "path",
          {
            d: "M21 10V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l2-1.14"
          }
        ],
        ["path", { d: "m7.5 4.27 9 5.15" }],
        ["polyline", { points: "3.29 7 12 12 20.71 7" }],
        ["line", { x1: "12", x2: "12", y1: "22", y2: "12" }]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/panel-right.js
var PanelRight;
var init_panel_right = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/panel-right.js"() {
    "use strict";
    init_defaultAttributes();
    PanelRight = [
      "svg",
      defaultAttributes,
      [
        ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }],
        ["path", { d: "M15 3v18" }]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/panel-top.js
var PanelTop;
var init_panel_top = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/panel-top.js"() {
    "use strict";
    init_defaultAttributes();
    PanelTop = [
      "svg",
      defaultAttributes,
      [
        ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }],
        ["path", { d: "M3 9h18" }]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/smile.js
var Smile;
var init_smile = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/smile.js"() {
    "use strict";
    init_defaultAttributes();
    Smile = [
      "svg",
      defaultAttributes,
      [
        ["circle", { cx: "12", cy: "12", r: "10" }],
        ["path", { d: "M8 14s1.5 2 4 2 4-2 4-2" }],
        ["line", { x1: "9", x2: "9.01", y1: "9", y2: "9" }],
        ["line", { x1: "15", x2: "15.01", y1: "9", y2: "9" }]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/square-arrow-up-right.js
var SquareArrowUpRight;
var init_square_arrow_up_right = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/square-arrow-up-right.js"() {
    "use strict";
    init_defaultAttributes();
    SquareArrowUpRight = [
      "svg",
      defaultAttributes,
      [
        ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }],
        ["path", { d: "M8 8h8v8" }],
        ["path", { d: "m8 16 8-8" }]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/star.js
var Star;
var init_star = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/star.js"() {
    "use strict";
    init_defaultAttributes();
    Star = [
      "svg",
      defaultAttributes,
      [
        [
          "polygon",
          {
            points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"
          }
        ]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/sun.js
var Sun;
var init_sun = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/sun.js"() {
    "use strict";
    init_defaultAttributes();
    Sun = [
      "svg",
      defaultAttributes,
      [
        ["circle", { cx: "12", cy: "12", r: "4" }],
        ["path", { d: "M12 2v2" }],
        ["path", { d: "M12 20v2" }],
        ["path", { d: "m4.93 4.93 1.41 1.41" }],
        ["path", { d: "m17.66 17.66 1.41 1.41" }],
        ["path", { d: "M2 12h2" }],
        ["path", { d: "M20 12h2" }],
        ["path", { d: "m6.34 17.66-1.41 1.41" }],
        ["path", { d: "m19.07 4.93-1.41 1.41" }]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/twitter.js
var Twitter;
var init_twitter = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/twitter.js"() {
    "use strict";
    init_defaultAttributes();
    Twitter = [
      "svg",
      defaultAttributes,
      [
        [
          "path",
          {
            d: "M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z"
          }
        ]
      ]
    ];
  }
});

// node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/lucide.js
var createIcons;
var init_lucide = __esm({
  "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/lucide.js"() {
    "use strict";
    init_replaceElement();
    init_createElement();
    init_book_open_check();
    init_chevron_down();
    init_chevrons_up();
    init_eye_off();
    init_heart();
    init_house();
    init_message_square_plus();
    init_message_square();
    init_moon();
    init_package_plus();
    init_panel_right();
    init_panel_top();
    init_smile();
    init_square_arrow_up_right();
    init_star();
    init_sun();
    init_twitter();
    createIcons = ({ icons = {}, nameAttr = "data-lucide", attrs = {} } = {}) => {
      if (!Object.values(icons).length) {
        throw new Error(
          "Please provide an icons object.\nIf you want to use all the icons you can import it like:\n `import { createIcons, icons } from 'lucide';\nlucide.createIcons({icons});`"
        );
      }
      if (typeof document === "undefined") {
        throw new Error("`createIcons()` only works in a browser environment.");
      }
      const elementsToReplace = document.querySelectorAll(`[${nameAttr}]`);
      Array.from(elementsToReplace).forEach(
        (element) => replaceElement(element, { nameAttr, icons, attrs })
      );
      if (nameAttr === "data-lucide") {
        const deprecatedElements = document.querySelectorAll("[icon-name]");
        if (deprecatedElements.length > 0) {
          console.warn(
            "[Lucide] Some icons were found with the now deprecated icon-name attribute. These will still be replaced for backwards compatibility, but will no longer be supported in v1.0 and you should switch to data-lucide"
          );
          Array.from(deprecatedElements).forEach(
            (element) => replaceElement(element, { nameAttr: "icon-name", icons, attrs })
          );
        }
      }
    };
  }
});

// src/components/toast.ts
function createToast(props) {
  const { message, duration = 3e3 } = props;
  const $existTosat = $(".v2p-toast");
  if ($existTosat.length > 0) {
    $existTosat.remove();
  }
  const $toast = $(`<div class="v2p-toast">${message}</div>`).hide();
  $body.append($toast);
  $toast.fadeIn("fast");
  if (duration !== 0) {
    setTimeout(() => {
      $toast.fadeOut("fast", () => {
        $toast.remove();
      });
    }, duration);
  }
  return {
    clear() {
      $toast.remove();
    }
  };
}
var init_toast = __esm({
  "src/components/toast.ts"() {
    "use strict";
    init_globals();
  }
});

// src/contents/helpers.ts
function focusReplyInput() {
  if (replyTextArea instanceof HTMLTextAreaElement) {
    replyTextArea.focus();
  }
}
function insertTextToReplyInput(text) {
  if (replyTextArea instanceof HTMLTextAreaElement) {
    const startPos = replyTextArea.selectionStart;
    const endPos = replyTextArea.selectionEnd;
    const valueToStart = replyTextArea.value.substring(0, startPos);
    const valueFromEnd = replyTextArea.value.substring(endPos, replyTextArea.value.length);
    replyTextArea.value = `${valueToStart}${text}${valueFromEnd}`;
    focusReplyInput();
    replyTextArea.selectionStart = replyTextArea.selectionEnd = startPos + text.length;
  }
}
async function setMemberTags(params) {
  const { memberName, memberAvatar, tags } = params;
  const storage = await getStorage(false);
  const tagData = storage["member-tag" /* MemberTag */];
  if (!isBrowserExtension()) {
    return;
  }
  if (tags && tags.length > 0) {
    const newTagData = {
      ...tagData,
      [memberName]: { tags, avatar: memberAvatar || tagData?.[memberName]?.avatar }
    };
    await setStorage("member-tag" /* MemberTag */, newTagData);
  } else {
    if (tagData && Reflect.has(tagData, memberName)) {
      delete tagData[memberName];
      await setStorage("member-tag" /* MemberTag */, tagData);
    }
  }
}
async function addToReadingList(params) {
  const { url, title, content } = params;
  if (!(typeof url === "string" || typeof title === "string" || typeof content === "string")) {
    const message = "\u65E0\u6CD5\u8BC6\u522B\u5C06\u8BE5\u4E3B\u9898\u7684\u5143\u6570\u636E";
    createToast({ message });
    throw new Error(message);
  }
  const storage = await getStorage();
  const currentData = storage["reading-list" /* ReadingList */]?.data || [];
  const exist = currentData.findIndex((it) => it.url === url) !== -1;
  if (exist) {
    createToast({ message: "\u8BE5\u4E3B\u9898\u5DF2\u5B58\u5728\u4E8E\u7A0D\u540E\u9605\u8BFB" });
  } else {
    if (window.__V2P_AddingReading !== true) {
      window.__V2P_AddingReading = true;
      try {
        await setStorage("reading-list" /* ReadingList */, {
          data: [
            {
              url,
              title: title.replace(" - V2EX", ""),
              content: content.length > READING_CONTENT_LIMIT ? content.substring(0, READING_CONTENT_LIMIT) + "..." : content,
              addedTime: Date.now()
            },
            ...currentData
          ]
        });
        createToast({ message: "\u2705 \u5DF2\u6DFB\u52A0\u8FDB\u7A0D\u540E\u9605\u8BFB" });
        await sleep(500);
      } finally {
        window.__V2P_AddingReading = false;
      }
    }
  }
}
function customEscape(str) {
  return str.replace(
    /[^a-zA-Z0-9_.!~*'()-]/g,
    (c) => `%${c.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`
  );
}
function decodeBase64TopicPage() {
  const dataTitle = "\u70B9\u51FB\u590D\u5236";
  if (window.__V2P_DecodeStatus === "decodeed") {
    createToast({ message: "\u5DF2\u89E3\u6790\u5B8C\u672C\u9875\u6240\u6709\u7684 Base64 \u5B57\u7B26\u4E32" });
  } else {
    const $topicContentBox2 = $("#Main .box:has(.topic_content)");
    const $commentBox2 = $('#Main .box:has(.cell[id^="r_"])');
    const $commentCells2 = $commentBox2.find('.cell[id^="r_"]');
    let count = 0;
    const excludeList = [
      "boss",
      "bilibili",
      "Bilibili",
      "Encrypto",
      "encrypto",
      "Window10",
      "airpords",
      "Windows7"
    ];
    const convertHTMLText = (text, excludeTextList) => {
      if (text.length % 4 !== 0 || text.length <= 8) {
        return text;
      }
      if (excludeList.includes(text)) {
        return text;
      }
      if (text.includes("=")) {
        const paddingIndex = text.indexOf("=");
        if (paddingIndex !== text.length - 1 && paddingIndex !== text.length - 2) {
          return text;
        }
      }
      if (excludeTextList?.some((excludeText) => excludeText.includes(text))) {
        return text;
      }
      try {
        const decodedStr = decodeURIComponent(customEscape(window.atob(text)));
        count += 1;
        return `${text}<span class="v2p-decode-block">(<ins class="v2p-decode" data-title="${dataTitle}">${decodedStr}</ins>)</span>`;
      } catch (err) {
        if (err instanceof Error) {
          console.error(`\u89E3\u6790 Base64 \u51FA\u9519\uFF1A${err.message}`);
        }
        return text;
      }
    };
    const base64regex = /[A-z0-9+/=]+/g;
    const contentHandler = (_, content) => {
      const excludeTextList = [
        ...content.getElementsByTagName("a"),
        ...content.getElementsByTagName("img")
      ].map((ele) => ele.outerHTML);
      content.innerHTML = content.innerHTML.replace(
        base64regex,
        (htmlText) => convertHTMLText(htmlText, excludeTextList)
      );
    };
    $commentCells2.find(".reply_content").each(contentHandler);
    $topicContentBox2.find(".topic_content").each(contentHandler);
    if (count === 0) {
      createToast({ message: "\u672C\u9875\u672A\u53D1\u73B0 Base64 \u5B57\u7B26\u4E32" });
    } else {
      window.__V2P_DecodeStatus = "decodeed";
      createToast({ message: `\u2705 \u5DF2\u89E3\u6790\u672C\u9875\u6240\u6709\u7684 Base64 \u5B57\u7B26\u4E32\uFF0C\u5171 ${count} \u6761` });
    }
    $(".v2p-decode").on("click", (ev) => {
      const text = ev.target.innerText;
      void navigator.clipboard.writeText(text).then(() => {
        ev.target.dataset.title = "\u2705 \u5DF2\u590D\u5236";
        setTimeout(() => {
          ev.target.dataset.title = dataTitle;
        }, 1e3);
      });
    });
  }
}
function postTask(expression, callback) {
  if (!isBrowserExtension()) {
    const result = Function(`"use strict"; ${expression}`)();
    callback?.(result);
  } else {
    if (callback) {
      if (window.__V2P_Tasks) {
        window.__V2P_Tasks.set(Date.now(), callback);
      } else {
        window.__V2P_Tasks = /* @__PURE__ */ new Map([[Date.now(), callback]]);
      }
    }
    const messageData = {
      from: 0 /* Content */,
      payload: { task: { id: Date.now(), expression } }
    };
    window.postMessage(messageData);
  }
}
function loadIcons() {
  setTimeout(() => {
    createIcons({
      attrs: {
        width: "100%",
        height: "100%"
      },
      icons: {
        MessageSquarePlus,
        MessageSquare,
        BookOpenCheck,
        ChevronsUp,
        Heart,
        EyeOff,
        Sun,
        Moon,
        Smile,
        PackagePlus,
        Star,
        Twitter,
        ChevronDown,
        ArrowUpRightSquare: SquareArrowUpRight,
        House
      }
    });
  }, 0);
}
function transformEmoji(textValue) {
  return textValue.replace(/\[[^\]]+\]/g, (x) => {
    if (Object.hasOwn(emojiLinks, x)) {
      const emojiLink = emojiLinks[x].ld;
      if (typeof emojiLink === "string") {
        return `${emojiLink} `;
      }
    }
    return x;
  });
}
function getTagsText(tags) {
  return tags.map((it) => it.name).join("\uFF0C");
}
function setTheme(type) {
  $body.get(0)?.classList.forEach((cls) => {
    if (cls.startsWith("v2p-theme-")) {
      $body.removeClass(cls);
    }
  });
  $body.addClass(`v2p-theme-${type}`);
}
function toggleTheme({
  $toggle,
  prefersDark,
  themeType = "light-default"
}) {
  const isPageDark = $wrapper.hasClass("Night");
  const shouldSync = prefersDark !== isPageDark;
  if (shouldSync) {
    const toggleThemeUrl = $toggle.attr("href");
    if (typeof toggleThemeUrl === "string") {
      fetch(toggleThemeUrl);
    }
    if (prefersDark) {
      $toggle.prop("title", "\u4F7F\u7528\u6D45\u8272\u4E3B\u9898");
      $toggle.html('<i data-lucide="sun"></i>');
    } else {
      $toggle.prop("title", "\u4F7F\u7528\u6DF1\u8272\u4E3B\u9898");
      $toggle.html('<i data-lucide="moon"></i>');
    }
  }
  if (prefersDark) {
    setTheme("dark-default");
    $wrapper.addClass("Night");
  } else {
    setTheme(themeType);
    $wrapper.removeClass("Night");
  }
  loadIcons();
}
function replaceEmojiWithHD($emojiImgs) {
  if ($emojiImgs.length > 0) {
    const srcMap = /* @__PURE__ */ new Map();
    Object.values(emojiLinks).forEach(({ ld, hd }) => {
      srcMap.set(ld, hd);
    });
    $emojiImgs.each((_, img) => {
      const $img = $(img);
      const src = $img.attr("src");
      if (typeof src === "string") {
        const hd = srcMap.get(src);
        if (typeof hd === "string") {
          $img.attr("src", hd);
          $img.css({
            width: "var(--v2p-emoji-size)",
            height: "var(--v2p-emoji-size)"
          });
        }
      }
    });
  }
}
function replaceCommentEmojiWithHD($cells = $commentCells) {
  const srcMap = /* @__PURE__ */ new Map();
  Object.values(emojiLinks).forEach(({ ld, hd }) => {
    srcMap.set(ld, hd);
  });
  const $embedImages = $cells.find(`.reply_content .embedded_image, .payload .embedded_image`);
  if ($embedImages.length > 0) {
    replaceEmojiWithHD($embedImages);
  }
}
function openV2PSettings() {
  chrome.runtime.sendMessage({ ["showOptions" /* showOptions */]: true });
}
function getRegisterDays(created) {
  const registerDays = Math.ceil((Date.now() / 1e3 - created) / (60 * 60 * 24));
  return registerDays;
}
var init_helpers = __esm({
  "src/contents/helpers.ts"() {
    "use strict";
    init_lucide();
    init_toast();
    init_constants();
    init_utils();
    init_globals();
  }
});

// src/contents/common.ts
var common_exports = {};
var init_common = __esm({
  "src/contents/common.ts"() {
    "use strict";
    init_polyfill();
    init_constants();
    init_icons();
    init_utils();
    init_globals();
    init_helpers();
    if ($("#site-header").length > 0) {
      $body.addClass("v2p-mobile");
    }
    void (async () => {
      const isBrowserExt = isBrowserExtension();
      const storage = await getStorage();
      const options = storage["options" /* Options */];
      if (options.theme.mode === "compact") {
        $body.addClass("v2p-mode-compact");
      }
      const $toggle = $("#Rightbar .light-toggle").addClass("v2p-color-mode-toggle");
      const colorMedia = window.matchMedia("(prefers-color-scheme: dark)");
      const handleColorSchemeChange = ({ matches }) => {
        getStorage(false).then((storage2) => {
          const options2 = storage2["options" /* Options */];
          const themeType2 = options2.theme.type || "light-default";
          toggleTheme({
            $toggle,
            prefersDark: matches,
            themeType: matches ? "dark-default" : themeType2
          });
        });
      };
      const themeType = options.theme.type || "light-default";
      if (options.theme.autoSwitch) {
        const prefersDark = colorMedia.matches;
        toggleTheme({
          $toggle,
          prefersDark,
          themeType: prefersDark ? "dark-default" : themeType
        });
        colorMedia.addEventListener("change", handleColorSchemeChange);
      } else {
        const prefersDark = isBrowserExt ? themeType === "dark-default" : $wrapper.hasClass("Night");
        toggleTheme({ $toggle, prefersDark, themeType });
      }
      $toggle.on("click", () => {
        const wrapperDark = $wrapper.hasClass("Night");
        const newTheme = {
          type: wrapperDark ? "light-default" : "dark-default",
          autoSwitch: false
          // 当用户主动设置颜色主题后,取消自动跟随系统。
        };
        void setStorage("options" /* Options */, deepMerge(options, { theme: newTheme }));
      });
      const syncInfo = storage["settings-sync" /* SyncInfo */];
      if (syncInfo) {
        const lastCheckTime = syncInfo.lastCheckTime;
        const twoHours = 2 * 60 * 1e3 * 60;
        const neverChecked = !lastCheckTime;
        if (lastCheckTime && Date.now() - lastCheckTime >= twoHours || neverChecked) {
          const isSignInPage = window.location.href.includes("/signin");
          if (!isSignInPage) {
            void getV2P_Settings().then(async (res) => {
              const settings = res?.config;
              const remoteSyncInfo = settings?.["settings-sync" /* SyncInfo */];
              if (settings && remoteSyncInfo) {
                if (syncInfo.version < remoteSyncInfo.version || neverChecked) {
                  await chrome.storage.sync.set(
                    deepMerge(storage, {
                      ...settings,
                      ["settings-sync" /* SyncInfo */]: {
                        ...settings["settings-sync" /* SyncInfo */],
                        lastCheckTime: Date.now()
                      }
                    })
                  );
                }
              }
            });
          }
        }
      }
      {
        const $toggleImg = $toggle.find("> img");
        const alt = $toggleImg.prop("alt");
        if (alt === "Light") {
          $toggle.prop("title", "\u4F7F\u7528\u6DF1\u8272\u4E3B\u9898");
          $toggleImg.replaceWith('<i data-lucide="moon"></i>');
        } else if (alt === "Dark") {
          $toggle.prop("title", "\u4F7F\u7528\u6D45\u8272\u4E3B\u9898");
          $toggleImg.replaceWith('<i data-lucide="sun"></i>');
        }
      }
      {
        $("#Top .site-nav .tools > .top").addClass("v2p-hover-btn");
      }
      if (options.hideAccount) {
        const faviconLink = $("link[rel~='icon']");
        faviconLink.prop("href", "https://v2p.app/favicon.svg");
        $("#Logo").append(`<i data-lucide="house"></i>`).addClass("v2p-logo");
        $("#Top").find('a[href^="/member/"]').remove();
        $infoCard.find('a[href^="/member/"], table:nth-of-type(1) td:nth-of-type(3) .fade').addClass("v2p-hide-account");
        $infoCard.find(".balance_area").addClass("v2p-hide-balance");
      }
      if (isBrowserExt) {
        injectScript(chrome.runtime.getURL("scripts/web_accessible_resources.min.js"));
        window.addEventListener("message", (ev) => {
          if (ev.data.from === 1 /* Web */) {
            const payload = ev.data.payload;
            const task = payload?.task;
            if (payload?.status === "ready") {
              postTask('if (typeof window.once === "string") { return window.once; }', (result) => {
                if (typeof result === "string") {
                  window.once = result;
                }
              });
            }
            if (task) {
              window.__V2P_Tasks?.get(task.id)?.(task.result);
            }
          }
        });
      }
      {
        const $extraFooter = $(`
    <div class="v2p-footer">
      <div class="v2p-footer-text">\u6269\u5C55\u81EA V2EX Polish </div>

      <div class="v2p-footer-links">
        <a class="v2p-footer-link v2p-hover-btn" href="${"https://v2p.app" /* Home */}" target="_blank">\u63D2\u4EF6\u5B98\u7F51</a>
        <a class="v2p-footer-link v2p-hover-btn" href="${"https://github.com/coolpace/V2EX_Polish/discussions/1?sort=new" /* Feedback */}" target="_blank">\u95EE\u9898\u53CD\u9988</a>
        <a class="v2p-footer-link v2p-hover-btn" href="${"https://v2p.app/support" /* Support */}" target="_blank">\u8D5E\u8D4F\u652F\u6301</a>
        <a class="v2p-footer-link v2p-hover-btn v2p-optbtn" href="javascript:void(0);">\u9009\u9879\u8BBE\u7F6E</a>
      </div>

      <div class="v2p-footer-brand">
        <a
          href="https://github.com/coolpace/V2EX_Polish"
          target="_blank"
          title="GitHub \u4ED3\u5E93"
          class="v2p-hover-btn v2p-github-ref"
        >
          ${iconGitHub}
        </a>
      </div>
    </div>
    `);
        $extraFooter.find(".v2p-optbtn").on("click", () => {
          openV2PSettings();
        });
        $(`<div class="v2p-footer-logo">${iconLogo}</div>`).prependTo($extraFooter);
        $("#Bottom .content").append($extraFooter);
      }
      chrome.storage.onChanged.addListener((changes, storageType) => {
        if (storageType === "sync") {
          const options2 = changes["options" /* Options */];
          if (options2) {
            const { newValue, oldValue } = options2;
            const newOptions = newValue;
            const oldOptions = oldValue;
            const newTheme = newOptions?.theme;
            const oldTheme = oldOptions?.theme;
            if (newTheme && oldTheme) {
              const prefersDark = newTheme.autoSwitch ? window.matchMedia("(prefers-color-scheme: dark)").matches : isBrowserExt ? newTheme.type === "dark-default" : $wrapper.hasClass("Night");
              if (newTheme.type !== oldTheme.type) {
                toggleTheme({
                  $toggle,
                  prefersDark,
                  themeType: newTheme.type
                });
              } else {
                if (newTheme.autoSwitch !== oldTheme.autoSwitch) {
                  if (newTheme.autoSwitch) {
                    colorMedia.addEventListener("change", handleColorSchemeChange);
                  } else {
                    colorMedia.removeEventListener("change", handleColorSchemeChange);
                  }
                  toggleTheme({
                    $toggle,
                    prefersDark,
                    themeType: prefersDark ? "dark-default" : newTheme.type
                  });
                }
              }
              if (newTheme.mode !== oldTheme.mode) {
                if (newTheme.mode === "compact") {
                  $body.addClass("v2p-mode-compact");
                } else {
                  $body.removeClass("v2p-mode-compact");
                }
              }
            }
          }
        }
      });
    })();
  }
});

// src/services.ts
async function legacyRequest(url, options) {
  const res = await fetch(url, options);
  if (res.ok) {
    return res.json();
  }
  throw new Error("\u8C03\u7528 V2EX API v1 \u51FA\u9519", { cause: res.status });
}
async function fetchUserInfo(memberName, options) {
  try {
    const member = await legacyRequest(
      `${V2EX_LEGACY_API}/members/show.json?username=${memberName}`,
      options
    );
    return member;
  } catch (err) {
    if (err instanceof Error) {
      if (err.name === "AbortError") {
        throw new Error("\u8BF7\u6C42\u88AB\u53D6\u6D88");
      } else if (err.cause === 404) {
        throw new Error("\u67E5\u65E0\u6B64\u7528\u6237\uFF0C\u7591\u4F3C\u5DF2\u88AB\u5C01\u7981", { cause: err.cause });
      }
    }
    throw new Error("\u83B7\u53D6\u7528\u6237\u4FE1\u606F\u5931\u8D25");
  }
}
async function request(url, options) {
  const storage = await getStorage();
  const PAT = storage["api" /* API */]?.pat;
  const res = await fetch(url, {
    ...options,
    headers: { Authorization: PAT ? `Bearer ${PAT}` : "", ...options?.headers }
  });
  {
    const limit = res.headers.get("X-Rate-Limit-Limit");
    const reset = res.headers.get("X-Rate-Limit-Reset");
    const remaining = res.headers.get("X-Rate-Limit-Remaining");
    const api = {
      pat: PAT,
      limit: limit ? Number(limit) : void 0,
      reset: reset ? Number(reset) : void 0,
      remaining: remaining ? Number(remaining) : void 0
    };
    void setStorage("api" /* API */, api);
  }
  const resultData = await res.json();
  if (typeof resultData.success === "boolean" && !resultData.success) {
    throw new Error(resultData.message, { cause: resultData });
  }
  return resultData;
}
function fetchTopic(topicId, options) {
  return request(`${V2EX_API}/topics/${topicId}`, { method: "GET", ...options });
}
async function uploadImage(file) {
  const formData = new FormData();
  formData.append("image", file);
  const randomIndex = Math.floor(Math.random() * imgurClientIdPool.length);
  const clidenId = imgurClientIdPool[randomIndex];
  const res = await fetch("https://api.imgur.com/3/upload", {
    method: "POST",
    headers: { Authorization: `Client-ID ${clidenId}` },
    body: formData
  });
  if (res.ok) {
    const resData = await res.json();
    if (resData.success) {
      return resData.data.link;
    }
  }
  throw new Error("\u4E0A\u4F20\u5931\u8D25");
}
async function refreshMoney() {
  const res = await fetch("/ajax/money", { method: "POST" });
  const data = await res.text();
  $("#money").html(data);
}
async function thankReply(params) {
  try {
    const res = await fetch(`/thank/reply/${params.replyId}?once=${window.once}`, {
      method: "POST"
    });
    const data = await res.json();
    postTask(`window.once = ${data.once}`);
    window.once = data.once;
    if (data.success) {
      $("#thank_area_" + params.replyId).addClass("thanked").html("\u611F\u8C22\u5DF2\u53D1\u9001");
      params.onSuccess?.();
      await refreshMoney();
    } else {
      alert(data.message);
    }
  } catch {
    params.onFail?.();
  }
}
async function crawlTopicPage(path, page = "1") {
  const res = await fetch(`${V2EX_ORIGIN}${path}?p=${page}`);
  const htmlText = await res.text();
  return htmlText;
}
async function getCommentPreview(params) {
  const formData = new FormData();
  formData.append("text", params.text);
  const res = await fetch(`${V2EX_ORIGIN}/preview/${params.syntax}`, {
    method: "POST",
    body: formData
  });
  if (res.ok) {
    const renderedContent = await res.text();
    return renderedContent;
  } else {
    throw new Error("\u9884\u89C8\u5931\u8D25");
  }
}
var V2EX_LEGACY_API, V2EX_API;
var init_services = __esm({
  "src/services.ts"() {
    "use strict";
    init_constants();
    init_helpers();
    init_utils();
    V2EX_LEGACY_API = `${V2EX_ORIGIN}/api`;
    V2EX_API = `${V2EX_ORIGIN}/api/v2`;
  }
});

// src/components/button.ts
function createButton(props) {
  const { children, className = "", type = "button", tag = "button" } = props;
  const $button = $(`<${tag} class="normal button ${className}">${children}</${tag}>`);
  if (tag === "button") {
    $button.prop("type", type);
  }
  return $button;
}
var init_button = __esm({
  "src/components/button.ts"() {
    "use strict";
  }
});

// src/components/modal.ts
function createModal(props) {
  const { root, title, onMount, onOpen, onClose } = props;
  const $mask = $('<div class="v2p-modal-mask">');
  const $content = $('<div class="v2p-modal-content">');
  const $closeBtn = createButton({
    children: "\u5173\u95ED<kbd>Esc</kbd>",
    className: "v2p-modal-close-btn"
  });
  const $title = $(`<div class="v2p-modal-title">${title ?? ""}</div>`);
  const $actions = $('<div class="v2p-modal-actions">').append($closeBtn);
  const $header = $('<div class="v2p-modal-header">').append($title, $actions);
  const $main2 = $('<div class="v2p-modal-main">').append($header, $content).on("click", (ev) => {
    ev.stopPropagation();
  });
  const $container = $mask.append($main2).hide();
  const modalElements = {
    $mask,
    $main: $main2,
    $header,
    $container,
    $title,
    $actions,
    $content
  };
  let boundEvent = false;
  let mouseDownTarget;
  const mouseDownHandler = (ev) => {
    mouseDownTarget = ev.target;
  };
  const mouseUpHandler = (ev) => {
    if (mouseDownTarget === $mask.get(0) && ev.target === $mask.get(0) && ev.currentTarget === ev.target) {
      handleModalClose();
    }
  };
  const keyupHandler = (ev) => {
    if (ev.key === "Escape") {
      handleModalClose();
    }
  };
  const handleModalClose = () => {
    $mask.off("mousedown", mouseDownHandler);
    $mask.off("mouseup", mouseUpHandler);
    $(document).off("keydown", keyupHandler);
    boundEvent = false;
    $container.fadeOut("fast");
    document.body.classList.remove("v2p-modal-open");
    onClose?.(modalElements);
  };
  const handleModalOpen = () => {
    if (root && !$container.parent().length) {
      root.append($container);
      $closeBtn.on("click", handleModalClose);
      onMount?.(modalElements);
    }
    setTimeout(() => {
      if (!boundEvent) {
        $mask.on("mousedown", mouseDownHandler);
        $mask.on("mouseup", mouseUpHandler);
        $(document).on("keydown", keyupHandler);
        boundEvent = true;
      }
    });
    $container.fadeIn("fast");
    document.body.classList.add("v2p-modal-open");
    onOpen?.(modalElements);
  };
  return { ...modalElements, open: handleModalOpen, close: handleModalClose };
}
var init_modal = __esm({
  "src/components/modal.ts"() {
    "use strict";
    init_button();
  }
});

// src/contents/topic/content.ts
function handleTopicImgHeight() {
  const $topicContentImgs = $topicContentBox.find(".topic_content .embedded_image");
  $topicContentImgs.each((_, img) => {
    const $img = $(img);
    const height = $img.height() ?? 0;
    const shouldWrap = height > 600;
    if (shouldWrap) {
      const collapsedCSS = {
        maxHeight: `${READABLE_CONTENT_HEIGHT}px`,
        overflow: "hidden",
        paddingBottom: "0",
        "--bg-reply": "var(--v2p-color-bg-content)"
      };
      const $contentBox = $('<div class="v2p-reply-content v2p-collapsed">').css(collapsedCSS);
      const $expandBtn = createButton({ children: "\u5C55\u5F00\u56FE\u7247", className: "v2p-expand-btn" });
      const toggleContent = () => {
        const collapsed = $contentBox.hasClass("v2p-collapsed");
        $contentBox.toggleClass("v2p-collapsed").css(
          collapsed ? { maxHeight: "none", overflow: "auto", paddingBottom: "40px" } : collapsedCSS
        );
        $expandBtn.html(collapsed ? "\u6536\u8D77\u56FE\u7247" : "\u5C55\u5F00\u56FE\u7247");
      };
      $expandBtn.on("click", () => {
        toggleContent();
      });
      $contentBox.append($img.clone()).replaceAll($img).append($expandBtn);
    }
  });
}
function handleContent() {
  const storage = getStorageSync();
  const options = storage["options" /* Options */];
  if (options.openInNewTab) {
    $topicContentBox.find(".topic_content a[href]").prop("target", "_blank").prop("rel", "noopener noreferrer");
  }
  {
    const $topicContents = $topicContentBox.find(".subtle > .topic_content");
    const textLength = $topicContents.text().length;
    if (textLength >= 200) {
      $topicContents.each((_, topicContent) => {
        if (textLength >= 400) {
          topicContent.style.fontSize = "14px";
        }
        topicContent.style.fontSize = "14.5px";
      });
    }
  }
  {
    const $topicBtns = $(".topic_buttons");
    const $topicBtn = $topicBtns.find(".tb").addClass("v2p-tb v2p-hover-btn");
    const $favoriteBtn = $topicBtn.eq(0);
    $favoriteBtn.append('<span class="v2p-tb-icon"><i data-lucide="star"></i></span>');
    $topicBtn.eq(1).append('<span class="v2p-tb-icon"><i data-lucide="twitter"></i></span>');
    $topicBtn.eq(2).append('<span class="v2p-tb-icon"><i data-lucide="eye-off"></i></span>');
    $topicBtn.eq(3).append('<span class="v2p-tb-icon"><i data-lucide="heart"></i></span>');
    if (pathTopicId) {
      $topicBtns.append(
        ` &nbsp;<a href="${"https://v2p.app/share" /* Share */}/${pathTopicId}" target="_blank" class="tb v2p-tb v2p-hover-btn">\u5206\u4EAB<span class="v2p-tb-icon"><i data-lucide="arrow-up-right-square"></i></span></a>`
      );
    }
    loadIcons();
  }
  window.requestIdleCallback(() => {
    handleTopicImgHeight();
  });
}
function processReplyContent($cellDom) {
  if ($cellDom.find(".v2p-reply-content").length > 0) {
    return;
  }
  const $replyContent = $cellDom.find(".reply_content");
  const contentHeight = $replyContent.height() ?? 0;
  const shouldCollapsed = contentHeight + READABLE_CONTENT_HEIGHT >= MAX_CONTENT_HEIGHT;
  if (shouldCollapsed) {
    const collapsedCSS = {
      maxHeight: `${READABLE_CONTENT_HEIGHT}px`,
      overflow: "hidden",
      paddingBottom: "0"
    };
    const $contentBox = $('<div class="v2p-reply-content v2p-collapsed">').css(collapsedCSS);
    const $expandBtn = createButton({ children: "\u5C55\u5F00\u56DE\u590D", className: "v2p-expand-btn" });
    const toggleContent = () => {
      const collapsed = $contentBox.hasClass("v2p-collapsed");
      $contentBox.toggleClass("v2p-collapsed").css(
        collapsed ? { maxHeight: "none", overflow: "auto", paddingBottom: "40px" } : collapsedCSS
      );
      $expandBtn.html(collapsed ? "\u6536\u8D77\u56DE\u590D" : "\u5C55\u5F00\u56DE\u590D");
    };
    $expandBtn.on("click", () => {
      toggleContent();
    });
    $contentBox.append($replyContent.clone()).replaceAll($replyContent).append($expandBtn);
  }
}
function updateMemberTag(params) {
  const { memberName, memberAvatar, tags, options, ...callbacks } = params;
  const $v2pTags = $(`.v2p-tags-${memberName}`);
  const tagsText = tags ? getTagsText(tags) : void 0;
  if ($v2pTags.length > 0) {
    if (tagsText) {
      $v2pTags.html(`<b>#</b>&nbsp;${tagsText}`);
    } else {
      $v2pTags.remove();
      callbacks.onRemoveExistingTagBlock?.();
    }
  } else {
    if (tagsText) {
      const $tags = $(
        `<div class="v2p-reply-tags v2p-tags-${memberName}" title="${tagsText}"><b>#</b>&nbsp;${tagsText}</div>`
      );
      $tags.on("click", () => {
        openTagsSetter({ memberName, memberAvatar, ...callbacks });
      });
      if (callbacks.onInsertNewTagBlock) {
        callbacks.onInsertNewTagBlock({ $tags });
      } else {
        if (memberName === topicOwnerName) {
          $topicHeader.append($tags.clone(true));
        }
        if (options.userTag.display === "inline") {
          $tags.addClass("v2p-reply-tags-inline").insertBefore(
            $commentCells.filter(`:has(> table strong > a[href="/member/${memberName}"])`).find("> table .badges")
          );
        } else {
          $tags.insertBefore(
            $commentCells.filter(`:has(> table strong > a[href="/member/${memberName}"])`).find("> table .reply_content")
          );
        }
      }
    }
  }
}
function openTagsSetter(params) {
  const { memberName, memberAvatar, ...callbacks } = params;
  void (async () => {
    const storage = await getStorage(false);
    const latestTagsData = storage["member-tag" /* MemberTag */];
    const options = storage["options" /* Options */];
    const memberTagData = latestTagsData?.[memberName];
    const tagsValue = memberTagData ? Reflect.has(latestTagsData, memberName) ? memberTagData.tags ? getTagsText(memberTagData.tags) : void 0 : void 0 : void 0;
    const newTagsValue = window.prompt(
      `\u5BF9 @${memberName} \u8BBE\u7F6E\u6807\u7B7E\uFF0C\u591A\u4E2A\u6807\u7B7E\u4EE5\u9017\u53F7\uFF08\uFF0C\uFF09\u5206\u9694\u3002`,
      tagsValue
    );
    if (newTagsValue !== null) {
      const tags = newTagsValue.trim().length > 0 ? newTagsValue.split(/,|,/g).filter((it) => it.trim().length > 0).map((it) => ({ name: it })) : void 0;
      await setMemberTags({ memberName, memberAvatar: memberTagData?.avatar || memberAvatar, tags });
      updateMemberTag({ memberName, memberAvatar, tags, options, ...callbacks });
    }
  })();
}
function handleTopicImg() {
  const $imgs = $(".embedded_image");
  if ($imgs.length > 0) {
    const modal = createModal({
      root: $body,
      onMount: ({ $main: $main2, $header, $content }) => {
        $main2.css({
          width: "auto",
          height: "auto",
          display: "flex",
          "justify-content": "center",
          "background-color": "transparent",
          "pointer-events": "none"
        });
        $header.remove();
        $content.css({
          display: "flex",
          "justify-content": "center",
          "align-items": "center",
          "pointer-events": "none"
        });
      },
      onOpen: ({ $content }) => {
        $content.empty();
      }
    });
    $imgs.each((_, img) => {
      const $img = $(img);
      if (img instanceof HTMLImageElement) {
        $img.parent().removeAttr("href");
        if (img.clientWidth !== img.naturalWidth) {
          $img.css({ cursor: "zoom-in" });
          $img.on("click", () => {
            const $clonedImg = $img.clone();
            $clonedImg.css({ cursor: "default", "pointer-events": "auto" });
            modal.open();
            modal.$content.append($clonedImg);
          });
        }
      }
    });
  }
}
function handleLinkPreview() {
  const $topicLinks = $(
    '.topic_content a[href*="v2ex.com/t/"], .reply_content a[href*="v2ex.com/t/"], .topic_content a[href^="/t/"], .reply_content a[href^="/t/"]'
  );
  const { handlePreview } = useTopicPreview();
  const $previewBtn = $('<span class="v2p-link-preview-btn">\u9884\u89C8</span>');
  $topicLinks.each((_, link) => {
    const $link = $(link);
    const $cloned = $previewBtn.clone(true);
    $cloned.on("click", (ev) => {
      ev.preventDefault();
      const linkHref = $link.attr("href");
      const match = linkHref?.match(/\/t\/(\d+)/);
      const topicId = match?.at(1);
      handlePreview({ topicId, linkHref });
    });
    const $previewBtnInLink = $link.find(".v2p-link-preview-btn");
    if ($previewBtnInLink.length > 0) {
      $previewBtnInLink.replaceWith($cloned);
    } else {
      $link.append($cloned);
    }
  });
}
var init_content = __esm({
  "src/contents/topic/content.ts"() {
    "use strict";
    init_button();
    init_modal();
    init_constants();
    init_use_topic_preview();
    init_utils();
    init_globals();
    init_helpers();
  }
});

// src/contents/dom.ts
function getCommentDataList({
  options,
  $commentTableRows: $commentTableRows2,
  $commentCells: $commentCells2
}) {
  return $commentTableRows2.map((idx, tr) => {
    const id = $commentCells2[idx].id;
    const $tr = $(tr);
    const $td = $tr.find("> td:nth-child(3)");
    const thanked = $tr.find("> td:last-of-type > .fr").find("> .thank_area").hasClass("thanked");
    const $member = $td.find("> strong > a");
    const memberName = $member.text();
    const memberLink = $member.prop("href");
    const memberAvatar = $tr.find(".avatar").prop("src");
    const $content = $td.find("> .reply_content");
    const content = $content.text();
    const likes = Number($td.find("span.small").text());
    const floor = $td.find("span.no").text();
    const memberNameMatches = Array.from(content.matchAll(/@([a-zA-Z0-9]+)/g));
    const refMemberNames = memberNameMatches.length > 0 ? memberNameMatches.map(([, name]) => {
      return name;
    }) : void 0;
    const floorNumberMatches = Array.from(content.matchAll(/#(\d+)/g));
    const refFloors = floorNumberMatches.length > 0 ? floorNumberMatches.map(([, floor2]) => {
      return floor2;
    }) : void 0;
    let contentHtml = void 0;
    if (refMemberNames) {
      const canHideRefName = options.nestedReply.display === "indent" && !!options.replyContent.hideRefName;
      if (canHideRefName) {
        if (refMemberNames.length === 1) {
          contentHtml = $content.html();
          const pattern = /(@<a href="\/member\/\w+">[\w\s]+<\/a>)\s+/g;
          const replacement = '<span class="v2p-member-ref">$1</span> ';
          contentHtml = contentHtml.replace(pattern, replacement);
        }
      }
    }
    return {
      id,
      memberName,
      memberLink,
      memberAvatar,
      content,
      contentHtml,
      likes,
      floor,
      index: idx,
      refMemberNames,
      refFloors,
      thanked
    };
  }).get();
}
function handleNestedComment({
  options,
  $commentCells: $commentCells2,
  commentDataList: commentDataList2
}) {
  const display = options.nestedReply.display;
  if (display !== "off") {
    $commentCells2.each((i, cellDom) => {
      const $cellDom = $(cellDom);
      const dataFromIndex = commentDataList2.at(i);
      if (options.replyContent.autoFold) {
        processReplyContent($cellDom);
      }
      const currentComment = dataFromIndex?.id === cellDom.id ? dataFromIndex : commentDataList2.find((data) => data.id === cellDom.id);
      if (currentComment) {
        const { refMemberNames, refFloors } = currentComment;
        if (!refMemberNames || refMemberNames.length === 0) {
          return;
        }
        const moreThanOneRefMember = refMemberNames.length > 1;
        if (options.nestedReply.multipleInsideOne === "off" && refMemberNames.length > 1) {
          return;
        }
        for (const refName of moreThanOneRefMember ? refMemberNames.toReversed() : refMemberNames) {
          for (let j = i - 1; j >= 0; j--) {
            const { memberName: compareName, floor: eachFloor } = commentDataList2.at(j) || {};
            if (compareName === refName) {
              let refCommentIdx = j;
              const firstRefFloor = moreThanOneRefMember ? refFloors?.toReversed().at(0) : refFloors?.at(0);
              if (firstRefFloor && firstRefFloor !== eachFloor) {
                const targetIdx = commentDataList2.slice(0, j).findIndex((data) => data.floor === firstRefFloor && data.memberName === refName);
                if (targetIdx >= 0) {
                  refCommentIdx = targetIdx;
                }
              }
              if (display === "indent") {
                cellDom.classList.add("v2p-indent");
              }
              $commentCells2.eq(refCommentIdx).append(cellDom);
              return;
            }
          }
        }
      }
    });
  }
}
var init_dom = __esm({
  "src/contents/dom.ts"() {
    "use strict";
    init_content();
  }
});

// src/use-topic-preview.ts
function useTopicPreview() {
  const storage = getStorageSync();
  const options = storage["options" /* Options */];
  const PAT = storage["api" /* API */]?.pat;
  let abortController = null;
  const $detailBtn = createButton({
    children: "\u8FDB\u5165\u4E3B\u9898",
    className: "special",
    tag: "a"
  });
  if (options.openInNewTab) {
    $detailBtn.prop("target", "_blank");
  }
  const modal = createModal({
    root: $body,
    onMount: ({ $actions }) => {
      $actions.prepend($detailBtn);
    },
    onClose: ({ $title, $content }) => {
      $title.empty();
      $content.empty();
      abortController?.abort();
    }
  });
  const handlePreview = (params) => {
    const { topicId, topicTitle = "", linkHref } = params;
    if (topicId) {
      modal.open();
      $detailBtn.prop("href", linkHref);
      const $titleLink = $(`
        <a class="v2p-topic-preview-title-link" title="${topicTitle}" href="${linkHref || ""}">
          ${topicTitle}
        </a>
      `);
      if (options.openInNewTab) {
        $titleLink.prop("target", "_blank");
      }
      modal.$title.empty().append($titleLink);
      if (PAT) {
        const load = async () => {
          let cacheData = topicDataCache.get(topicId);
          if (!cacheData || Date.now() - cacheData.cacheTime > 1e3 * 60 * 10) {
            abortController = new AbortController();
            modal.$content.empty().append(`
              <div class="v2p-tpr-loading">
                <div class="v2p-tpr-info">
                  <div class="v2p-tpr v2p-tpr-info-avatar"></div>
                  <div class="v2p-tpr v2p-tpr-info-text"></div>
                </div>

                <div class="v2p-tpr-content">
                  <div class="v2p-tpr v2p-tpr-content-p"></div>
                  <div class="v2p-tpr v2p-tpr-content-p"></div>
                  <div class="v2p-tpr v2p-tpr-content-p" style="width: 70%;"></div>
                </div>

                <div class="v2p-tpr-cmt">
                  <div class="v2p-tpr v2p-tpr-cmt-avatar"></div>
                  <div class="v2p-tpr-cmt-right">
                    <div class="v2p-tpr v2p-tpr-cmt-header"></div>
                    <div class="v2p-tpr v2p-tpr-cmt-p"></div>
                    <div class="v2p-tpr v2p-tpr-cmt-p" style="width: 70%;"></div>
                  </div>
                </div>

                <div class="v2p-tpr-cmt" style="opacity: 0.8;">
                  <div class="v2p-tpr v2p-tpr-cmt-avatar"></div>
                  <div class="v2p-tpr-cmt-right">
                    <div class="v2p-tpr v2p-tpr-cmt-header"></div>
                    <div class="v2p-tpr v2p-tpr-cmt-p"></div>
                    <div class="v2p-tpr v2p-tpr-cmt-p" style="width: 70%;"></div>
                  </div>
                </div>

                <div class="v2p-tpr-cmt" style="opacity: 0.6;">
                  <div class="v2p-tpr v2p-tpr-cmt-avatar"></div>
                  <div class="v2p-tpr-cmt-right">
                    <div class="v2p-tpr v2p-tpr-cmt-header"></div>
                    <div class="v2p-tpr v2p-tpr-cmt-p"></div>
                    <div class="v2p-tpr v2p-tpr-cmt-p" style="width: 70%;"></div>
                  </div>
                </div>
                <div class="v2p-tpr-cmt" style="opacity: 0.4;">
                  <div class="v2p-tpr v2p-tpr-cmt-avatar"></div>
                  <div class="v2p-tpr-cmt-right">
                    <div class="v2p-tpr v2p-tpr-cmt-header"></div>
                    <div class="v2p-tpr v2p-tpr-cmt-p"></div>
                    <div class="v2p-tpr v2p-tpr-cmt-p" style="width: 70%;"></div>
                  </div>
                </div>
              </div>
            `);
            const promises = [
              fetchTopic(topicId, { signal: abortController.signal }),
              crawlTopicPage(`/t/${topicId}`)
            ];
            try {
              const [{ result: topic }, topicPageText] = await Promise.all(promises);
              const data = {
                topic,
                cacheTime: Date.now(),
                topicPageText
              };
              topicDataCache.set(topicId, data);
              cacheData = data;
            } catch (err) {
              const $errorTip = $('<div style="padding: 20px; text-align: center;">');
              if (err instanceof Error) {
                if (
                  // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
                  err.message === "Invalid token" /* InvalidToken */ || // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
                  err.message === "Token expired" /* TokenExpired */
                ) {
                  $errorTip.html(
                    invalidTemplate(
                      '\u60A8\u7684 Token \u5DF2\u5931\u6548\uFF0C\u8BF7<a class="v2p-topic-preview-retry" href="https://www.v2ex.com/settings/tokens" target="_blank">\u91CD\u65B0\u8BBE\u7F6E</a>\u3002'
                    )
                  );
                }
              } else {
                $errorTip.html('\u52A0\u8F7D\u4E3B\u9898\u5931\u8D25\uFF0C<a class="v2p-topic-preview-retry">\u70B9\u51FB\u91CD\u8BD5</a>\u3002');
                $errorTip.find(".v2p-topic-preview-retry").on("click", () => {
                  load();
                });
              }
              modal.$content.empty().append($errorTip);
            }
          }
          if (cacheData) {
            const { topic, topicPageText } = cacheData;
            if (!topicTitle) {
              $titleLink.attr("title", topic.title);
              $titleLink.text(topic.title);
            }
            const $page = $(topicPageText);
            const $topicPreview = $('<div id="Main" class="v2p-topic-preview">');
            const $infoBar = $(`
              <div class="v2p-tp-info-bar">
                <div class="v2p-tp-info">
                  <a class="v2p-tp-member" href="${topic.member.url}">
                    <img class="v2p-tp-avatar" src="${topic.member.avatar}">
                    <span>${topic.member.username}</span>
                  </a>

                  <span>
                    ${formatTimestamp(topic.created, { format: "YMDHM" })}
                  </span>

                  <span>${topic.replies} \u6761\u56DE\u590D</span>
                </div>
              </div>
            `);
            const iconBook = createElement$1(BookOpenCheck);
            iconBook.setAttribute("width", "100%");
            iconBook.setAttribute("height", "100%");
            const $readingBtn = $(
              '<div class="v2p-tp-read"><span class="v2p-tp-read-icon"></span>\u7A0D\u540E\u9605\u8BFB</div>'
            );
            $readingBtn.find(".v2p-tp-read-icon").append(iconBook);
            $readingBtn.on("click", () => {
              void addToReadingList({
                url: topic.url,
                title: topic.title,
                content: topic.content
              });
            }).appendTo($infoBar);
            $topicPreview.append($infoBar);
            const $topicMain = $page.find("#Main");
            const $topicContent = $topicMain.find("> .box > .cell > .topic_content");
            const $topicSubtle = $topicMain.find("> .box >.subtle");
            if ($topicContent.length <= 0) {
              $topicPreview.append(`
                <div class="v2p-empty-content">
                  <div class="v2p-text-emoji">\xAF\\_(\u30C4)_/\xAF</div>
                  <p>\u8BE5\u4E3B\u9898\u6CA1\u6709\u6B63\u6587\u5185\u5BB9</p>
                </div>
              `);
            } else {
              $topicPreview.append($topicContent);
              $topicContent.wrap('<div class="cell">');
            }
            $topicPreview.append($topicSubtle);
            const $topicReplyBox = $topicMain.find('.box:has(.cell[id^="r_"])');
            if ($topicReplyBox.length > 0) {
              $topicReplyBox.css({ "margin-top": "20px", padding: "0" });
              const $commentCells2 = $topicReplyBox.find('.cell[id^="r_"]');
              const $commentTableRows2 = $commentCells2.find("> table > tbody > tr");
              const commentDataList2 = getCommentDataList({
                options,
                $commentTableRows: $commentTableRows2,
                $commentCells: $commentCells2
              });
              $commentCells2.each((i, cellDom) => {
                const currentComment = commentDataList2.at(i);
                if (currentComment?.id !== cellDom.id) {
                  return;
                }
                const $cellDom = $(cellDom);
                const { memberName, thanked } = currentComment;
                if (memberName === loginName && !options.hideAccount) {
                  $cellDom.find(".badges").append(
                    `<div class="badge ${memberName === topic.member.username ? "mod" : "you"}">YOU</div>`
                  );
                }
                const $likesBox = $cellDom.find(".small.fade").addClass("v2p-likes-box");
                $likesBox.find('img[alt="\u2764\uFE0F"]').replaceWith('<span class="v2p-icon-heart"><i data-lucide="heart"></i></span>');
                if (thanked) {
                  $likesBox.addClass("v2p-thanked");
                }
              });
              handleNestedComment({ options, $commentCells: $commentCells2, commentDataList: commentDataList2 });
              const $rightArea = $topicReplyBox.find('.cell[id^="r_"] > table > tbody > tr > td:last-of-type > .fr').children(":not(.no)");
              $rightArea.remove();
              $topicPreview.append($topicReplyBox);
              if (topic.replies > 100) {
                $topicPreview.append(`
                  <div class="v2p-topic-reply-tip">
                    <a
                      href="${linkHref || ""}"
                      style="color: currentColor;"
                    >
                        \u5728\u4E3B\u9898\u5185\u67E5\u770B\u5B8C\u6574\u8BC4\u8BBA...
                    </a>
                  </div>
                `);
              }
              replaceCommentEmojiWithHD($commentCells2);
            }
            if (options.openInNewTab) {
              $topicPreview.find("a").prop("target", "_blank");
            }
            modal.$content.empty().append($topicPreview);
            handleLinkPreview();
            modal.$content.attr("tabindex", "0");
            modal.$content.trigger("focus");
            loadIcons();
          }
        };
        load();
      } else {
        modal.$content.empty().append(invalidTemplate("\u60A8\u9700\u8981\u5148\u8BBE\u7F6E PAT \u624D\u80FD\u83B7\u53D6\u9884\u89C8\u5185\u5BB9\u3002"));
      }
    }
  };
  return {
    handlePreview
  };
}
var invalidTemplate, topicDataCache;
var init_use_topic_preview = __esm({
  "src/use-topic-preview.ts"() {
    "use strict";
    init_lucide();
    init_button();
    init_modal();
    init_constants();
    init_dom();
    init_globals();
    init_helpers();
    init_content();
    init_icons();
    init_services();
    init_utils();
    invalidTemplate = (tip) => `
<div class="v2p-no-pat">
  <div class="v2p-no-pat-title">${tip}</div>
  <div class="v2p-no-pat-desc">
    \u8BF7\u524D\u5F80<span class="v2p-no-pat-block"><span class="v2p-icon-logo">${iconLogo}</span> <span style="margin: 0 5px;">></span> \u8BBE\u7F6E</span> \u8FDB\u884C\u8BBE\u7F6E\u3002
  </div>

  <div class="v2p-no-pat-steps">
    <div class="v2p-no-pat-step">
      <div style="font-weight:bold;margin-bottom:10px;font-size:15px;">1. \u5728\u6269\u5C55\u7A0B\u5E8F\u5217\u8868\u4E2D\u627E\u5230\u5E76\u70B9\u51FB\u300CV2EX Polish\u300D\u3002</div>
      <img class="v2p-no-pat-img" src="https://i.imgur.com/UfNkuTF.png">
    </div>
    <div class="v2p-no-pat-step">
      <div style="font-weight:bold;margin-bottom:10px;font-size:15px;">2. \u5728\u5F39\u51FA\u7684\u5C0F\u7A97\u53E3\u4E2D\u627E\u5230\u300C\u2699\uFE0F \u6309\u94AE\u300D\uFF0C\u8F93\u5165 PAT\u3002</div>
      <img class="v2p-no-pat-img" src="https://i.imgur.com/O6hP86A.png">
    </div>
  </div>
</div>
`;
    topicDataCache = /* @__PURE__ */ new Map();
  }
});

// src/contents/home/topic-list.ts
function handleTopicList() {
  if (!isBrowserExtension()) {
    return;
  }
  const storage = getStorageSync();
  const PAT = storage["api" /* API */]?.pat;
  const { handlePreview } = useTopicPreview();
  const $previewBtn = $('<button class="v2p-topic-preview-btn">\u9884\u89C8</button>');
  const $ignoreBtn = $('<span class="v2p-topic-ignore-btn">\u5C4F\u853D</span>');
  const $topicActions = $('<span class="v2p-topic-actions" />');
  $topicList.each((_, topicItem) => {
    const $topicItem = $(topicItem);
    const $itemTitle = $topicItem.find(".item_title");
    const $topicInfo = $topicItem.find(".topic_info");
    const topicTitle = $itemTitle.find(".topic-link").text();
    const linkHref = $topicItem.find(".topic-link").attr("href");
    const match = linkHref?.match(/\/t\/(\d+)/);
    const topicId = match?.at(1);
    const $lastChild = $topicInfo.find("> span:first-of-type");
    const $clonedTopicActions = $topicActions.clone();
    $clonedTopicActions.insertAfter($lastChild);
    $ignoreBtn.clone().on("click", () => {
      if (confirm(`\u786E\u5B9A\u5C4F\u853D\u4E3B\u9898 \u2308${topicTitle}\u230B\uFF1F`)) {
        if (typeof topicId === "string") {
          void (async () => {
            const toast = createToast({ message: `\u6B63\u5728\u5C4F\u853D\u4E3B\u9898 \u2308${topicTitle}\u230B`, duration: 0 });
            const pageText = await crawlTopicPage(`/t/${topicId}`, "0");
            const $ignoreBtn2 = $(pageText).find(".topic_buttons a:nth-of-type(3)");
            const txt = $ignoreBtn2.attr("onclick");
            if (txt) {
              const match2 = txt.match(/'\/.*'/);
              if (match2) {
                const result = match2[0].slice(1, -1);
                if (result.startsWith("/ignore/topic")) {
                  try {
                    await fetch(`${"https://www.v2ex.com" /* Origin */}${result}`);
                    createToast({ message: `\u2705 \u5DF2\u5C4F\u853D` });
                    $topicItem.remove();
                  } finally {
                    toast.clear();
                  }
                }
              }
            }
          })();
        }
      }
    }).appendTo($clonedTopicActions);
    $previewBtn.clone().on("click", () => {
      handlePreview({ topicId, topicTitle, linkHref });
    }).appendTo($clonedTopicActions);
  });
  if (PAT) {
    $("#TopicsHot,#my-recent-topics").find(".cell .item_hot_topic_title").each((_, topicTitle) => {
      const $topicItem = $(topicTitle);
      $previewBtn.clone().on("click", () => {
        const $link = $topicItem.find("> a");
        const linkHref = $link.attr("href");
        const match = linkHref?.match(/\/t\/(\d+)/);
        const topicId = match?.at(1);
        const topicTitle2 = $link.text();
        handlePreview({ topicId, topicTitle: topicTitle2, linkHref });
      }).appendTo($topicItem);
    });
  }
}
var init_topic_list = __esm({
  "src/contents/home/topic-list.ts"() {
    "use strict";
    init_toast();
    init_constants();
    init_services();
    init_use_topic_preview();
    init_utils();
    init_globals();
  }
});

// src/contents/home/index.ts
var home_exports = {};
var init_home = __esm({
  "src/contents/home/index.ts"() {
    "use strict";
    init_constants();
    init_utils();
    init_globals();
    init_helpers();
    init_topic_list();
    void (async () => {
      const storage = await getStorage();
      const options = storage["options" /* Options */];
      {
        $("#Main .tab").addClass("v2p-hover-btn");
        if (options.openInNewTab) {
          $('#Main .topic-link, .item_hot_topic_title > a, .item_node, a[href="/write"]').prop(
            "target",
            "_blank"
          );
        }
      }
      handleTopicList();
      {
        const dailyInfo = storage["daily" /* Daily */];
        if (dailyInfo?.lastCheckInTime) {
          if (isSameDay(dailyInfo.lastCheckInTime, Date.now())) {
            const $info = $(`
          <a class="cell v2p-info-row" href="/mission/daily">
            \u4ECA\u65E5\u5DF2\u81EA\u52A8\u7B7E\u5230
          </a>
        `);
            $infoCard.append($info);
          }
        }
      }
      loadIcons();
    })();
  }
});

// node_modules/.pnpm/@floating-ui+utils@0.2.3/node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs
function clamp(start, value, end) {
  return max(start, min(value, end));
}
function evaluate(value, param) {
  return typeof value === "function" ? value(param) : value;
}
function getSide(placement) {
  return placement.split("-")[0];
}
function getAlignment(placement) {
  return placement.split("-")[1];
}
function getOppositeAxis(axis) {
  return axis === "x" ? "y" : "x";
}
function getAxisLength(axis) {
  return axis === "y" ? "height" : "width";
}
function getSideAxis(placement) {
  return ["top", "bottom"].includes(getSide(placement)) ? "y" : "x";
}
function getAlignmentAxis(placement) {
  return getOppositeAxis(getSideAxis(placement));
}
function getAlignmentSides(placement, rects, rtl) {
  if (rtl === void 0) {
    rtl = false;
  }
  const alignment = getAlignment(placement);
  const alignmentAxis = getAlignmentAxis(placement);
  const length = getAxisLength(alignmentAxis);
  let mainAlignmentSide = alignmentAxis === "x" ? alignment === (rtl ? "end" : "start") ? "right" : "left" : alignment === "start" ? "bottom" : "top";
  if (rects.reference[length] > rects.floating[length]) {
    mainAlignmentSide = getOppositePlacement(mainAlignmentSide);
  }
  return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)];
}
function getExpandedPlacements(placement) {
  const oppositePlacement = getOppositePlacement(placement);
  return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];
}
function getOppositeAlignmentPlacement(placement) {
  return placement.replace(/start|end/g, (alignment) => oppositeAlignmentMap[alignment]);
}
function getSideList(side, isStart, rtl) {
  const lr = ["left", "right"];
  const rl = ["right", "left"];
  const tb = ["top", "bottom"];
  const bt = ["bottom", "top"];
  switch (side) {
    case "top":
    case "bottom":
      if (rtl) return isStart ? rl : lr;
      return isStart ? lr : rl;
    case "left":
    case "right":
      return isStart ? tb : bt;
    default:
      return [];
  }
}
function getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {
  const alignment = getAlignment(placement);
  let list = getSideList(getSide(placement), direction === "start", rtl);
  if (alignment) {
    list = list.map((side) => side + "-" + alignment);
    if (flipAlignment) {
      list = list.concat(list.map(getOppositeAlignmentPlacement));
    }
  }
  return list;
}
function getOppositePlacement(placement) {
  return placement.replace(/left|right|bottom|top/g, (side) => oppositeSideMap[side]);
}
function expandPaddingObject(padding) {
  return {
    top: 0,
    right: 0,
    bottom: 0,
    left: 0,
    ...padding
  };
}
function getPaddingObject(padding) {
  return typeof padding !== "number" ? expandPaddingObject(padding) : {
    top: padding,
    right: padding,
    bottom: padding,
    left: padding
  };
}
function rectToClientRect(rect) {
  const {
    x,
    y,
    width,
    height
  } = rect;
  return {
    width,
    height,
    top: y,
    left: x,
    right: x + width,
    bottom: y + height,
    x,
    y
  };
}
var min, max, oppositeSideMap, oppositeAlignmentMap;
var init_floating_ui_utils = __esm({
  "node_modules/.pnpm/@floating-ui+utils@0.2.3/node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs"() {
    "use strict";
    min = Math.min;
    max = Math.max;
    oppositeSideMap = {
      left: "right",
      right: "left",
      bottom: "top",
      top: "bottom"
    };
    oppositeAlignmentMap = {
      start: "end",
      end: "start"
    };
  }
});

// node_modules/.pnpm/@floating-ui+core@1.6.3/node_modules/@floating-ui/core/dist/floating-ui.core.mjs
function computeCoordsFromPlacement(_ref, placement, rtl) {
  let {
    reference,
    floating
  } = _ref;
  const sideAxis = getSideAxis(placement);
  const alignmentAxis = getAlignmentAxis(placement);
  const alignLength = getAxisLength(alignmentAxis);
  const side = getSide(placement);
  const isVertical = sideAxis === "y";
  const commonX = reference.x + reference.width / 2 - floating.width / 2;
  const commonY = reference.y + reference.height / 2 - floating.height / 2;
  const commonAlign = reference[alignLength] / 2 - floating[alignLength] / 2;
  let coords;
  switch (side) {
    case "top":
      coords = {
        x: commonX,
        y: reference.y - floating.height
      };
      break;
    case "bottom":
      coords = {
        x: commonX,
        y: reference.y + reference.height
      };
      break;
    case "right":
      coords = {
        x: reference.x + reference.width,
        y: commonY
      };
      break;
    case "left":
      coords = {
        x: reference.x - floating.width,
        y: commonY
      };
      break;
    default:
      coords = {
        x: reference.x,
        y: reference.y
      };
  }
  switch (getAlignment(placement)) {
    case "start":
      coords[alignmentAxis] -= commonAlign * (rtl && isVertical ? -1 : 1);
      break;
    case "end":
      coords[alignmentAxis] += commonAlign * (rtl && isVertical ? -1 : 1);
      break;
  }
  return coords;
}
async function detectOverflow(state, options) {
  var _await$platform$isEle;
  if (options === void 0) {
    options = {};
  }
  const {
    x,
    y,
    platform: platform2,
    rects,
    elements,
    strategy
  } = state;
  const {
    boundary = "clippingAncestors",
    rootBoundary = "viewport",
    elementContext = "floating",
    altBoundary = false,
    padding = 0
  } = evaluate(options, state);
  const paddingObject = getPaddingObject(padding);
  const altContext = elementContext === "floating" ? "reference" : "floating";
  const element = elements[altBoundary ? altContext : elementContext];
  const clippingClientRect = rectToClientRect(await platform2.getClippingRect({
    element: ((_await$platform$isEle = await (platform2.isElement == null ? void 0 : platform2.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || await (platform2.getDocumentElement == null ? void 0 : platform2.getDocumentElement(elements.floating)),
    boundary,
    rootBoundary,
    strategy
  }));
  const rect = elementContext === "floating" ? {
    x,
    y,
    width: rects.floating.width,
    height: rects.floating.height
  } : rects.reference;
  const offsetParent = await (platform2.getOffsetParent == null ? void 0 : platform2.getOffsetParent(elements.floating));
  const offsetScale = await (platform2.isElement == null ? void 0 : platform2.isElement(offsetParent)) ? await (platform2.getScale == null ? void 0 : platform2.getScale(offsetParent)) || {
    x: 1,
    y: 1
  } : {
    x: 1,
    y: 1
  };
  const elementClientRect = rectToClientRect(platform2.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform2.convertOffsetParentRelativeRectToViewportRelativeRect({
    elements,
    rect,
    offsetParent,
    strategy
  }) : rect);
  return {
    top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
    bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
    left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
    right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
  };
}
async function convertValueToCoords(state, options) {
  const {
    placement,
    platform: platform2,
    elements
  } = state;
  const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(elements.floating));
  const side = getSide(placement);
  const alignment = getAlignment(placement);
  const isVertical = getSideAxis(placement) === "y";
  const mainAxisMulti = ["left", "top"].includes(side) ? -1 : 1;
  const crossAxisMulti = rtl && isVertical ? -1 : 1;
  const rawValue = evaluate(options, state);
  let {
    mainAxis,
    crossAxis,
    alignmentAxis
  } = typeof rawValue === "number" ? {
    mainAxis: rawValue,
    crossAxis: 0,
    alignmentAxis: null
  } : {
    mainAxis: 0,
    crossAxis: 0,
    alignmentAxis: null,
    ...rawValue
  };
  if (alignment && typeof alignmentAxis === "number") {
    crossAxis = alignment === "end" ? alignmentAxis * -1 : alignmentAxis;
  }
  return isVertical ? {
    x: crossAxis * crossAxisMulti,
    y: mainAxis * mainAxisMulti
  } : {
    x: mainAxis * mainAxisMulti,
    y: crossAxis * crossAxisMulti
  };
}
var computePosition, flip, offset, shift;
var init_floating_ui_core = __esm({
  "node_modules/.pnpm/@floating-ui+core@1.6.3/node_modules/@floating-ui/core/dist/floating-ui.core.mjs"() {
    "use strict";
    init_floating_ui_utils();
    init_floating_ui_utils();
    computePosition = async (reference, floating, config) => {
      const {
        placement = "bottom",
        strategy = "absolute",
        middleware = [],
        platform: platform2
      } = config;
      const validMiddleware = middleware.filter(Boolean);
      const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(floating));
      let rects = await platform2.getElementRects({
        reference,
        floating,
        strategy
      });
      let {
        x,
        y
      } = computeCoordsFromPlacement(rects, placement, rtl);
      let statefulPlacement = placement;
      let middlewareData = {};
      let resetCount = 0;
      for (let i = 0; i < validMiddleware.length; i++) {
        const {
          name,
          fn
        } = validMiddleware[i];
        const {
          x: nextX,
          y: nextY,
          data,
          reset
        } = await fn({
          x,
          y,
          initialPlacement: placement,
          placement: statefulPlacement,
          strategy,
          middlewareData,
          rects,
          platform: platform2,
          elements: {
            reference,
            floating
          }
        });
        x = nextX != null ? nextX : x;
        y = nextY != null ? nextY : y;
        middlewareData = {
          ...middlewareData,
          [name]: {
            ...middlewareData[name],
            ...data
          }
        };
        if (reset && resetCount <= 50) {
          resetCount++;
          if (typeof reset === "object") {
            if (reset.placement) {
              statefulPlacement = reset.placement;
            }
            if (reset.rects) {
              rects = reset.rects === true ? await platform2.getElementRects({
                reference,
                floating,
                strategy
              }) : reset.rects;
            }
            ({
              x,
              y
            } = computeCoordsFromPlacement(rects, statefulPlacement, rtl));
          }
          i = -1;
        }
      }
      return {
        x,
        y,
        placement: statefulPlacement,
        strategy,
        middlewareData
      };
    };
    flip = function(options) {
      if (options === void 0) {
        options = {};
      }
      return {
        name: "flip",
        options,
        async fn(state) {
          var _middlewareData$arrow, _middlewareData$flip;
          const {
            placement,
            middlewareData,
            rects,
            initialPlacement,
            platform: platform2,
            elements
          } = state;
          const {
            mainAxis: checkMainAxis = true,
            crossAxis: checkCrossAxis = true,
            fallbackPlacements: specifiedFallbackPlacements,
            fallbackStrategy = "bestFit",
            fallbackAxisSideDirection = "none",
            flipAlignment = true,
            ...detectOverflowOptions
          } = evaluate(options, state);
          if ((_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
            return {};
          }
          const side = getSide(placement);
          const initialSideAxis = getSideAxis(initialPlacement);
          const isBasePlacement = getSide(initialPlacement) === initialPlacement;
          const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(elements.floating));
          const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement));
          const hasFallbackAxisSideDirection = fallbackAxisSideDirection !== "none";
          if (!specifiedFallbackPlacements && hasFallbackAxisSideDirection) {
            fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));
          }
          const placements2 = [initialPlacement, ...fallbackPlacements];
          const overflow = await detectOverflow(state, detectOverflowOptions);
          const overflows = [];
          let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
          if (checkMainAxis) {
            overflows.push(overflow[side]);
          }
          if (checkCrossAxis) {
            const sides2 = getAlignmentSides(placement, rects, rtl);
            overflows.push(overflow[sides2[0]], overflow[sides2[1]]);
          }
          overflowsData = [...overflowsData, {
            placement,
            overflows
          }];
          if (!overflows.every((side2) => side2 <= 0)) {
            var _middlewareData$flip2, _overflowsData$filter;
            const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;
            const nextPlacement = placements2[nextIndex];
            if (nextPlacement) {
              return {
                data: {
                  index: nextIndex,
                  overflows: overflowsData
                },
                reset: {
                  placement: nextPlacement
                }
              };
            }
            let resetPlacement = (_overflowsData$filter = overflowsData.filter((d) => d.overflows[0] <= 0).sort((a, b) => a.overflows[1] - b.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement;
            if (!resetPlacement) {
              switch (fallbackStrategy) {
                case "bestFit": {
                  var _overflowsData$filter2;
                  const placement2 = (_overflowsData$filter2 = overflowsData.filter((d) => {
                    if (hasFallbackAxisSideDirection) {
                      const currentSideAxis = getSideAxis(d.placement);
                      return currentSideAxis === initialSideAxis || // Create a bias to the `y` side axis due to horizontal
                      // reading directions favoring greater width.
                      currentSideAxis === "y";
                    }
                    return true;
                  }).map((d) => [d.placement, d.overflows.filter((overflow2) => overflow2 > 0).reduce((acc, overflow2) => acc + overflow2, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$filter2[0];
                  if (placement2) {
                    resetPlacement = placement2;
                  }
                  break;
                }
                case "initialPlacement":
                  resetPlacement = initialPlacement;
                  break;
              }
            }
            if (placement !== resetPlacement) {
              return {
                reset: {
                  placement: resetPlacement
                }
              };
            }
          }
          return {};
        }
      };
    };
    offset = function(options) {
      if (options === void 0) {
        options = 0;
      }
      return {
        name: "offset",
        options,
        async fn(state) {
          var _middlewareData$offse, _middlewareData$arrow;
          const {
            x,
            y,
            placement,
            middlewareData
          } = state;
          const diffCoords = await convertValueToCoords(state, options);
          if (placement === ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse.placement) && (_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
            return {};
          }
          return {
            x: x + diffCoords.x,
            y: y + diffCoords.y,
            data: {
              ...diffCoords,
              placement
            }
          };
        }
      };
    };
    shift = function(options) {
      if (options === void 0) {
        options = {};
      }
      return {
        name: "shift",
        options,
        async fn(state) {
          const {
            x,
            y,
            placement
          } = state;
          const {
            mainAxis: checkMainAxis = true,
            crossAxis: checkCrossAxis = false,
            limiter = {
              fn: (_ref) => {
                let {
                  x: x2,
                  y: y2
                } = _ref;
                return {
                  x: x2,
                  y: y2
                };
              }
            },
            ...detectOverflowOptions
          } = evaluate(options, state);
          const coords = {
            x,
            y
          };
          const overflow = await detectOverflow(state, detectOverflowOptions);
          const crossAxis = getSideAxis(getSide(placement));
          const mainAxis = getOppositeAxis(crossAxis);
          let mainAxisCoord = coords[mainAxis];
          let crossAxisCoord = coords[crossAxis];
          if (checkMainAxis) {
            const minSide = mainAxis === "y" ? "top" : "left";
            const maxSide = mainAxis === "y" ? "bottom" : "right";
            const min3 = mainAxisCoord + overflow[minSide];
            const max3 = mainAxisCoord - overflow[maxSide];
            mainAxisCoord = clamp(min3, mainAxisCoord, max3);
          }
          if (checkCrossAxis) {
            const minSide = crossAxis === "y" ? "top" : "left";
            const maxSide = crossAxis === "y" ? "bottom" : "right";
            const min3 = crossAxisCoord + overflow[minSide];
            const max3 = crossAxisCoord - overflow[maxSide];
            crossAxisCoord = clamp(min3, crossAxisCoord, max3);
          }
          const limitedCoords = limiter.fn({
            ...state,
            [mainAxis]: mainAxisCoord,
            [crossAxis]: crossAxisCoord
          });
          return {
            ...limitedCoords,
            data: {
              x: limitedCoords.x - x,
              y: limitedCoords.y - y
            }
          };
        }
      };
    };
  }
});

// node_modules/.pnpm/@floating-ui+dom@1.4.5/node_modules/@floating-ui/dom/dist/floating-ui.dom.mjs
function getWindow(node) {
  var _node$ownerDocument;
  return (node == null ? void 0 : (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
}
function getComputedStyle$1(element) {
  return getWindow(element).getComputedStyle(element);
}
function isNode(value) {
  return value instanceof getWindow(value).Node;
}
function getNodeName(node) {
  if (isNode(node)) {
    return (node.nodeName || "").toLowerCase();
  }
  return "#document";
}
function isHTMLElement(value) {
  return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;
}
function isShadowRoot(node) {
  if (typeof ShadowRoot === "undefined") {
    return false;
  }
  return node instanceof getWindow(node).ShadowRoot || node instanceof ShadowRoot;
}
function isOverflowElement(element) {
  const {
    overflow,
    overflowX,
    overflowY,
    display
  } = getComputedStyle$1(element);
  return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !["inline", "contents"].includes(display);
}
function isTableElement(element) {
  return ["table", "td", "th"].includes(getNodeName(element));
}
function isContainingBlock(element) {
  const safari = isSafari();
  const css = getComputedStyle$1(element);
  return css.transform !== "none" || css.perspective !== "none" || (css.containerType ? css.containerType !== "normal" : false) || !safari && (css.backdropFilter ? css.backdropFilter !== "none" : false) || !safari && (css.filter ? css.filter !== "none" : false) || ["transform", "perspective", "filter"].some((value) => (css.willChange || "").includes(value)) || ["paint", "layout", "strict", "content"].some((value) => (css.contain || "").includes(value));
}
function isSafari() {
  if (typeof CSS === "undefined" || !CSS.supports) return false;
  return CSS.supports("-webkit-backdrop-filter", "none");
}
function isLastTraversableNode(node) {
  return ["html", "body", "#document"].includes(getNodeName(node));
}
function getCssDimensions(element) {
  const css = getComputedStyle$1(element);
  let width = parseFloat(css.width) || 0;
  let height = parseFloat(css.height) || 0;
  const hasOffset = isHTMLElement(element);
  const offsetWidth = hasOffset ? element.offsetWidth : width;
  const offsetHeight = hasOffset ? element.offsetHeight : height;
  const shouldFallback = round(width) !== offsetWidth || round(height) !== offsetHeight;
  if (shouldFallback) {
    width = offsetWidth;
    height = offsetHeight;
  }
  return {
    width,
    height,
    $: shouldFallback
  };
}
function isElement(value) {
  return value instanceof Element || value instanceof getWindow(value).Element;
}
function unwrapElement(element) {
  return !isElement(element) ? element.contextElement : element;
}
function getScale(element) {
  const domElement = unwrapElement(element);
  if (!isHTMLElement(domElement)) {
    return createCoords(1);
  }
  const rect = domElement.getBoundingClientRect();
  const {
    width,
    height,
    $: $2
  } = getCssDimensions(domElement);
  let x = ($2 ? round(rect.width) : rect.width) / width;
  let y = ($2 ? round(rect.height) : rect.height) / height;
  if (!x || !Number.isFinite(x)) {
    x = 1;
  }
  if (!y || !Number.isFinite(y)) {
    y = 1;
  }
  return {
    x,
    y
  };
}
function getVisualOffsets(element) {
  const win = getWindow(element);
  if (!isSafari() || !win.visualViewport) {
    return noOffsets;
  }
  return {
    x: win.visualViewport.offsetLeft,
    y: win.visualViewport.offsetTop
  };
}
function shouldAddVisualOffsets(element, isFixed, floatingOffsetParent) {
  if (isFixed === void 0) {
    isFixed = false;
  }
  if (!floatingOffsetParent || isFixed && floatingOffsetParent !== getWindow(element)) {
    return false;
  }
  return isFixed;
}
function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetParent) {
  if (includeScale === void 0) {
    includeScale = false;
  }
  if (isFixedStrategy === void 0) {
    isFixedStrategy = false;
  }
  const clientRect = element.getBoundingClientRect();
  const domElement = unwrapElement(element);
  let scale = createCoords(1);
  if (includeScale) {
    if (offsetParent) {
      if (isElement(offsetParent)) {
        scale = getScale(offsetParent);
      }
    } else {
      scale = getScale(element);
    }
  }
  const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : createCoords(0);
  let x = (clientRect.left + visualOffsets.x) / scale.x;
  let y = (clientRect.top + visualOffsets.y) / scale.y;
  let width = clientRect.width / scale.x;
  let height = clientRect.height / scale.y;
  if (domElement) {
    const win = getWindow(domElement);
    const offsetWin = offsetParent && isElement(offsetParent) ? getWindow(offsetParent) : offsetParent;
    let currentIFrame = win.frameElement;
    while (currentIFrame && offsetParent && offsetWin !== win) {
      const iframeScale = getScale(currentIFrame);
      const iframeRect = currentIFrame.getBoundingClientRect();
      const css = getComputedStyle(currentIFrame);
      const left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x;
      const top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y;
      x *= iframeScale.x;
      y *= iframeScale.y;
      width *= iframeScale.x;
      height *= iframeScale.y;
      x += left;
      y += top;
      currentIFrame = getWindow(currentIFrame).frameElement;
    }
  }
  return rectToClientRect({
    width,
    height,
    x,
    y
  });
}
function getNodeScroll(element) {
  if (isElement(element)) {
    return {
      scrollLeft: element.scrollLeft,
      scrollTop: element.scrollTop
    };
  }
  return {
    scrollLeft: element.pageXOffset,
    scrollTop: element.pageYOffset
  };
}
function getDocumentElement(node) {
  var _ref;
  return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;
}
function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
  let {
    rect,
    offsetParent,
    strategy
  } = _ref;
  const isOffsetParentAnElement = isHTMLElement(offsetParent);
  const documentElement = getDocumentElement(offsetParent);
  if (offsetParent === documentElement) {
    return rect;
  }
  let scroll = {
    scrollLeft: 0,
    scrollTop: 0
  };
  let scale = createCoords(1);
  const offsets = createCoords(0);
  if (isOffsetParentAnElement || !isOffsetParentAnElement && strategy !== "fixed") {
    if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) {
      scroll = getNodeScroll(offsetParent);
    }
    if (isHTMLElement(offsetParent)) {
      const offsetRect = getBoundingClientRect(offsetParent);
      scale = getScale(offsetParent);
      offsets.x = offsetRect.x + offsetParent.clientLeft;
      offsets.y = offsetRect.y + offsetParent.clientTop;
    }
  }
  return {
    width: rect.width * scale.x,
    height: rect.height * scale.y,
    x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x,
    y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y
  };
}
function getClientRects(element) {
  return Array.from(element.getClientRects());
}
function getWindowScrollBarX(element) {
  return getBoundingClientRect(getDocumentElement(element)).left + getNodeScroll(element).scrollLeft;
}
function getDocumentRect(element) {
  const html = getDocumentElement(element);
  const scroll = getNodeScroll(element);
  const body = element.ownerDocument.body;
  const width = max2(html.scrollWidth, html.clientWidth, body.scrollWidth, body.clientWidth);
  const height = max2(html.scrollHeight, html.clientHeight, body.scrollHeight, body.clientHeight);
  let x = -scroll.scrollLeft + getWindowScrollBarX(element);
  const y = -scroll.scrollTop;
  if (getComputedStyle$1(body).direction === "rtl") {
    x += max2(html.clientWidth, body.clientWidth) - width;
  }
  return {
    width,
    height,
    x,
    y
  };
}
function getParentNode(node) {
  if (getNodeName(node) === "html") {
    return node;
  }
  const result = (
    // Step into the shadow DOM of the parent of a slotted node.
    node.assignedSlot || // DOM Element detected.
    node.parentNode || // ShadowRoot detected.
    isShadowRoot(node) && node.host || // Fallback.
    getDocumentElement(node)
  );
  return isShadowRoot(result) ? result.host : result;
}
function getNearestOverflowAncestor(node) {
  const parentNode = getParentNode(node);
  if (isLastTraversableNode(parentNode)) {
    return node.ownerDocument ? node.ownerDocument.body : node.body;
  }
  if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {
    return parentNode;
  }
  return getNearestOverflowAncestor(parentNode);
}
function getOverflowAncestors(node, list) {
  var _node$ownerDocument;
  if (list === void 0) {
    list = [];
  }
  const scrollableAncestor = getNearestOverflowAncestor(node);
  const isBody = scrollableAncestor === ((_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.body);
  const win = getWindow(scrollableAncestor);
  if (isBody) {
    return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : []);
  }
  return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor));
}
function getViewportRect(element, strategy) {
  const win = getWindow(element);
  const html = getDocumentElement(element);
  const visualViewport = win.visualViewport;
  let width = html.clientWidth;
  let height = html.clientHeight;
  let x = 0;
  let y = 0;
  if (visualViewport) {
    width = visualViewport.width;
    height = visualViewport.height;
    const visualViewportBased = isSafari();
    if (!visualViewportBased || visualViewportBased && strategy === "fixed") {
      x = visualViewport.offsetLeft;
      y = visualViewport.offsetTop;
    }
  }
  return {
    width,
    height,
    x,
    y
  };
}
function getInnerBoundingClientRect(element, strategy) {
  const clientRect = getBoundingClientRect(element, true, strategy === "fixed");
  const top = clientRect.top + element.clientTop;
  const left = clientRect.left + element.clientLeft;
  const scale = isHTMLElement(element) ? getScale(element) : createCoords(1);
  const width = element.clientWidth * scale.x;
  const height = element.clientHeight * scale.y;
  const x = left * scale.x;
  const y = top * scale.y;
  return {
    width,
    height,
    x,
    y
  };
}
function getClientRectFromClippingAncestor(element, clippingAncestor, strategy) {
  let rect;
  if (clippingAncestor === "viewport") {
    rect = getViewportRect(element, strategy);
  } else if (clippingAncestor === "document") {
    rect = getDocumentRect(getDocumentElement(element));
  } else if (isElement(clippingAncestor)) {
    rect = getInnerBoundingClientRect(clippingAncestor, strategy);
  } else {
    const visualOffsets = getVisualOffsets(element);
    rect = {
      ...clippingAncestor,
      x: clippingAncestor.x - visualOffsets.x,
      y: clippingAncestor.y - visualOffsets.y
    };
  }
  return rectToClientRect(rect);
}
function hasFixedPositionAncestor(element, stopNode) {
  const parentNode = getParentNode(element);
  if (parentNode === stopNode || !isElement(parentNode) || isLastTraversableNode(parentNode)) {
    return false;
  }
  return getComputedStyle$1(parentNode).position === "fixed" || hasFixedPositionAncestor(parentNode, stopNode);
}
function getClippingElementAncestors(element, cache) {
  const cachedResult = cache.get(element);
  if (cachedResult) {
    return cachedResult;
  }
  let result = getOverflowAncestors(element).filter((el) => isElement(el) && getNodeName(el) !== "body");
  let currentContainingBlockComputedStyle = null;
  const elementIsFixed = getComputedStyle$1(element).position === "fixed";
  let currentNode = elementIsFixed ? getParentNode(element) : element;
  while (isElement(currentNode) && !isLastTraversableNode(currentNode)) {
    const computedStyle = getComputedStyle$1(currentNode);
    const currentNodeIsContaining = isContainingBlock(currentNode);
    if (!currentNodeIsContaining && computedStyle.position === "fixed") {
      currentContainingBlockComputedStyle = null;
    }
    const shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === "static" && !!currentContainingBlockComputedStyle && ["absolute", "fixed"].includes(currentContainingBlockComputedStyle.position) || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element, currentNode);
    if (shouldDropCurrentNode) {
      result = result.filter((ancestor) => ancestor !== currentNode);
    } else {
      currentContainingBlockComputedStyle = computedStyle;
    }
    currentNode = getParentNode(currentNode);
  }
  cache.set(element, result);
  return result;
}
function getClippingRect(_ref) {
  let {
    element,
    boundary,
    rootBoundary,
    strategy
  } = _ref;
  const elementClippingAncestors = boundary === "clippingAncestors" ? getClippingElementAncestors(element, this._c) : [].concat(boundary);
  const clippingAncestors = [...elementClippingAncestors, rootBoundary];
  const firstClippingAncestor = clippingAncestors[0];
  const clippingRect = clippingAncestors.reduce((accRect, clippingAncestor) => {
    const rect = getClientRectFromClippingAncestor(element, clippingAncestor, strategy);
    accRect.top = max2(rect.top, accRect.top);
    accRect.right = min2(rect.right, accRect.right);
    accRect.bottom = min2(rect.bottom, accRect.bottom);
    accRect.left = max2(rect.left, accRect.left);
    return accRect;
  }, getClientRectFromClippingAncestor(element, firstClippingAncestor, strategy));
  return {
    width: clippingRect.right - clippingRect.left,
    height: clippingRect.bottom - clippingRect.top,
    x: clippingRect.left,
    y: clippingRect.top
  };
}
function getDimensions(element) {
  return getCssDimensions(element);
}
function getRectRelativeToOffsetParent(element, offsetParent, strategy) {
  const isOffsetParentAnElement = isHTMLElement(offsetParent);
  const documentElement = getDocumentElement(offsetParent);
  const isFixed = strategy === "fixed";
  const rect = getBoundingClientRect(element, true, isFixed, offsetParent);
  let scroll = {
    scrollLeft: 0,
    scrollTop: 0
  };
  const offsets = createCoords(0);
  if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
    if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) {
      scroll = getNodeScroll(offsetParent);
    }
    if (isHTMLElement(offsetParent)) {
      const offsetRect = getBoundingClientRect(offsetParent, true, isFixed, offsetParent);
      offsets.x = offsetRect.x + offsetParent.clientLeft;
      offsets.y = offsetRect.y + offsetParent.clientTop;
    } else if (documentElement) {
      offsets.x = getWindowScrollBarX(documentElement);
    }
  }
  return {
    x: rect.left + scroll.scrollLeft - offsets.x,
    y: rect.top + scroll.scrollTop - offsets.y,
    width: rect.width,
    height: rect.height
  };
}
function getTrueOffsetParent(element, polyfill) {
  if (!isHTMLElement(element) || getComputedStyle$1(element).position === "fixed") {
    return null;
  }
  if (polyfill) {
    return polyfill(element);
  }
  return element.offsetParent;
}
function getContainingBlock(element) {
  let currentNode = getParentNode(element);
  while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {
    if (isContainingBlock(currentNode)) {
      return currentNode;
    } else {
      currentNode = getParentNode(currentNode);
    }
  }
  return null;
}
function getOffsetParent(element, polyfill) {
  const window2 = getWindow(element);
  if (!isHTMLElement(element)) {
    return window2;
  }
  let offsetParent = getTrueOffsetParent(element, polyfill);
  while (offsetParent && isTableElement(offsetParent) && getComputedStyle$1(offsetParent).position === "static") {
    offsetParent = getTrueOffsetParent(offsetParent, polyfill);
  }
  if (offsetParent && (getNodeName(offsetParent) === "html" || getNodeName(offsetParent) === "body" && getComputedStyle$1(offsetParent).position === "static" && !isContainingBlock(offsetParent))) {
    return window2;
  }
  return offsetParent || getContainingBlock(element) || window2;
}
function isRTL(element) {
  return getComputedStyle(element).direction === "rtl";
}
var min2, max2, round, createCoords, noOffsets, getElementRects, platform, computePosition2;
var init_floating_ui_dom = __esm({
  "node_modules/.pnpm/@floating-ui+dom@1.4.5/node_modules/@floating-ui/dom/dist/floating-ui.dom.mjs"() {
    "use strict";
    init_floating_ui_core();
    init_floating_ui_core();
    min2 = Math.min;
    max2 = Math.max;
    round = Math.round;
    createCoords = (v) => ({
      x: v,
      y: v
    });
    noOffsets = /* @__PURE__ */ createCoords(0);
    getElementRects = async function(_ref) {
      let {
        reference,
        floating,
        strategy
      } = _ref;
      const getOffsetParentFn = this.getOffsetParent || getOffsetParent;
      const getDimensionsFn = this.getDimensions;
      return {
        reference: getRectRelativeToOffsetParent(reference, await getOffsetParentFn(floating), strategy),
        floating: {
          x: 0,
          y: 0,
          ...await getDimensionsFn(floating)
        }
      };
    };
    platform = {
      convertOffsetParentRelativeRectToViewportRelativeRect,
      getDocumentElement,
      getClippingRect,
      getOffsetParent,
      getElementRects,
      getClientRects,
      getDimensions,
      getScale,
      isElement,
      isRTL
    };
    computePosition2 = (reference, floating, options) => {
      const cache = /* @__PURE__ */ new Map();
      const mergedOptions = {
        platform,
        ...options
      };
      const platformWithCache = {
        ...mergedOptions.platform,
        _c: cache
      };
      return computePosition(reference, floating, {
        ...mergedOptions,
        platform: platformWithCache
      });
    };
  }
});

// src/components/popup.ts
function createPopup(props) {
  const {
    root,
    trigger,
    triggerType = "click",
    content,
    options,
    onOpen,
    onClose,
    placement = "bottom-start",
    offsetOptions = { mainAxis: 5, crossAxis: 5 }
  } = props;
  const $popupContent = $('<div class="v2p-popup-content">');
  const $popup = $('<div class="v2p-popup" tabindex="0">').css("visibility", "hidden").append($popupContent);
  root.append($popup);
  if (content) {
    $popup.append(content);
  }
  const popup = $popup.get(0);
  const handleClickOutside = (ev) => {
    if ($(ev.target).closest(popup).length === 0) {
      handlePopupClose();
    }
  };
  const handlePopupClose = () => {
    $popup.css("visibility", "hidden");
    $(document).off("click", handleClickOutside);
    onClose?.();
    popupControl2.onClose?.();
  };
  const handlePopupOpen = ($reference) => {
    if (!$reference) {
      return;
    }
    setTimeout(() => {
      $(document).on("click", handleClickOutside);
    });
    const referenceElement = $reference.get(0);
    computePosition2(referenceElement, popup, {
      placement,
      middleware: [offset(offsetOptions), flip(), shift({ padding: 8 })],
      ...options
    }).then(({ x, y }) => {
      Object.assign(popup.style, {
        left: `${x}px`,
        top: `${y}px`
      });
      $popup.css("visibility", "visible");
    }).catch(() => {
      handlePopupClose();
      createToast({ message: "\u274C Popup \u6E32\u67D3\u5931\u8D25" });
    });
    onOpen?.();
  };
  const popupControl2 = {
    $content: $popupContent,
    isOver: false,
    open: (reference) => {
      handlePopupOpen(reference);
    },
    close: handlePopupClose
  };
  if (triggerType === "hover") {
    $popup.on("mouseover", () => {
      if (!popupControl2.isOver) {
        popupControl2.isOver = true;
        $popup.off("mouseleave").on("mouseleave", () => {
          popupControl2.isOver = false;
          setTimeout(() => {
            if (!popupControl2.isOver) {
              popupControl2.close();
            }
          }, hoverDelay);
        });
      }
    });
  }
  trigger?.on("click", () => {
    if (popup.style.visibility !== "hidden") {
      handlePopupClose();
    } else {
      handlePopupOpen(trigger);
    }
  });
  return popupControl2;
}
var hoverDelay;
var init_popup = __esm({
  "src/components/popup.ts"() {
    "use strict";
    init_floating_ui_dom();
    init_toast();
    hoverDelay = 350;
  }
});

// src/contents/topic/avatar.ts
function processAvatar(params) {
  const {
    $trigger,
    popupControl: popupControl2,
    commentData,
    shouldWrap = true,
    openInNewTab = false,
    onSetTagsClick
  } = params;
  const { memberName, memberAvatar, memberLink } = commentData;
  let abortController = null;
  const handleOver = () => {
    popupControl2.close();
    popupControl2.open($trigger);
    const $content = $(`
      <div class="v2p-member-card">
        <div class="v2p-info">
          <div class="v2p-info-left">
            <a class="v2p-avatar-box" href="${memberLink}" target="${openInNewTab ? "_blank" : "_self"}">
              <img class="v2p-avatar" src="${memberAvatar}">
            </a>
          </div>

          <div class="v2p-info-right">
            <div class="v2p-username">
              <a href="${memberLink}" target="${openInNewTab ? "_blank" : "_self"}">${memberName}</a>
            </div>
            <div class="v2p-no v2p-loading"></div>
            <div class="v2p-created-date v2p-loading"></div>
          </div>

          </div>

          <div class="v2p-bio" style="disply:none;"></div>

          <div class="v2p-member-card-actions"></div>
      </div>
    `);
    popupControl2.$content.empty().append($content);
    createButton({ children: "\u6DFB\u52A0\u7528\u6237\u6807\u7B7E" }).on("click", () => {
      popupControl2.close();
      openTagsSetter({ memberName, memberAvatar });
      onSetTagsClick?.();
    }).appendTo($(".v2p-member-card-actions"));
    void (async () => {
      if (!memberDataCache.has(memberName)) {
        abortController = new AbortController();
        popupControl2.onClose = () => {
          abortController?.abort();
        };
        try {
          const memberData = await fetchUserInfo(memberName, {
            signal: abortController.signal
          });
          memberDataCache.set(memberName, {
            ...memberData,
            registerDays: getRegisterDays(memberData.created)
          });
        } catch (err) {
          if (err instanceof Error) {
            $content.html(`<span>${err.message}</span>`);
            if (err.cause === 404) {
              memberDataCache.set(memberName, banned);
            }
          }
          return null;
        }
      }
      const data = memberDataCache.get(memberName);
      if (typeof data === "object") {
        $content.find(".v2p-no").removeClass("v2p-loading").text(`V2EX \u7B2C ${data.id} \u53F7\u4F1A\u5458`);
        $content.find(".v2p-created-date").removeClass("v2p-loading").text(`\u52A0\u5165\u4E8E ${formatTimestamp(data.created)}`);
        if (data.registerDays <= 30) {
          $content.find(".v2p-info-right").append(
            `<div class="v2p-register-days" style="margin: 5px 0;">${data.registerDays <= 15 ? "15" : "30"} \u5929\u5185\u6CE8\u518C</div>`
          );
        }
        if (data.bio && data.bio.trim().length > 0) {
          $content.find(".v2p-bio").css("disply", "block").text(data.bio);
        }
      } else if (typeof data === "symbol" && data === banned) {
        $content.html("<span>\u67E5\u65E0\u6B64\u7528\u6237\uFF0C\u7591\u4F3C\u5DF2\u88AB\u5C01\u7981</span>");
      }
    })();
  };
  let isOver = false;
  $trigger.on("mouseover", () => {
    isOver = true;
    setTimeout(() => {
      if (isOver) {
        handleOver();
      }
    }, hoverDelay);
  }).on("mouseleave", () => {
    isOver = false;
    setTimeout(() => {
      if (!popupControl2.isOver && !isOver) {
        popupControl2.close();
      }
    }, hoverDelay);
  });
  if (shouldWrap) {
    $trigger.wrap(
      `<a href="/member/${commentData.memberName}" target="_blank" style="cursor: pointer;">`
    );
  }
}
var banned, memberDataCache;
var init_avatar = __esm({
  "src/contents/topic/avatar.ts"() {
    "use strict";
    init_button();
    init_popup();
    init_services();
    init_utils();
    init_helpers();
    init_content();
    banned = Symbol();
    memberDataCache = /* @__PURE__ */ new Map();
  }
});

// src/contents/topic/comment.ts
function handleFilteredComments() {
  const iconHeart = createElement$1(Heart);
  iconHeart.setAttribute("width", "100%");
  iconHeart.setAttribute("height", "100%");
  const $commentsBtn = $(
    `<span class="v2p-tool v2p-hover-btn"><span class="v2p-tool-icon"></span>\u70ED\u95E8\u56DE\u590D</span>`
  );
  $commentsBtn.find(".v2p-tool-icon").append(iconHeart);
  $(".v2p-tools").prepend($commentsBtn);
  const popularCommentData = commentDataList.filter(({ likes }) => likes > 0).sort((a, b) => b.likes - a.likes);
  const popularCount = popularCommentData.length;
  const modal = createModal({
    root: $main,
    onMount: ({ $title, $content }) => {
      const $template = $('<div class="v2p-modal-comments">');
      const $t1 = $template.clone().attr("data-tab-key", "hot").addClass("v2p-tab-content-active");
      const $t2 = $template.clone().attr("data-tab-key", "recent");
      const $t3 = $template.clone().attr("data-tab-key", "op");
      {
        if (popularCount > 0) {
          popularCommentData.forEach(({ index, refMemberNames }) => {
            const $clonedCell = $commentCells.eq(index).clone();
            $clonedCell.find(".v2p-controls > a:has(.v2p-control-reply)").remove();
            $clonedCell.find(".no").css("pointer-events", "none");
            const firstRefMember = refMemberNames?.at(0);
            if (firstRefMember) {
              const replyMember = commentDataList.findLast(
                (it, idx) => idx < index && it.memberName === firstRefMember
              );
              if (replyMember) {
                $clonedCell.prepend(
                  $(`
                    <div class="v2p-topic-reply-ref">
                      <div class="v2p-topic-reply">
                        <div class="v2p-topic-reply-member">
                          <a href="${replyMember.memberLink}" target="_blank">
                            <img class="v2p-topic-reply-avatar" src="${replyMember.memberAvatar}">
                            <span>${replyMember.memberName}</span>
                          </a>\uFF1A
                        </div>
                        <div class="v2p-topic-reply-content">${escapeHTML(replyMember.content)}</div>
                      </div>
                    </div>
                  `)
                );
              }
            }
            $t1.append($clonedCell);
          });
        } else {
          $t1.append($("<div>\u6682\u65E0\u70ED\u95E8\u56DE\u590D</div>").css({ padding: "20px", textAlign: "center" }));
        }
        $content.append($t1);
      }
      {
        const len = commentDataList.length;
        const displayNum = len < 10 ? len : len <= 10 ? 5 : len <= 30 ? 10 : len <= 60 ? 20 : len <= 100 ? 40 : len <= 200 ? 60 : 90;
        if (displayNum > 0) {
          const recentCommentData = commentDataList.slice(-1 * displayNum).reverse();
          recentCommentData.forEach(({ index, refMemberNames }) => {
            const $clonedCell = $commentCells.eq(index).clone();
            $clonedCell.find(".v2p-controls > a:has(.v2p-control-reply)").remove();
            $clonedCell.find(".no").css("pointer-events", "none");
            const firstRefMember = refMemberNames?.at(0);
            if (firstRefMember) {
              const replyMember = commentDataList.findLast(
                (it, idx) => idx < index && it.memberName === firstRefMember
              );
              if (replyMember) {
                $clonedCell.prepend(
                  $(`
                    <div class="v2p-topic-reply-ref">
                      <div class="v2p-topic-reply">
                        <div class="v2p-topic-reply-member">
                          <a href="${replyMember.memberLink}" target="_blank">
                            <img class="v2p-topic-reply-avatar" src="${replyMember.memberAvatar}">
                            <span>${replyMember.memberName}</span>
                          </a>\uFF1A
                        </div>
                        <div class="v2p-topic-reply-content">${escapeHTML(replyMember.content)}</div>
                      </div>
                    </div>
                  `)
                );
              }
            }
            $t2.append($clonedCell);
          });
        } else {
          $t2.append($("<div>\u6682\u65E0\u6700\u8FD1\u56DE\u590D</div>").css({ padding: "20px", textAlign: "center" }));
        }
        $content.append($t2);
      }
      {
        const opCommentData = commentDataList.filter(
          ({ memberName }) => memberName === topicOwnerName
        );
        if (opCommentData.length > 0) {
          opCommentData.forEach(({ index, refMemberNames }) => {
            const $clonedCell = $commentCells.eq(index).clone();
            $clonedCell.find(".v2p-controls > a:has(.v2p-control-reply)").remove();
            $clonedCell.find(".no").css("pointer-events", "none");
            const firstRefMember = refMemberNames?.at(0);
            if (firstRefMember) {
              const replyMember = commentDataList.findLast(
                (it, idx) => idx < index && it.memberName === firstRefMember
              );
              if (replyMember) {
                $clonedCell.prepend(
                  $(`
                    <div class="v2p-topic-reply-ref">
                      <div class="v2p-topic-reply">
                        <div class="v2p-topic-reply-member">
                          <a href="${replyMember.memberLink}" target="_blank">
                            <img class="v2p-topic-reply-avatar" src="${replyMember.memberAvatar}">
                            <span>${replyMember.memberName}</span>
                          </a>\uFF1A
                        </div>
                        <div class="v2p-topic-reply-content">${escapeHTML(replyMember.content)}</div>
                      </div>
                    </div>
                  `)
                );
              }
            }
            $t3.append($clonedCell);
          });
        } else {
          $t3.append($("<div>\u6682\u65E0\u9898\u4E3B\u56DE\u590D</div>").css({ padding: "20px", textAlign: "center" }));
        }
        $content.append($t3);
      }
      const $tabs = $(`
        <div class="v2p-modal-comment-tabs">
          <div data-tab-key="hot" class="v2p-tab-active">\u70ED\u95E8\u56DE\u590D</div>
          <div data-tab-key="recent">\u6700\u8FD1\u56DE\u590D</div>
          <div data-tab-key="op">\u9898\u4E3B\u56DE\u590D</div>
        </div>
      `);
      $title.append($tabs);
      $tabs.find("[data-tab-key]").on("click", (ev) => {
        const $target = $(ev.currentTarget);
        const { tabKey } = $target.data();
        if (typeof tabKey === "string") {
          $target.addClass("v2p-tab-active").siblings().removeClass("v2p-tab-active");
          $(`.v2p-modal-comments[data-tab-key="${tabKey}"]`).addClass("v2p-tab-content-active").siblings().removeClass("v2p-tab-content-active");
        }
      });
      replaceCommentEmojiWithHD($content.find('.cell[id^="r_"]'));
    },
    onOpen: ({ $content }) => {
      const storage = getStorageSync();
      const options = storage["options" /* Options */];
      $content.find('.cell[id^="r_"]').each((_, cellDom) => {
        if (options.replyContent.autoFold) {
          processReplyContent($(cellDom));
        }
      });
      handleLinkPreview();
    }
  });
  $commentsBtn.on("click", () => {
    modal.open();
  });
  {
    const $commentBoxCount = $commentBox.find(".cell:first-of-type > span.gray");
    const countText = $commentBoxCount.text();
    const newCountText = countText.substring(0, countText.indexOf("\u56DE\u590D") + 2);
    const countTextSpan = `<span class="count-text">${newCountText}</span><span class="v2p-dot">\xB7</span>${popularCount} \u6761\u70ED\u95E8\u56DE\u590D`;
    $commentBoxCount.empty().append(countTextSpan);
  }
}
function processActions($cellDom, data) {
  const $actions = $cellDom.find("> table > tbody > tr > td:last-of-type > .fr");
  const $controls = $('<span class="v2p-controls">');
  const $thankIcon = $(
    `<span
      class="v2p-control v2p-control-thank"
      data-id="${data.id}"
      data-member-name="${data.memberName}"
     >
        <i data-lucide="heart"></i>
     </span>`
  );
  const thankArea = $actions.find("> .thank_area");
  const thanked = thankArea.hasClass("thanked");
  if (thanked) {
    $thankIcon.addClass("v2p-thanked");
    $controls.append($("<a>").append($thankIcon));
  } else {
    const thankEle = thankArea.find("> .thank");
    const $hide = thankEle.eq(0).removeClass("thank");
    const $thank = thankEle.eq(1).removeClass("thank");
    $hide.html(
      `<span class="v2p-control v2p-hover-btn v2p-control-hide"><i data-lucide="eye-off"></i></span>`
    );
    $thankIcon.addClass("v2p-hover-btn").replaceAll($thank);
    $controls.append($hide).append($thankIcon);
  }
  const $reply = $actions.find("a:last-of-type");
  $reply.find('> img[alt="Reply"]').replaceWith(
    `<span class="v2p-control v2p-hover-btn v2p-control-reply"><i data-lucide="message-square"></i></span>`
  );
  $controls.append($reply);
  thankArea.remove();
  const floorNum = $actions.find(".no").clone();
  $reply.on("click", () => {
    const replyVal = $replyTextArea.val();
    if (typeof replyVal === "string" && replyVal.length > 0) {
      const floor = floorNum.text();
      const replyComment = commentDataList.find((it) => it.floor === floor);
      if (replyComment) {
        const replyMemberName = replyComment.memberName;
        const moreThanOneReply = commentDataList.findIndex(
          (it) => it.memberName === replyMemberName && it.floor !== floor
        ) !== -1;
        if (moreThanOneReply) {
          insertTextToReplyInput(`#${floor} `);
        } else {
          const $page = $(".v2p-paging").eq(0).find(".page_normal, .page_current");
          if ($page.length > 1) {
            const onLastPage = $page.last().hasClass("page_current");
            if (!onLastPage) {
              insertTextToReplyInput(`#${floor} `);
            }
          }
        }
      }
    }
  });
  $actions.empty().append($controls, floorNum);
}
async function handleComments() {
  const storage = getStorageSync();
  const tagData = storage["member-tag" /* MemberTag */];
  const options = storage["options" /* Options */];
  if (options.reply.preload !== "off") {
    const $paging = $(".v2p-paging");
    if ($paging.length > 0) {
      const $pagingTop = $paging.eq(0);
      const $pagingBottom = $paging.eq(1);
      const $pageNormal = $paging.find(".page_normal");
      const $pagingTopNormal = $pagingTop.find(".page_normal");
      const toastControl = createToast({ message: "\u6B63\u5728\u9884\u52A0\u8F7D\u56DE\u590D\uFF0C\u8BF7\u7A0D\u5019...", duration: 0 });
      try {
        const $pagingBottomNormal = $pagingBottom.find(".page_normal");
        const $pageCurrent = $pagingTop.find(".page_current");
        const currentPage = $pageCurrent.text();
        if (currentPage === "1") {
          const pages = [];
          $pagingTopNormal.each((i, ele) => {
            if (i <= 1) {
              if (ele.textContent) {
                ele.classList.add("page_current");
                ele.classList.remove("page_normal");
                $pagingBottomNormal.eq(i).addClass("page_current").removeClass("page_normal");
                pages.push(ele.textContent);
              }
            }
          });
          if (pages.length > 0) {
            const pagesText = await Promise.all(
              pages.map((p) => crawlTopicPage(window.location.pathname, p))
            );
            pagesText.map((pageText) => {
              $pagingBottom.before($(pageText).find('.cell[id^="r_"]'));
            });
          }
          updateCommentCells();
        }
        toastControl.clear();
      } catch (err) {
        if (err instanceof Error) {
          console.error(`\u52A0\u8F7D\u591A\u9875\u56DE\u590D\u51FA\u9519\uFF1A${err.message}`);
        }
        createToast({ message: "\u274C \u52A0\u8F7D\u591A\u9875\u56DE\u590D\u5931\u8D25" });
        $pageNormal.removeClass("page_current").addClass("page_normal");
      }
    }
  }
  if (options.replyContent.hideReplyTime) {
    $(".cell .ago").addClass("v2p-auto-hide");
  }
  const canHideRefName = options.nestedReply.display === "indent" && !!options.replyContent.hideRefName;
  commentDataList = getCommentDataList({ options, $commentTableRows, $commentCells });
  {
    const memberNames = /* @__PURE__ */ new Set([topicOwnerName]);
    $commentCells.each((i, cellDom) => {
      const currentComment = commentDataList.at(i);
      if (currentComment?.id !== cellDom.id) {
        return;
      }
      const $cellDom = $(cellDom);
      const { memberName, thanked } = currentComment;
      memberNames.add(memberName);
      processAvatar({
        $trigger: $cellDom.find(".avatar, .dark"),
        popupControl,
        commentData: currentComment,
        openInNewTab: options.openInNewTab
      });
      if (memberName === loginName && !options.hideAccount) {
        $cellDom.find(".badges").append(`<div class="badge ${memberName === topicOwnerName ? "mod" : "you"}">YOU</div>`);
      }
      const $likesBox = $cellDom.find(".small.fade").addClass("v2p-likes-box");
      $likesBox.find('img[alt="\u2764\uFE0F"]').replaceWith('<span class="v2p-icon-heart"><i data-lucide="heart"></i></span>');
      if (thanked) {
        $likesBox.addClass("v2p-thanked");
      }
      processActions($cellDom, currentComment);
      if (canHideRefName) {
        if (currentComment.contentHtml) {
          $cellDom.find(".reply_content").html(currentComment.contentHtml);
        }
      }
    });
    if (tagData) {
      Object.entries(tagData).forEach(([memberName, { tags, avatar }]) => {
        if (memberNames.has(memberName)) {
          updateMemberTag({ memberName, memberAvatar: avatar, tags, options });
        }
      });
    }
    updateCommentCells();
    handleFilteredComments();
    $(".v2p-control-thank").on("click", (ev) => {
      ev.stopPropagation();
      const id = ev.currentTarget.dataset.id;
      const memberName = ev.currentTarget.dataset.memberName;
      if (typeof id === "string" && typeof memberName === "string") {
        if (confirm(`\u786E\u8BA4\u82B1\u8D39 10 \u4E2A\u94DC\u5E01\u5411 @${memberName} \u7684\u8FD9\u6761\u56DE\u590D\u53D1\u9001\u611F\u8C22\uFF1F`)) {
          const replyId = id.split("_").at(1);
          if (replyId) {
            void thankReply({
              replyId,
              onSuccess: () => {
                const $cell = $(`.cell[id="r_${replyId}"]`);
                const $tableInCell = $cell.find("> table");
                const $likesBox = $tableInCell.find(".v2p-likes-box");
                const $firstLikesBox = $likesBox.eq(0);
                const likes = Number($firstLikesBox.text());
                const $clonedIconHeart = $firstLikesBox.find(".v2p-icon-heart").clone();
                if (likes > 0) {
                  $likesBox.addClass("v2p-thanked").empty().append($clonedIconHeart, ` ${likes + 1}`);
                } else {
                  $(`
                      <span class="small v2p-likes-box v2p-thanked" style="position:relative;top:-1px;">
                        &nbsp;&nbsp;<span class="v2p-icon-heart"><i data-lucide="heart"></i></span>1
                      </span>
                      `).insertAfter($tableInCell.find(".ago"));
                  loadIcons();
                }
                const $thankAction = $tableInCell.find(".v2p-control-thank");
                $thankAction.addClass("v2p-thanked").off("click");
                $thankAction.siblings().has(".v2p-control-hide").hide();
              },
              onFail: () => {
                createToast({ message: "\u274C \u611F\u8C22\u56DE\u590D\u5931\u8D25" });
              }
            });
          }
        }
      }
    });
  }
  handleNestedComment({ options, $commentCells, commentDataList });
  {
    const $opAvatar = $topicHeader.find(".avatar");
    const $opName = $topicHeader.find('.gray a[href^="/member"]');
    const memberName = $opAvatar.prop("alt");
    const memberAvatar = $opAvatar.prop("src");
    const memberLink = $topicHeader.find(".fr > a").prop("href");
    if (typeof memberName === "string" && typeof memberAvatar === "string" && typeof memberLink === "string") {
      processAvatar({
        $trigger: $opAvatar,
        popupControl,
        commentData: { memberName, memberAvatar, memberLink },
        openInNewTab: options.openInNewTab
      });
      processAvatar({
        $trigger: $opName,
        popupControl,
        commentData: { memberName, memberAvatar, memberLink },
        shouldWrap: false,
        openInNewTab: options.openInNewTab
      });
      fetchUserInfo(memberName).then((memberData) => {
        const registerDays = getRegisterDays(memberData.created);
        memberDataCache.set(memberName, { ...memberData, registerDays });
        if (registerDays <= 30) {
          $opName.append(
            `<span class="v2p-register-days">${registerDays <= 15 ? "15" : "30"} \u5929\u5185\u6CE8\u518C</span>`
          );
        }
      });
    }
  }
  if (options.replyContent.showImgInPage) {
    window.requestIdleCallback(() => {
      handleTopicImg();
    });
  }
  window.requestIdleCallback(() => {
    replaceCommentEmojiWithHD();
    handleLinkPreview();
  });
}
var commentDataList, popupControl;
var init_comment = __esm({
  "src/contents/topic/comment.ts"() {
    "use strict";
    init_lucide();
    init_modal();
    init_popup();
    init_toast();
    init_constants();
    init_services();
    init_utils();
    init_dom();
    init_globals();
    init_helpers();
    init_avatar();
    init_content();
    commentDataList = [];
    popupControl = createPopup({
      root: $wrapper,
      triggerType: "hover",
      placement: "right-start",
      offsetOptions: { mainAxis: 8, crossAxis: -4 }
    });
  }
});

// src/contents/topic/layout.ts
function toggleTopicLayout() {
  if ($wrapperContent.hasClass("v2p-content-layout")) {
    switchToVerticalLayout();
  } else {
    switchToHorizontalLayout();
  }
}
function handleLayout() {
  const storage = getStorageSync();
  const options = storage["options" /* Options */];
  if (options.reply.layout === "auto") {
    const contentHeight = $topicContentBox.height();
    if (typeof contentHeight === "number" && contentHeight >= 600) {
      switchToHorizontalLayout();
    } else {
      switchToVerticalLayout();
    }
  } else {
    if (options.reply.layout === "horizontal") {
      switchToHorizontalLayout();
    } else {
      switchToVerticalLayout();
    }
  }
  $layoutToggle.on("click", () => {
    toggleTopicLayout();
  });
  $(".tools").prepend($layoutToggle);
}
var $layoutToggle, iconLayoutV, iconLayoutH, switchToHorizontalLayout, switchToVerticalLayout;
var init_layout = __esm({
  "src/contents/topic/layout.ts"() {
    "use strict";
    init_lucide();
    init_constants();
    init_utils();
    init_globals();
    $layoutToggle = $('<span class="v2p-layout-toggle v2p-hover-btn">');
    iconLayoutV = createElement$1(PanelTop);
    iconLayoutV.setAttribute("width", "100%");
    iconLayoutV.setAttribute("height", "100%");
    iconLayoutH = createElement$1(PanelRight);
    iconLayoutH.setAttribute("width", "100%");
    iconLayoutH.setAttribute("height", "100%");
    switchToHorizontalLayout = () => {
      if (!$wrapperContent.hasClass("v2p-content-layout")) {
        const $divider1 = $main.find("> .sep20:first-of-type");
        const $leftGroup = $divider1.add($divider1.next(".box"));
        const $leftSide = $('<div class="v2p-left-side">');
        $leftGroup.wrapAll($leftSide);
        const $content = $leftGroup.find("> .cell");
        $content.add($content.nextAll(".subtle")).wrapAll('<div class="v2p-left-side-content">');
        const $divider2 = $main.find(".sep20:nth-of-type(2)");
        const $rightGroup = $divider2.add($divider2.nextAll());
        $rightGroup.wrapAll('<div class="v2p-right-side">');
        $wrapperContent.addClass("v2p-content-layout");
        $main.addClass("v2p-horizontal-layout");
      }
      $layoutToggle.html(iconLayoutV);
      $layoutToggle.attr("title", "\u5207\u6362\u4E3A\u5782\u76F4\u5E03\u5C40");
      $(".v2p-reply-tool-layout").text("\u5207\u6362\u4E3A\u5782\u76F4\u5E03\u5C40");
    };
    switchToVerticalLayout = () => {
      if ($wrapperContent.hasClass("v2p-content-layout")) {
        $wrapperContent.removeClass("v2p-content-layout");
        $main.removeClass("v2p-horizontal-layout");
        $(".v2p-left-side-content").children().unwrap();
        $(".v2p-left-side").children().unwrap();
        $(".v2p-right-side").children().unwrap();
      }
      $layoutToggle.html(iconLayoutH);
      $layoutToggle.attr("title", "\u5207\u6362\u4E3A\u6C34\u5E73\u5E03\u5C40");
      $(".v2p-reply-tool-layout").text("\u5207\u6362\u4E3A\u6C34\u5E73\u5E03\u5C40");
    };
  }
});

// src/contents/topic/paging.ts
function handlePaging() {
  const $notCommentCells = $commentBox.find('> .cell:not([id^="r_"])');
  if ($notCommentCells.length <= 1) {
    return;
  }
  const pagingCells = $notCommentCells.slice(1).addClass("v2p-paging");
  const pageBtns = pagingCells.find(".super.button");
  pageBtns.eq(0).addClass("v2p-prev-btn");
  pageBtns.eq(1).addClass("v2p-next-btn");
}
var init_paging = __esm({
  "src/contents/topic/paging.ts"() {
    "use strict";
    init_globals();
  }
});

// src/components/image-upload.ts
function bindImageUpload(props) {
  const { $wrapper: $wrapper2, $input, insertText, replaceText } = props;
  const $uploadBar = $(`<div class="v2p-reply-upload-bar">${uploadTip}</div>`);
  const handleUploadImage = (file) => {
    const placeholder = "[\u4E0A\u4F20\u56FE\u7247\u4E2D...]";
    insertText(` ${placeholder} `);
    $uploadBar.addClass("v2p-reply-upload-bar-disabled").text("\u6B63\u5728\u4E0A\u4F20\u56FE\u7247...");
    uploadImage(file).then((imgLink) => {
      replaceText(placeholder, imgLink);
    }).catch(() => {
      replaceText(placeholder, "");
      window.alert("\u274C \u4E0A\u4F20\u56FE\u7247\u5931\u8D25\uFF0C\u8BF7\u6253\u5F00\u63A7\u5236\u53F0\u67E5\u770B\u539F\u56E0");
    }).finally(() => {
      $uploadBar.removeClass("v2p-reply-upload-bar-disabled").text(uploadTip);
    });
  };
  const handleClickUploadImage = () => {
    const imgInput = document.createElement("input");
    imgInput.style.display = "none";
    imgInput.type = "file";
    imgInput.accept = "image/*";
    imgInput.addEventListener("change", () => {
      const selectedFile = imgInput.files?.[0];
      if (selectedFile) {
        handleUploadImage(selectedFile);
      }
    });
    imgInput.click();
  };
  document.addEventListener("paste", (ev) => {
    if (!(ev instanceof ClipboardEvent)) {
      return;
    }
    if ($input && !$input.get(0)?.matches(":focus")) {
      return;
    }
    const items = ev.clipboardData?.items;
    if (!items) {
      return;
    }
    const imageItem = Array.from(items).find((item) => item.type.includes("image"));
    if (imageItem) {
      const file = imageItem.getAsFile();
      if (file) {
        handleUploadImage(file);
      }
    }
  });
  $wrapper2.get(0)?.addEventListener("drop", (ev) => {
    ev.preventDefault();
    if (!(ev instanceof DragEvent)) {
      return;
    }
    const file = ev.dataTransfer?.files[0];
    if (file) {
      handleUploadImage(file);
    }
  });
  $(".flex-one-row:last-of-type > .gray").text("");
  $uploadBar.on("click", () => {
    if (!$uploadBar.hasClass("v2p-reply-upload-bar-disabled")) {
      handleClickUploadImage();
    }
  });
  $wrapper2.append($uploadBar);
  return {
    uploadBar: $uploadBar
  };
}
var uploadTip;
var init_image_upload = __esm({
  "src/components/image-upload.ts"() {
    "use strict";
    init_services();
    uploadTip = "\u9009\u62E9\u3001\u7C98\u8D34\u3001\u62D6\u653E\u4E0A\u4F20\u56FE\u7247\u3002";
  }
});

// src/contents/topic/reply.ts
function handleReplyActions() {
  const os = getOS();
  const replyBtnText = `\u56DE\u590D<kbd>${os === "macos" ? "Cmd" : "Ctrl"}+Enter</kbd>`;
  const $replyBtn = createButton({
    children: replyBtnText,
    type: "submit"
  }).replaceAll($replyBox.find('input[type="submit"]'));
  $replyForm.on("submit", () => {
    const replyVal = $replyTextArea.val();
    if (typeof replyVal === "string") {
      $replyTextArea.val(transformEmoji(replyVal));
    }
    $replyBtn.text("\u63D0\u4EA4\u56DE\u590D\u4E2D...").prop("disabled", true);
    setTimeout(() => {
      $replyBtn.html(replyBtnText).prop("disabled", false);
    }, 5e3);
  });
  document.addEventListener("keydown", (ev) => {
    if (ev.key === "Enter" && (ev.ctrlKey || ev.metaKey)) {
      ev.preventDefault();
      $replyForm.trigger("submit");
    }
  });
  {
    const emoticonGroup = $('<div class="v2p-emoji-group">');
    const emoticonList = $('<div class="v2p-emoji-list">');
    const emoticonSpan = $('<span class="v2p-emoji">');
    const groups = emoticons.map((emojiGroup) => {
      const group = emoticonGroup.clone();
      const list = emoticonList.clone();
      group.append(`<div class="v2p-emoji-title">${emojiGroup.title}</div>`);
      list.append(
        emojiGroup.list.map((emoji) => {
          const emoticon = emoticonSpan.clone();
          if (emojiGroup.title === "\u6D41\u884C") {
            const emojiLink = emojiLinks[emoji].hd;
            emoticon.html(`<img src="${emojiLink}" />`).prop("title", emoji);
          } else {
            emoticon.text(emoji);
          }
          emoticon.on("click", () => {
            insertTextToReplyInput(emoji);
          });
          return emoticon;
        })
      );
      group.append(list);
      return group;
    });
    const emoticonsBox = $('<div class="v2p-emoticons-box">').append(groups);
    const $emojiBtn = createButton({
      children: '<span style="width:18px; height:18px;"><i data-lucide="smile"></i></span>'
    }).insertAfter($replyBtn);
    const $emojiContent = $('<div class="v2p-emoji-container">').append(emoticonsBox).appendTo($replyBox).on("click", () => {
      focusReplyInput();
    });
    const keyupHandler = (ev) => {
      if (ev.key === "Escape") {
        ev.preventDefault();
        emojiPopup.close();
      }
    };
    $emojiBtn.on("click", () => {
      focusReplyInput();
    });
    const emojiPopup = createPopup({
      root: $replyBox,
      trigger: $emojiBtn,
      content: $emojiContent,
      options: { placement: "right-end" },
      onOpen: () => {
        $body.on("keydown", keyupHandler);
      },
      onClose: () => {
        $body.off("keydown", keyupHandler);
      }
    });
  }
  {
    $replyBox.find("#undock-button, #undock-button + a").addClass("v2p-hover-btn").css("padding", "5px 4px");
  }
}
function handleReply() {
  $replyTextArea.attr("placeholder", "\u7559\u4E0B\u5BF9\u4ED6\u4EBA\u6709\u5E2E\u52A9\u7684\u56DE\u590D").wrap('<div class="v2p-reply-wrap">');
  const $replyWrap = $(".v2p-reply-wrap");
  const $replyPreview = $('<div class="v2p-reply-preview">');
  $replyPreview.hide().insertAfter($replyWrap);
  bindImageUpload({
    $wrapper: $replyWrap,
    $input: $replyTextArea,
    insertText: (text) => {
      insertTextToReplyInput(text);
    },
    replaceText: (find, replace) => {
      const val = $replyTextArea.val();
      if (typeof val === "string") {
        const newVal = val.replace(find, replace);
        $replyTextArea.val(newVal).trigger("focus");
      }
    }
  });
  {
    const $replyTabs = $('<div class="v2p-reply-tabs">');
    const $replyTabEdit = $('<div class="v2p-reply-tab active">\u7F16\u8F91</div>');
    const $replyTabPreview = $('<div class="v2p-reply-tab">\u9884\u89C8</div>');
    $replyTabEdit.on("click", () => {
      $replyTabEdit.addClass("active");
      $replyTabPreview.removeClass("active");
      $replyWrap.show();
      $replyPreview.hide();
    }).appendTo($replyTabs);
    let lastPreviewText = null;
    $replyTabPreview.on("click", () => {
      if (!$replyTabPreview.hasClass("active")) {
        $replyTabPreview.addClass("active");
        $replyTabEdit.removeClass("active");
        const replyText = $replyTextArea.val();
        if (typeof replyText === "string") {
          $replyWrap.hide();
          $replyPreview.show();
          if (replyText.trim() === "") {
            $replyPreview.html("\u6CA1\u6709\u53EF\u9884\u89C8\u7684\u5185\u5BB9");
          } else {
            const textToPreview = transformEmoji(replyText);
            const handlePreview = async () => {
              $replyPreview.html("\u6B63\u5728\u52A0\u8F7D\u9884\u89C8...");
              try {
                const renderedContent = await getCommentPreview({
                  text: textToPreview,
                  syntax: "default"
                });
                $replyPreview.html(renderedContent);
                replaceEmojiWithHD($replyPreview.find(".embedded_image"));
                lastPreviewText = textToPreview;
              } catch {
                $replyPreview.html('\u9884\u89C8\u5931\u8D25\uFF0C<a class="v2p-preview-retry">\u70B9\u51FB\u91CD\u8BD5</a>\u3002');
                $replyPreview.find(".v2p-preview-retry").on("click", () => {
                  void handlePreview();
                });
              }
            };
            if (replyText !== lastPreviewText) {
              void handlePreview();
            }
          }
        }
      }
    }).appendTo($replyTabs);
    $replyBox.find("> .cell:first-of-type > div:first-of-type").replaceWith($replyTabs);
  }
  $(".flex-one-row:last-of-type > .gray").text("");
  handleReplyActions();
}
var init_reply = __esm({
  "src/contents/topic/reply.ts"() {
    "use strict";
    init_button();
    init_image_upload();
    init_popup();
    init_constants();
    init_services();
    init_utils();
    init_globals();
    init_helpers();
  }
});

// src/contents/topic/tool.ts
function handleTools() {
  const storage = getStorageSync();
  const options = storage["options" /* Options */];
  const $tools = $(`
    <div class="cell v2p-tools">
      <span class="v2p-tool v2p-hover-btn v2p-tool-reply">
        <span class="v2p-tool-icon"><i data-lucide="message-square-plus"></i></span>\u56DE\u590D\u4E3B\u9898
      </span>
      <span class="v2p-tool v2p-hover-btn v2p-tool-reading">
        <span class="v2p-tool-icon"><i data-lucide="book-open-check"></i></span>\u7A0D\u540E\u9605\u8BFB
      </span>
      <span class="v2p-tool v2p-hover-btn v2p-tool-scroll-top">
        <span class="v2p-tool-icon"><i data-lucide="chevrons-up"></i></span>\u56DE\u5230\u9876\u90E8
      </span>
      <span class="v2p-tool v2p-hover-btn v2p-tool-more">
        <span class="v2p-tool-icon"><i data-lucide="package-plus"></i></span>\u66F4\u591A\u529F\u80FD
      </span>
    </div>
  `);
  $tools.find(".v2p-tool-reply").on("click", () => {
    $replyTextArea.trigger("focus");
  });
  $tools.find(".v2p-tool-reading").on("click", () => {
    void addToReadingList({
      url: window.location.href,
      title: document.title.replace(" - V2EX", ""),
      content: String($('head meta[property="og:description"]').prop("content"))
    });
  });
  $tools.find(".v2p-tool-scroll-top").on("click", () => {
    window.scrollTo({ top: 0, behavior: "smooth" });
  });
  {
    const $moreTool = $tools.find(".v2p-tool-more");
    const $toolContent = $(`
      <div class="v2p-select-dropdown">
        <div class="v2p-select-item v2p-reply-tool-decode">\u89E3\u6790\u672C\u9875 Base64</div>
        <div class="v2p-select-item v2p-reply-tool-encode">\u6587\u672C\u8F6C Base64</div>
        <div class="v2p-select-item v2p-reply-tool-share">\u751F\u6210\u5206\u4EAB\u56FE\u7247</div>
      </div>
    `);
    const toolsPopup = createPopup({
      root: $replyBox,
      trigger: $moreTool,
      content: $toolContent,
      offsetOptions: { mainAxis: 5, crossAxis: -5 }
    });
    $toolContent.find(".v2p-reply-tool-decode").on("click", () => {
      decodeBase64TopicPage();
    });
    $toolContent.find(".v2p-reply-tool-encode").on("click", () => {
      focusReplyInput();
      setTimeout(() => {
        const inputText = window.prompt("\u8F93\u5165\u8981\u52A0\u5BC6\u7684\u5B57\u7B26\u4E32\uFF0C\u5B8C\u6210\u540E\u5C06\u586B\u5199\u5230\u56DE\u590D\u6846\u4E2D\uFF1A");
        if (inputText) {
          let encodedText;
          try {
            encodedText = window.btoa(encodeURIComponent(inputText));
          } catch (err) {
            const errorTip = "\u8BE5\u6587\u672C\u65E0\u6CD5\u7F16\u7801\u4E3A Base64";
            console.error(err, `${errorTip}\uFF0C\u53EF\u80FD\u7684\u9519\u8BEF\u539F\u56E0\uFF1A\u6587\u672C\u5305\u542B\u4E2D\u6587\u3002`);
            createToast({ message: errorTip });
          }
          if (encodedText) {
            insertTextToReplyInput(encodedText);
          }
        }
      });
    });
    $toolContent.find(".v2p-reply-tool-share").on("click", () => {
      if (pathTopicId) {
        window.open(`${"https://v2p.app" /* Home */}/share/${pathTopicId}`, "_blank");
      }
    });
    const canHideRefName = options.nestedReply.display === "indent" && !!options.replyContent.hideRefName;
    if (canHideRefName) {
      let isHidden = options.replyContent.hideRefName;
      const $toolToggleDisplay = $('<div class="v2p-select-item">\u663E\u793A @ \u7528\u6237\u540D</div>');
      $toolToggleDisplay.on("click", () => {
        if (isHidden) {
          isHidden = false;
          $toolToggleDisplay.text("\u9690\u85CF @ \u7528\u6237\u540D");
          $(".v2p-member-ref").addClass("v2p-member-ref-show");
        } else {
          isHidden = true;
          $toolToggleDisplay.text("\u663E\u793A @ \u7528\u6237\u540D");
          $(".v2p-member-ref").removeClass("v2p-member-ref-show");
        }
      });
      $toolContent.prepend($toolToggleDisplay);
    }
    const $toolToggleLayout = $(
      `
      <div class="v2p-select-item v2p-reply-tool-layout">
        ${options.reply.layout === "horizontal" ? "\u5207\u6362\u4E3A\u5782\u76F4\u5E03\u5C40" : "\u5207\u6362\u4E3A\u6C34\u5E73\u5E03\u5C40"}
      </div>
      `
    );
    $toolToggleLayout.on("click", () => {
      toggleTopicLayout();
    });
    $toolContent.prepend($toolToggleLayout);
    $toolContent.find(".v2p-select-item").on("click", () => {
      toolsPopup.close();
    });
  }
  $infoCard.addClass("v2p-tool-box").append($tools);
  loadIcons();
}
var init_tool = __esm({
  "src/contents/topic/tool.ts"() {
    "use strict";
    init_popup();
    init_toast();
    init_constants();
    init_utils();
    init_globals();
    init_helpers();
    init_layout();
  }
});

// src/contents/topic/index.ts
var topic_exports = {};
var init_topic = __esm({
  "src/contents/topic/index.ts"() {
    "use strict";
    init_constants();
    init_utils();
    init_globals();
    init_helpers();
    init_comment();
    init_content();
    init_layout();
    init_paging();
    init_reply();
    init_tool();
    void (async () => {
      const storage = await getStorage();
      const options = storage["options" /* Options */];
      handleLayout();
      if (options.openInNewTab) {
        $topicHeader.find('a[href^="/member/"]').prop("target", "_blank");
        $commentTableRows.find("> td:nth-child(3) > strong > a").prop("target", "_blank");
      }
      handleTools();
      {
        $(document).on("keydown", (ev) => {
          if (!ev.isDefaultPrevented()) {
            if (ev.key === "Escape") {
              const $replyContent = $("#reply_content");
              if ($replyBox.hasClass("reply-box-sticky")) {
                $replyBox.removeClass("reply-box-sticky");
                $("#undock-button").css("display", "none");
              }
              $replyContent.trigger("blur");
            }
          }
        });
      }
      handleContent();
      if (document.referrer !== "") {
        if (document.referrer.includes(document.location.pathname)) {
          const url = new URL(document.location.href);
          const page = url.searchParams.get("p");
          if (page && page !== "1") {
            document.querySelector(".topic_buttons")?.scrollIntoView({ behavior: "smooth" });
          }
        }
      }
      handlePaging();
      await handleComments();
      handleReply();
      loadIcons();
      {
        const isFlamewarNode = $topicHeader.find('a[href^="/go"]').attr("href")?.endsWith("/flamewar");
        if (isFlamewarNode) {
          $("#node_sidebar").addClass("v2p-node-sidebar-flamewar");
        }
      }
    })();
  }
});

// src/contents/write/write.ts
function handleWrite() {
  bindImageUpload({
    $wrapper: $("#workspace"),
    insertText: (text) => {
      postTask(`editor.getDoc().replaceRange("${text}", editor.getCursor())`);
    },
    replaceText: (find, replace) => {
      if (replace) {
        const mode = $("input[name=syntax]:checked").val();
        if (mode === "markdown") {
          replace = `![](${replace})`;
        }
      }
      postTask(`
      editor.setValue(editor.getValue().replace("${find}", "${replace}"));
      const doc = editor.getDoc(); 
      const lastLine = doc.lastLine(); 
      const lastChar = doc.getLine(lastLine).length; 
      doc.setCursor({ line: doc.lastLine(), ch: lastChar });
      `);
    }
  });
}
var init_write = __esm({
  "src/contents/write/write.ts"() {
    "use strict";
    init_image_upload();
    init_helpers();
  }
});

// src/contents/write/index.ts
var write_exports = {};
var init_write2 = __esm({
  "src/contents/write/index.ts"() {
    "use strict";
    init_helpers();
    init_write();
    handleWrite();
    loadIcons();
  }
});

// node_modules/.pnpm/webext-patterns@1.5.0/node_modules/webext-patterns/index.js
var patternValidationRegex = /^(https?|wss?|file|ftp|\*):\/\/(\*|\*\.[^*/]+|[^*/]+)\/.*$|^file:\/\/\/.*$|^resource:\/\/(\*|\*\.[^*/]+|[^*/]+)\/.*$|^about:/;
var isFirefox = globalThis.navigator?.userAgent.includes("Firefox/");
var allStarsRegex = isFirefox ? /^(https?|wss?):[/][/][^/]+([/].*)?$/ : /^https?:[/][/][^/]+([/].*)?$/;
var allUrlsRegex = /^(https?|file|ftp):[/]+/;
function assertValidPattern(matchPattern) {
  if (!isValidPattern(matchPattern)) {
    throw new Error(matchPattern + " is an invalid pattern. See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns for more info.");
  }
}
function isValidPattern(matchPattern) {
  return matchPattern === "<all_urls>" || patternValidationRegex.test(matchPattern);
}
function getRawPatternRegex(matchPattern) {
  assertValidPattern(matchPattern);
  let [, protocol, host = "", pathname] = matchPattern.split(/(^[^:]+:[/][/])([^/]+)?/);
  protocol = protocol.replace("*", isFirefox ? "(https?|wss?)" : "https?").replaceAll(/[/]/g, "[/]");
  if (host === "*") {
    host = "[^/]+";
  }
  host &&= host.replace(/^[*][.]/, "([^/]+.)*").replaceAll(/[.]/g, "[.]").replace(/[*]$/, "[^.]+");
  pathname = pathname.replaceAll(/[/]/g, "[/]").replaceAll(/[.]/g, "[.]").replaceAll(/[*]/g, ".*");
  return "^" + protocol + host + "(" + pathname + ")?$";
}
function patternToRegex(...matchPatterns) {
  if (matchPatterns.length === 0) {
    return /$./;
  }
  if (matchPatterns.includes("<all_urls>")) {
    return allUrlsRegex;
  }
  if (matchPatterns.includes("*://*/*")) {
    return allStarsRegex;
  }
  return new RegExp(matchPatterns.map((x) => getRawPatternRegex(x)).join("|"));
}

// src/user-scripts/style.ts
var style = `:root{--zidx-serach: 100;--zidx-tabs: 10;--zidx-tools-card: 10;--zidx-reply-box: 99;--zidx-modal-header: 50;--zidx-modal-mask: 888;--zidx-toast: 999;--zidx-tip: 99;--zidx-popup: 99;--zidx-expand-mask: 10;--zidx-expand-btn: 20;--v2p-underline-offset: 0.5ex;--v2p-layout-column-gap: 25px;--v2p-layout-row-gap: 20px;--v2p-nav-height: 55px;--v2p-tp-item-x: 20px;--v2p-tp-item-y: 10px;--v2p-tp-tabs-pd: 10px;--v2p-tp-nested-pd: 15px;--v2p-tp-preview-pd: 20px;--v2p-emoji-size: 21px;--v2p-box-radius: 10px}:root body{--v2p-color-main-50: #f7f9fb;--v2p-color-main-100: #f1f5f9;--v2p-color-main-200: #e2e8f0;--v2p-color-main-300: #cbd5e1;--v2p-color-main-350: #94a3b8cc;--v2p-color-main-400: #94a3b8;--v2p-color-main-500: #64748b;--v2p-color-main-600: #475569;--v2p-color-main-700: #334155;--v2p-color-main-800: #1e293b;--v2p-color-accent-50: #ecfdf5;--v2p-color-accent-100: #d1fae5;--v2p-color-accent-200: #a7f3d0;--v2p-color-accent-300: #6ee7b7;--v2p-color-accent-400: #34d399;--v2p-color-accent-500: #10b981;--v2p-color-accent-600: #059669;--v2p-color-orange-50: #fff7ed;--v2p-color-orange-100: #ffedd5;--v2p-color-orange-400: #fb923c;--v2p-color-background: #f2f3f5;--v2p-color-foreground: var(--v2p-color-main-800);--v2p-color-selection-foreground: var(--v2p-color-main-100);--v2p-color-selection-background: var(--v2p-color-main-700);--v2p-color-selection-background-img: var(--v2p-color-main-500);--v2p-color-font-secondary: var(--v2p-color-main-600);--v2p-color-font-tertiary: var(--v2p-color-main-500);--v2p-color-font-quaternary: var(--v2p-color-main-400);--v2p-color-button-background: var(--v2p-color-main-100);--v2p-color-button-foreground: var(--v2p-color-main-500);--v2p-color-button-background-hover: var(--v2p-color-main-200);--v2p-color-button-foreground-hover: var(--v2p-color-main-600);--v2p-color-bg-content: #fff;--v2p-color-bg-footer: var(--v2p-color-bg-content);--v2p-color-bg-hover-btn: rgb(226 232 240 / 70%);--v2p-color-bg-subtle: rgb(236 253 245 / 90%);--v2p-color-bg-input: var(--v2p-color-main-50);--v2p-color-bg-search: var(--v2p-color-main-100);--v2p-color-bg-search-active: var(--v2p-color-main-200);--v2p-color-bg-widget: rgb(255 255 255 / 70%);--v2p-color-bg-reply: var(--v2p-color-main-100);--v2p-color-bg-tooltip: var(--v2p-color-bg-content);--v2p-color-bg-tabs: var(--v2p-color-main-100);--v2p-color-bg-tpr: var(--v2p-color-main-100);--v2p-color-bg-avatar: var(--v2p-color-main-300);--v2p-color-bg-block: var(--v2p-color-main-100);--v2p-color-bg-block-darker: var(--v2p-color-main-300);--v2p-color-bg-link: var(--v2p-color-main-100);--v2p-color-bg-link-hover: var(--v2p-color-main-200);--v2p-color-tabs: var(--v2p-color-foreground);--v2p-color-heart: #ef4444;--v2p-color-heart-fill: #fee2e2;--v2p-color-mask: rgb(0 0 0 / 25%);--v2p-color-divider: var(--v2p-color-main-200);--v2p-color-border: var(--v2p-color-main-200);--v2p-color-input-border: var(--v2p-color-main-300);--v2p-color-border-darker: var(--v2p-color-main-300);--v2p-color-link-visited: var(--v2p-color-main-400);--v2p-color-error: #ef4444;--v2p-color-bg-error: #fee2e2;--v2p-color-cell-num: var(--v2p-color-main-350);--v2p-box-shadow: 0 3px 5px 0 rgb(0 0 0 / 4%);--v2p-widget-shadow: 0 9px 24px -3px rgb(0 0 0 / 6%), 0 4px 8px -1px rgb(0 0 0 /12%);--v2p-toast-shadow: 0 6px 16px 0 rgb(0 0 0 / 8%), 0 3px 6px -4px rgb(0 0 0 / 12%), 0 9px 28px 8px rgb(0 0 0 / 5%);--color-fade: var(--v2p-color-font-secondary);--color-gray: var(--v2p-color-font-secondary);--link-color: var(--v2p-color-foreground);--link-darker-color: var(--v2p-color-main-600);--link-hover-color: var(--v2p-color-foreground);--link-caution-color: var(--v2p-color-orange-400);--box-border-color: var(--v2p-color-border);--box-foreground-color: var(--v2p-color-foreground);--box-background-color: var(--v2p-color-bg-content);--box-background-alt-color: var(--v2p-color-main-100);--box-background-hover-color: var(--v2p-color-main-200);--box-border-focus-color: var(--v2p-color-main-200);--box-border-radius: var(--v2p-box-radius);--button-background-color: var(--v2p-color-button-background);--button-foreground-color: var(--v2p-color-button-foreground);--button-hover-color: var(--v2p-color-button-background-hover);--button-background-hover-color: var(--v2p-color-button-background-hover);--button-foreground-hover-color: var(--v2p-color-button-foreground-hover);--button-border-color: var(--v2p-color-main-300);--button-border-hover-color: var(--v2p-color-main-400);font-family:system-ui,sans-serif;color:var(--v2p-color-foreground);background-color:var(--v2p-color-background)}:root body.v2p-theme-light-default,:root body .v2p-theme-light-default{--v2p-color-main-50: #f7f9fb;--v2p-color-main-100: #f1f5f9;--v2p-color-main-200: #e2e8f0;--v2p-color-main-300: #cbd5e1;--v2p-color-main-350: #94a3b8cc;--v2p-color-main-400: #94a3b8;--v2p-color-main-500: #64748b;--v2p-color-main-600: #475569;--v2p-color-main-700: #334155;--v2p-color-main-800: #1e293b;--v2p-color-accent-50: #ecfdf5;--v2p-color-accent-100: #d1fae5;--v2p-color-accent-200: #a7f3d0;--v2p-color-accent-300: #6ee7b7;--v2p-color-accent-400: #34d399;--v2p-color-accent-500: #10b981;--v2p-color-accent-600: #059669;--v2p-color-orange-50: #fff7ed;--v2p-color-orange-100: #ffedd5;--v2p-color-orange-400: #fb923c;--v2p-color-background: #f2f3f5;--v2p-color-foreground: var(--v2p-color-main-800);--v2p-color-selection-foreground: var(--v2p-color-main-100);--v2p-color-selection-background: var(--v2p-color-main-700);--v2p-color-selection-background-img: var(--v2p-color-main-500);--v2p-color-font-secondary: var(--v2p-color-main-600);--v2p-color-font-tertiary: var(--v2p-color-main-500);--v2p-color-font-quaternary: var(--v2p-color-main-400);--v2p-color-button-background: var(--v2p-color-main-100);--v2p-color-button-foreground: var(--v2p-color-main-500);--v2p-color-button-background-hover: var(--v2p-color-main-200);--v2p-color-button-foreground-hover: var(--v2p-color-main-600);--v2p-color-bg-content: #fff;--v2p-color-bg-footer: var(--v2p-color-bg-content);--v2p-color-bg-hover-btn: rgb(226 232 240 / 70%);--v2p-color-bg-subtle: rgb(236 253 245 / 90%);--v2p-color-bg-input: var(--v2p-color-main-50);--v2p-color-bg-search: var(--v2p-color-main-100);--v2p-color-bg-search-active: var(--v2p-color-main-200);--v2p-color-bg-widget: rgb(255 255 255 / 70%);--v2p-color-bg-reply: var(--v2p-color-main-100);--v2p-color-bg-tooltip: var(--v2p-color-bg-content);--v2p-color-bg-tabs: var(--v2p-color-main-100);--v2p-color-bg-tpr: var(--v2p-color-main-100);--v2p-color-bg-avatar: var(--v2p-color-main-300);--v2p-color-bg-block: var(--v2p-color-main-100);--v2p-color-bg-block-darker: var(--v2p-color-main-300);--v2p-color-bg-link: var(--v2p-color-main-100);--v2p-color-bg-link-hover: var(--v2p-color-main-200);--v2p-color-tabs: var(--v2p-color-foreground);--v2p-color-heart: #ef4444;--v2p-color-heart-fill: #fee2e2;--v2p-color-mask: rgb(0 0 0 / 25%);--v2p-color-divider: var(--v2p-color-main-200);--v2p-color-border: var(--v2p-color-main-200);--v2p-color-input-border: var(--v2p-color-main-300);--v2p-color-border-darker: var(--v2p-color-main-300);--v2p-color-link-visited: var(--v2p-color-main-400);--v2p-color-error: #ef4444;--v2p-color-bg-error: #fee2e2;--v2p-color-cell-num: var(--v2p-color-main-350);--v2p-box-shadow: 0 3px 5px 0 rgb(0 0 0 / 4%);--v2p-widget-shadow: 0 9px 24px -3px rgb(0 0 0 / 6%), 0 4px 8px -1px rgb(0 0 0 /12%);--v2p-toast-shadow: 0 6px 16px 0 rgb(0 0 0 / 8%), 0 3px 6px -4px rgb(0 0 0 / 12%), 0 9px 28px 8px rgb(0 0 0 / 5%);--color-fade: var(--v2p-color-font-secondary);--color-gray: var(--v2p-color-font-secondary);--link-color: var(--v2p-color-foreground);--link-darker-color: var(--v2p-color-main-600);--link-hover-color: var(--v2p-color-foreground);--link-caution-color: var(--v2p-color-orange-400);--box-border-color: var(--v2p-color-border);--box-foreground-color: var(--v2p-color-foreground);--box-background-color: var(--v2p-color-bg-content);--box-background-alt-color: var(--v2p-color-main-100);--box-background-hover-color: var(--v2p-color-main-200);--box-border-focus-color: var(--v2p-color-main-200);--box-border-radius: var(--v2p-box-radius);--button-background-color: var(--v2p-color-button-background);--button-foreground-color: var(--v2p-color-button-foreground);--button-hover-color: var(--v2p-color-button-background-hover);--button-background-hover-color: var(--v2p-color-button-background-hover);--button-foreground-hover-color: var(--v2p-color-button-foreground-hover);--button-border-color: var(--v2p-color-main-300);--button-border-hover-color: var(--v2p-color-main-400)}:root body #Logo{background-image:url("https://www.v2ex.com/static/img/v2ex@2x.png")}:root body ::selection{color:var(--v2p-color-selection-foreground);background-color:var(--v2p-color-selection-background)}:root body img::selection{background-color:var(--v2p-color-selection-background-img)}
:root{color-scheme:light}:root html,:root body{min-height:100vh}body{scrollbar-gutter:stable;overflow:overlay;visibility:hidden}body.v2p-theme-light-default{visibility:visible}body h1{font-weight:bold}body a{cursor:default;text-decoration:none}body a[href]{cursor:pointer}body a:hover{text-decoration:underline 1px;text-underline-offset:var(--v2p-underline-offset)}body pre{max-width:calc(830px - 2*var(--v2p-layout-column-gap) - 24px)}body #Top{height:var(--v2p-nav-height);background-color:var(--v2p-color-bg-content);border:none}body #Bottom{color:var(--v2p-color-font-secondary);background-color:var(--v2p-color-bg-footer);border:none}body #Bottom .content{flex-direction:column}body #Wrapper{background-color:inherit;background-image:none}body #Wrapper.Night{background-color:inherit;background-image:none}body #Wrapper .content{display:flex;gap:var(--v2p-layout-column-gap)}#Navcol .nav_item:hover{background-color:var(--box-background-hover-color)}#Navcol .nav_item:hover:active{box-shadow:none}#Navcol .nav_item_current:hover{color:var(--box-foreground-color);background-color:var(--v2p-color-bg-content)}#Navcol .nav_item_current:active{box-shadow:none}#Rightcol #page-outline-title{background-color:var(--v2p-color-button-background-hover)}#Rightcol .page-outline-item:hover{background-color:var(--box-background-hover-color)}body #Wrapper:has(#Singleton){padding:20px 0 0}body #Wrapper:has(#Singleton) #Singleton{overflow:hidden;box-shadow:var(--v2p-box-shadow)}body #Leftbar{float:none;order:1}body #Main{flex:1;order:2;max-width:85vw;margin:0}body #Rightbar{float:none;order:3;margin-right:var(--v2p-layout-column-gap)}body #search-container{height:30px;margin:0 30px;background-color:var(--v2p-color-bg-search);border:none;border-radius:6px}body #search-container::before{top:0;left:4px;opacity:.6;background-size:14px 14px;filter:none}body #search-container.active{background-color:var(--v2p-color-bg-search-active)}body #search-container #search-result{z-index:var(--zidx-serach);top:42px;font-size:14px;color:var(--v2p-color-font-secondary);background:var(--v2p-color-bg-widget);backdrop-filter:blur(16px);border:1px solid var(--box-border-color);box-shadow:var(--v2p-widget-shadow)}body #search-container #search-result .fade{color:var(--v2p-color-font-secondary)}body #search-container #search-result .search-item{font-weight:bold;color:var(--v2p-color-foreground);border-radius:5px}body #search-container #search-result .search-item.active{color:var(--v2p-color-foreground)}body #search-container #search-result .search-item.active.v2p-no-active{background-color:rgba(0,0,0,0)}body .box{color:var(--box-foreground-color);background-color:var(--v2p-color-bg-content);border:none;border-radius:var(--box-border-radius);box-shadow:var(--v2p-box-shadow)}body .box .header>h1{font-size:22px;font-weight:bold}body .box .header .gray{color:var(--color-gray)}body .button{--button-hover-shadow: 0 1.8px 0 var(--button-border-color), 0 1.8px 0 var(--button-background-color)}body .button.normal,body .button.super{cursor:pointer;user-select:none;position:relative;display:inline-flex;gap:5px;align-items:center;height:28px;padding:0 12px;font-family:inherit;font-size:14px;font-weight:500;line-height:28px;color:var(--v2p-color-button-foreground);text-shadow:none;white-space:nowrap;background:var(--v2p-color-button-background);border:none;border-radius:6px;outline:none;box-shadow:0 1.8px 0 var(--box-background-hover-color),0 1.8px 0 var(--button-background-color);transition:color .25s,background-color .25s,box-shadow .25s}body .button.normal:is(:hover:enabled,:active:enabled),body .button.super:is(:hover:enabled,:active:enabled){font-weight:500;color:var(--v2p-color-button-foreground-hover);text-shadow:none;background:var(--v2p-color-button-background-hover);border:none;box-shadow:var(--button-hover-shadow)}body .button.normal:is(.hover_now,.disable_now),body .button.super:is(.hover_now,.disable_now){color:var(--v2p-color-button-foreground) !important;text-shadow:none !important;background:var(--button-background-color) !important;border:none !important;box-shadow:0 1.8px 0 var(--box-background-hover-color) !important,0 1.8px 0 var(--button-background-color) !important}body .button.normal:is(.disable_now,:disabled),body .button.super:is(.disable_now,:disabled){pointer-events:none;cursor:default;font-weight:500;color:var(--v2p-color-button-foreground);text-shadow:none;opacity:.8;background:var(--button-background-color);box-shadow:0 1.8px 0 var(--box-background-hover-color),0 1.8px 0 var(--button-background-color)}body .button.normal kbd,body .button.super kbd{position:relative;right:-4px;padding:0 3px;font-family:inherit;font-size:90%;line-height:initial;border:1px solid var(--button-border-color);border-radius:4px}body .button.special{--button-hover-shadow: 0 1.8px 0 var(--v2p-color-accent-200), 0 1.8px 0 var(--v2p-color-accent-100);color:var(--v2p-color-accent-500);background:var(--v2p-color-accent-100);box-shadow:var(--button-hover-shadow)}body .button.special:hover,body .button.special:hover:enabled{color:var(--v2p-color-accent-600);background:var(--v2p-color-accent-100);border:none;box-shadow:var(--button-hover-shadow)}body .button a{color:inherit;text-decoration:none}body .badge{user-select:none;padding:2px 5px;font-weight:bold;border:1px solid var(--v2p-color-accent-400)}body .badge:first-child{border:1px solid var(--v2p-color-accent-400);border-top-left-radius:4px;border-bottom-left-radius:4px}body .badge:last-child{border:1px solid var(--v2p-color-accent-400);border-top-right-radius:4px;border-bottom-right-radius:4px}body .badge.op{color:var(--v2p-color-accent-500);background-color:var(--v2p-color-accent-50)}body .badge.mod{color:var(--v2p-color-bg-content);background-color:var(--v2p-color-accent-400)}body .badge.you{color:var(--v2p-color-orange-400);background-color:var(--v2p-color-orange-50);border:1px solid var(--v2p-color-orange-400)}body .badge.mini{height:1.2em;padding:0 3px;font-size:12px;font-weight:normal;line-height:1}body a.node:is(:active,:link,:visited){padding:5px 6px;font-size:13px;color:var(--v2p-color-font-secondary);background-color:var(--v2p-color-bg-block);border-radius:4px}body a.node:is(:active,:link,:visited):hover{color:var(--v2p-color-font-tertiary);background-color:var(--v2p-color-button-background-hover)}body .outdated{font-size:12px;border-color:var(--v2p-color-border);border-bottom:none}body :is(.page_normal,.page_current):is(:link,:visited){user-select:none;padding:6px 9px;font-size:14px;border:none;border-radius:4px}body .page_normal:is(:link,:visited){font-weight:500;background-color:var(--v2p-color-bg-content);box-shadow:0 2px 2px var(--box-background-hover-color);transition:transform .25s}body .page_normal:is(:link,:visited):hover{transform:scale(1.1) translateY(-2px)}body .page_current:is(:link,:visited){pointer-events:none;font-weight:bold;background-color:var(--box-background-hover-color);box-shadow:none}body .page_input{display:none}body .dock_area{margin:12px 0;background:var(--v2p-color-bg-block)}body .member-activity-bar{background-color:var(--v2p-color-divider)}body .member-activity-bar .member-activity-start{background-color:var(--v2p-color-accent-200)}body .member-activity-bar .member-activity-fourth{background-color:var(--v2p-color-accent-400)}body .member-activity-bar .member-activity-half{background-color:var(--v2p-color-accent-500)}body .member-activity-bar .member-activity-almost{background-color:var(--v2p-color-accent-600)}body .member-activity-bar .member-activity-done{background-color:var(--v2p-color-orange-400)}body .online{user-select:none;padding:6px 8px;font-size:13px;color:var(--v2p-color-bg-content);background:var(--v2p-color-accent-400);border-radius:5px}body #topic_supplement{resize:none;overflow:hidden;height:unset;min-height:550px !important;max-height:800px !important;font-size:15px;color:currentColor;background-color:var(--v2p-color-bg-input);border:1px solid var(--button-border-color);border-radius:8px;transition:opacity .25s;overflow-y:auto}body #topic_supplement::placeholder{font-size:15px;color:var(--v2p-color-font-tertiary)}body #topic_supplement:is(:focus,:focus-within){background-color:rgba(0,0,0,0);outline:none;box-shadow:0 0 0 1px var(--button-border-color)}body .item_hot_topic_title{--offset: 2.4px;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-height:1.4;position:relative;padding:var(--offset) 0;text-shadow:none}body .item_hot_topic_title>a:hover{text-underline-offset:var(--offset)}body form textarea#topic_title{resize:none;overflow:hidden;height:unset;min-height:75px !important;max-height:800px !important;font-size:15px;color:currentColor;background-color:var(--v2p-color-bg-input);border:1px solid var(--button-border-color);border-radius:8px;transition:opacity .25s}body form textarea#topic_title::placeholder{font-size:15px;color:var(--v2p-color-font-tertiary)}body form textarea#topic_title:is(:focus,:focus-within){background-color:rgba(0,0,0,0);outline:none;box-shadow:0 0 0 1px var(--button-border-color)}body form #topic_title{resize:none;overflow:hidden;height:unset;min-height:30px !important;max-height:800px !important;font-size:15px;color:currentColor;background-color:var(--v2p-color-bg-input);border:1px solid var(--button-border-color);border-radius:8px;transition:opacity .25s}body form #topic_title::placeholder{font-size:15px;color:var(--v2p-color-font-tertiary)}body form #topic_title:is(:focus,:focus-within){background-color:rgba(0,0,0,0);outline:none;box-shadow:0 0 0 1px var(--button-border-color)}body form #topic_content{resize:none;overflow:hidden;height:unset;min-height:120px !important;max-height:800px !important;font-size:15px;color:currentColor;background-color:var(--v2p-color-bg-input);border:1px solid var(--button-border-color);border-radius:8px;transition:opacity .25s}body form #topic_content::placeholder{font-size:15px;color:var(--v2p-color-font-tertiary)}body form #topic_content:is(:focus,:focus-within){background-color:rgba(0,0,0,0);outline:none;box-shadow:0 0 0 1px var(--button-border-color)}body form[action^="/notes"] .cell{background-color:rgba(0,0,0,0) !important}body #syntax-selector .radio-group{padding:3px;background-color:var(--v2p-color-background)}body #syntax-selector .radio-group>input[type=radio]:checked+label{background-color:var(--v2p-color-accent-100)}body #syntax-selector .radio-group>input[type=radio]+label{cursor:pointer;font-size:13px}body #syntax-selector label{color:var(--v2p-color-foreground)}body .snow{color:var(--v2p-color-font-quaternary)}body .orange-dot{background:var(--v2p-color-orange-400)}body .alt{background-color:var(--v2p-color-bg-input);border:1px solid var(--button-border-color)}body a.btn_hero{border-color:var(--v2p-color-foreground)}body a.btn_hero:hover{background-color:var(--v2p-color-foreground)}body .cell_ops{background-color:rgba(0,0,0,0)}body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href*="v2ex.com/t"],body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href*="v2ex.com/t"][href^=http],body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href^="/"]{text-decoration:underline 1.5px;text-underline-offset:.46ex;color:var(--v2p-color-accent-500);background-color:var(--v2p-color-accent-50)}body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href*="v2ex.com/t"]:hover,body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href*="v2ex.com/t"][href^=http]:hover,body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href^="/"]:hover{color:var(--v2p-color-accent-500);background-color:var(--v2p-color-accent-50)}body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href^=http],body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href*="/email-protection"],body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href^="/member/"]{text-decoration:underline 1.5px;text-underline-offset:.46ex;color:currentColor;background-color:var(--v2p-color-bg-link)}body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href^=http]:hover,body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href*="/email-protection"]:hover,body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href^="/member/"]:hover{color:currentColor;background-color:var(--v2p-color-bg-link-hover)}body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href^=http]:has(>.embedded_image),body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href*="/email-protection"]:has(>.embedded_image),body :is(.topic_content,.reply_content,.v2p-topic-preview-content,.v2p-topic-preview-addons,.v2p-reply-preview,.markdown_body) a[href^="/member/"]:has(>.embedded_image){background-color:rgba(0,0,0,0)}body .CodeMirror{color:currentColor;background-color:var(--v2p-color-bg-input)}body .CodeMirror.CodeMirror-focused{background-color:var(--v2p-color-bg-content)}body .CodeMirror .CodeMirror-gutters{padding-right:5px;background-color:var(--v2p-color-bg-input);border-right:1px solid var(--v2p-color-border-darker)}body .CodeMirror .CodeMirror-linenumber{color:var(--v2p-color-font-quaternary)}body .CodeMirror .CodeMirror-cursors{background-color:var(--v2p-color-foreground)}body .cm-s-one-dark{background-color:var(--v2p-color-bg-input)}body #workspace{overflow:hidden;border:1px solid var(--button-border-color);border-radius:8px}body .select2-container{width:200px !important}body .select2-container .select2-selection{background-color:var(--v2p-color-background);border:1px solid var(--v2p-color-border)}body .select2-container .select2-selection .select2-selection__rendered,body .select2-container .select2-selection .select2-selection__placeholder{color:var(--v2p-color-foreground)}body .select2-container .select2-dropdown{font-size:14px;background:var(--v2p-color-bg-widget);backdrop-filter:blur(16px);border:1px solid var(--box-border-color);border-radius:8px;box-shadow:var(--v2p-widget-shadow);transform:translateY(5px)}body .select2-container .select2-dropdown .select2-search{padding:5px}body .select2-container .select2-dropdown .select2-search .select2-search__field{padding:6px 4px;background-color:rgba(0,0,0,0);border:1px solid var(--v2p-color-border);border-radius:4px}body .select2-container .select2-dropdown .select2-search .select2-search__field:focus-visible{border-color:var(--v2p-color-font-quaternary);outline:none}body .select2-container .select2-dropdown .select2-results>.select2-results__options{padding:5px}body .select2-container .select2-dropdown .select2-container--default .select2-results__option--selected{color:currentColor;background-color:var(--v2p-color-accent-100)}body .select2-container .select2-results__option{border-radius:4px}body .select2-container .select2-results__option--highlighted.select2-results__option--selectable{color:currentColor;background-color:var(--v2p-color-main-200)}body .select2-container .select2-results__option--selected{color:currentColor !important;background-color:var(--v2p-color-accent-100) !important}body .problem{color:currentColor;color:var(--v2p-color-orange-400);background-color:var(--v2p-color-orange-50);border-color:var(--v2p-color-orange-400);border-bottom:none}body .markdown_body table{border-top:1px solid var(--v2p-color-border-darker);box-shadow:none}body .markdown_body table tr th,body .markdown_body table tr td{border:1px solid var(--v2p-color-border-darker)}body .markdown_body table tr:nth-child(2n){background-color:var(--box-background-alt-color)}body .markdown_body blockquote{margin-inline:0;padding:0 1em;color:var(--v2p-color-font-tertiary);border-left:3px solid var(--v2p-color-border)}body .markdown_body pre{line-height:1.5}body .social_label:is(:link,:visited,:active){background-color:var(--v2p-color-button-background);border-radius:var(--box-border-radius);box-shadow:none}body .social_label:is(:link,:visited,:active):hover{background-color:var(--v2p-color-button-background-hover)}body .green{color:var(--v2p-color-accent-500)}body .message{color:var(--v2p-color-orange-400);background-color:var(--v2p-color-orange-50);border:none}body .balance_area,body a.balance_area:is(:link,:visited){display:inline-flex;gap:3px;align-items:center;font-weight:600;color:var(--v2p-color-foreground);text-shadow:none;background:var(--v2p-color-button-background)}body .balance_area:hover,body a.balance_area:is(:link,:visited):hover{background:var(--v2p-color-button-background-hover)}body :is(.subtle){background-color:var(--v2p-color-bg-subtle);border-left:3px solid var(--v2p-color-accent-200)}body :is(.subtle) .topic_content{font-size:15px}body .onoffswitch label .frame::before{color:#fff;background-color:var(--v2p-color-accent-400)}body .onoffswitch label .frame::after{color:var(--v2p-color-font-secondary);background-color:var(--v2p-color-bg-search)}body select{color:var(--v2p-color-foreground);background-color:var(--v2p-color-background);border:1px solid var(--v2p-color-border);border-radius:4px;padding:4px 6px}body .ml,body .mle,body .mll,body .sl,body .sll,body .sls{color:var(--v2p-color-foreground);background-color:var(--v2p-color-bg-content);border-color:var(--v2p-color-input-border)}body .ml:focus,body .mle:focus,body .mll:focus,body .sl:focus,body .sll:focus,body .sls:focus{border-color:var(--v2p-color-input-border)}body input,body select,body textarea{color:var(--v2p-color-foreground)}body .onoffswitch{width:90px;min-width:90px;max-width:90px}.box .tag::before{color:var(--v2p-color-font-secondary)}.box .tag:link,.box .tag:visited{font-size:12px;color:var(--v2p-color-font-secondary);background-color:var(--v2p-color-main-100);border-radius:5px}.box .tag>li{opacity:.6}#Top .content{height:100%}#Top .site-nav{height:100%;padding:0}#Top .tools{display:flex;gap:8px 14px;align-items:center;justify-content:flex-end;font-size:14px;font-weight:400}#Top .tools .top{height:26px;padding:0 6px;line-height:26px;color:var(--v2p-color-button-foreground);white-space:nowrap;border-radius:4px}#Top .tools .top:hover{color:var(--v2p-color-foreground)}#Top .tools .top:not(.v2p-hover-btn):hover{background-color:var(--v2p-color-button-background-hover)}#Top .tools *{margin-left:0}#Main .box{overflow:auto;padding:0 12px}#Main .box.node-header>.cell{margin:0 -12px}#Main .box .cell{padding:var(--v2p-tp-item-x) var(--v2p-tp-item-y);background-image:none !important}#Main .box .cell_ops{padding:15px 5px}#Main .box:has(form[action="/write"]) .cell:nth-child(1),#Main .box:has(form[action="/write"]) .cell:nth-child(2){border:none}#Main .box:has(form[action="/write"]) .cell:has(#syntax-selector){padding:8px 0 !important}#Main .box:has(form[action="/write"]) .cell:has(#syntax-selector) .tab-alt-container{gap:0 8px}#Main .box:has(form[action="/write"]) .cell:has(#syntax-selector) .tab-alt{padding:4px 2px;border-bottom-width:2px;transition:none}#Main .box:has(form[action="/write"]) .cell:has(#syntax-selector) .tab-alt:not(.active):hover{border-color:rgba(0,0,0,0)}#Main .box:has(form[action="/write"]) .cell#preview{padding:2px 5px}#Main .topic_buttons{display:flex;flex-wrap:wrap;column-gap:5px;align-items:center;padding:8px 0;background:none}#Main .topic_buttons .topic_stats{float:none;flex:1;order:99;margin-left:10px;padding:0 !important;font-size:12px;text-shadow:none;white-space:nowrap}#Main .topic_buttons .topic_thanked{font-size:12px}#Main .topic_buttons a.tb:link{display:flex;flex-direction:row-reverse;column-gap:5px;align-items:center;padding:5px;text-shadow:none;white-space:nowrap;background:none;border-radius:4px}#Main .topic_buttons a.tb:link:not(.v2p-hover-btn){color:var(--v2p-color-font-secondary)}#Main .topic_buttons a.tb:link:hover:not(.v2p-hover-btn){color:currentColor;background:var(--v2p-color-bg-block)}#Main .vote:link{color:var(--v2p-color-font-tertiary);border-color:var(--v2p-color-border-darker);border-radius:5px}#Main .vote:link:hover{box-shadow:0 2px 2px var(--v2p-color-main-200)}#Main .cell .topic-link{color:var(--v2p-color-foreground);text-decoration:none}#Main .cell .topic-link:visited{color:var(--v2p-color-link-visited)}#Main .cell .topic_info{pointer-events:none;user-select:none;position:relative;display:flex;flex-wrap:wrap;align-items:center}#Main .cell .topic_info::after{content:"";position:absolute;z-index:1;inset:0 0 -6px;background-color:var(--v2p-color-bg-content)}#Main .cell .topic_info .votes,#Main .cell .topic_info .node,#Main .cell .topic_info strong:first-of-type,#Main .cell .topic_info span:first-of-type,#Main .cell .topic_info .v2p-topic-actions{pointer-events:auto;position:relative;z-index:2}#Main .cell .topic_info a[href^="/member"]{font-weight:500;color:var(--v2p-color-font-tertiary);background-color:rgba(0,0,0,0)}#Main .cell .count_livid{user-select:none;display:inline-block;padding:5px 10px;font-size:12px;font-weight:400;white-space:nowrap;border-radius:5px;margin-right:0;color:var(--v2p-color-button-foreground);background-color:var(--v2p-color-bg-block)}#Main .cell .count_orange{user-select:none;display:inline-block;padding:5px 10px;font-size:12px;font-weight:400;white-space:nowrap;border-radius:5px;font-weight:bold;color:var(--v2p-color-bg-block);background-color:var(--v2p-color-orange-400)}#Main .cell .item_title .topic-link{font-size:15px;font-weight:500}#Main .cell.item tr>td:nth-child(2){width:30px}#Main .box>.cell[id^=r]:not(:has(.cell[id^=r])) .reply_content,#Main .v2p-modal-content>.cell[id^=r]:not(:has(.cell[id^=r])) .reply_content{padding-bottom:0}#Main .cell[id^=r]{--bg-reply: var(--v2p-color-bg-content);background-color:var(--bg-reply)}#Main .cell[id^=r]:not(:has(+.cell[id^=r])){border-bottom:none}#Main .cell[id^=r]:hover>table td:last-of-type .fr a{opacity:1}#Main .cell[id^=r] .ago{font-size:12px;color:var(--v2p-color-font-quaternary);white-space:nowrap}#Main .cell[id^=r] .reply_content{padding-bottom:10px;line-height:1.5}#Main .cell[id^=r]>table:first-of-type td:first-of-type{width:40px}#Main .cell[id^=r]>table:first-of-type td:first-of-type .avatar{display:inline-block;aspect-ratio:1;width:40px !important;height:40px !important;background-color:var(--v2p-color-bg-avatar);border-radius:5px}#Main .cell[id^=r]>table~.cell[id^=r]{--bg-reply: var(--v2p-color-bg-reply);position:relative;z-index:var(--zidx-expand-btn);padding:var(--v2p-tp-nested-pd) 0 0 var(--v2p-tp-nested-pd);border:none;border-radius:0;box-shadow:-2.4px 0 var(--v2p-color-border-darker)}#Main .cell[id^=r]>table~.cell[id^=r] .cell[id^=r]{padding:0;box-shadow:none}#Main .cell[id^=r]>table~.cell[id^=r] .cell[id^=r].v2p-indent{padding-left:var(--v2p-tp-nested-pd);border-left:1px solid var(--v2p-color-border-darker)}#Main .cell[id^=r]>table~.cell[id^=r] tr td:first-of-type{width:25px}#Main .cell[id^=r]>table~.cell[id^=r] tr td:first-of-type .avatar{width:25px !important;height:25px !important;border-radius:4px}#Main .cell[id^=r]>table~.cell[id^=r] tr td:nth-child(3) strong a{font-size:13px}#Main .cell[id^=r]>table~.cell[id^=r] .reply_content{padding-right:5px}#Main .cell[id^=r]>table td:nth-of-type(2){width:15px}#Main .cell[id^=r]>table td:last-of-type a.dark{color:var(--v2p-color-font-secondary);text-decoration:none}#Main .cell[id^=r]>table td:last-of-type a.dark:hover{text-decoration:none}#Main .cell[id^=r]>table td:last-of-type .fr{user-select:none;position:relative;top:-3px}#Main .cell[id^=r]>table td:last-of-type .fr a{opacity:0}#Main .cell[id^=r]>table td:last-of-type .fr+.sep3{height:0}#Main .cell[id^=r]:last-of-type{border:none}#Main .cell[id^=r] .no{user-select:none;position:relative;top:-4px;padding:5px 10px;font-size:12px;color:var(--v2p-color-cell-num);background-color:rgba(0,0,0,0);border-radius:5px}#Main #Tabs{user-select:none;position:sticky;z-index:var(--zidx-tabs);top:0;display:flex;flex-wrap:wrap;gap:5px 3px;align-items:center;padding:var(--v2p-tp-tabs-pd);background-color:var(--v2p-color-bg-content);border-bottom:1px solid var(--box-border-color)}#Main #Tabs .tab_current{margin-right:0}#Main #Tabs .tab{margin:0}#Main #Tabs .tab.v2p-hover-btn::before{inset:0}#Main #SecondaryTabs{padding:10px;background-color:var(--v2p-color-bg-tabs);border-radius:5px}#Main #SecondaryTabs a{color:var(--v2p-color-tabs)}#Main .topic_content,#Main .reply_content{font-size:15px;line-height:1.6;color:currentColor}#Main .topic_content a[href^="/member"],#Main .reply_content a[href^="/member"]{position:relative;bottom:1px;font-size:13px;color:var(--v2p-color-font-tertiary);text-decoration:underline;text-underline-offset:.4ex;background-color:rgba(0,0,0,0)}#Main .thank_area{font-size:12px}#Main .tab{user-select:none;color:var(--v2p-color-foreground);background-color:rgba(0,0,0,0);border-radius:3px}#Main .tab:not(.v2p-hover-btn):hover{background-color:var(--v2p-color-bg-block)}#Main .tab_current{user-select:none;color:var(--v2p-color-bg-content);background-color:var(--v2p-color-foreground);border-radius:3px}#Main #reply-box.reply-box-sticky{z-index:var(--zidx-reply-box);bottom:20px;overflow:visible;margin:0 -10px;padding:0 22px;border:none;border-radius:var(--box-border-radius);outline:2px solid var(--v2p-color-border)}#Main #reply-box .flex-one-row:last-of-type{flex-direction:row-reverse;gap:10px;justify-content:flex-start}#Main #reply-box .flex-one-row:last-of-type .gray{margin-right:auto}#Main #reply-box>.cell{font-size:12px}#Main #reply-box>.cell.flex-one-row{min-height:45px;padding:0 10px;border:none}#Main #reply-box>.cell.flex-row-end{padding:12px 10px;border:none}#Main #reply-box>.cell:has(form){padding-top:0}#Main #no-comments-yet{color:var(--color-gray);border-color:var(--color-gray)}#Main #notifications .cell[id^=n]:hover .node{opacity:1}#Main #notifications .cell[id^=n] .node{opacity:0}#Main #notifications .cell[id^=n] .payload{color:var(--v2p-color-foreground);background-color:var(--v2p-color-bg-block)}#Main #notifications .cell[id^=n] .payload:has(.embedded_video_wrapper){min-width:50%}#Main #notifications .cell[id^=n] .topic-link:visited{color:var(--v2p-color-font-quaternary)}#Main .cell_tabs .cell_tab_current{font-weight:bold;border-color:var(--v2p-color-foreground)}#Main .cell_tabs .cell_tab{color:var(--v2p-color-foreground)}#Main .cell_tabs .cell_tab:hover{border-color:var(--v2p-color-border-darker)}#Rightbar .cell:has(.light-toggle){font-size:13px}#Rightbar .box .item_node{font-size:12px;color:var(--v2p-color-font-secondary);border-color:var(--v2p-color-border);border-radius:5px}#Rightbar .box .item_node:hover{box-shadow:var(--v2p-box-shadow)}#Rightbar a.dark:is(:link,:active,:visited,:hover){color:var(--v2p-color-font-tertiary)}#Rightbar a.dark:is(:link,:active,:visited,:hover):hover{color:var(--v2p-color-font-secondary)}#Bottom{position:sticky;top:100%}#Bottom a.dark{font-size:13px;font-weight:400}#Bottom a.dark:is(:link,:active,:visited,:hover){color:var(--v2p-color-font-tertiary)}.wwads-cn{border:none !important;box-shadow:none !important}.box:has(a[href^="/advertise"]){overflow:hidden;border:none !important;box-shadow:none !important}.box:has(a[href^="/advertise"]) .sidebar_compliance{background-color:var(--v2p-color-bg-block)}
:root body.v2p-theme-dark-default,:root .v2p-theme-dark-default,:root[data-darkreader-scheme=dark] body,:root body:has(#Wrapper.Night){color-scheme:dark;--v2p-color-main-50: unset;--v2p-color-main-100: #2d333b;--v2p-color-main-200: #374151;--v2p-color-main-300: #374151;--v2p-color-main-350: #6b7280cc;--v2p-color-main-400: #6b7280;--v2p-color-main-500: #9ca3af;--v2p-color-main-600: #9ca3af;--v2p-color-main-700: #d1d5db;--v2p-color-main-800: #e5e7eb;--v2p-color-main-900: #111827;--v2p-color-main-950: #030712;--v2p-color-accent-50: #064e3b;--v2p-color-accent-100: #065f46;--v2p-color-accent-200: #047857;--v2p-color-accent-300: #059669;--v2p-color-accent-400: #10b981;--v2p-color-accent-500: #34d399;--v2p-color-accent-600: #6ee7b7;--v2p-color-orange-50: #593600;--v2p-color-orange-100: #9a3412;--v2p-color-orange-400: #fbe090;--v2p-color-background: #1c2128;--v2p-color-foreground: #adbac7;--v2p-color-font-secondary: var(--v2p-color-main-600);--v2p-color-button-background: #373e47;--v2p-color-button-foreground: var(--v2p-color-foreground);--v2p-color-button-background-hover: #444c56;--v2p-color-button-foreground-hover: var(--v2p-color-foreground);--v2p-color-bg-content: #22272e;--v2p-color-bg-hover-btn: var(--v2p-color-button-background-hover);--v2p-color-bg-subtle: rgb(6 78 59 / 30%);--v2p-color-bg-input: var(--v2p-color-background);--v2p-color-bg-search: var(--v2p-color-main-100);--v2p-color-bg-search-active: var(--v2p-color-main-200);--v2p-color-bg-widget: var(--v2p-color-bg-content);--v2p-color-bg-reply: var(--v2p-color-main-100);--v2p-color-bg-tooltip: var(--v2p-color-main-100);--v2p-color-bg-avatar: var(--v2p-color-main-300);--v2p-color-bg-block: #373e47;--v2p-color-heart: #ef4444;--v2p-color-heart-fill: #fca5a5;--v2p-color-mask: rgb(99 110 123 / 40%);--v2p-color-border: #444c56;--v2p-color-input-border: #444c56;--v2p-color-border-darker: #444c56;--v2p-box-shadow: 0 0 0 1px var(--v2p-color-border);--v2p-toast-shadow: none;--link-color: var(--v2p-color-foreground);--box-background-alt-color: var(--v2p-color-main-100);--box-background-hover-color: var(--v2p-color-main-300);--button-hover-color: var(--button-background-hover-color);--button-border-color: var(--v2p-color-border);--button-border-hover-color: #768390;visibility:visible}:root body.v2p-theme-dark-default #Logo,:root .v2p-theme-dark-default #Logo,:root[data-darkreader-scheme=dark] body #Logo,:root body:has(#Wrapper.Night) #Logo{background-image:url("https://www.v2ex.com/static/img/v2ex-alt@2x.png")}:root body.v2p-theme-dark-default ::selection,:root .v2p-theme-dark-default ::selection,:root[data-darkreader-scheme=dark] body ::selection,:root body:has(#Wrapper.Night) ::selection{color:var(--v2p-color-background, #1c2128);background-color:var(--v2p-color-foreground, #adbac7)}:root body.v2p-theme-dark-default img::selection,:root .v2p-theme-dark-default img::selection,:root[data-darkreader-scheme=dark] body img::selection,:root body:has(#Wrapper.Night) img::selection{background-color:var(--v2p-color-foreground, #adbac7)}:root body.v2p-theme-dark-default #Top,:root .v2p-theme-dark-default #Top,:root[data-darkreader-scheme=dark] body #Top,:root body:has(#Wrapper.Night) #Top{background-color:rgba(0,0,0,0)}:root body.v2p-theme-dark-default #Main .cell .item_title .topic-link,:root .v2p-theme-dark-default #Main .cell .item_title .topic-link,:root[data-darkreader-scheme=dark] body #Main .cell .item_title .topic-link,:root body:has(#Wrapper.Night) #Main .cell .item_title .topic-link{font-weight:normal}:root body.v2p-theme-dark-default #search-container::before,:root .v2p-theme-dark-default #search-container::before,:root[data-darkreader-scheme=dark] body #search-container::before,:root body:has(#Wrapper.Night) #search-container::before{background-image:url("/static/img/search_icon_light.png")}@supports not selector(:has(*)){:root #Wrapper.Night{--v2p-color-main-50: unset;--v2p-color-main-100: #2d333b;--v2p-color-main-200: #374151;--v2p-color-main-300: #374151;--v2p-color-main-350: #6b7280cc;--v2p-color-main-400: #6b7280;--v2p-color-main-500: #9ca3af;--v2p-color-main-600: #9ca3af;--v2p-color-main-700: #d1d5db;--v2p-color-main-800: #e5e7eb;--v2p-color-main-900: #111827;--v2p-color-main-950: #030712;--v2p-color-accent-50: #064e3b;--v2p-color-accent-100: #065f46;--v2p-color-accent-200: #047857;--v2p-color-accent-300: #059669;--v2p-color-accent-400: #10b981;--v2p-color-accent-500: #34d399;--v2p-color-accent-600: #6ee7b7;--v2p-color-orange-50: #593600;--v2p-color-orange-100: #9a3412;--v2p-color-orange-400: #fbe090;--v2p-color-background: #1c2128;--v2p-color-foreground: #adbac7;--v2p-color-font-secondary: var(--v2p-color-main-600);--v2p-color-button-background: #373e47;--v2p-color-button-foreground: var(--v2p-color-foreground);--v2p-color-button-background-hover: #444c56;--v2p-color-button-foreground-hover: var(--v2p-color-foreground);--v2p-color-bg-content: #22272e;--v2p-color-bg-hover-btn: var(--v2p-color-button-background-hover);--v2p-color-bg-subtle: rgb(6 78 59 / 30%);--v2p-color-bg-input: var(--v2p-color-background);--v2p-color-bg-search: var(--v2p-color-main-100);--v2p-color-bg-search-active: var(--v2p-color-main-200);--v2p-color-bg-widget: var(--v2p-color-bg-content);--v2p-color-bg-reply: var(--v2p-color-main-100);--v2p-color-bg-tooltip: var(--v2p-color-main-100);--v2p-color-bg-avatar: var(--v2p-color-main-300);--v2p-color-bg-block: #373e47;--v2p-color-heart: #ef4444;--v2p-color-heart-fill: #fca5a5;--v2p-color-mask: rgb(99 110 123 / 40%);--v2p-color-border: #444c56;--v2p-color-input-border: #444c56;--v2p-color-border-darker: #444c56;--v2p-box-shadow: 0 0 0 1px var(--v2p-color-border);--v2p-toast-shadow: none;--link-color: var(--v2p-color-foreground);--box-background-alt-color: var(--v2p-color-main-100);--box-background-hover-color: var(--v2p-color-main-300);--button-hover-color: var(--button-background-hover-color);--button-border-color: var(--v2p-color-border);--button-border-hover-color: #768390;visibility:visible}:root #Wrapper.Night #Logo{background-image:url("https://www.v2ex.com/static/img/v2ex-alt@2x.png")}:root #Wrapper.Night ::selection{color:var(--v2p-color-background, #1c2128);background-color:var(--v2p-color-foreground, #adbac7)}:root #Wrapper.Night img::selection{background-color:var(--v2p-color-foreground, #adbac7)}}
body.v2p-theme-dawn,.v2p-theme-dawn{--v2p-color-base: 32deg 57% 95%;--v2p-color-surface: 35deg 100% 98%;--v2p-color-overlay: 33deg 43% 91%;--v2p-color-muted: 257deg 9% 61%;--v2p-color-subtle: 248deg 12% 52%;--v2p-color-text: 248deg 19% 40%;--v2p-color-love: 343deg 35% 55%;--v2p-color-gold: 35deg 81% 56%;--v2p-color-rose: 3deg 53% 67%;--v2p-color-pine: 197deg 53% 34%;--v2p-color-foam: 189deg 30% 48%;--v2p-color-iris: 268deg 21% 57%;--v2p-color-accent-50: hsl(var(--v2p-color-foam) / 10%);--v2p-color-accent-100: hsl(var(--v2p-color-foam) / 20%);--v2p-color-accent-200: hsl(var(--v2p-color-foam) / 30%);--v2p-color-accent-300: hsl(var(--v2p-color-foam) / 40%);--v2p-color-accent-400: hsl(var(--v2p-color-foam) / 50%);--v2p-color-accent-500: hsl(var(--v2p-color-foam) / 65%);--v2p-color-accent-600: hsl(var(--v2p-color-foam) / 80%);--v2p-color-orange-50: hsl(var(--v2p-color-gold) / 10%);--v2p-color-orange-100: hsl(var(--v2p-color-gold) / 20%);--v2p-color-orange-400: hsl(var(--v2p-color-gold));--v2p-color-background: hsl(var(--v2p-color-base));--v2p-color-foreground: hsl(var(--v2p-color-text));--v2p-color-selection-foreground: var(--v2p-color-foreground);--v2p-color-selection-background: hsl(var(--v2p-color-muted) / 20%);--v2p-color-selection-background-img: hsl(var(--v2p-color-muted) / 60%);--v2p-color-font-secondary: hsl(var(--v2p-color-subtle));--v2p-color-font-tertiary: hsl(var(--v2p-color-subtle));--v2p-color-font-quaternary: hsl(var(--v2p-color-subtle));--v2p-color-button-background: hsl(var(--v2p-color-text) / 10%);--v2p-color-button-foreground: var(--v2p-color-foreground);--v2p-color-button-background-hover: hsl(var(--v2p-color-text) / 15%);--v2p-color-button-foreground-hover: var(--v2p-color-foreground);--v2p-color-bg-content: hsl(var(--v2p-color-surface));--v2p-color-bg-footer: var(--v2p-color-bg-content);--v2p-color-bg-hover-btn: rgb(152 147 165 / 10%);--v2p-color-bg-subtle: hsl(var(--v2p-color-pine) / 10%);--v2p-color-bg-input: hsl(var(--v2p-color-overlay) / 40%);--v2p-color-bg-search: hsl(var(--v2p-color-overlay) / 60%);--v2p-color-bg-search-active: hsl(var(--v2p-color-overlay) / 90%);--v2p-color-bg-widget: rgb(255 255 255 / 70%);--v2p-color-bg-reply: #faf4ed;--v2p-color-bg-tooltip: var(--v2p-color-bg-content);--v2p-color-bg-tabs: hsl(var(--v2p-color-pine) / 10%);--v2p-color-bg-tpr: hsl(var(--v2p-color-text) / 10%);--v2p-color-bg-avatar: hsl(var(--v2p-color-overlay));--v2p-color-bg-block: hsl(var(--v2p-color-text) / 10%);--v2p-color-bg-block-darker: hsl(var(--v2p-color-text) / 25%);--v2p-color-bg-link: hsl(var(--v2p-color-text) / 10%);--v2p-color-bg-link-hover: hsl(var(--v2p-color-text) / 15%);--v2p-color-tabs: hsl(var(--v2p-color-pine));--v2p-color-heart: #eb6f92;--v2p-color-heart-fill: rgb(235 111 146 / 50%);--v2p-color-mask: rgb(0 0 0 / 25%);--v2p-color-divider: hsl(var(--v2p-color-muted) / 20%);--v2p-color-border: hsl(var(--v2p-color-muted) / 20%);--v2p-color-input-border: rgb(152 147 165 / 20%);--v2p-color-border-darker: hsl(var(--v2p-color-muted) / 40%);--v2p-color-link-visited: hsl(var(--v2p-color-subtle));--v2p-color-error: #eb6f92;--v2p-color-bg-error: #fee2e2;--v2p-color-cell-num: hsl(var(--v2p-color-subtle));--v2p-box-shadow: 0 3px 5px 0 rgb(0 0 0 / 4%);--v2p-widget-shadow: 0 9px 24px -3px rgb(0 0 0 / 6%), 0 4px 8px -1px rgb(0 0 0 /12%);--v2p-toast-shadow: 0 6px 16px 0 rgb(0 0 0 / 8%), 0 3px 6px -4px rgb(0 0 0 / 12%), 0 9px 28px 8px rgb(0 0 0 / 5%);--link-color: var(--v2p-color-foreground);--box-background-alt-color: var(--v2p-color-bg-block);--box-background-hover-color: var(--v2p-color-bg-link-hover);--button-hover-color: var(--v2p-color-button-background-hover);--button-border-color: var(--v2p-color-border);--button-border-hover-color: var(--v2p-color-border-darker);visibility:visible}body.v2p-theme-dawn .button.special:hover,body.v2p-theme-dawn .button.special:hover:enabled,.v2p-theme-dawn .button.special:hover,.v2p-theme-dawn .button.special:hover:enabled{text-shadow:none}
\uFEFFbody{position:relative}body.v2p-modal-open{overflow:hidden}body .button.v2p-prev-btn,body .button.v2p-next-btn{padding:0 15px}body #Top a:has(#Logo.v2p-logo){display:inline-flex;align-items:center}body #Logo.v2p-logo{width:unset;height:25px;padding:0 8px;background-image:none !important}.v2p-hover-btn{cursor:pointer;user-select:none;position:relative;z-index:1;margin:0;text-decoration:none;white-space:nowrap;background:none;background-color:rgba(0,0,0,0);transition:color .2s}.v2p-hover-btn::before{content:"";position:absolute;z-index:-1;inset:0 -5px;transform:scale(0.65);opacity:0;background-color:var(--v2p-color-bg-hover-btn);border-radius:5px;transition:background-color .15s,color .15s,transform .15s,opacity .15s}.v2p-hover-btn:hover{text-decoration:none}.v2p-hover-btn:hover::before{transform:scale(1);opacity:1}.v2p-hover-btn-disabled{pointer-events:none;opacity:.8}.v2p-icon-heart{display:inline-flex;width:16px;height:16px;color:var(--v2p-color-heart)}.v2p-icon-heart svg{fill:var(--v2p-color-heart-fill)}#Main .cell[id^=r] .v2p-auto-hide{overflow:hidden;display:inline-flex;width:0}#Main #reply-box .v2p-reply-preview{font-size:15px;line-height:1.6}#Main .cell:hover .v2p-topic-preview-btn,#Main .cell:hover .v2p-topic-ignore-btn,#Rightbar .cell:hover .v2p-topic-preview-btn,#Rightbar .cell:hover .v2p-topic-ignore-btn{visibility:visible}#Rightbar .v2p-info-row{display:block;font-size:12px;color:var(--v2p-color-accent-500);text-align:center}#Rightbar .v2p-info-row:hover{text-decoration:none;background-color:var(--v2p-color-accent-50)}#Rightbar .v2p-topic-preview-btn{position:absolute;top:0;right:0;bottom:0;height:20px;font-size:12px;backdrop-filter:blur(8px);box-shadow:0 0 0 3px var(--v2p-color-bg-content)}.v2p-tool-box{position:sticky;z-index:var(--zidx-tools-card);top:var(--v2p-layout-row-gap)}.v2p-tool-box .v2p-tools{display:grid;grid-auto-rows:auto;grid-template-columns:repeat(3, 1fr);gap:8px 15px;align-items:center;justify-content:center;font-size:12px;color:var(--v2p-color-font-secondary)}.v2p-tool{display:inline-flex;gap:0 5px;align-items:center;padding:3px 0}.v2p-tool:hover{color:var(--v2p-color-button-foreground-hover)}.v2p-tool .v2p-tool-icon{width:16px;height:16px}.v2p-topic-actions{display:inline-flex;gap:2px 10px}.v2p-topic-preview-btn{cursor:pointer;font-size:13px;color:var(--v2p-color-button-foreground);visibility:hidden;background-color:var(--v2p-color-button-background-hover);border:none;border-radius:3px;outline:none}.v2p-topic-ignore-btn{cursor:pointer;margin-left:8px;visibility:hidden}.v2p-topic-preview{font-size:15px;line-height:1.6;padding:var(--v2p-tp-preview-pd)}.v2p-tpr-loading{--tpr-h: 30px;--tpr-h-p: 22px;display:flex;flex-direction:column;gap:10px;padding:25px}.v2p-tpr-loading .v2p-tpr{background-color:var(--v2p-color-bg-tpr);border-radius:5px}.v2p-tpr-loading .v2p-tpr-info{display:flex;gap:15px;align-items:center}.v2p-tpr-info-avatar{width:var(--tpr-h);height:var(--tpr-h)}.v2p-tpr-info-text{width:50%;height:var(--tpr-h)}.v2p-tpr-loading .v2p-tpr-content{display:flex;flex-direction:column;gap:12px;padding:15px 0 20px}.v2p-tpr-loading .v2p-tpr-content .v2p-tpr-content-p{height:var(--tpr-h-p)}.v2p-tpr-loading .v2p-tpr-cmt{display:flex;gap:15px;padding-top:15px;border-top:1px solid var(--v2p-color-border)}.v2p-tpr-loading .v2p-tpr-cmt .v2p-tpr-cmt-avatar{width:50px;height:50px}.v2p-tpr-loading .v2p-tpr-cmt .v2p-tpr-cmt-right{display:flex;flex:1;flex-direction:column;gap:10px}.v2p-tpr-loading .v2p-tpr-cmt .v2p-tpr-cmt-right .v2p-tpr-cmt-header{width:50%;height:var(--tpr-h)}.v2p-tpr-loading .v2p-tpr-cmt .v2p-tpr-cmt-right .v2p-tpr-cmt-p{height:var(--tpr-h-p)}.v2p-tp-info-bar{display:flex;gap:10px;align-items:center;margin-bottom:10px}.v2p-tp-info,.v2p-tp-read{overflow:hidden;display:inline-flex;gap:20px;align-items:center;padding:5px 10px;font-size:13px;background-color:var(--v2p-color-button-background);border-radius:5px}.v2p-tp-read{cursor:pointer;user-select:none;gap:4px}.v2p-tp-read:hover{background-color:var(--v2p-color-button-background-hover)}.v2p-tp-read-icon{width:16px;height:16px}.v2p-tp-member{display:inline-flex;gap:5px;align-items:center;font-weight:bold}.v2p-tp-avatar{width:20px;height:20px;background-color:var(--v2p-color-bg-avatar);border-radius:3px}.v2p-topic-preview-addons{margin-top:30px}#Main.v2p-topic-preview>.box{border:1px solid var(--v2p-color-border)}a.v2p-topic-preview-title-link:hover{text-decoration:underline 1.5px;text-underline-offset:.46ex}.v2p-dot{margin:0 8px;font-size:15px;font-weight:800}.v2p-paging{background:none !important}.v2p-paging.cell{border-bottom:none}.v2p-modal-mask{position:fixed;z-index:var(--zidx-modal-mask);inset:0;overflow:hidden;overflow-y:auto;padding:min(2vh,60px);background-color:var(--v2p-color-mask)}.v2p-popup{font-size:14px;background:var(--v2p-color-bg-widget);backdrop-filter:blur(16px);border:1px solid var(--box-border-color);border-radius:8px;box-shadow:var(--v2p-widget-shadow);position:absolute;z-index:var(--zidx-popup);top:0;left:0}.v2p-popup-content{overflow-y:auto;width:max-content}.v2p-toast{position:fixed;z-index:var(--zidx-toast);top:50px;left:50%;transform:translateX(-50%);padding:10px 15px;font-size:14px;color:var(--v2p-color-background);background:var(--v2p-color-foreground);border-radius:8px;box-shadow:var(--v2p-toast-shadow)}.v2p-modal-main{position:relative;overflow:hidden;display:flex;flex-direction:column;box-sizing:border-box;width:800px;height:100%;margin:0 auto;background-color:var(--v2p-color-bg-content);border-radius:var(--box-border-radius)}.v2p-modal-header{display:flex;gap:0 20px;align-items:center;padding:15px 20px 20px;background-color:var(--v2p-color-bg-content);border-bottom:1px solid var(--box-border-color)}.v2p-modal-title{overflow:hidden;padding:2px 0;font-size:16px;font-weight:bold;text-overflow:ellipsis;white-space:nowrap}.v2p-modal-actions{display:flex;gap:0 10px;align-items:center;margin-left:auto}.v2p-modal-content{position:relative;overflow-y:auto;overscroll-behavior-y:contain;flex:1;outline:none}.v2p-modal-content #Main.v2p-topic-preview>.box{border:none;box-shadow:none}.v2p-modal-comments{position:absolute;inset:0;overflow-y:auto;padding:0 20px;visibility:hidden}.v2p-modal-comments.v2p-tab-content-active{z-index:20;visibility:visible}.v2p-modal-comment-tabs{display:flex;gap:4px;align-items:center;padding:4px 5px;font-size:14px;font-weight:normal;background-color:var(--button-background-color);border-radius:4px}.v2p-modal-comment-tabs>[data-tab-key]{cursor:pointer;padding:4px 5px;border-radius:4px}.v2p-modal-comment-tabs>[data-tab-key]:hover{background-color:var(--v2p-color-button-background-hover)}.v2p-modal-comment-tabs>[data-tab-key].v2p-tab-active{color:var(--v2p-color-foreground);background-color:var(--v2p-color-accent-100)}.v2p-no-pat{padding:30px 20px;font-size:15px;text-align:center}.v2p-no-pat .v2p-no-pat-title{font-size:16px;font-weight:bold}.v2p-no-pat .v2p-no-pat-desc{display:flex;align-items:center;justify-content:center;margin-top:15px}.v2p-no-pat .v2p-no-pat-block{display:inline-flex;align-items:center;margin:0 5px;padding:2px 10px;background-color:var(--v2p-color-bg-block);border-radius:2px}.v2p-no-pat .v2p-no-pat-steps{display:flex;flex-wrap:wrap;gap:20px;max-width:800px;margin-top:20px;padding:20px;background-color:var(--v2p-color-bg-block);border-radius:10px}.v2p-no-pat .v2p-no-pat-step{flex:1}.v2p-no-pat .v2p-no-pat-img{width:100%;border-radius:8px;box-shadow:var(--v2p-widget-shadow)}.v2p-no-pat .v2p-icon-logo{width:15px;height:15px}.v2p-likes-box{user-select:none;position:relative;top:3px;display:inline-flex;column-gap:5px;align-items:center}.v2p-likes-box.v2p-thanked{font-weight:bold;color:var(--v2p-color-heart);opacity:.8}.v2p-likes-box.v2p-thanked .v2p-icon-heart svg{fill:var(--v2p-color-heart)}@supports not selector(:has(*)){#Main .cell[id^=r]>table:hover .v2p-controls{opacity:1}}@supports selector(:has(*)){#Main .cell[id^=r]:not(:has(.cell:hover))>table:hover .v2p-auto-hide{width:auto}#Main .cell[id^=r]:not(:has(.cell:hover))>table:hover .v2p-controls{opacity:1}}.v2p-controls{display:inline-flex;column-gap:15px;align-items:center;margin-right:15px;font-size:12px;opacity:0}.v2p-controls>a{text-decoration:none}.v2p-control{position:relative;display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:4px 0;color:var(--v2p-color-font-tertiary)}.v2p-control::after{pointer-events:none;z-index:var(--zidx-tip);overflow:hidden;width:max-content;min-width:30px;padding:2px 5px;font-size:12px;color:var(--v2p-color-foreground);text-align:center;white-space:nowrap;background-color:var(--v2p-color-bg-tooltip);border-radius:4px;box-shadow:var(--v2p-widget-shadow);position:absolute;top:-8px;transform:translateY(-100%);opacity:0}.v2p-control:hover{color:var(--v2p-color-font-secondary)}.v2p-control.v2p-thanked{cursor:default;color:var(--v2p-color-heart)}.v2p-control:hover::after{opacity:1}.v2p-control.v2p-control-hide::after{content:"\u9690\u85CF\u56DE\u590D"}.v2p-control.v2p-control-thank::after{content:"\u611F\u8C22\u56DE\u590D"}.v2p-control.v2p-control-thank.v2p-thanked::after{content:"\u5DF2\u611F\u8C22"}.v2p-control.v2p-control-reply::after{content:"\u56DE\u590D"}.topic_buttons .v2p-tb.v2p-hover-btn{color:var(--v2p-color-font-secondary)}.topic_buttons .v2p-tb.v2p-hover-btn::after{display:none}.topic_buttons .v2p-tb.v2p-hover-btn:hover{color:currentColor}.v2p-tb-icon{width:15px;height:15px}.v2p-emoji-container{overflow-y:auto;max-height:285px;padding:15px 18px;color:var(--v2p-color-font-secondary)}.v2p-member-card{max-width:300px;max-height:285px;padding:12px;font-size:13px;text-align:left}.v2p-member-card .v2p-info{display:flex;gap:15px}.v2p-member-card .v2p-info-right{padding:2px 0}.v2p-member-card .v2p-avatar-box{overflow:hidden;display:inline-block;width:73px;height:73px;background-color:var(--button-background-hover-color);border-radius:5px}.v2p-member-card .v2p-avatar{width:100%;height:100%}.v2p-member-card .v2p-username{font-size:16px;font-weight:bold}.v2p-member-card .v2p-no{margin:5px 0}.v2p-member-card .v2p-no,.v2p-member-card .v2p-created-date{width:160px;height:16px}.v2p-member-card .v2p-loading{background-color:var(--button-background-hover-color);border-radius:4px}.v2p-member-card .v2p-bio{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-height:1.4;margin-top:10px}.v2p-member-card-actions{padding:10px 0 0}.v2p-reply-tags{cursor:pointer;display:inline-flex;margin:0 0 2px;padding:0 3px;font-size:12px;background-color:var(--button-background-hover-color);border-radius:3px}.v2p-reply-tags-inline{overflow:hidden;max-width:300px;margin:0 5px 0 0;text-overflow:ellipsis;white-space:nowrap}.v2p-emoticons-box{font-size:15px}.v2p-emoji-group~.v2p-emoji-group{margin-top:10px}.v2p-emoji-title{margin:0 0 10px;font-size:14px;text-align:left}.v2p-emoji-list{display:grid;grid-template-columns:repeat(8, 1fr);gap:5px;font-size:20px}.v2p-emoji{cursor:pointer;height:20px;padding:3px;line-height:20px;border-radius:4px}.v2p-emoji:hover{background-color:var(--box-background-hover-color)}.v2p-emoji>img{height:100%}.v2p-decode{cursor:copy;position:relative;padding:2px 4px;font-size:13px;color:var(--v2p-color-orange-400);text-decoration:none;background-color:var(--v2p-color-orange-50)}.v2p-decode::after{pointer-events:none;z-index:var(--zidx-tip);overflow:hidden;width:max-content;min-width:30px;padding:2px 5px;font-size:12px;color:var(--v2p-color-foreground);text-align:center;white-space:nowrap;background-color:var(--v2p-color-bg-tooltip);border-radius:4px;box-shadow:var(--v2p-widget-shadow);content:attr(data-title);position:absolute;top:-8px;left:50%;transform:translate(-50%, -100%);opacity:0}.v2p-decode:hover{color:var(--v2p-color-orange-400)}.v2p-decode:hover::after{opacity:1}.v2p-reply-content{position:relative}.v2p-reply-content .v2p-expand-btn.normal.button{position:absolute;z-index:var(--zidx-expand-btn);bottom:5px;left:50%;transform:translateX(-50%);font-size:12px;font-weight:400}.v2p-reply-content.v2p-collapsed::before{pointer-events:none;content:"";position:absolute;z-index:var(--zidx-expand-mask);right:0;bottom:0;left:0;height:130px;background:linear-gradient(to top, var(--bg-reply) 10px, transparent)}.v2p-reply-content.v2p-collapsed .reply_content a,.v2p-reply-content.v2p-collapsed .reply_content .embedded_video{pointer-events:none}.v2p-reply-content.v2p-collapsed .v2p-expand-btn.normal.button{bottom:10px;transform:translateX(-50%)}.cell[id^=r] .cell[id^=r] .v2p-reply-content .v2p-expand-btn.normal.button{color:var(--v2p-color-button-foreground);background:var(--v2p-color-button-background-hover);box-shadow:var(--button-hover-shadow)}.v2p-empty-content{display:flex;flex-direction:column;align-items:center;padding-top:20px;font-size:14px;color:var(--v2p-color-font-secondary)}.v2p-empty-content .v2p-text-emoji{font-size:20px}.v2p-topic-reply-ref{margin:0 -10px 15px;padding:5px 10px;font-size:13px;color:var(--v2p-color-font-tertiary);background-color:var(--v2p-color-bg-block);border-radius:5px}.v2p-topic-reply-box{margin-top:50px;padding:30px 0;font-size:14px;line-height:1.55;color:var(--v2p-color-font-secondary);border-top:1px solid var(--v2p-color-divider)}.v2p-topic-reply~.v2p-topic-reply{margin-top:15px}.v2p-topic-reply-member{display:inline;font-weight:bold;color:var(--v2p-color-main-700)}.v2p-topic-reply-avatar{position:relative;top:2px;overflow:hidden;width:15px;height:15px;margin-right:5px;object-fit:cover;background-color:var(--v2p-color-bg-avatar);border-radius:2px}.v2p-topic-reply-content{display:inline}.v2p-topic-reply-tip{margin-top:20px;font-size:13px;color:var(--v2p-color-font-quaternary);text-align:center}.v2p-reply-wrap{resize:none;overflow:hidden;height:unset;min-height:140px !important;max-height:800px !important;font-size:15px;color:currentColor;background-color:var(--v2p-color-bg-input);border:1px solid var(--button-border-color);border-radius:8px;transition:opacity .25s}.v2p-reply-wrap::placeholder{font-size:15px;color:var(--v2p-color-font-tertiary)}.v2p-reply-wrap:is(:focus,:focus-within){background-color:rgba(0,0,0,0);outline:none;box-shadow:0 0 0 1px var(--button-border-color)}.v2p-reply-wrap #reply_content{background-color:rgba(0,0,0,0);border:none}.v2p-reply-wrap #reply_content::placeholder{font-size:14px;color:var(--v2p-color-font-tertiary)}.v2p-reply-wrap #reply_content:focus{background-color:var(--v2p-color-bg-content);outline:none}.v2p-reply-upload-bar{cursor:pointer;padding:6px 10px;font-size:12px;color:var(--v2p-color-font-tertiary);background-color:var(--v2p-color-bg-input);border-top:1px dashed var(--v2p-color-border-darker)}.v2p-reply-upload-bar-disabled{pointer-events:none}.v2p-footer{position:relative;display:flex;align-items:center;justify-content:space-between;padding:35px 10px 20px;font-size:12px;color:var(--v2p-color-font-tertiary);border-top:1px solid var(--v2p-color-divider)}.v2p-footer a:hover{text-decoration:none}.v2p-footer-logo{--logo-size: 16px;position:absolute;top:calc(-1*(var(--logo-size) + 5px)/2);left:50%;transform:translateX(-50%);display:inline-flex;box-sizing:border-box;padding:3px 25px;background-color:var(--v2p-color-bg-footer)}.v2p-footer-logo svg{width:var(--logo-size)}.v2p-footer-text{display:inline-flex;align-items:center;justify-content:flex-start;width:240px;color:var(--v2p-color-font-secondary)}.v2p-footer-links{display:inline-flex;gap:0 8px;align-items:center}.v2p-footer-link{padding:4px 5px;color:currentColor}.v2p-footer-brand{display:inline-flex;gap:0 15px;align-items:center;justify-content:flex-end;width:240px}.v2p-footer-brand .v2p-github-ref{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:2px 0}.v2p-color-mode-toggle{width:22px;height:22px;opacity:.8}.v2p-color-mode-toggle:hover{opacity:1}.v2p-reply-tabs{display:flex;gap:0 6px;align-items:center;font-size:14px}.v2p-reply-tabs .v2p-reply-tab{cursor:pointer;padding:2px 3px}.v2p-reply-tabs .v2p-reply-tab.active{text-decoration:underline;text-decoration-color:var(--v2p-color-font-tertiary);text-decoration-thickness:2px;text-underline-offset:4px}.v2p-select-dropdown{padding:5px;font-size:12px;border-radius:5px}.v2p-select-item{cursor:pointer;padding:5px 10px;white-space:nowrap;border-radius:4px}.v2p-select-item:hover{background-color:var(--v2p-color-button-background-hover)}.v2p-select-item.v2p-select-item-active{background-color:var(--v2p-color-accent-50)}.v2p-preview-retry,.v2p-topic-preview-retry,a.v2p-preview-retry,a.v2p-topic-preview-retry,a:link.v2p-preview-retry,a:link.v2p-topic-preview-retry{text-decoration:underline 1px;text-underline-offset:var(--v2p-underline-offset);cursor:pointer}.v2p-indent .v2p-member-ref{display:none}.v2p-member-ref+br{display:none}.v2p-member-ref+br+b{display:none}.v2p-member-ref.v2p-member-ref-show{display:inline}.v2p-layout-toggle{display:inline-block;width:18px;height:18px;padding:4px 2px;color:var(--v2p-color-font-tertiary)}.v2p-content-layout.v2p-content-layout{max-width:2000px}.v2p-content-layout.v2p-content-layout .v2p-horizontal-layout{display:flex;flex-wrap:wrap;gap:var(--v2p-layout-column-gap)}.v2p-left-side{flex:1}.v2p-left-side>.box{position:sticky;top:var(--v2p-layout-row-gap);display:flex;flex-direction:column;max-height:calc(100vh - 2*var(--v2p-layout-row-gap))}.v2p-left-side>.box>.header{flex-shrink:0}.v2p-left-side .v2p-left-side-content{overflow:auto;flex:1;border-bottom:1px solid var(--box-border-color)}.v2p-right-side{flex:1}.v2p-register-days{display:inline-flex;align-items:center;margin-left:2px;padding:0 2px;color:var(--v2p-color-orange-400);background-color:var(--v2p-color-orange-100);border-radius:2px}.v2p-register-days.v2p-register-days-large{display:inline-flex;margin-left:10px;padding:2px 5px;font-size:16px;line-height:1.4;border-radius:4px}.v2p-topics-hot-loading{display:flex;align-items:center;justify-content:center;padding:50px 0;color:currentColor}.v2p-topics-hot-loading .v2p-icon-loading{width:40px}.v2p-topics-hot-header{display:flex;align-items:center}.v2p-topics-hot-picker{cursor:pointer;display:inline-flex;gap:4px;align-items:center;margin-left:auto;padding:1px 6px;font-size:13px;background-color:var(--v2p-color-button-background);border-radius:4px}.v2p-topics-hot-picker:hover{background-color:var(--v2p-color-button-background-hover)}.v2p-topics-hot-icon{position:relative;top:-2px;width:1em;height:1em}.v2p-tag-block{margin-bottom:10px}@supports(filter: blur(6px)){.v2p-hide-account{opacity:.5;filter:blur(6px)}}@supports not (filter: blur(6px)){.v2p-hide-account{opacity:0}}@supports(filter: blur(6px)){.v2p-hide-balance{opacity:.5;filter:blur(6px)}.v2p-hide-balance:hover{opacity:1;filter:none}}@supports not (filter: blur(6px)){.v2p-hide-balance{opacity:0}.v2p-hide-balance:hover{opacity:1}}.v2p-member-name{display:flex;align-items:center}.v2p-settings-header.page-content-header{gap:10px}.v2p-settings-header.page-content-header .v2p-settings-icon{width:40px;height:40px;margin:0}.v2p-settings-header.page-content-header .v2p-settings-title{padding:0;white-space:nowrap}.v2p-settings-header.page-content-header .v2p-settings-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end}.v2p-link-preview-btn{cursor:pointer;user-select:none;display:inline-flex;height:100%;margin-left:5px;padding:0 5px;font-size:12px;color:var(--v2p-color-bg-content);background-color:var(--v2p-color-accent-500);border-radius:3px}.v2p-link-preview-btn:hover{background-color:var(--v2p-color-accent-600)}#node_sidebar.v2p-node-sidebar-flamewar{background-color:var(--v2p-color-orange-50);border:1px solid var(--v2p-color-orange-400);border-radius:var(--v2p-box-radius)}
`;

// src/user-scripts/index.ts
function runAfterLoaded(fn) {
  if (document.readyState !== "loading") {
    fn();
  } else {
    document.addEventListener("DOMContentLoaded", () => {
      fn();
    });
  }
}
if (typeof window.GM_addStyle !== "undefined") {
  window.GM_addStyle(style);
} else {
  runAfterLoaded(() => {
    $(`<style type='text/css'>${style}</style>`).appendTo("head");
  });
}
var allowedHosts = [
  "https://v2ex.com",
  "https://www.v2ex.com",
  "https://cn.v2ex.com",
  "https://jp.v2ex.com",
  "https://de.v2ex.com",
  "https://us.v2ex.com",
  "https://hk.v2ex.com",
  "https://global.v2ex.com",
  "https://fast.v2ex.com",
  "https://s.v2ex.com",
  "https://origin.v2ex.com",
  "https://staging.v2ex.com"
];
var commonRegex = patternToRegex(...allowedHosts.map((host) => `${host}/*`));
var topicRegex = patternToRegex(...allowedHosts.map((host) => `${host}/t/*`));
var writeRegex = patternToRegex(...allowedHosts.map((host) => `${host}/write/*`));
runAfterLoaded(() => {
  const url = window.location.href;
  void (async () => {
    if (commonRegex.test(url)) {
      await Promise.resolve().then(() => (init_common(), common_exports));
      await Promise.resolve().then(() => (init_home(), home_exports));
    }
    if (topicRegex.test(url)) {
      await Promise.resolve().then(() => (init_topic(), topic_exports));
    }
    if (writeRegex.test(url)) {
      await Promise.resolve().then(() => (init_write2(), write_exports));
    }
  })();
});
/*! Bundled license information:

lucide/dist/esm/createElement.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/replaceElement.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/defaultAttributes.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/book-open-check.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/chevron-down.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/chevrons-up.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/eye-off.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/heart.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/house.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/message-square-plus.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/message-square.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/moon.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/package-plus.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/panel-right.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/panel-top.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/smile.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/square-arrow-up-right.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/star.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/sun.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/icons/twitter.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)

lucide/dist/esm/lucide.js:
  (**
   * @license lucide v0.445.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)
*/