// ==UserScript== // @name V2EX Plus - plus // @namespace https://v2ex.com/ // @version 3.5.1 // @description V2EX Plus userscript port of plus.js // @match https://v2ex.com/* // @match https://*.v2ex.com/* // @run-at document-start // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @icon https://v2ex.com/static/apple-touch-icon-180.png // @require https://code.jquery.com/jquery-3.7.1.min.js // @connect * // @updateURL https://raw.githubusercontent.com/thinktip/V2ex-Polish-Plus/main/v2ex.polish.plus.user.js // @downloadURL https://raw.githubusercontent.com/thinktip/V2ex-Polish-Plus/main/v2ex.polish.plus.user.js // ==/UserScript== (function () { if (typeof window.chrome !== "object") { window.chrome = {}; } if (typeof window.chrome.extension === "undefined") { window.chrome.extension = {}; } const runtimeState = { lastError: null, }; function normalizeStorageKeys(keys) { if (keys == null) return []; if (Array.isArray(keys)) return keys; if (typeof keys === "string") return [keys]; if (typeof keys === "object") return Object.keys(keys); return []; } function readStoredValues(keys) { const data = {}; for (const key of keys) { data[key] = GM_getValue(key); } return data; } function v2pGMRequest(details) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ timeout: 30000, ...details, onload: (response) => resolve(response), onerror: (error) => reject(error), ontimeout: () => reject(new Error("Request timed out")), }); }); } class WebDAV { constructor(serverUrl, username, password) { this.serverUrl = serverUrl.endsWith("/") ? serverUrl : `${serverUrl}/`; this.username = username; this.password = password; this.authHeader = `Basic ${btoa(`${username}:${password}`)}`; } async test() { const response = await v2pGMRequest({ method: "PROPFIND", url: this.serverUrl, headers: { Authorization: this.authHeader, Depth: "0", }, }); return response.status >= 200 && response.status < 300; } async get(filename) { const response = await v2pGMRequest({ method: "GET", url: this.serverUrl + filename, headers: { Authorization: this.authHeader, }, }); if (response.status === 404) { return null; } if (response.status < 200 || response.status >= 300) { throw new Error("WebDAV GET failed"); } return response.responseText ? JSON.parse(response.responseText) : null; } async put(filename, data) { const response = await v2pGMRequest({ method: "PUT", url: this.serverUrl + filename, headers: { Authorization: this.authHeader, "Content-Type": "application/json", }, data: JSON.stringify(data), }); if (response.status < 200 || response.status >= 300) { throw new Error("WebDAV PUT failed"); } return true; } } window.chrome.storage = window.chrome.storage || {}; window.chrome.storage.local = window.chrome.storage.local || { get(keys, callback) { callback(readStoredValues(normalizeStorageKeys(keys))); }, set(items, callback) { for (const [key, value] of Object.entries(items || {})) { GM_setValue(key, value); } if (typeof callback === "function") { callback(); } }, }; window.chrome.runtime = window.chrome.runtime || {}; Object.defineProperty(window.chrome.runtime, "lastError", { configurable: true, enumerable: true, get() { return runtimeState.lastError; }, }); window.chrome.runtime.sendMessage = window.chrome.runtime.sendMessage || function sendMessage(message, callback) { const done = (payload, error) => { runtimeState.lastError = error ? { message: error.message || String(error) } : null; if (typeof callback === "function") { callback(payload); } runtimeState.lastError = null; }; (async () => { try { if (!message || typeof message !== "object") { throw new Error("Invalid runtime message"); } if (message.type === "v2p_sync_test") { const client = new WebDAV( message.config.url, message.config.user, message.config.password, ); done({ ok: await client.test() }); return; } if (message.type === "v2p_sync_push") { const client = new WebDAV( message.config.url, message.config.user, message.config.password, ); await client.put(message.filename, message.data); done({ ok: true }); return; } if (message.type === "v2p_sync_pull") { const client = new WebDAV( message.config.url, message.config.user, message.config.password, ); const data = await client.get(message.filename); done({ ok: true, data }); return; } done({ ok: false, error: `Unsupported runtime message: ${message.type}`, }); } catch (error) { done({ ok: false, error: error.message || String(error) }, error); } })(); }; })(); (function () { /* WebDAV class removed from content script as it is now in background.js */ /** * Sync Manager */ const V2PSyncManager = { STORAGE_KEY: "v2p_webdav_config", SYNC_FILENAME: "v2p_sync_v1.json", async getConfig() { return new Promise((resolve) => { chrome.storage.local.get([this.STORAGE_KEY], (res) => resolve(res[this.STORAGE_KEY] || null), ); }); }, async saveConfig(config) { return new Promise((resolve) => { chrome.storage.local.set({ [this.STORAGE_KEY]: config }, resolve); }); }, async getClient() { const config = await this.getConfig(); if (config && config.url && config.user && config.password) { return new WebDAV(config.url, config.user, config.password); } return null; }, /** * Collect local data to sync */ getLocalData() { const navConfig = null; // Will be handled by chrome.storage logic const themeMode = localStorage.getItem("user_preferred_theme_mode"); const sidebarOrder = localStorage.getItem("v2p_sidebar_order"); const navCollapsed = localStorage.getItem("v2p_nav_collapsed"); return { themeMode, sidebarOrder, navCollapsed, updatedAt: Date.now(), }; }, async push() { const config = await this.getConfig(); if (!config) throw new Error("未配置 WebDAV"); const localData = this.getLocalData(); const navConfig = await new Promise((r) => chrome.storage.local.get(["v2p_nav_config"], (res) => r(res["v2p_nav_config"]), ), ); localData.navConfig = navConfig; return new Promise((resolve, reject) => { chrome.runtime.sendMessage( { type: "v2p_sync_push", config, filename: this.SYNC_FILENAME, data: localData, }, (res) => { if (chrome.runtime.lastError) return reject(new Error(chrome.runtime.lastError.message)); if (res && res.ok) resolve(true); else reject(new Error((res && res.error) || "推送失败")); }, ); }); }, async pull() { const config = await this.getConfig(); if (!config) throw new Error("未配置 WebDAV"); return new Promise((resolve, reject) => { chrome.runtime.sendMessage( { type: "v2p_sync_pull", config, filename: this.SYNC_FILENAME, }, (res) => { if (chrome.runtime.lastError) return reject(new Error(chrome.runtime.lastError.message)); if (res && res.ok) { const remoteData = res.data; if (remoteData) { if (remoteData.themeMode) localStorage.setItem( "user_preferred_theme_mode", remoteData.themeMode, ); if (remoteData.sidebarOrder) localStorage.setItem( "v2p_sidebar_order", remoteData.sidebarOrder, ); if (remoteData.navCollapsed) localStorage.setItem( "v2p_nav_collapsed", remoteData.navCollapsed, ); if (remoteData.navConfig) { chrome.storage.local.set({ v2p_nav_config: remoteData.navConfig, }); } resolve(true); } else { reject(new Error("云端文件为空")); } } else { reject(new Error((res && res.error) || "拉取失败")); } }, ); }); }, async testConnection(config) { return new Promise((resolve, reject) => { chrome.runtime.sendMessage({ type: "v2p_sync_test", config }, (res) => { if (chrome.runtime.lastError) return reject(new Error(chrome.runtime.lastError.message)); if (res && res.ok) resolve(true); else reject(new Error((res && res.error) || "连接失败")); }); }); }, }; window.V2PSyncManager = V2PSyncManager; const v2pShowToast = (message, duration = 3000) => { const existing = document.querySelector(".v2p-toast"); if (existing) existing.remove(); const toast = document.createElement("div"); toast.className = "v2p-toast"; toast.textContent = message; const append = () => { document.body.appendChild(toast); if (duration !== 0) { setTimeout(() => toast.remove(), duration); } }; if (document.body) { append(); } else { const wait = () => { if (document.body) return append(); requestAnimationFrame(wait); }; wait(); } }; window.v2pShowToast = v2pShowToast; // 前台自动签到 const CHECKIN_DATE_KEY = "v2p_checkin_date"; const CHECKIN_USER_KEY = "v2p_checkin_user"; let checking = false; const getUserName = () => { const link = document.querySelector('#Top .tools a[href^="/member/"]'); return link ? link.textContent.trim() : null; }; const alreadyCheckedToday = (username) => { if (!username) return false; const today = new Date().toISOString().split("T")[0]; return ( localStorage.getItem(CHECKIN_DATE_KEY) === today && localStorage.getItem(CHECKIN_USER_KEY) === username ); }; const markCheckedToday = (username) => { const today = new Date().toISOString().split("T")[0]; localStorage.setItem(CHECKIN_DATE_KEY, today); localStorage.setItem(CHECKIN_USER_KEY, username || ""); }; const extractRedeemUrl = (html) => { const doc = new DOMParser().parseFromString(html, "text/html"); const btn = doc.querySelector('input[value^="领取"]'); if (btn) { const onclick = btn.getAttribute("onclick") || ""; const match = onclick.match(/'(\/mission\/daily\/redeem\?once=\d+)'/); if (match && match[1]) return match[1]; } const match = html.match(/\/mission\/daily\/redeem\?once=\d+/); return match ? match[0] : null; }; const parseDays = (html) => { const match = html.match(/已连续登[^0-9]*?(\d+)\s*天/); return match ? match[1] : null; }; const parseCoins = (html) => { const match = html.match(/每日登录奖励\s*(\d+)\s*铜币/); return match ? match[1] : null; }; const runCheckin = async () => { if (checking) return; const username = getUserName(); if (!username) return; if (alreadyCheckedToday(username)) return; checking = true; try { const dailyHtml = await fetch("/mission/daily", { credentials: "include", }).then((r) => r.text()); if (!dailyHtml.includes("/signout")) { checking = false; return; } if ( dailyHtml.includes("每日登录奖励已领取") || dailyHtml.includes("已领取") ) { markCheckedToday(username); checking = false; return; } const redeemUrl = extractRedeemUrl(dailyHtml); if (!redeemUrl) { checking = false; return; } const redeemHtml = await fetch(redeemUrl, { credentials: "include", }).then((r) => r.text()); const days = parseDays(redeemHtml); markCheckedToday(username); let message = "签到成功 · 今日登录奖励已领取"; try { const balanceHtml = await fetch("/balance", { credentials: "include", }).then((r) => r.text()); const coins = parseCoins(balanceHtml); if (days && coins) message = `连续签到 ${days} 天,本次 ${coins} 铜币`; else if (coins) message = `签到成功 · 本次 ${coins} 铜币`; } catch (e) {} v2pShowToast(message); } catch (e) { console.log("V2P: Front-end checkin error", e); } finally { checking = false; } }; const scheduleCheckin = () => { let retries = 0; const tryRun = () => { if (getUserName()) { runCheckin(); return; } retries += 1; if (retries < 10) setTimeout(tryRun, 300); }; tryRun(); }; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", scheduleCheckin); } else { scheduleCheckin(); } ("use strict"); // 想要的头像尺寸上限,自己改,比如 48 / 64 / 96 都行 const MAX_GRAVATAR_SIZE = 64; const clamp = (n, min, max) => Math.max(min, Math.min(max, n)); function getDesiredAvatarSize(img) { const dpr = window.devicePixelRatio || 1; const w = img.clientWidth || 0; const h = img.clientHeight || 0; const base = Math.max(w, h); if (base > 0) { return clamp(Math.ceil(base * dpr), 32, MAX_GRAVATAR_SIZE); } return MAX_GRAVATAR_SIZE; } function upgradeAvatar(img) { // 1. 基础检查:必须是图片元素且有 src if (!img || !img.src) return; // 2. 防重复处理检查 if (img.dataset.v2pProcessed) return; // 3. 快速字符串检查,避免不必要的 URL 对象创建 // V2EX 头像通常包含 /avatar/ 或 /gravatar/ const src = img.src; if (!src.includes("/avatar/") && !src.includes("/gravatar/")) { return; } // 标记为已处理,避免重复计算 img.dataset.v2pProcessed = "true"; let url; try { url = new URL(src, location.href); } catch (e) { return; } const pathname = url.pathname; const hostname = url.hostname; // 4. 处理逻辑 // Case A: /avatar/ 路径且带 _normal 的图片 -> 视显示尺寸决定是否升级 if (pathname.includes("/avatar/") && pathname.includes("_normal")) { const desired = getDesiredAvatarSize(img); if (desired >= 48) { // 使用字符串替换比正则稍快,且对于这种固定格式足够安全 img.src = src.replace("_normal", "_large"); } return; } // Case B: V2EX 的 gravatar 头像:通过 s=xx 控制尺寸 if (hostname.endsWith("v2ex.com") && pathname.includes("/gravatar/")) { const params = url.searchParams; const s = params.get("s"); if (s) { const curSize = parseInt(s, 10); const desired = getDesiredAvatarSize(img); if (!Number.isNaN(curSize) && curSize < desired) { params.set("s", String(desired)); img.src = url.toString(); } } } } function scanAll() { document.querySelectorAll("img.avatar").forEach(scheduleUpgrade); } const idle = window.requestIdleCallback || function (cb) { return setTimeout(cb, 16); }; const io = "IntersectionObserver" in window ? new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { io.unobserve(entry.target); idle(() => upgradeAvatar(entry.target)); } }); }) : null; function scheduleUpgrade(img) { if (io) { io.observe(img); } else { idle(() => upgradeAvatar(img)); } } // 首次扫描 scanAll(); // 监听后续动态加载的头像(比如 PJAX / AJAX) const observer = new MutationObserver((mutations) => { for (const m of mutations) { if (m.addedNodes.length === 0) continue; for (const node of m.addedNodes) { if (node.nodeType !== 1) continue; // 只处理元素节点 // 检查节点本身 if (node.tagName === "IMG" && node.classList.contains("avatar")) { scheduleUpgrade(node); } // 检查子节点 (如果插入的是一个容器) if (node.querySelectorAll) { // 使用更具体的选择器,减少遍历范围 const avatars = node.querySelectorAll("img.avatar"); if (avatars.length > 0) { avatars.forEach(scheduleUpgrade); } } } } }); observer.observe(document.documentElement, { childList: true, subtree: true, }); })(); ("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: "off", 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 = ` `; iconGitHub = ` `; }, }); // 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() { return false; } function escapeHTML(htmlString) { return htmlString.replace(/[<>&"'']/g, (match) => { switch (match) { case "<": return "<"; case ">": return ">"; case "&": return "&"; case '"': return """; case "'": return "'"; 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); } }); } 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 "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)"); if ($topicContentBox.length === 0) { // 移动端 / 特殊布局兜底:不依赖 #Main $topicContentBox = $(".box:has(.topic_buttons)"); } $topicHeader = $topicContentBox.find(".header"); // 评论列表区域 $commentBox = $('#Main .box:has(.cell[id^="r_"])'); if ($commentBox.length === 0) { // 移动端兜底:不依赖 #Main $commentBox = $('.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; } 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/icons/image.js var Image; var init_image = __esm({ "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/image.js"() { "use strict"; init_defaultAttributes(); Image = [ "svg", defaultAttributes, [ [ "rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }, ], ["circle", { cx: "8.5", cy: "8.5", r: "1.5" }], ["polyline", { points: "21 15 16 10 5 21" }], ], ]; }, }); // node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/file-text.js var FileText; var init_file_text = __esm({ "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/file-text.js"() { "use strict"; init_defaultAttributes(); FileText = [ "svg", defaultAttributes, [ [ "path", { d: "M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z", }, ], ["polyline", { points: "14 2 14 8 20 8" }], ["line", { x1: "16", x2: "8", y1: "13", y2: "13" }], ["line", { x1: "16", x2: "8", y1: "17", y2: "17" }], ["line", { x1: "10", x2: "8", y1: "9", y2: "9" }], ], ]; }, }); // node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/globe.js var Globe; var init_globe = __esm({ "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/globe.js"() { "use strict"; init_defaultAttributes(); Globe = [ "svg", defaultAttributes, [ ["circle", { cx: "12", cy: "12", r: "10" }], ["line", { x1: "2", x2: "22", y1: "12", y2: "12" }], [ "path", { d: "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z", }, ], ], ]; }, }); // node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/clock.js var Clock; var init_clock = __esm({ "node_modules/.pnpm/lucide@0.445.0/node_modules/lucide/dist/esm/icons/clock.js"() { "use strict"; init_defaultAttributes(); Clock = [ "svg", defaultAttributes, [ ["circle", { cx: "12", cy: "12", r: "10" }], ["polyline", { points: "12 6 12 12 16 14" }], ], ]; }, }); // 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(); init_image(); init_file_text(); init_globe(); init_clock(); 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) { 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 = $(`