高亮关键词,可设置关键词的样式,支持正则匹配
// ==UserScript== // @name highlight-keywords // @namespace https://github.com/mudssky/highlight-keywords // @version 3.2.2 // @author mudssky // @description 高亮关键词,可设置关键词的样式,支持正则匹配 // @license MIT // @icon https://vitejs.dev/logo.svg // @homepage https://github.com/mudssky/highlight-keywords // @homepageURL https://github.com/mudssky/highlight-keywords // @supportURL https://github.com/mudssky/highlight-keywords/issues // @match *://*/* // @exclude *://element-plus* // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js // @require data:application/javascript,%3Bwindow.Vue%3DVue%3B // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/index.full.min.js // @resource element-plus/dist/index.css https://cdn.jsdelivr.net/npm/[email protected]/dist/index.css // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_getValue // @grant GM_info // @grant GM_registerMenuCommand // @grant GM_setClipboard // @grant GM_setValue // @run-at document-end // ==/UserScript== (function (vue, ElementPlus) { 'use strict'; const d=new Set;const importCSS = async e=>{d.has(e)||(d.add(e),(t=>{typeof GM_addStyle=="function"?GM_addStyle(t):(document.head||document.documentElement).appendChild(document.createElement("style")).append(t);})(e));}; importCSS(" .config-dialog[data-v-3c39e8f9] .el-dialog{border-radius:12px}.config-dialog[data-v-3c39e8f9] .el-dialog__header{background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;border-radius:12px 12px 0 0;padding:20px}.config-dialog[data-v-3c39e8f9] .el-dialog__title{color:#fff;font-weight:600}.config-dialog[data-v-3c39e8f9] .el-dialog__body{padding:24px}.preview-highlight[data-v-3c39e8f9],.preview-active[data-v-3c39e8f9]{display:inline-block;min-width:80px;text-align:center;border:1px solid #ddd}.debug-dialog[data-v-b2ed8f72] .el-dialog{border-radius:12px}.debug-dialog[data-v-b2ed8f72] .el-dialog__header{background:linear-gradient(135deg,#8b5cf6,#7c3aed);color:#fff;border-radius:12px 12px 0 0;padding:20px}.debug-dialog[data-v-b2ed8f72] .el-dialog__title{color:#fff;font-weight:600}.debug-dialog[data-v-b2ed8f72] .el-dialog__body{padding:24px;max-height:600px;overflow-y:auto}.debug-section[data-v-b2ed8f72]{display:flex;flex-direction:column;gap:1rem}.debug-section h4[data-v-b2ed8f72]{font-size:1.125rem;font-weight:600;color:#1f2937;border-bottom:1px solid #e5e7eb;padding-bottom:.5rem;margin-bottom:.75rem}.debug-grid[data-v-b2ed8f72]{display:grid;grid-template-columns:1fr;gap:.75rem}@media(min-width:768px){.debug-grid[data-v-b2ed8f72]{grid-template-columns:1fr 1fr}}.debug-item[data-v-b2ed8f72]{display:flex;flex-direction:column;gap:.25rem;padding:.75rem;background-color:#f9fafb;border-radius:.5rem}.debug-item .label[data-v-b2ed8f72]{font-size:.875rem;font-weight:500;color:#4b5563}.debug-item .value[data-v-b2ed8f72]{font-size:.875rem;color:#111827;font-family:monospace;word-break:break-all}.debug-list[data-v-b2ed8f72]{display:flex;flex-direction:column;gap:.5rem;max-height:15rem;overflow-y:auto}.debug-rule[data-v-b2ed8f72]{padding:.75rem;background-color:#f9fafb;border-radius:.5rem;border-left:4px solid #d1d5db}.debug-rule.matched[data-v-b2ed8f72]{background-color:#f0fdf4;border-left-color:#4ade80}.rule-header[data-v-b2ed8f72]{display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}.rule-index[data-v-b2ed8f72]{font-size:.75rem;font-weight:700;color:#6b7280;background-color:#e5e7eb;padding:.25rem .5rem;border-radius:.25rem}.rule-url[data-v-b2ed8f72]{font-size:.875rem;font-family:monospace;color:#2563eb}.rule-keywords[data-v-b2ed8f72]{display:flex;flex-wrap:wrap;gap:.25rem}.keyword-tag[data-v-b2ed8f72]{font-size:.75rem;background-color:#dbeafe;color:#1e40af;padding:.25rem .5rem;border-radius:9999px}.keyword-tag.active[data-v-b2ed8f72]{background-color:#dcfce7;color:#166534}.keyword-list[data-v-b2ed8f72]{display:flex;flex-wrap:wrap;gap:.5rem}.log-header[data-v-b2ed8f72]{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem}.log-actions[data-v-b2ed8f72]{display:flex;gap:.5rem}.log-container[data-v-b2ed8f72]{background-color:#111827;border-radius:.5rem;padding:1rem;max-height:20rem;overflow-y:auto}.no-logs[data-v-b2ed8f72]{color:#9ca3af;text-align:center;padding:2rem 0}.log-list[data-v-b2ed8f72]{display:flex;flex-direction:column;gap:.25rem;font-family:monospace;font-size:.875rem}.log-item[data-v-b2ed8f72]{display:flex;gap:.75rem;padding:.25rem 0}.log-time[data-v-b2ed8f72]{color:#9ca3af;font-size:.75rem;min-width:80px}.log-level[data-v-b2ed8f72]{font-size:.75rem;font-weight:700;min-width:50px}.log-message[data-v-b2ed8f72]{flex:1;word-break:break-all}.log-info .log-level[data-v-b2ed8f72]{color:#60a5fa}.log-info .log-message[data-v-b2ed8f72]{color:#d1d5db}.log-warn .log-level[data-v-b2ed8f72]{color:#fbbf24}.log-warn .log-message[data-v-b2ed8f72]{color:#fde047}.log-error .log-level[data-v-b2ed8f72]{color:#f87171}.log-error .log-message[data-v-b2ed8f72]{color:#fca5a5}.dialog-footer button[data-v-e0b7c8bd]:first-child{margin-right:10px}.debug-section[data-v-e0b7c8bd]{margin-bottom:20px;padding:15px;border:1px solid #e0e0e0;border-radius:8px;background-color:#fafafa}.debug-section h4[data-v-e0b7c8bd]{margin:0 0 15px;color:#333;font-size:16px;font-weight:600}.logs-container[data-v-e0b7c8bd]{max-height:400px;overflow-y:auto;background:#f8f9fa;border:1px solid #dee2e6;border-radius:4px;padding:10px}.log-item[data-v-e0b7c8bd]{display:flex;align-items:center;padding:4px 8px;margin-bottom:2px;border-radius:3px;font-family:Courier New,monospace;font-size:12px}.log-time[data-v-e0b7c8bd]{color:#6c757d;margin-right:8px;min-width:80px}.log-level[data-v-e0b7c8bd]{margin-right:8px;padding:2px 6px;border-radius:3px;font-weight:700;min-width:50px;text-align:center}.log-message[data-v-e0b7c8bd]{flex:1}.log-info[data-v-e0b7c8bd]{background-color:#d1ecf1;border-left:3px solid #17a2b8}.log-info .log-level[data-v-e0b7c8bd]{background-color:#17a2b8;color:#fff}.log-warn[data-v-e0b7c8bd]{background-color:#fff3cd;border-left:3px solid #ffc107}.log-warn .log-level[data-v-e0b7c8bd]{background-color:#ffc107;color:#212529}.log-error[data-v-e0b7c8bd]{background-color:#f8d7da;border-left:3px solid #dc3545}.log-error .log-level[data-v-e0b7c8bd]{background-color:#dc3545;color:#fff}.keywords-display[data-v-e0b7c8bd]{max-height:200px;overflow-y:auto;padding:10px;background:#f8f9fa;border:1px solid #dee2e6;border-radius:4px} "); var zhCn = { name: "zh-cn", el: { breadcrumb: { label: "面包屑" }, colorpicker: { confirm: "确定", clear: "清空", defaultLabel: "颜色选择器", description: "当前颜色 {color},按 Enter 键选择新颜色", alphaLabel: "选择透明度的值", alphaDescription: "透明度 {alpha}, 当前颜色 {color}", hueLabel: "选择色相值", hueDescription: "色相 {hue}, 当前颜色 {color}", svLabel: "选择饱和度与明度的值", svDescription: "饱和度 {saturation}, 明度 {brightness}, 当前颜色 {color}", predefineDescription: "选择 {value} 作为颜色" }, datepicker: { now: "此刻", today: "今天", cancel: "取消", clear: "清空", confirm: "确定", dateTablePrompt: "使用方向键与 Enter 键可选择日期", monthTablePrompt: "使用方向键与 Enter 键可选择月份", yearTablePrompt: "使用方向键与 Enter 键可选择年份", selectedDate: "已选日期", selectDate: "选择日期", selectTime: "选择时间", startDate: "开始日期", startTime: "开始时间", endDate: "结束日期", endTime: "结束时间", prevYear: "前一年", nextYear: "后一年", prevMonth: "上个月", nextMonth: "下个月", year: "年", month1: "1 月", month2: "2 月", month3: "3 月", month4: "4 月", month5: "5 月", month6: "6 月", month7: "7 月", month8: "8 月", month9: "9 月", month10: "10 月", month11: "11 月", month12: "12 月", weeks: { sun: "日", mon: "一", tue: "二", wed: "三", thu: "四", fri: "五", sat: "六" }, weeksFull: { sun: "星期日", mon: "星期一", tue: "星期二", wed: "星期三", thu: "星期四", fri: "星期五", sat: "星期六" }, months: { jan: "一月", feb: "二月", mar: "三月", apr: "四月", may: "五月", jun: "六月", jul: "七月", aug: "八月", sep: "九月", oct: "十月", nov: "十一月", dec: "十二月" } }, inputNumber: { decrease: "减少数值", increase: "增加数值" }, select: { loading: "加载中", noMatch: "无匹配数据", noData: "无数据", placeholder: "请选择" }, mention: { loading: "加载中" }, dropdown: { toggleDropdown: "切换下拉选项" }, cascader: { noMatch: "无匹配数据", loading: "加载中", placeholder: "请选择", noData: "暂无数据" }, pagination: { goto: "前往", pagesize: "条/页", total: "共 {total} 条", pageClassifier: "页", page: "页", prev: "上一页", next: "下一页", currentPage: "第 {pager} 页", prevPages: "向前 {pager} 页", nextPages: "向后 {pager} 页", deprecationWarning: "你使用了一些已被废弃的用法,请参考 el-pagination 的官方文档" }, dialog: { close: "关闭此对话框" }, drawer: { close: "关闭此对话框" }, messagebox: { title: "提示", confirm: "确定", cancel: "取消", error: "输入的数据不合法!", close: "关闭此对话框" }, upload: { deleteTip: "按 Delete 键可删除", delete: "删除", preview: "查看图片", continue: "继续上传" }, slider: { defaultLabel: "滑块介于 {min} 至 {max}", defaultRangeStartLabel: "选择起始值", defaultRangeEndLabel: "选择结束值" }, table: { emptyText: "暂无数据", confirmFilter: "筛选", resetFilter: "重置", clearFilter: "全部", sumText: "合计" }, tour: { next: "下一步", previous: "上一步", finish: "结束导览", close: "关闭此对话框" }, tree: { emptyText: "暂无数据" }, transfer: { noMatch: "无匹配数据", noData: "无数据", titles: ["列表 1", "列表 2"], filterPlaceholder: "请输入搜索内容", noCheckedFormat: "共 {total} 项", hasCheckedFormat: "已选 {checked}/{total} 项" }, image: { error: "加载失败" }, pageHeader: { title: "返回" }, popconfirm: { confirmButtonText: "确定", cancelButtonText: "取消" }, carousel: { leftArrow: "上一张幻灯片", rightArrow: "下一张幻灯片", indicator: "幻灯片切换至索引 {index}" } } }; const _hoisted_1$4 = ["title"]; const _hoisted_2$3 = ["title"]; const _sfc_main$5 = vue.defineComponent({ __name: "TriggerButtons", props: { isDarkMode: { type: Boolean }, panelPinned: { type: Boolean }, isDebugMode: { type: Boolean }, dynamicColors: {} }, emits: ["toggleDarkMode", "togglePanelPin", "toggleDebugDialog", "closePanel"], setup(__props, { emit: __emit }) { const emit = __emit; function onToggleDarkMode() { emit("toggleDarkMode"); } function onTogglePanelPin() { emit("togglePanelPin"); } function onToggleDebugDialog() { emit("toggleDebugDialog"); } function onClosePanel() { emit("closePanel"); } return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", { class: vue.normalizeClass(["panel-trigger w-[50px] h-[140px] flex flex-col items-center justify-center cursor-pointer rounded-l-xl backdrop-blur-[10px] gap-1.5", __props.dynamicColors.triggerBg]) }, [ vue.createElementVNode("div", { onClick: onToggleDarkMode, class: vue.normalizeClass(["p-1.5 rounded-md transition-all duration-200 ease-in-out cursor-pointer hover:scale-110", __props.isDarkMode ? "bg-yellow-500/30" : "bg-slate-600/20"]), title: __props.isDarkMode ? "切换到日间模式" : "切换到夜间模式" }, vue.toDisplayString(__props.isDarkMode ? "☀️" : "🌙"), 11, _hoisted_1$4), vue.createElementVNode("div", { onClick: onTogglePanelPin, class: vue.normalizeClass(["p-1.5 rounded-md transition-all duration-200 ease-in-out cursor-pointer hover:scale-110", __props.panelPinned ? "bg-blue-500/30" : "bg-white/10"]), title: __props.panelPinned ? "取消固定" : "固定面板" }, vue.toDisplayString(__props.panelPinned ? "📌" : "📍"), 11, _hoisted_2$3), __props.isDebugMode ? (vue.openBlock(), vue.createElementBlock("div", { key: 0, onClick: onToggleDebugDialog, class: "p-1.5 rounded-md bg-purple-500/20 transition-all duration-200 ease-in-out cursor-pointer hover:scale-110", title: "调试信息" }, " 🐛 ")) : vue.createCommentVNode("", true), vue.createElementVNode("div", { onClick: onClosePanel, class: "p-1.5 rounded-md bg-red-500/20 transition-all duration-200 ease-in-out cursor-pointer hover:scale-110", title: "关闭面板(1小时)" }, " ✕ ") ], 2); }; } }); const _hoisted_1$3 = { key: 0 }; const _hoisted_2$2 = { class: "space-y-2" }; const _hoisted_3$2 = { class: "flex gap-2" }; const _hoisted_4$2 = ["disabled"]; const _hoisted_5$1 = ["disabled"]; const _hoisted_6$1 = ["disabled"]; const _sfc_main$4 = vue.defineComponent({ __name: "NavigationPanel", props: { panelExpanded: { type: Boolean }, highlightState: {}, matchedKeywords: {}, dynamicColors: {} }, emits: ["previous", "next", "enableHighlight", "clearHighlight", "openConfig"], setup(__props) { return (_ctx, _cache) => { return __props.panelExpanded ? (vue.openBlock(), vue.createElementBlock("div", { key: 0, class: vue.normalizeClass(["panel-content w-[260px] p-4 backdrop-blur-[10px] rounded-r-xl", __props.dynamicColors.contentBg]) }, [ vue.createElementVNode("div", { class: vue.normalizeClass(["mb-4 p-3 rounded-lg", [__props.dynamicColors.infoBg, __props.dynamicColors.borderColor]]) }, [ vue.createElementVNode("div", { class: vue.normalizeClass(["text-sm font-medium mb-2", __props.dynamicColors.textPrimary]) }, " 匹配信息 ", 2), vue.createElementVNode("div", { class: vue.normalizeClass(["text-xs space-y-1", __props.dynamicColors.textSecondary]) }, [ vue.createElementVNode("div", null, "关键词: " + vue.toDisplayString(__props.matchedKeywords.length) + " 个", 1), vue.createElementVNode("div", null, "高亮: " + vue.toDisplayString(__props.highlightState.totalCount) + " 处", 1), __props.highlightState.totalCount > 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, " 当前: " + vue.toDisplayString(__props.highlightState.currentIndex + 1) + " / " + vue.toDisplayString(__props.highlightState.totalCount), 1)) : vue.createCommentVNode("", true) ], 2) ], 2), vue.createElementVNode("div", _hoisted_2$2, [ vue.createElementVNode("div", _hoisted_3$2, [ vue.createElementVNode("button", { onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("previous")), disabled: __props.highlightState.totalCount === 0, class: "flex-1 px-3 py-2 text-xs font-medium text-white rounded-lg transition-all duration-200 ease-in-out disabled:opacity-50 disabled:cursor-not-allowed hover:scale-105 active:scale-95", style: vue.normalizeStyle({ background: __props.dynamicColors.buttonPrimary }) }, " ⬆️ 上一个 ", 12, _hoisted_4$2), vue.createElementVNode("button", { onClick: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("next")), disabled: __props.highlightState.totalCount === 0, class: "flex-1 px-3 py-2 text-xs font-medium text-white rounded-lg transition-all duration-200 ease-in-out disabled:opacity-50 disabled:cursor-not-allowed hover:scale-105 active:scale-95", style: vue.normalizeStyle({ background: __props.dynamicColors.buttonPrimary }) }, " ⬇️ 下一个 ", 12, _hoisted_5$1) ]), vue.createElementVNode("button", { onClick: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("enableHighlight")), class: "w-full px-3 py-2 text-xs font-medium text-white rounded-lg transition-all duration-200 ease-in-out hover:scale-105 active:scale-95", style: vue.normalizeStyle({ background: __props.dynamicColors.buttonSuccess }) }, " 🔍 启用高亮 ", 4), vue.createElementVNode("button", { onClick: _cache[3] || (_cache[3] = ($event) => _ctx.$emit("clearHighlight")), disabled: __props.highlightState.totalCount === 0, class: "w-full px-3 py-2 text-xs font-medium text-white rounded-lg transition-all duration-200 ease-in-out disabled:opacity-50 disabled:cursor-not-allowed hover:scale-105 active:scale-95", style: vue.normalizeStyle({ background: __props.dynamicColors.buttonDanger }) }, " 🧹 清除高亮 ", 12, _hoisted_6$1), vue.createElementVNode("button", { onClick: _cache[4] || (_cache[4] = ($event) => _ctx.$emit("openConfig")), class: "w-full px-3 py-2 text-xs font-medium text-white rounded-lg transition-all duration-200 ease-in-out hover:scale-105 active:scale-95", style: vue.normalizeStyle({ background: __props.dynamicColors.buttonSecondary }) }, " ⚙️ 配置 ", 4) ]) ], 2)) : vue.createCommentVNode("", true); }; } }); const CONFIG_NAME = "hightlight-config"; const themePresets = { default: { highlight: "background: yellow; color: black;", active: "background: orange; color: white; outline: 2px solid #ff5722;" }, dark: { highlight: "background: #333; color: #fff; border: 1px solid #666;", active: "background: #555; color: #fff; outline: 2px solid #00bcd4;" }, modern: { highlight: "background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 3px; padding: 1px 3px;", active: "background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; border-radius: 3px; padding: 1px 3px; box-shadow: 0 2px 4px rgba(0,0,0,0.3);" }, minimal: { highlight: "background: #e3f2fd; color: #1976d2; border-bottom: 2px solid #2196f3;", active: "background: #ffecb3; color: #f57c00; border-bottom: 2px solid #ff9800; font-weight: bold;" } }; const defaultFormData = { configJson: "", defaultHightlightStyle: "background:gold;color:black;", highlightStyle: "background:gold;color:black;", activeStyle: "background: orange; color: white; outline: 2px solid #ff5722;", selectedTheme: "default", placeholder: `//示例: [ { "keywords": ["成年コミック"], "matchUrl": "sukebei.nyaa.si", }, ] ` }; const generateDynamicColors = (isDarkMode) => { if (isDarkMode) { return { panelBg: "linear-gradient(135deg, rgba(15, 23, 42, 0.95), rgba(30, 41, 59, 0.98))", triggerBg: "bg-slate-700/30", contentBg: "bg-slate-800/20", infoBg: "bg-slate-700/30", borderColor: "border-slate-600/30", textPrimary: "text-slate-100", textSecondary: "text-slate-300", textMuted: "text-slate-400", buttonPrimary: "linear-gradient(135deg, #3b82f6, #1d4ed8)", buttonSecondary: "linear-gradient(135deg, #6366f1, #4338ca)", buttonDanger: "linear-gradient(135deg, #ef4444, #dc2626)", buttonSuccess: "linear-gradient(135deg, #10b981, #059669)" }; } else { return { panelBg: "linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 250, 252, 0.98))", triggerBg: "bg-white/40", contentBg: "bg-white/20", infoBg: "bg-blue-50/50", borderColor: "border-gray-200/50", textPrimary: "text-gray-800", textSecondary: "text-gray-600", textMuted: "text-gray-500", buttonPrimary: "linear-gradient(135deg, #3b82f6, #2563eb)", buttonSecondary: "linear-gradient(135deg, #8b5cf6, #7c3aed)", buttonDanger: "linear-gradient(135deg, #f59e0b, #d97706)", buttonSuccess: "linear-gradient(135deg, #10b981, #059669)" }; } }; function validateConfig(configList) { const res = [false, "配置项格式不对"]; if (!Array.isArray(configList)) { return res; } if (configList.some((item) => { return typeof item !== "object"; })) { return res; } for (const property of ["keywords", "matchUrl"]) { if (configList.some((item) => { return !(item?.[property] ?? false); })) { res[1] = `${property} 属性是必须的`; return res; } } for (const item of configList) { if (typeof item.matchUrl !== "string") { res[1] = "matchUrl类型错误"; return res; } if (!Array.isArray(item.keywords)) { res[1] = "keywords类型错误"; return res; } for (const keyword of item.keywords) { if (typeof keyword !== "string") { res[1] = "keywords类型错误"; return res; } if (keyword.trim() === "") { console.log("空字符串"); res[1] = "keywords不能为空"; return res; } } } return [true, res[1]]; } const _hoisted_1$2 = { class: "flex gap-4 items-center" }; const _hoisted_2$1 = { class: "flex justify-between" }; const _hoisted_3$1 = { class: "space-x-2" }; const _hoisted_4$1 = { class: "space-x-2" }; const _sfc_main$3 = vue.defineComponent({ __name: "ConfigDialog", props: { visible: { type: Boolean }, form: {} }, emits: ["update:visible", "close", "themeChange", "copyJson", "previewStyle", "updateConfig"], setup(__props, { emit: __emit }) { const emit = __emit; function handleClose() { emit("update:visible", false); emit("close"); } function handleThemeChange(theme) { emit("themeChange", theme); } function handleCopyJson() { emit("copyJson"); } function handlePreviewStyle() { emit("previewStyle"); } function handleUpdateConfig() { emit("updateConfig"); } return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElDialog), { "model-value": __props.visible, "onUpdate:modelValue": handleClose, title: "配置面板", width: "600px", "before-close": handleClose, class: "config-dialog" }, { footer: vue.withCtx(() => [ vue.createElementVNode("div", _hoisted_2$1, [ vue.createElementVNode("div", _hoisted_3$1, [ vue.createVNode(vue.unref(ElementPlus.ElButton), { onClick: handleCopyJson, type: "info", size: "small" }, { default: vue.withCtx(() => [..._cache[4] || (_cache[4] = [ vue.createTextVNode(" 📋 复制配置 ", -1) ])]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElButton), { onClick: handlePreviewStyle, type: "warning", size: "small" }, { default: vue.withCtx(() => [..._cache[5] || (_cache[5] = [ vue.createTextVNode(" 👁️ 预览样式 ", -1) ])]), _: 1 }) ]), vue.createElementVNode("div", _hoisted_4$1, [ vue.createVNode(vue.unref(ElementPlus.ElButton), { onClick: handleClose }, { default: vue.withCtx(() => [..._cache[6] || (_cache[6] = [ vue.createTextVNode("取消", -1) ])]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElButton), { onClick: handleUpdateConfig, type: "primary" }, { default: vue.withCtx(() => [..._cache[7] || (_cache[7] = [ vue.createTextVNode(" 更新配置 ", -1) ])]), _: 1 }) ]) ]) ]), default: vue.withCtx(() => [ vue.createVNode(vue.unref(ElementPlus.ElForm), { model: __props.form, "label-width": "120px", class: "space-y-4" }, { default: vue.withCtx(() => [ vue.createVNode(vue.unref(ElementPlus.ElFormItem), { label: "高亮样式" }, { default: vue.withCtx(() => [ vue.createVNode(vue.unref(ElementPlus.ElInput), { modelValue: __props.form.highlightStyle, "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => __props.form.highlightStyle = $event), type: "textarea", rows: 2, placeholder: "例如: background: yellow; color: black;" }, null, 8, ["modelValue"]) ]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElFormItem), { label: "当前选中样式" }, { default: vue.withCtx(() => [ vue.createVNode(vue.unref(ElementPlus.ElInput), { modelValue: __props.form.activeStyle, "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => __props.form.activeStyle = $event), type: "textarea", rows: 2, placeholder: "例如: background: orange; color: white;" }, null, 8, ["modelValue"]) ]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElFormItem), { label: "样式预设" }, { default: vue.withCtx(() => [ vue.createVNode(vue.unref(ElementPlus.ElSelect), { modelValue: __props.form.selectedTheme, "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => __props.form.selectedTheme = $event), placeholder: "选择预设主题", onChange: handleThemeChange, class: "w-full" }, { default: vue.withCtx(() => [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(themePresets), (theme, key) => { return vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElOption), { key, label: key, value: key }, null, 8, ["label", "value"]); }), 128)) ]), _: 1 }, 8, ["modelValue"]) ]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElFormItem), { label: "样式预览" }, { default: vue.withCtx(() => [ vue.createElementVNode("div", _hoisted_1$2, [ vue.createElementVNode("span", { class: "preview-highlight px-2 py-1 rounded", style: vue.normalizeStyle(__props.form.highlightStyle) }, " 高亮样式 ", 4), vue.createElementVNode("span", { class: "preview-active px-2 py-1 rounded", style: vue.normalizeStyle(__props.form.activeStyle) }, " 选中样式 ", 4) ]) ]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElFormItem), { label: "关键词配置" }, { default: vue.withCtx(() => [ vue.createVNode(vue.unref(ElementPlus.ElInput), { modelValue: __props.form.configJson, "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => __props.form.configJson = $event), type: "textarea", rows: 10, placeholder: __props.form.placeholder, class: "font-mono text-sm" }, null, 8, ["modelValue", "placeholder"]) ]), _: 1 }) ]), _: 1 }, 8, ["model"]) ]), _: 1 }, 8, ["model-value"]); }; } }); const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const ConfigDialog = _export_sfc(_sfc_main$3, [["__scopeId", "data-v-3c39e8f9"]]); const _hoisted_1$1 = { class: "debug-section" }; const _hoisted_2 = { class: "debug-grid" }; const _hoisted_3 = { class: "debug-item" }; const _hoisted_4 = { class: "value" }; const _hoisted_5 = { class: "debug-item" }; const _hoisted_6 = { class: "value" }; const _hoisted_7 = { class: "debug-item" }; const _hoisted_8 = { class: "value" }; const _hoisted_9 = { class: "debug-item" }; const _hoisted_10 = { class: "value text-xs" }; const _hoisted_11 = { class: "debug-grid" }; const _hoisted_12 = { class: "debug-item" }; const _hoisted_13 = { class: "value" }; const _hoisted_14 = { class: "debug-item" }; const _hoisted_15 = { class: "value" }; const _hoisted_16 = { class: "debug-item" }; const _hoisted_17 = { class: "value" }; const _hoisted_18 = { class: "debug-section" }; const _hoisted_19 = { class: "debug-list" }; const _hoisted_20 = { class: "rule-header" }; const _hoisted_21 = { class: "rule-index" }; const _hoisted_22 = { class: "rule-url" }; const _hoisted_23 = { class: "rule-keywords" }; const _hoisted_24 = { class: "debug-list" }; const _hoisted_25 = { class: "rule-header" }; const _hoisted_26 = { class: "rule-index" }; const _hoisted_27 = { class: "rule-url" }; const _hoisted_28 = { class: "rule-keywords" }; const _hoisted_29 = { class: "keyword-list" }; const _hoisted_30 = { class: "debug-section" }; const _hoisted_31 = { class: "debug-grid" }; const _hoisted_32 = { class: "debug-item" }; const _hoisted_33 = { class: "value" }; const _hoisted_34 = { class: "debug-item" }; const _hoisted_35 = { class: "value" }; const _hoisted_36 = { class: "debug-item" }; const _hoisted_37 = { class: "value" }; const _hoisted_38 = { class: "debug-grid" }; const _hoisted_39 = { class: "debug-item" }; const _hoisted_40 = { class: "value" }; const _hoisted_41 = { class: "debug-item" }; const _hoisted_42 = { class: "value" }; const _hoisted_43 = { class: "debug-item" }; const _hoisted_44 = { class: "value" }; const _hoisted_45 = { class: "debug-item" }; const _hoisted_46 = { class: "value" }; const _hoisted_47 = { class: "debug-section" }; const _hoisted_48 = { class: "log-header" }; const _hoisted_49 = { class: "log-actions" }; const _hoisted_50 = { class: "log-container" }; const _hoisted_51 = { key: 0, class: "no-logs" }; const _hoisted_52 = { key: 1, class: "log-list" }; const _hoisted_53 = { class: "log-time" }; const _hoisted_54 = { class: "log-level" }; const _hoisted_55 = { class: "log-message" }; const _hoisted_56 = { style: { "display": "flex", "justify-content": "space-between" } }; const _sfc_main$2 = vue.defineComponent({ __name: "DebugDialog", props: { visible: { type: Boolean }, activeTab: {}, debugInfo: {}, debugLogs: {}, highlightState: {}, ruleList: {}, matchedRuleList: {}, matchedKeywords: {} }, emits: ["update:visible", "update:activeTab", "close", "refreshInfo", "clearLogs", "exportDebug"], setup(__props, { emit: __emit }) { const emit = __emit; function handleClose() { emit("update:visible", false); emit("close"); } return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElDialog), { "model-value": __props.visible, "onUpdate:modelValue": handleClose, title: "🐛 调试信息", width: "800px", "before-close": handleClose, class: "debug-dialog" }, { footer: vue.withCtx(() => [ vue.createElementVNode("div", _hoisted_56, [ vue.createVNode(vue.unref(ElementPlus.ElButton), { onClick: _cache[3] || (_cache[3] = ($event) => _ctx.$emit("refreshInfo")), type: "info" }, { default: vue.withCtx(() => [..._cache[24] || (_cache[24] = [ vue.createTextVNode(" 🔄 刷新信息 ", -1) ])]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElButton), { onClick: handleClose }, { default: vue.withCtx(() => [..._cache[25] || (_cache[25] = [ vue.createTextVNode("关闭", -1) ])]), _: 1 }) ]) ]), default: vue.withCtx(() => [ vue.createVNode(vue.unref(ElementPlus.ElTabs), { "model-value": __props.activeTab, "onUpdate:modelValue": _cache[2] || (_cache[2] = (value) => _ctx.$emit("update:activeTab", value)), class: "debug-tabs" }, { default: vue.withCtx(() => [ vue.createVNode(vue.unref(ElementPlus.ElTabPane), { label: "📋 基本信息", name: "basic" }, { default: vue.withCtx(() => [ vue.createElementVNode("div", _hoisted_1$1, [ _cache[11] || (_cache[11] = vue.createElementVNode("h4", null, "脚本状态", -1)), vue.createElementVNode("div", _hoisted_2, [ vue.createElementVNode("div", _hoisted_3, [ _cache[4] || (_cache[4] = vue.createElementVNode("span", { class: "label" }, "当前URL:", -1)), vue.createElementVNode("span", _hoisted_4, vue.toDisplayString(__props.debugInfo.currentUrl), 1) ]), vue.createElementVNode("div", _hoisted_5, [ _cache[5] || (_cache[5] = vue.createElementVNode("span", { class: "label" }, "页面标题:", -1)), vue.createElementVNode("span", _hoisted_6, vue.toDisplayString(__props.debugInfo.pageTitle), 1) ]), vue.createElementVNode("div", _hoisted_7, [ _cache[6] || (_cache[6] = vue.createElementVNode("span", { class: "label" }, "脚本版本:", -1)), vue.createElementVNode("span", _hoisted_8, vue.toDisplayString(__props.debugInfo.scriptVersion), 1) ]), vue.createElementVNode("div", _hoisted_9, [ _cache[7] || (_cache[7] = vue.createElementVNode("span", { class: "label" }, "用户代理:", -1)), vue.createElementVNode("span", _hoisted_10, vue.toDisplayString(__props.debugInfo.userAgent), 1) ]) ]), _cache[12] || (_cache[12] = vue.createElementVNode("h4", null, "高亮状态", -1)), vue.createElementVNode("div", _hoisted_11, [ vue.createElementVNode("div", _hoisted_12, [ _cache[8] || (_cache[8] = vue.createElementVNode("span", { class: "label" }, "总计数:", -1)), vue.createElementVNode("span", _hoisted_13, vue.toDisplayString(__props.highlightState.totalCount), 1) ]), vue.createElementVNode("div", _hoisted_14, [ _cache[9] || (_cache[9] = vue.createElementVNode("span", { class: "label" }, "当前索引:", -1)), vue.createElementVNode("span", _hoisted_15, vue.toDisplayString(__props.highlightState.currentIndex), 1) ]), vue.createElementVNode("div", _hoisted_16, [ _cache[10] || (_cache[10] = vue.createElementVNode("span", { class: "label" }, "关键词数:", -1)), vue.createElementVNode("span", _hoisted_17, vue.toDisplayString(__props.highlightState.keywords.length), 1) ]) ]) ]) ]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElTabPane), { label: "⚙️ 配置信息", name: "config" }, { default: vue.withCtx(() => [ vue.createElementVNode("div", _hoisted_18, [ vue.createElementVNode("h4", null, "规则列表 (" + vue.toDisplayString(__props.ruleList.length) + ")", 1), vue.createElementVNode("div", _hoisted_19, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(__props.ruleList, (rule, index) => { return vue.openBlock(), vue.createElementBlock("div", { key: index, class: "debug-rule" }, [ vue.createElementVNode("div", _hoisted_20, [ vue.createElementVNode("span", _hoisted_21, "#" + vue.toDisplayString(index + 1), 1), vue.createElementVNode("span", _hoisted_22, vue.toDisplayString(rule.matchUrl), 1) ]), vue.createElementVNode("div", _hoisted_23, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(rule.keywords, (keyword) => { return vue.openBlock(), vue.createElementBlock("span", { key: keyword, class: "keyword-tag" }, vue.toDisplayString(keyword), 1); }), 128)) ]) ]); }), 128)) ]), vue.createElementVNode("h4", null, "匹配规则 (" + vue.toDisplayString(__props.matchedRuleList.length) + ")", 1), vue.createElementVNode("div", _hoisted_24, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(__props.matchedRuleList, (rule, index) => { return vue.openBlock(), vue.createElementBlock("div", { key: index, class: "debug-rule matched" }, [ vue.createElementVNode("div", _hoisted_25, [ vue.createElementVNode("span", _hoisted_26, "#" + vue.toDisplayString(index + 1), 1), vue.createElementVNode("span", _hoisted_27, vue.toDisplayString(rule.matchUrl), 1) ]), vue.createElementVNode("div", _hoisted_28, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(rule.keywords, (keyword) => { return vue.openBlock(), vue.createElementBlock("span", { key: keyword, class: "keyword-tag" }, vue.toDisplayString(keyword), 1); }), 128)) ]) ]); }), 128)) ]), vue.createElementVNode("h4", null, "当前关键词 (" + vue.toDisplayString(__props.matchedKeywords.length) + ")", 1), vue.createElementVNode("div", _hoisted_29, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(__props.matchedKeywords, (keyword) => { return vue.openBlock(), vue.createElementBlock("span", { key: keyword, class: "keyword-tag active" }, vue.toDisplayString(keyword), 1); }), 128)) ]) ]) ]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElTabPane), { label: "📊 性能信息", name: "performance" }, { default: vue.withCtx(() => [ vue.createElementVNode("div", _hoisted_30, [ _cache[20] || (_cache[20] = vue.createElementVNode("h4", null, "性能指标", -1)), vue.createElementVNode("div", _hoisted_31, [ vue.createElementVNode("div", _hoisted_32, [ _cache[13] || (_cache[13] = vue.createElementVNode("span", { class: "label" }, "页面加载时间:", -1)), vue.createElementVNode("span", _hoisted_33, vue.toDisplayString(__props.debugInfo.pageLoadTime) + "ms", 1) ]), vue.createElementVNode("div", _hoisted_34, [ _cache[14] || (_cache[14] = vue.createElementVNode("span", { class: "label" }, "脚本初始化时间:", -1)), vue.createElementVNode("span", _hoisted_35, vue.toDisplayString(__props.debugInfo.scriptInitTime) + "ms", 1) ]), vue.createElementVNode("div", _hoisted_36, [ _cache[15] || (_cache[15] = vue.createElementVNode("span", { class: "label" }, "内存使用:", -1)), vue.createElementVNode("span", _hoisted_37, vue.toDisplayString(__props.debugInfo.memoryUsage), 1) ]) ]), _cache[21] || (_cache[21] = vue.createElementVNode("h4", null, "DOM 信息", -1)), vue.createElementVNode("div", _hoisted_38, [ vue.createElementVNode("div", _hoisted_39, [ _cache[16] || (_cache[16] = vue.createElementVNode("span", { class: "label" }, "DOM 元素数:", -1)), vue.createElementVNode("span", _hoisted_40, vue.toDisplayString(__props.debugInfo.domElementCount), 1) ]), vue.createElementVNode("div", _hoisted_41, [ _cache[17] || (_cache[17] = vue.createElementVNode("span", { class: "label" }, "文本节点数:", -1)), vue.createElementVNode("span", _hoisted_42, vue.toDisplayString(__props.debugInfo.textNodeCount), 1) ]), vue.createElementVNode("div", _hoisted_43, [ _cache[18] || (_cache[18] = vue.createElementVNode("span", { class: "label" }, "高亮元素数:", -1)), vue.createElementVNode("span", _hoisted_44, vue.toDisplayString(__props.debugInfo.highlightElementCount), 1) ]), vue.createElementVNode("div", _hoisted_45, [ _cache[19] || (_cache[19] = vue.createElementVNode("span", { class: "label" }, "页面高度:", -1)), vue.createElementVNode("span", _hoisted_46, vue.toDisplayString(__props.debugInfo.pageHeight) + "px", 1) ]) ]) ]) ]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElTabPane), { label: "📝 控制台日志", name: "logs" }, { default: vue.withCtx(() => [ vue.createElementVNode("div", _hoisted_47, [ vue.createElementVNode("div", _hoisted_48, [ vue.createElementVNode("h4", null, "日志记录 (" + vue.toDisplayString(__props.debugLogs.length) + ")", 1), vue.createElementVNode("div", _hoisted_49, [ vue.createVNode(vue.unref(ElementPlus.ElButton), { onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("clearLogs")), size: "small", type: "warning" }, { default: vue.withCtx(() => [..._cache[22] || (_cache[22] = [ vue.createTextVNode(" 🧹 清空日志 ", -1) ])]), _: 1 }), vue.createVNode(vue.unref(ElementPlus.ElButton), { onClick: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("exportDebug")), size: "small", type: "success" }, { default: vue.withCtx(() => [..._cache[23] || (_cache[23] = [ vue.createTextVNode(" 📤 导出调试信息 ", -1) ])]), _: 1 }) ]) ]), vue.createElementVNode("div", _hoisted_50, [ __props.debugLogs.length === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_51, " 暂无日志记录 ")) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_52, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(__props.debugLogs, (log, index) => { return vue.openBlock(), vue.createElementBlock("div", { key: index, class: vue.normalizeClass(["log-item", `log-${log.level}`]) }, [ vue.createElementVNode("span", _hoisted_53, vue.toDisplayString(log.timestamp), 1), vue.createElementVNode("span", _hoisted_54, vue.toDisplayString(log.level.toUpperCase()), 1), vue.createElementVNode("span", _hoisted_55, vue.toDisplayString(log.message), 1) ], 2); }), 128)) ])) ]) ]) ]), _: 1 }) ]), _: 1 }, 8, ["model-value"]) ]), _: 1 }, 8, ["model-value"]); }; } }); const DebugDialog = _export_sfc(_sfc_main$2, [["__scopeId", "data-v-b2ed8f72"]]); var _GM_addStyle = (() => typeof GM_addStyle != "undefined" ? GM_addStyle : void 0)(); var _GM_getResourceText = (() => typeof GM_getResourceText != "undefined" ? GM_getResourceText : void 0)(); var _GM_getValue = (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)(); var _GM_registerMenuCommand = (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)(); var _GM_setValue = (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)(); function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } class Highlighter { constructor(targetNode, config = {}, callbacks = {}) { Object.defineProperty(this, "targetNode", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "config", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "callbacks", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "highlights", { enumerable: true, configurable: true, writable: true, value: [] }); Object.defineProperty(this, "currentIndex", { enumerable: true, configurable: true, writable: true, value: -1 }); Object.defineProperty(this, "currentKeywords", { enumerable: true, configurable: true, writable: true, value: [] }); Object.defineProperty(this, "currentPattern", { enumerable: true, configurable: true, writable: true, value: [] }); if (!targetNode || !(targetNode instanceof HTMLElement)) { throw new Error("targetNode must be a valid HTMLElement"); } this.targetNode = targetNode; this.config = Object.assign({ highlightTag: "mark", highlightClass: "highlight", activeClass: "highlight-active", skipTags: ["SCRIPT", "STYLE", "NOSCRIPT"], scrollOptions: { behavior: "smooth", block: "center" }, enablePerformanceOptimization: true, smartScroll: true, scrollPadding: 50 }, config); this.callbacks = callbacks; } _prepareApplyRegex(regex) { if (!regex || !(regex instanceof RegExp)) { console.warn("Highlighter: 提供的正则表达式无效"); return null; } if (!regex.global) { throw new Error('Highlighter: 正则表达式必须包含全局标志 "g"'); } this.remove(); const walker = document.createTreeWalker(this.targetNode, NodeFilter.SHOW_TEXT, { acceptNode: (node) => { var _a; if (node.parentElement && this.config.skipTags.includes(node.parentElement.nodeName.toUpperCase())) { return NodeFilter.FILTER_REJECT; } if ((_a = node.parentElement) === null || _a === void 0 ? void 0 : _a.classList.contains(this.config.highlightClass)) { return NodeFilter.FILTER_REJECT; } return NodeFilter.FILTER_ACCEPT; } }); return { finalRegex: regex, walker }; } _prepareApply(keywords, options = {}) { this.remove(); const keywordArray = Array.isArray(keywords) ? keywords : [keywords]; const validKeywords = keywordArray.filter((keyword) => keyword != null && typeof keyword === "string" && keyword.trim()).map((keyword) => keyword.trim()); if (validKeywords.length === 0) { return null; } this.currentKeywords = validKeywords; const safeKeywords = validKeywords.map((keyword) => escapeRegExp(keyword)); const regexFlags = options.caseSensitive ? "g" : "gi"; const keywordPattern = safeKeywords.join("|"); const finalRegex = options.wholeWord ? new RegExp(`\\b(${keywordPattern})\\b`, regexFlags) : new RegExp(`(${keywordPattern})`, regexFlags); const walker = document.createTreeWalker(this.targetNode, NodeFilter.SHOW_TEXT, { acceptNode: (node) => { var _a; if (node.parentElement && this.config.skipTags.includes(node.parentElement.nodeName.toUpperCase())) { return NodeFilter.FILTER_REJECT; } if ((_a = node.parentElement) === null || _a === void 0 ? void 0 : _a.classList.contains(this.config.highlightClass)) { return NodeFilter.FILTER_REJECT; } return NodeFilter.FILTER_ACCEPT; } }); return { finalRegex, walker }; } _finalizeApplyRegex(nodesToReplace, regex) { var _a, _b; nodesToReplace.forEach((replacement) => { var _a2; (_a2 = replacement.oldNode.parentNode) === null || _a2 === void 0 ? void 0 : _a2.replaceChild(replacement.fragment, replacement.oldNode); }); this.highlights = Array.from(this.targetNode.querySelectorAll(`.${this.config.highlightClass}`)); if (this.highlights.length > 0) { this.currentIndex = 0; this.setActiveHighlight(); } this.currentPattern = regex; this.currentKeywords = []; (_b = (_a = this.callbacks).onHighlightApplied) === null || _b === void 0 ? void 0 : _b.call(_a, this.highlights.length, []); return this.highlights.length; } _finalizeApply(nodesToReplace) { var _a, _b; nodesToReplace.forEach((replacement) => { var _a2; (_a2 = replacement.oldNode.parentNode) === null || _a2 === void 0 ? void 0 : _a2.replaceChild(replacement.fragment, replacement.oldNode); }); this.highlights = Array.from(this.targetNode.querySelectorAll(`.${this.config.highlightClass}`)); if (this.highlights.length > 0) { this.currentIndex = 0; this.setActiveHighlight(); } this.currentPattern = this.currentKeywords; (_b = (_a = this.callbacks).onHighlightApplied) === null || _b === void 0 ? void 0 : _b.call(_a, this.highlights.length, [ ...this.currentKeywords ]); return this.highlights.length; } async apply(keywords, options = {}) { const prepared = this._prepareApply(keywords, options); if (!prepared) { return 0; } const { finalRegex, walker } = prepared; const nodesToReplace = []; let currentNode = walker.nextNode(); const batchSize = this.config.enablePerformanceOptimization ? 100 : Infinity; let processedCount = 0; while (currentNode) { const textContent = currentNode.textContent; if (textContent && finalRegex.test(textContent)) { const fragment = this.createHighlightedFragment(textContent, finalRegex); nodesToReplace.push({ oldNode: currentNode, fragment }); } currentNode = walker.nextNode(); processedCount++; if (this.config.enablePerformanceOptimization && processedCount >= batchSize) { if (typeof requestIdleCallback !== "undefined") { await new Promise((resolve) => requestIdleCallback(() => resolve())); } else { await new Promise((resolve) => setTimeout(() => resolve(), 0)); } processedCount = 0; } } return this._finalizeApply(nodesToReplace); } applySync(keywords, options = {}) { const prepared = this._prepareApply(keywords, options); if (!prepared) { return 0; } const { finalRegex, walker } = prepared; const nodesToReplace = []; let currentNode = walker.nextNode(); while (currentNode) { const textContent = currentNode.textContent; if (textContent && finalRegex.test(textContent)) { const fragment = this.createHighlightedFragment(textContent, finalRegex); nodesToReplace.push({ oldNode: currentNode, fragment }); } currentNode = walker.nextNode(); } return this._finalizeApply(nodesToReplace); } async applyRegex(regex) { const prepared = this._prepareApplyRegex(regex); if (!prepared) { return 0; } const { finalRegex, walker } = prepared; const nodesToReplace = []; let currentNode = walker.nextNode(); const batchSize = this.config.enablePerformanceOptimization ? 100 : Infinity; let processedCount = 0; while (currentNode) { const textContent = currentNode.textContent; if (textContent && finalRegex.test(textContent)) { const fragment = this.createHighlightedFragment(textContent, finalRegex); nodesToReplace.push({ oldNode: currentNode, fragment }); } currentNode = walker.nextNode(); processedCount++; if (this.config.enablePerformanceOptimization && processedCount >= batchSize) { if (typeof requestIdleCallback !== "undefined") { await new Promise((resolve) => requestIdleCallback(() => resolve())); } else { await new Promise((resolve) => setTimeout(() => resolve(), 0)); } processedCount = 0; } } return this._finalizeApplyRegex(nodesToReplace, regex); } applyRegexSync(regex) { const prepared = this._prepareApplyRegex(regex); if (!prepared) { return 0; } const { finalRegex, walker } = prepared; const nodesToReplace = []; let currentNode = walker.nextNode(); while (currentNode) { const textContent = currentNode.textContent; if (textContent && finalRegex.test(textContent)) { const fragment = this.createHighlightedFragment(textContent, finalRegex); nodesToReplace.push({ oldNode: currentNode, fragment }); } currentNode = walker.nextNode(); } return this._finalizeApplyRegex(nodesToReplace, regex); } remove() { var _a, _b; const highlights = this.targetNode.querySelectorAll(`${this.config.highlightTag}.${this.config.highlightClass}`); highlights.forEach((element) => { const parent = element.parentNode; if (parent) { parent.replaceChild(document.createTextNode(element.textContent || ""), element); parent.normalize(); } }); this.highlights = []; this.currentIndex = -1; this.currentKeywords = []; this.currentPattern = []; (_b = (_a = this.callbacks).onHighlightRemoved) === null || _b === void 0 ? void 0 : _b.call(_a); } _navigate(direction) { if (this.highlights.length === 0) return false; let nextIndex = this.currentIndex; if (direction > 0) { nextIndex = (this.currentIndex + 1) % this.highlights.length; } else { nextIndex = (this.currentIndex - 1 + this.highlights.length) % this.highlights.length; } return this.jumpTo(nextIndex); } next() { return this._navigate(1); } previous() { return this._navigate(-1); } jumpTo(index) { if (this.highlights.length === 0 || index < 0 || index >= this.highlights.length) { return false; } this.currentIndex = index; this.setActiveHighlight(); return true; } getMatchCount() { return this.highlights.length; } getCurrentIndex() { return this.currentIndex; } getCurrentKeywords() { return [...this.currentKeywords]; } getCurrentPattern() { return this.currentPattern instanceof RegExp ? this.currentPattern : [...this.currentPattern]; } getCurrentKeyword() { return this.currentKeywords.join(", "); } getCurrentElement() { return this.currentIndex >= 0 && this.currentIndex < this.highlights.length ? this.highlights[this.currentIndex] : null; } getAllHighlights() { return [...this.highlights]; } updateConfig(newConfig) { this.config = Object.assign(Object.assign({}, this.config), newConfig); } updateCallbacks(newCallbacks) { this.callbacks = Object.assign(Object.assign({}, this.callbacks), newCallbacks); } _isElementInViewport(el) { const rect = el.getBoundingClientRect(); const padding = this.config.scrollPadding; return rect.top >= padding && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) - padding; } createHighlightedFragment(text, regex) { const fragment = document.createDocumentFragment(); let lastIndex = 0; let match; regex.lastIndex = 0; while ((match = regex.exec(text)) !== null) { if (match.index > lastIndex) { fragment.appendChild(document.createTextNode(text.substring(lastIndex, match.index))); } const highlightElement = document.createElement(this.config.highlightTag); highlightElement.className = this.config.highlightClass; highlightElement.textContent = match[0]; fragment.appendChild(highlightElement); lastIndex = regex.lastIndex; } if (lastIndex < text.length) { fragment.appendChild(document.createTextNode(text.substring(lastIndex))); } return fragment; } setActiveHighlight() { var _a, _b; this.highlights.forEach((node) => node.classList.remove(this.config.activeClass)); const activeNode = this.highlights[this.currentIndex]; if (activeNode) { activeNode.classList.add(this.config.activeClass); if (!this.config.smartScroll || !this._isElementInViewport(activeNode)) { activeNode.scrollIntoView(this.config.scrollOptions); } (_b = (_a = this.callbacks).onNavigate) === null || _b === void 0 ? void 0 : _b.call(_a, this.currentIndex, this.highlights.length, activeNode); } } _findOffscreenIndex(direction) { const total = this.highlights.length; if (total <= 1) { return -1; } for (let i = 1; i < total; i++) { const nextIndex = (this.currentIndex + i * direction + total) % total; const nextNode = this.highlights[nextIndex]; if (!this._isElementInViewport(nextNode)) { return nextIndex; } } return -1; } findNextOffscreenIndex() { return this._findOffscreenIndex(1); } findPreviousOffscreenIndex() { return this._findOffscreenIndex(-1); } jumpToNextOffscreen() { const targetIndex = this.findNextOffscreenIndex(); if (targetIndex !== -1) { return this.jumpTo(targetIndex); } else { return this.next(); } } jumpToPreviousOffscreen() { const targetIndex = this.findPreviousOffscreenIndex(); if (targetIndex !== -1) { return this.jumpTo(targetIndex); } else { return this.previous(); } } destroy() { this.remove(); this.highlights = []; this.callbacks = {}; } } function r(e) { var t, f, n = ""; if ("string" == typeof e || "number" == typeof e) n += e; else if ("object" == typeof e) if (Array.isArray(e)) { var o = e.length; for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f); } else for (f in e) e[f] && (n && (n += " "), n += f); return n; } function clsx() { for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t); return n; } const concatArrays = (array1, array2) => { const combinedArray = new Array(array1.length + array2.length); for (let i = 0; i < array1.length; i++) { combinedArray[i] = array1[i]; } for (let i = 0; i < array2.length; i++) { combinedArray[array1.length + i] = array2[i]; } return combinedArray; }; const createClassValidatorObject = (classGroupId, validator) => ({ classGroupId, validator }); const createClassPartObject = (nextPart = new Map(), validators = null, classGroupId) => ({ nextPart, validators, classGroupId }); const CLASS_PART_SEPARATOR = "-"; const EMPTY_CONFLICTS = []; const ARBITRARY_PROPERTY_PREFIX = "arbitrary.."; const createClassGroupUtils = (config) => { const classMap = createClassMap(config); const { conflictingClassGroups, conflictingClassGroupModifiers } = config; const getClassGroupId = (className) => { if (className.startsWith("[") && className.endsWith("]")) { return getGroupIdForArbitraryProperty(className); } const classParts = className.split(CLASS_PART_SEPARATOR); const startIndex = classParts[0] === "" && classParts.length > 1 ? 1 : 0; return getGroupRecursive(classParts, startIndex, classMap); }; const getConflictingClassGroupIds = (classGroupId, hasPostfixModifier) => { if (hasPostfixModifier) { const modifierConflicts = conflictingClassGroupModifiers[classGroupId]; const baseConflicts = conflictingClassGroups[classGroupId]; if (modifierConflicts) { if (baseConflicts) { return concatArrays(baseConflicts, modifierConflicts); } return modifierConflicts; } return baseConflicts || EMPTY_CONFLICTS; } return conflictingClassGroups[classGroupId] || EMPTY_CONFLICTS; }; return { getClassGroupId, getConflictingClassGroupIds }; }; const getGroupRecursive = (classParts, startIndex, classPartObject) => { const classPathsLength = classParts.length - startIndex; if (classPathsLength === 0) { return classPartObject.classGroupId; } const currentClassPart = classParts[startIndex]; const nextClassPartObject = classPartObject.nextPart.get(currentClassPart); if (nextClassPartObject) { const result = getGroupRecursive(classParts, startIndex + 1, nextClassPartObject); if (result) return result; } const validators = classPartObject.validators; if (validators === null) { return void 0; } const classRest = startIndex === 0 ? classParts.join(CLASS_PART_SEPARATOR) : classParts.slice(startIndex).join(CLASS_PART_SEPARATOR); const validatorsLength = validators.length; for (let i = 0; i < validatorsLength; i++) { const validatorObj = validators[i]; if (validatorObj.validator(classRest)) { return validatorObj.classGroupId; } } return void 0; }; const getGroupIdForArbitraryProperty = (className) => className.slice(1, -1).indexOf(":") === -1 ? void 0 : (() => { const content = className.slice(1, -1); const colonIndex = content.indexOf(":"); const property = content.slice(0, colonIndex); return property ? ARBITRARY_PROPERTY_PREFIX + property : void 0; })(); const createClassMap = (config) => { const { theme, classGroups } = config; return processClassGroups(classGroups, theme); }; const processClassGroups = (classGroups, theme) => { const classMap = createClassPartObject(); for (const classGroupId in classGroups) { const group = classGroups[classGroupId]; processClassesRecursively(group, classMap, classGroupId, theme); } return classMap; }; const processClassesRecursively = (classGroup, classPartObject, classGroupId, theme) => { const len = classGroup.length; for (let i = 0; i < len; i++) { const classDefinition = classGroup[i]; processClassDefinition(classDefinition, classPartObject, classGroupId, theme); } }; const processClassDefinition = (classDefinition, classPartObject, classGroupId, theme) => { if (typeof classDefinition === "string") { processStringDefinition(classDefinition, classPartObject, classGroupId); return; } if (typeof classDefinition === "function") { processFunctionDefinition(classDefinition, classPartObject, classGroupId, theme); return; } processObjectDefinition(classDefinition, classPartObject, classGroupId, theme); }; const processStringDefinition = (classDefinition, classPartObject, classGroupId) => { const classPartObjectToEdit = classDefinition === "" ? classPartObject : getPart(classPartObject, classDefinition); classPartObjectToEdit.classGroupId = classGroupId; }; const processFunctionDefinition = (classDefinition, classPartObject, classGroupId, theme) => { if (isThemeGetter(classDefinition)) { processClassesRecursively(classDefinition(theme), classPartObject, classGroupId, theme); return; } if (classPartObject.validators === null) { classPartObject.validators = []; } classPartObject.validators.push(createClassValidatorObject(classGroupId, classDefinition)); }; const processObjectDefinition = (classDefinition, classPartObject, classGroupId, theme) => { const entries = Object.entries(classDefinition); const len = entries.length; for (let i = 0; i < len; i++) { const [key, value] = entries[i]; processClassesRecursively(value, getPart(classPartObject, key), classGroupId, theme); } }; const getPart = (classPartObject, path) => { let current = classPartObject; const parts = path.split(CLASS_PART_SEPARATOR); const len = parts.length; for (let i = 0; i < len; i++) { const part = parts[i]; let next = current.nextPart.get(part); if (!next) { next = createClassPartObject(); current.nextPart.set(part, next); } current = next; } return current; }; const isThemeGetter = (func) => "isThemeGetter" in func && func.isThemeGetter === true; const createLruCache = (maxCacheSize) => { if (maxCacheSize < 1) { return { get: () => void 0, set: () => { } }; } let cacheSize = 0; let cache = Object.create(null); let previousCache = Object.create(null); const update = (key, value) => { cache[key] = value; cacheSize++; if (cacheSize > maxCacheSize) { cacheSize = 0; previousCache = cache; cache = Object.create(null); } }; return { get(key) { let value = cache[key]; if (value !== void 0) { return value; } if ((value = previousCache[key]) !== void 0) { update(key, value); return value; } }, set(key, value) { if (key in cache) { cache[key] = value; } else { update(key, value); } } }; }; const IMPORTANT_MODIFIER = "!"; const MODIFIER_SEPARATOR = ":"; const EMPTY_MODIFIERS = []; const createResultObject = (modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition, isExternal) => ({ modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition, isExternal }); const createParseClassName = (config) => { const { prefix, experimentalParseClassName } = config; let parseClassName = (className) => { const modifiers = []; let bracketDepth = 0; let parenDepth = 0; let modifierStart = 0; let postfixModifierPosition; const len = className.length; for (let index = 0; index < len; index++) { const currentCharacter = className[index]; if (bracketDepth === 0 && parenDepth === 0) { if (currentCharacter === MODIFIER_SEPARATOR) { modifiers.push(className.slice(modifierStart, index)); modifierStart = index + 1; continue; } if (currentCharacter === "/") { postfixModifierPosition = index; continue; } } if (currentCharacter === "[") bracketDepth++; else if (currentCharacter === "]") bracketDepth--; else if (currentCharacter === "(") parenDepth++; else if (currentCharacter === ")") parenDepth--; } const baseClassNameWithImportantModifier = modifiers.length === 0 ? className : className.slice(modifierStart); let baseClassName = baseClassNameWithImportantModifier; let hasImportantModifier = false; if (baseClassNameWithImportantModifier.endsWith(IMPORTANT_MODIFIER)) { baseClassName = baseClassNameWithImportantModifier.slice(0, -1); hasImportantModifier = true; } else if ( baseClassNameWithImportantModifier.startsWith(IMPORTANT_MODIFIER) ) { baseClassName = baseClassNameWithImportantModifier.slice(1); hasImportantModifier = true; } const maybePostfixModifierPosition = postfixModifierPosition && postfixModifierPosition > modifierStart ? postfixModifierPosition - modifierStart : void 0; return createResultObject(modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition); }; if (prefix) { const fullPrefix = prefix + MODIFIER_SEPARATOR; const parseClassNameOriginal = parseClassName; parseClassName = (className) => className.startsWith(fullPrefix) ? parseClassNameOriginal(className.slice(fullPrefix.length)) : createResultObject(EMPTY_MODIFIERS, false, className, void 0, true); } if (experimentalParseClassName) { const parseClassNameOriginal = parseClassName; parseClassName = (className) => experimentalParseClassName({ className, parseClassName: parseClassNameOriginal }); } return parseClassName; }; const createSortModifiers = (config) => { const modifierWeights = new Map(); config.orderSensitiveModifiers.forEach((mod, index) => { modifierWeights.set(mod, 1e6 + index); }); return (modifiers) => { const result = []; let currentSegment = []; for (let i = 0; i < modifiers.length; i++) { const modifier = modifiers[i]; const isArbitrary = modifier[0] === "["; const isOrderSensitive = modifierWeights.has(modifier); if (isArbitrary || isOrderSensitive) { if (currentSegment.length > 0) { currentSegment.sort(); result.push(...currentSegment); currentSegment = []; } result.push(modifier); } else { currentSegment.push(modifier); } } if (currentSegment.length > 0) { currentSegment.sort(); result.push(...currentSegment); } return result; }; }; const createConfigUtils = (config) => ({ cache: createLruCache(config.cacheSize), parseClassName: createParseClassName(config), sortModifiers: createSortModifiers(config), ...createClassGroupUtils(config) }); const SPLIT_CLASSES_REGEX = /\s+/; const mergeClassList = (classList, configUtils) => { const { parseClassName, getClassGroupId, getConflictingClassGroupIds, sortModifiers } = configUtils; const classGroupsInConflict = []; const classNames = classList.trim().split(SPLIT_CLASSES_REGEX); let result = ""; for (let index = classNames.length - 1; index >= 0; index -= 1) { const originalClassName = classNames[index]; const { isExternal, modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition } = parseClassName(originalClassName); if (isExternal) { result = originalClassName + (result.length > 0 ? " " + result : result); continue; } let hasPostfixModifier = !!maybePostfixModifierPosition; let classGroupId = getClassGroupId(hasPostfixModifier ? baseClassName.substring(0, maybePostfixModifierPosition) : baseClassName); if (!classGroupId) { if (!hasPostfixModifier) { result = originalClassName + (result.length > 0 ? " " + result : result); continue; } classGroupId = getClassGroupId(baseClassName); if (!classGroupId) { result = originalClassName + (result.length > 0 ? " " + result : result); continue; } hasPostfixModifier = false; } const variantModifier = modifiers.length === 0 ? "" : modifiers.length === 1 ? modifiers[0] : sortModifiers(modifiers).join(":"); const modifierId = hasImportantModifier ? variantModifier + IMPORTANT_MODIFIER : variantModifier; const classId = modifierId + classGroupId; if (classGroupsInConflict.indexOf(classId) > -1) { continue; } classGroupsInConflict.push(classId); const conflictGroups = getConflictingClassGroupIds(classGroupId, hasPostfixModifier); for (let i = 0; i < conflictGroups.length; ++i) { const group = conflictGroups[i]; classGroupsInConflict.push(modifierId + group); } result = originalClassName + (result.length > 0 ? " " + result : result); } return result; }; const twJoin = (...classLists) => { let index = 0; let argument; let resolvedValue; let string = ""; while (index < classLists.length) { if (argument = classLists[index++]) { if (resolvedValue = toValue(argument)) { string && (string += " "); string += resolvedValue; } } } return string; }; const toValue = (mix) => { if (typeof mix === "string") { return mix; } let resolvedValue; let string = ""; for (let k = 0; k < mix.length; k++) { if (mix[k]) { if (resolvedValue = toValue(mix[k])) { string && (string += " "); string += resolvedValue; } } } return string; }; const createTailwindMerge = (createConfigFirst, ...createConfigRest) => { let configUtils; let cacheGet; let cacheSet; let functionToCall; const initTailwindMerge = (classList) => { const config = createConfigRest.reduce((previousConfig, createConfigCurrent) => createConfigCurrent(previousConfig), createConfigFirst()); configUtils = createConfigUtils(config); cacheGet = configUtils.cache.get; cacheSet = configUtils.cache.set; functionToCall = tailwindMerge; return tailwindMerge(classList); }; const tailwindMerge = (classList) => { const cachedResult = cacheGet(classList); if (cachedResult) { return cachedResult; } const result = mergeClassList(classList, configUtils); cacheSet(classList, result); return result; }; functionToCall = initTailwindMerge; return (...args) => functionToCall(twJoin(...args)); }; const fallbackThemeArr = []; const fromTheme = (key) => { const themeGetter = (theme) => theme[key] || fallbackThemeArr; themeGetter.isThemeGetter = true; return themeGetter; }; const arbitraryValueRegex = /^\[(?:(\w[\w-]*):)?(.+)\]$/i; const arbitraryVariableRegex = /^\((?:(\w[\w-]*):)?(.+)\)$/i; const fractionRegex = /^\d+\/\d+$/; const tshirtUnitRegex = /^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/; const lengthUnitRegex = /\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/; const colorFunctionRegex = /^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/; const shadowRegex = /^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/; const imageRegex = /^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/; const isFraction = (value) => fractionRegex.test(value); const isNumber = (value) => !!value && !Number.isNaN(Number(value)); const isInteger = (value) => !!value && Number.isInteger(Number(value)); const isPercent = (value) => value.endsWith("%") && isNumber(value.slice(0, -1)); const isTshirtSize = (value) => tshirtUnitRegex.test(value); const isAny = () => true; const isLengthOnly = (value) => ( lengthUnitRegex.test(value) && !colorFunctionRegex.test(value) ); const isNever = () => false; const isShadow = (value) => shadowRegex.test(value); const isImage = (value) => imageRegex.test(value); const isAnyNonArbitrary = (value) => !isArbitraryValue(value) && !isArbitraryVariable(value); const isArbitrarySize = (value) => getIsArbitraryValue(value, isLabelSize, isNever); const isArbitraryValue = (value) => arbitraryValueRegex.test(value); const isArbitraryLength = (value) => getIsArbitraryValue(value, isLabelLength, isLengthOnly); const isArbitraryNumber = (value) => getIsArbitraryValue(value, isLabelNumber, isNumber); const isArbitraryPosition = (value) => getIsArbitraryValue(value, isLabelPosition, isNever); const isArbitraryImage = (value) => getIsArbitraryValue(value, isLabelImage, isImage); const isArbitraryShadow = (value) => getIsArbitraryValue(value, isLabelShadow, isShadow); const isArbitraryVariable = (value) => arbitraryVariableRegex.test(value); const isArbitraryVariableLength = (value) => getIsArbitraryVariable(value, isLabelLength); const isArbitraryVariableFamilyName = (value) => getIsArbitraryVariable(value, isLabelFamilyName); const isArbitraryVariablePosition = (value) => getIsArbitraryVariable(value, isLabelPosition); const isArbitraryVariableSize = (value) => getIsArbitraryVariable(value, isLabelSize); const isArbitraryVariableImage = (value) => getIsArbitraryVariable(value, isLabelImage); const isArbitraryVariableShadow = (value) => getIsArbitraryVariable(value, isLabelShadow, true); const getIsArbitraryValue = (value, testLabel, testValue) => { const result = arbitraryValueRegex.exec(value); if (result) { if (result[1]) { return testLabel(result[1]); } return testValue(result[2]); } return false; }; const getIsArbitraryVariable = (value, testLabel, shouldMatchNoLabel = false) => { const result = arbitraryVariableRegex.exec(value); if (result) { if (result[1]) { return testLabel(result[1]); } return shouldMatchNoLabel; } return false; }; const isLabelPosition = (label) => label === "position" || label === "percentage"; const isLabelImage = (label) => label === "image" || label === "url"; const isLabelSize = (label) => label === "length" || label === "size" || label === "bg-size"; const isLabelLength = (label) => label === "length"; const isLabelNumber = (label) => label === "number"; const isLabelFamilyName = (label) => label === "family-name"; const isLabelShadow = (label) => label === "shadow"; const getDefaultConfig = () => { const themeColor = fromTheme("color"); const themeFont = fromTheme("font"); const themeText = fromTheme("text"); const themeFontWeight = fromTheme("font-weight"); const themeTracking = fromTheme("tracking"); const themeLeading = fromTheme("leading"); const themeBreakpoint = fromTheme("breakpoint"); const themeContainer = fromTheme("container"); const themeSpacing = fromTheme("spacing"); const themeRadius = fromTheme("radius"); const themeShadow = fromTheme("shadow"); const themeInsetShadow = fromTheme("inset-shadow"); const themeTextShadow = fromTheme("text-shadow"); const themeDropShadow = fromTheme("drop-shadow"); const themeBlur = fromTheme("blur"); const themePerspective = fromTheme("perspective"); const themeAspect = fromTheme("aspect"); const themeEase = fromTheme("ease"); const themeAnimate = fromTheme("animate"); const scaleBreak = () => ["auto", "avoid", "all", "avoid-page", "page", "left", "right", "column"]; const scalePosition = () => [ "center", "top", "bottom", "left", "right", "top-left", "left-top", "top-right", "right-top", "bottom-right", "right-bottom", "bottom-left", "left-bottom" ]; const scalePositionWithArbitrary = () => [...scalePosition(), isArbitraryVariable, isArbitraryValue]; const scaleOverflow = () => ["auto", "hidden", "clip", "visible", "scroll"]; const scaleOverscroll = () => ["auto", "contain", "none"]; const scaleUnambiguousSpacing = () => [isArbitraryVariable, isArbitraryValue, themeSpacing]; const scaleInset = () => [isFraction, "full", "auto", ...scaleUnambiguousSpacing()]; const scaleGridTemplateColsRows = () => [isInteger, "none", "subgrid", isArbitraryVariable, isArbitraryValue]; const scaleGridColRowStartAndEnd = () => ["auto", { span: ["full", isInteger, isArbitraryVariable, isArbitraryValue] }, isInteger, isArbitraryVariable, isArbitraryValue]; const scaleGridColRowStartOrEnd = () => [isInteger, "auto", isArbitraryVariable, isArbitraryValue]; const scaleGridAutoColsRows = () => ["auto", "min", "max", "fr", isArbitraryVariable, isArbitraryValue]; const scaleAlignPrimaryAxis = () => ["start", "end", "center", "between", "around", "evenly", "stretch", "baseline", "center-safe", "end-safe"]; const scaleAlignSecondaryAxis = () => ["start", "end", "center", "stretch", "center-safe", "end-safe"]; const scaleMargin = () => ["auto", ...scaleUnambiguousSpacing()]; const scaleSizing = () => [isFraction, "auto", "full", "dvw", "dvh", "lvw", "lvh", "svw", "svh", "min", "max", "fit", ...scaleUnambiguousSpacing()]; const scaleColor = () => [themeColor, isArbitraryVariable, isArbitraryValue]; const scaleBgPosition = () => [...scalePosition(), isArbitraryVariablePosition, isArbitraryPosition, { position: [isArbitraryVariable, isArbitraryValue] }]; const scaleBgRepeat = () => ["no-repeat", { repeat: ["", "x", "y", "space", "round"] }]; const scaleBgSize = () => ["auto", "cover", "contain", isArbitraryVariableSize, isArbitrarySize, { size: [isArbitraryVariable, isArbitraryValue] }]; const scaleGradientStopPosition = () => [isPercent, isArbitraryVariableLength, isArbitraryLength]; const scaleRadius = () => [ "", "none", "full", themeRadius, isArbitraryVariable, isArbitraryValue ]; const scaleBorderWidth = () => ["", isNumber, isArbitraryVariableLength, isArbitraryLength]; const scaleLineStyle = () => ["solid", "dashed", "dotted", "double"]; const scaleBlendMode = () => ["normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"]; const scaleMaskImagePosition = () => [isNumber, isPercent, isArbitraryVariablePosition, isArbitraryPosition]; const scaleBlur = () => [ "", "none", themeBlur, isArbitraryVariable, isArbitraryValue ]; const scaleRotate = () => ["none", isNumber, isArbitraryVariable, isArbitraryValue]; const scaleScale = () => ["none", isNumber, isArbitraryVariable, isArbitraryValue]; const scaleSkew = () => [isNumber, isArbitraryVariable, isArbitraryValue]; const scaleTranslate = () => [isFraction, "full", ...scaleUnambiguousSpacing()]; return { cacheSize: 500, theme: { animate: ["spin", "ping", "pulse", "bounce"], aspect: ["video"], blur: [isTshirtSize], breakpoint: [isTshirtSize], color: [isAny], container: [isTshirtSize], "drop-shadow": [isTshirtSize], ease: ["in", "out", "in-out"], font: [isAnyNonArbitrary], "font-weight": ["thin", "extralight", "light", "normal", "medium", "semibold", "bold", "extrabold", "black"], "inset-shadow": [isTshirtSize], leading: ["none", "tight", "snug", "normal", "relaxed", "loose"], perspective: ["dramatic", "near", "normal", "midrange", "distant", "none"], radius: [isTshirtSize], shadow: [isTshirtSize], spacing: ["px", isNumber], text: [isTshirtSize], "text-shadow": [isTshirtSize], tracking: ["tighter", "tight", "normal", "wide", "wider", "widest"] }, classGroups: { aspect: [{ aspect: ["auto", "square", isFraction, isArbitraryValue, isArbitraryVariable, themeAspect] }], container: ["container"], columns: [{ columns: [isNumber, isArbitraryValue, isArbitraryVariable, themeContainer] }], "break-after": [{ "break-after": scaleBreak() }], "break-before": [{ "break-before": scaleBreak() }], "break-inside": [{ "break-inside": ["auto", "avoid", "avoid-page", "avoid-column"] }], "box-decoration": [{ "box-decoration": ["slice", "clone"] }], box: [{ box: ["border", "content"] }], display: ["block", "inline-block", "inline", "flex", "inline-flex", "table", "inline-table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row-group", "table-row", "flow-root", "grid", "inline-grid", "contents", "list-item", "hidden"], sr: ["sr-only", "not-sr-only"], float: [{ float: ["right", "left", "none", "start", "end"] }], clear: [{ clear: ["left", "right", "both", "none", "start", "end"] }], isolation: ["isolate", "isolation-auto"], "object-fit": [{ object: ["contain", "cover", "fill", "none", "scale-down"] }], "object-position": [{ object: scalePositionWithArbitrary() }], overflow: [{ overflow: scaleOverflow() }], "overflow-x": [{ "overflow-x": scaleOverflow() }], "overflow-y": [{ "overflow-y": scaleOverflow() }], overscroll: [{ overscroll: scaleOverscroll() }], "overscroll-x": [{ "overscroll-x": scaleOverscroll() }], "overscroll-y": [{ "overscroll-y": scaleOverscroll() }], position: ["static", "fixed", "absolute", "relative", "sticky"], inset: [{ inset: scaleInset() }], "inset-x": [{ "inset-x": scaleInset() }], "inset-y": [{ "inset-y": scaleInset() }], start: [{ start: scaleInset() }], end: [{ end: scaleInset() }], top: [{ top: scaleInset() }], right: [{ right: scaleInset() }], bottom: [{ bottom: scaleInset() }], left: [{ left: scaleInset() }], visibility: ["visible", "invisible", "collapse"], z: [{ z: [isInteger, "auto", isArbitraryVariable, isArbitraryValue] }], basis: [{ basis: [isFraction, "full", "auto", themeContainer, ...scaleUnambiguousSpacing()] }], "flex-direction": [{ flex: ["row", "row-reverse", "col", "col-reverse"] }], "flex-wrap": [{ flex: ["nowrap", "wrap", "wrap-reverse"] }], flex: [{ flex: [isNumber, isFraction, "auto", "initial", "none", isArbitraryValue] }], grow: [{ grow: ["", isNumber, isArbitraryVariable, isArbitraryValue] }], shrink: [{ shrink: ["", isNumber, isArbitraryVariable, isArbitraryValue] }], order: [{ order: [isInteger, "first", "last", "none", isArbitraryVariable, isArbitraryValue] }], "grid-cols": [{ "grid-cols": scaleGridTemplateColsRows() }], "col-start-end": [{ col: scaleGridColRowStartAndEnd() }], "col-start": [{ "col-start": scaleGridColRowStartOrEnd() }], "col-end": [{ "col-end": scaleGridColRowStartOrEnd() }], "grid-rows": [{ "grid-rows": scaleGridTemplateColsRows() }], "row-start-end": [{ row: scaleGridColRowStartAndEnd() }], "row-start": [{ "row-start": scaleGridColRowStartOrEnd() }], "row-end": [{ "row-end": scaleGridColRowStartOrEnd() }], "grid-flow": [{ "grid-flow": ["row", "col", "dense", "row-dense", "col-dense"] }], "auto-cols": [{ "auto-cols": scaleGridAutoColsRows() }], "auto-rows": [{ "auto-rows": scaleGridAutoColsRows() }], gap: [{ gap: scaleUnambiguousSpacing() }], "gap-x": [{ "gap-x": scaleUnambiguousSpacing() }], "gap-y": [{ "gap-y": scaleUnambiguousSpacing() }], "justify-content": [{ justify: [...scaleAlignPrimaryAxis(), "normal"] }], "justify-items": [{ "justify-items": [...scaleAlignSecondaryAxis(), "normal"] }], "justify-self": [{ "justify-self": ["auto", ...scaleAlignSecondaryAxis()] }], "align-content": [{ content: ["normal", ...scaleAlignPrimaryAxis()] }], "align-items": [{ items: [...scaleAlignSecondaryAxis(), { baseline: ["", "last"] }] }], "align-self": [{ self: ["auto", ...scaleAlignSecondaryAxis(), { baseline: ["", "last"] }] }], "place-content": [{ "place-content": scaleAlignPrimaryAxis() }], "place-items": [{ "place-items": [...scaleAlignSecondaryAxis(), "baseline"] }], "place-self": [{ "place-self": ["auto", ...scaleAlignSecondaryAxis()] }], p: [{ p: scaleUnambiguousSpacing() }], px: [{ px: scaleUnambiguousSpacing() }], py: [{ py: scaleUnambiguousSpacing() }], ps: [{ ps: scaleUnambiguousSpacing() }], pe: [{ pe: scaleUnambiguousSpacing() }], pt: [{ pt: scaleUnambiguousSpacing() }], pr: [{ pr: scaleUnambiguousSpacing() }], pb: [{ pb: scaleUnambiguousSpacing() }], pl: [{ pl: scaleUnambiguousSpacing() }], m: [{ m: scaleMargin() }], mx: [{ mx: scaleMargin() }], my: [{ my: scaleMargin() }], ms: [{ ms: scaleMargin() }], me: [{ me: scaleMargin() }], mt: [{ mt: scaleMargin() }], mr: [{ mr: scaleMargin() }], mb: [{ mb: scaleMargin() }], ml: [{ ml: scaleMargin() }], "space-x": [{ "space-x": scaleUnambiguousSpacing() }], "space-x-reverse": ["space-x-reverse"], "space-y": [{ "space-y": scaleUnambiguousSpacing() }], "space-y-reverse": ["space-y-reverse"], size: [{ size: scaleSizing() }], w: [{ w: [themeContainer, "screen", ...scaleSizing()] }], "min-w": [{ "min-w": [ themeContainer, "screen", "none", ...scaleSizing() ] }], "max-w": [{ "max-w": [ themeContainer, "screen", "none", "prose", { screen: [themeBreakpoint] }, ...scaleSizing() ] }], h: [{ h: ["screen", "lh", ...scaleSizing()] }], "min-h": [{ "min-h": ["screen", "lh", "none", ...scaleSizing()] }], "max-h": [{ "max-h": ["screen", "lh", ...scaleSizing()] }], "font-size": [{ text: ["base", themeText, isArbitraryVariableLength, isArbitraryLength] }], "font-smoothing": ["antialiased", "subpixel-antialiased"], "font-style": ["italic", "not-italic"], "font-weight": [{ font: [themeFontWeight, isArbitraryVariable, isArbitraryNumber] }], "font-stretch": [{ "font-stretch": ["ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "normal", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded", isPercent, isArbitraryValue] }], "font-family": [{ font: [isArbitraryVariableFamilyName, isArbitraryValue, themeFont] }], "fvn-normal": ["normal-nums"], "fvn-ordinal": ["ordinal"], "fvn-slashed-zero": ["slashed-zero"], "fvn-figure": ["lining-nums", "oldstyle-nums"], "fvn-spacing": ["proportional-nums", "tabular-nums"], "fvn-fraction": ["diagonal-fractions", "stacked-fractions"], tracking: [{ tracking: [themeTracking, isArbitraryVariable, isArbitraryValue] }], "line-clamp": [{ "line-clamp": [isNumber, "none", isArbitraryVariable, isArbitraryNumber] }], leading: [{ leading: [ themeLeading, ...scaleUnambiguousSpacing() ] }], "list-image": [{ "list-image": ["none", isArbitraryVariable, isArbitraryValue] }], "list-style-position": [{ list: ["inside", "outside"] }], "list-style-type": [{ list: ["disc", "decimal", "none", isArbitraryVariable, isArbitraryValue] }], "text-alignment": [{ text: ["left", "center", "right", "justify", "start", "end"] }], "placeholder-color": [{ placeholder: scaleColor() }], "text-color": [{ text: scaleColor() }], "text-decoration": ["underline", "overline", "line-through", "no-underline"], "text-decoration-style": [{ decoration: [...scaleLineStyle(), "wavy"] }], "text-decoration-thickness": [{ decoration: [isNumber, "from-font", "auto", isArbitraryVariable, isArbitraryLength] }], "text-decoration-color": [{ decoration: scaleColor() }], "underline-offset": [{ "underline-offset": [isNumber, "auto", isArbitraryVariable, isArbitraryValue] }], "text-transform": ["uppercase", "lowercase", "capitalize", "normal-case"], "text-overflow": ["truncate", "text-ellipsis", "text-clip"], "text-wrap": [{ text: ["wrap", "nowrap", "balance", "pretty"] }], indent: [{ indent: scaleUnambiguousSpacing() }], "vertical-align": [{ align: ["baseline", "top", "middle", "bottom", "text-top", "text-bottom", "sub", "super", isArbitraryVariable, isArbitraryValue] }], whitespace: [{ whitespace: ["normal", "nowrap", "pre", "pre-line", "pre-wrap", "break-spaces"] }], break: [{ break: ["normal", "words", "all", "keep"] }], wrap: [{ wrap: ["break-word", "anywhere", "normal"] }], hyphens: [{ hyphens: ["none", "manual", "auto"] }], content: [{ content: ["none", isArbitraryVariable, isArbitraryValue] }], "bg-attachment": [{ bg: ["fixed", "local", "scroll"] }], "bg-clip": [{ "bg-clip": ["border", "padding", "content", "text"] }], "bg-origin": [{ "bg-origin": ["border", "padding", "content"] }], "bg-position": [{ bg: scaleBgPosition() }], "bg-repeat": [{ bg: scaleBgRepeat() }], "bg-size": [{ bg: scaleBgSize() }], "bg-image": [{ bg: ["none", { linear: [{ to: ["t", "tr", "r", "br", "b", "bl", "l", "tl"] }, isInteger, isArbitraryVariable, isArbitraryValue], radial: ["", isArbitraryVariable, isArbitraryValue], conic: [isInteger, isArbitraryVariable, isArbitraryValue] }, isArbitraryVariableImage, isArbitraryImage] }], "bg-color": [{ bg: scaleColor() }], "gradient-from-pos": [{ from: scaleGradientStopPosition() }], "gradient-via-pos": [{ via: scaleGradientStopPosition() }], "gradient-to-pos": [{ to: scaleGradientStopPosition() }], "gradient-from": [{ from: scaleColor() }], "gradient-via": [{ via: scaleColor() }], "gradient-to": [{ to: scaleColor() }], rounded: [{ rounded: scaleRadius() }], "rounded-s": [{ "rounded-s": scaleRadius() }], "rounded-e": [{ "rounded-e": scaleRadius() }], "rounded-t": [{ "rounded-t": scaleRadius() }], "rounded-r": [{ "rounded-r": scaleRadius() }], "rounded-b": [{ "rounded-b": scaleRadius() }], "rounded-l": [{ "rounded-l": scaleRadius() }], "rounded-ss": [{ "rounded-ss": scaleRadius() }], "rounded-se": [{ "rounded-se": scaleRadius() }], "rounded-ee": [{ "rounded-ee": scaleRadius() }], "rounded-es": [{ "rounded-es": scaleRadius() }], "rounded-tl": [{ "rounded-tl": scaleRadius() }], "rounded-tr": [{ "rounded-tr": scaleRadius() }], "rounded-br": [{ "rounded-br": scaleRadius() }], "rounded-bl": [{ "rounded-bl": scaleRadius() }], "border-w": [{ border: scaleBorderWidth() }], "border-w-x": [{ "border-x": scaleBorderWidth() }], "border-w-y": [{ "border-y": scaleBorderWidth() }], "border-w-s": [{ "border-s": scaleBorderWidth() }], "border-w-e": [{ "border-e": scaleBorderWidth() }], "border-w-t": [{ "border-t": scaleBorderWidth() }], "border-w-r": [{ "border-r": scaleBorderWidth() }], "border-w-b": [{ "border-b": scaleBorderWidth() }], "border-w-l": [{ "border-l": scaleBorderWidth() }], "divide-x": [{ "divide-x": scaleBorderWidth() }], "divide-x-reverse": ["divide-x-reverse"], "divide-y": [{ "divide-y": scaleBorderWidth() }], "divide-y-reverse": ["divide-y-reverse"], "border-style": [{ border: [...scaleLineStyle(), "hidden", "none"] }], "divide-style": [{ divide: [...scaleLineStyle(), "hidden", "none"] }], "border-color": [{ border: scaleColor() }], "border-color-x": [{ "border-x": scaleColor() }], "border-color-y": [{ "border-y": scaleColor() }], "border-color-s": [{ "border-s": scaleColor() }], "border-color-e": [{ "border-e": scaleColor() }], "border-color-t": [{ "border-t": scaleColor() }], "border-color-r": [{ "border-r": scaleColor() }], "border-color-b": [{ "border-b": scaleColor() }], "border-color-l": [{ "border-l": scaleColor() }], "divide-color": [{ divide: scaleColor() }], "outline-style": [{ outline: [...scaleLineStyle(), "none", "hidden"] }], "outline-offset": [{ "outline-offset": [isNumber, isArbitraryVariable, isArbitraryValue] }], "outline-w": [{ outline: ["", isNumber, isArbitraryVariableLength, isArbitraryLength] }], "outline-color": [{ outline: scaleColor() }], shadow: [{ shadow: [ "", "none", themeShadow, isArbitraryVariableShadow, isArbitraryShadow ] }], "shadow-color": [{ shadow: scaleColor() }], "inset-shadow": [{ "inset-shadow": ["none", themeInsetShadow, isArbitraryVariableShadow, isArbitraryShadow] }], "inset-shadow-color": [{ "inset-shadow": scaleColor() }], "ring-w": [{ ring: scaleBorderWidth() }], "ring-w-inset": ["ring-inset"], "ring-color": [{ ring: scaleColor() }], "ring-offset-w": [{ "ring-offset": [isNumber, isArbitraryLength] }], "ring-offset-color": [{ "ring-offset": scaleColor() }], "inset-ring-w": [{ "inset-ring": scaleBorderWidth() }], "inset-ring-color": [{ "inset-ring": scaleColor() }], "text-shadow": [{ "text-shadow": ["none", themeTextShadow, isArbitraryVariableShadow, isArbitraryShadow] }], "text-shadow-color": [{ "text-shadow": scaleColor() }], opacity: [{ opacity: [isNumber, isArbitraryVariable, isArbitraryValue] }], "mix-blend": [{ "mix-blend": [...scaleBlendMode(), "plus-darker", "plus-lighter"] }], "bg-blend": [{ "bg-blend": scaleBlendMode() }], "mask-clip": [{ "mask-clip": ["border", "padding", "content", "fill", "stroke", "view"] }, "mask-no-clip"], "mask-composite": [{ mask: ["add", "subtract", "intersect", "exclude"] }], "mask-image-linear-pos": [{ "mask-linear": [isNumber] }], "mask-image-linear-from-pos": [{ "mask-linear-from": scaleMaskImagePosition() }], "mask-image-linear-to-pos": [{ "mask-linear-to": scaleMaskImagePosition() }], "mask-image-linear-from-color": [{ "mask-linear-from": scaleColor() }], "mask-image-linear-to-color": [{ "mask-linear-to": scaleColor() }], "mask-image-t-from-pos": [{ "mask-t-from": scaleMaskImagePosition() }], "mask-image-t-to-pos": [{ "mask-t-to": scaleMaskImagePosition() }], "mask-image-t-from-color": [{ "mask-t-from": scaleColor() }], "mask-image-t-to-color": [{ "mask-t-to": scaleColor() }], "mask-image-r-from-pos": [{ "mask-r-from": scaleMaskImagePosition() }], "mask-image-r-to-pos": [{ "mask-r-to": scaleMaskImagePosition() }], "mask-image-r-from-color": [{ "mask-r-from": scaleColor() }], "mask-image-r-to-color": [{ "mask-r-to": scaleColor() }], "mask-image-b-from-pos": [{ "mask-b-from": scaleMaskImagePosition() }], "mask-image-b-to-pos": [{ "mask-b-to": scaleMaskImagePosition() }], "mask-image-b-from-color": [{ "mask-b-from": scaleColor() }], "mask-image-b-to-color": [{ "mask-b-to": scaleColor() }], "mask-image-l-from-pos": [{ "mask-l-from": scaleMaskImagePosition() }], "mask-image-l-to-pos": [{ "mask-l-to": scaleMaskImagePosition() }], "mask-image-l-from-color": [{ "mask-l-from": scaleColor() }], "mask-image-l-to-color": [{ "mask-l-to": scaleColor() }], "mask-image-x-from-pos": [{ "mask-x-from": scaleMaskImagePosition() }], "mask-image-x-to-pos": [{ "mask-x-to": scaleMaskImagePosition() }], "mask-image-x-from-color": [{ "mask-x-from": scaleColor() }], "mask-image-x-to-color": [{ "mask-x-to": scaleColor() }], "mask-image-y-from-pos": [{ "mask-y-from": scaleMaskImagePosition() }], "mask-image-y-to-pos": [{ "mask-y-to": scaleMaskImagePosition() }], "mask-image-y-from-color": [{ "mask-y-from": scaleColor() }], "mask-image-y-to-color": [{ "mask-y-to": scaleColor() }], "mask-image-radial": [{ "mask-radial": [isArbitraryVariable, isArbitraryValue] }], "mask-image-radial-from-pos": [{ "mask-radial-from": scaleMaskImagePosition() }], "mask-image-radial-to-pos": [{ "mask-radial-to": scaleMaskImagePosition() }], "mask-image-radial-from-color": [{ "mask-radial-from": scaleColor() }], "mask-image-radial-to-color": [{ "mask-radial-to": scaleColor() }], "mask-image-radial-shape": [{ "mask-radial": ["circle", "ellipse"] }], "mask-image-radial-size": [{ "mask-radial": [{ closest: ["side", "corner"], farthest: ["side", "corner"] }] }], "mask-image-radial-pos": [{ "mask-radial-at": scalePosition() }], "mask-image-conic-pos": [{ "mask-conic": [isNumber] }], "mask-image-conic-from-pos": [{ "mask-conic-from": scaleMaskImagePosition() }], "mask-image-conic-to-pos": [{ "mask-conic-to": scaleMaskImagePosition() }], "mask-image-conic-from-color": [{ "mask-conic-from": scaleColor() }], "mask-image-conic-to-color": [{ "mask-conic-to": scaleColor() }], "mask-mode": [{ mask: ["alpha", "luminance", "match"] }], "mask-origin": [{ "mask-origin": ["border", "padding", "content", "fill", "stroke", "view"] }], "mask-position": [{ mask: scaleBgPosition() }], "mask-repeat": [{ mask: scaleBgRepeat() }], "mask-size": [{ mask: scaleBgSize() }], "mask-type": [{ "mask-type": ["alpha", "luminance"] }], "mask-image": [{ mask: ["none", isArbitraryVariable, isArbitraryValue] }], filter: [{ filter: [ "", "none", isArbitraryVariable, isArbitraryValue ] }], blur: [{ blur: scaleBlur() }], brightness: [{ brightness: [isNumber, isArbitraryVariable, isArbitraryValue] }], contrast: [{ contrast: [isNumber, isArbitraryVariable, isArbitraryValue] }], "drop-shadow": [{ "drop-shadow": [ "", "none", themeDropShadow, isArbitraryVariableShadow, isArbitraryShadow ] }], "drop-shadow-color": [{ "drop-shadow": scaleColor() }], grayscale: [{ grayscale: ["", isNumber, isArbitraryVariable, isArbitraryValue] }], "hue-rotate": [{ "hue-rotate": [isNumber, isArbitraryVariable, isArbitraryValue] }], invert: [{ invert: ["", isNumber, isArbitraryVariable, isArbitraryValue] }], saturate: [{ saturate: [isNumber, isArbitraryVariable, isArbitraryValue] }], sepia: [{ sepia: ["", isNumber, isArbitraryVariable, isArbitraryValue] }], "backdrop-filter": [{ "backdrop-filter": [ "", "none", isArbitraryVariable, isArbitraryValue ] }], "backdrop-blur": [{ "backdrop-blur": scaleBlur() }], "backdrop-brightness": [{ "backdrop-brightness": [isNumber, isArbitraryVariable, isArbitraryValue] }], "backdrop-contrast": [{ "backdrop-contrast": [isNumber, isArbitraryVariable, isArbitraryValue] }], "backdrop-grayscale": [{ "backdrop-grayscale": ["", isNumber, isArbitraryVariable, isArbitraryValue] }], "backdrop-hue-rotate": [{ "backdrop-hue-rotate": [isNumber, isArbitraryVariable, isArbitraryValue] }], "backdrop-invert": [{ "backdrop-invert": ["", isNumber, isArbitraryVariable, isArbitraryValue] }], "backdrop-opacity": [{ "backdrop-opacity": [isNumber, isArbitraryVariable, isArbitraryValue] }], "backdrop-saturate": [{ "backdrop-saturate": [isNumber, isArbitraryVariable, isArbitraryValue] }], "backdrop-sepia": [{ "backdrop-sepia": ["", isNumber, isArbitraryVariable, isArbitraryValue] }], "border-collapse": [{ border: ["collapse", "separate"] }], "border-spacing": [{ "border-spacing": scaleUnambiguousSpacing() }], "border-spacing-x": [{ "border-spacing-x": scaleUnambiguousSpacing() }], "border-spacing-y": [{ "border-spacing-y": scaleUnambiguousSpacing() }], "table-layout": [{ table: ["auto", "fixed"] }], caption: [{ caption: ["top", "bottom"] }], transition: [{ transition: ["", "all", "colors", "opacity", "shadow", "transform", "none", isArbitraryVariable, isArbitraryValue] }], "transition-behavior": [{ transition: ["normal", "discrete"] }], duration: [{ duration: [isNumber, "initial", isArbitraryVariable, isArbitraryValue] }], ease: [{ ease: ["linear", "initial", themeEase, isArbitraryVariable, isArbitraryValue] }], delay: [{ delay: [isNumber, isArbitraryVariable, isArbitraryValue] }], animate: [{ animate: ["none", themeAnimate, isArbitraryVariable, isArbitraryValue] }], backface: [{ backface: ["hidden", "visible"] }], perspective: [{ perspective: [themePerspective, isArbitraryVariable, isArbitraryValue] }], "perspective-origin": [{ "perspective-origin": scalePositionWithArbitrary() }], rotate: [{ rotate: scaleRotate() }], "rotate-x": [{ "rotate-x": scaleRotate() }], "rotate-y": [{ "rotate-y": scaleRotate() }], "rotate-z": [{ "rotate-z": scaleRotate() }], scale: [{ scale: scaleScale() }], "scale-x": [{ "scale-x": scaleScale() }], "scale-y": [{ "scale-y": scaleScale() }], "scale-z": [{ "scale-z": scaleScale() }], "scale-3d": ["scale-3d"], skew: [{ skew: scaleSkew() }], "skew-x": [{ "skew-x": scaleSkew() }], "skew-y": [{ "skew-y": scaleSkew() }], transform: [{ transform: [isArbitraryVariable, isArbitraryValue, "", "none", "gpu", "cpu"] }], "transform-origin": [{ origin: scalePositionWithArbitrary() }], "transform-style": [{ transform: ["3d", "flat"] }], translate: [{ translate: scaleTranslate() }], "translate-x": [{ "translate-x": scaleTranslate() }], "translate-y": [{ "translate-y": scaleTranslate() }], "translate-z": [{ "translate-z": scaleTranslate() }], "translate-none": ["translate-none"], accent: [{ accent: scaleColor() }], appearance: [{ appearance: ["none", "auto"] }], "caret-color": [{ caret: scaleColor() }], "color-scheme": [{ scheme: ["normal", "dark", "light", "light-dark", "only-dark", "only-light"] }], cursor: [{ cursor: ["auto", "default", "pointer", "wait", "text", "move", "help", "not-allowed", "none", "context-menu", "progress", "cell", "crosshair", "vertical-text", "alias", "copy", "no-drop", "grab", "grabbing", "all-scroll", "col-resize", "row-resize", "n-resize", "e-resize", "s-resize", "w-resize", "ne-resize", "nw-resize", "se-resize", "sw-resize", "ew-resize", "ns-resize", "nesw-resize", "nwse-resize", "zoom-in", "zoom-out", isArbitraryVariable, isArbitraryValue] }], "field-sizing": [{ "field-sizing": ["fixed", "content"] }], "pointer-events": [{ "pointer-events": ["auto", "none"] }], resize: [{ resize: ["none", "", "y", "x"] }], "scroll-behavior": [{ scroll: ["auto", "smooth"] }], "scroll-m": [{ "scroll-m": scaleUnambiguousSpacing() }], "scroll-mx": [{ "scroll-mx": scaleUnambiguousSpacing() }], "scroll-my": [{ "scroll-my": scaleUnambiguousSpacing() }], "scroll-ms": [{ "scroll-ms": scaleUnambiguousSpacing() }], "scroll-me": [{ "scroll-me": scaleUnambiguousSpacing() }], "scroll-mt": [{ "scroll-mt": scaleUnambiguousSpacing() }], "scroll-mr": [{ "scroll-mr": scaleUnambiguousSpacing() }], "scroll-mb": [{ "scroll-mb": scaleUnambiguousSpacing() }], "scroll-ml": [{ "scroll-ml": scaleUnambiguousSpacing() }], "scroll-p": [{ "scroll-p": scaleUnambiguousSpacing() }], "scroll-px": [{ "scroll-px": scaleUnambiguousSpacing() }], "scroll-py": [{ "scroll-py": scaleUnambiguousSpacing() }], "scroll-ps": [{ "scroll-ps": scaleUnambiguousSpacing() }], "scroll-pe": [{ "scroll-pe": scaleUnambiguousSpacing() }], "scroll-pt": [{ "scroll-pt": scaleUnambiguousSpacing() }], "scroll-pr": [{ "scroll-pr": scaleUnambiguousSpacing() }], "scroll-pb": [{ "scroll-pb": scaleUnambiguousSpacing() }], "scroll-pl": [{ "scroll-pl": scaleUnambiguousSpacing() }], "snap-align": [{ snap: ["start", "end", "center", "align-none"] }], "snap-stop": [{ snap: ["normal", "always"] }], "snap-type": [{ snap: ["none", "x", "y", "both"] }], "snap-strictness": [{ snap: ["mandatory", "proximity"] }], touch: [{ touch: ["auto", "none", "manipulation"] }], "touch-x": [{ "touch-pan": ["x", "left", "right"] }], "touch-y": [{ "touch-pan": ["y", "up", "down"] }], "touch-pz": ["touch-pinch-zoom"], select: [{ select: ["none", "text", "all", "auto"] }], "will-change": [{ "will-change": ["auto", "scroll", "contents", "transform", isArbitraryVariable, isArbitraryValue] }], fill: [{ fill: ["none", ...scaleColor()] }], "stroke-w": [{ stroke: [isNumber, isArbitraryVariableLength, isArbitraryLength, isArbitraryNumber] }], stroke: [{ stroke: ["none", ...scaleColor()] }], "forced-color-adjust": [{ "forced-color-adjust": ["auto", "none"] }] }, conflictingClassGroups: { overflow: ["overflow-x", "overflow-y"], overscroll: ["overscroll-x", "overscroll-y"], inset: ["inset-x", "inset-y", "start", "end", "top", "right", "bottom", "left"], "inset-x": ["right", "left"], "inset-y": ["top", "bottom"], flex: ["basis", "grow", "shrink"], gap: ["gap-x", "gap-y"], p: ["px", "py", "ps", "pe", "pt", "pr", "pb", "pl"], px: ["pr", "pl"], py: ["pt", "pb"], m: ["mx", "my", "ms", "me", "mt", "mr", "mb", "ml"], mx: ["mr", "ml"], my: ["mt", "mb"], size: ["w", "h"], "font-size": ["leading"], "fvn-normal": ["fvn-ordinal", "fvn-slashed-zero", "fvn-figure", "fvn-spacing", "fvn-fraction"], "fvn-ordinal": ["fvn-normal"], "fvn-slashed-zero": ["fvn-normal"], "fvn-figure": ["fvn-normal"], "fvn-spacing": ["fvn-normal"], "fvn-fraction": ["fvn-normal"], "line-clamp": ["display", "overflow"], rounded: ["rounded-s", "rounded-e", "rounded-t", "rounded-r", "rounded-b", "rounded-l", "rounded-ss", "rounded-se", "rounded-ee", "rounded-es", "rounded-tl", "rounded-tr", "rounded-br", "rounded-bl"], "rounded-s": ["rounded-ss", "rounded-es"], "rounded-e": ["rounded-se", "rounded-ee"], "rounded-t": ["rounded-tl", "rounded-tr"], "rounded-r": ["rounded-tr", "rounded-br"], "rounded-b": ["rounded-br", "rounded-bl"], "rounded-l": ["rounded-tl", "rounded-bl"], "border-spacing": ["border-spacing-x", "border-spacing-y"], "border-w": ["border-w-x", "border-w-y", "border-w-s", "border-w-e", "border-w-t", "border-w-r", "border-w-b", "border-w-l"], "border-w-x": ["border-w-r", "border-w-l"], "border-w-y": ["border-w-t", "border-w-b"], "border-color": ["border-color-x", "border-color-y", "border-color-s", "border-color-e", "border-color-t", "border-color-r", "border-color-b", "border-color-l"], "border-color-x": ["border-color-r", "border-color-l"], "border-color-y": ["border-color-t", "border-color-b"], translate: ["translate-x", "translate-y", "translate-none"], "translate-none": ["translate", "translate-x", "translate-y", "translate-z"], "scroll-m": ["scroll-mx", "scroll-my", "scroll-ms", "scroll-me", "scroll-mt", "scroll-mr", "scroll-mb", "scroll-ml"], "scroll-mx": ["scroll-mr", "scroll-ml"], "scroll-my": ["scroll-mt", "scroll-mb"], "scroll-p": ["scroll-px", "scroll-py", "scroll-ps", "scroll-pe", "scroll-pt", "scroll-pr", "scroll-pb", "scroll-pl"], "scroll-px": ["scroll-pr", "scroll-pl"], "scroll-py": ["scroll-pt", "scroll-pb"], touch: ["touch-x", "touch-y", "touch-pz"], "touch-x": ["touch"], "touch-y": ["touch"], "touch-pz": ["touch"] }, conflictingClassGroupModifiers: { "font-size": ["leading"] }, orderSensitiveModifiers: ["*", "**", "after", "backdrop", "before", "details-content", "file", "first-letter", "first-line", "marker", "placeholder", "selection"] }; }; const twMerge = createTailwindMerge(getDefaultConfig); function cn(...inputs) { return twMerge(clsx(inputs)); } let globalHighlighter = null; function initHighlighter(container = document.body) { if (globalHighlighter) { globalHighlighter.remove(); } globalHighlighter = new Highlighter(container, { highlightTag: "span", highlightClass: "highlight-keywords", activeClass: "highlight-active", skipTags: ["SCRIPT", "STYLE", "NOSCRIPT"], scrollOptions: { behavior: "smooth", block: "center" }, enablePerformanceOptimization: true }); return globalHighlighter; } function getHighlighter() { if (!globalHighlighter) { globalHighlighter = initHighlighter(); } return globalHighlighter; } function generateHighlightStyle(styleText) { return `.highlight-keywords{${styleText}}`; } function getTextNodeCount(element) { let count = 0; const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null); while (walker.nextNode()) { count++; } return count; } function addDebugLog(debugLogs, isDebugMode, level, message) { if (!isDebugMode) return; const timestamp = ( new Date()).toLocaleTimeString(); debugLogs.unshift({ timestamp, level, message }); if (debugLogs.length > 100) { debugLogs.splice(100); } const consoleMethods = { info: console.info, warn: console.warn, error: console.error }; consoleMethods[level](`[HighlightKeywords] ${message}`); } function refreshDebugInfo(debugInfo) { debugInfo.currentUrl = window.location.href; debugInfo.pageTitle = document.title; debugInfo.userAgent = navigator.userAgent; debugInfo.scriptVersion = window.GM_info?.script?.version || "未知"; debugInfo.pageLoadTime = Math.round( performance.timing?.loadEventEnd - performance.timing?.navigationStart ) || 0; debugInfo.scriptInitTime = Math.round(performance.now()); debugInfo.domElementCount = document.querySelectorAll("*").length; debugInfo.textNodeCount = getTextNodeCount(document.body); debugInfo.highlightElementCount = document.querySelectorAll( "[data-highlight-keyword]" ).length; debugInfo.pageHeight = Math.max( document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight ); if ("memory" in performance) { const memory = performance.memory; debugInfo.memoryUsage = `${Math.round( memory.usedJSHeapSize / 1024 / 1024 )}MB / ${Math.round(memory.totalJSHeapSize / 1024 / 1024)}MB`; } else { debugInfo.memoryUsage = "不支持"; } } function exportDebugInfo(debugInfo, highlightState, ruleList, matchedRuleList, debugLogs) { const exportData = { timestamp: ( new Date()).toISOString(), debugInfo, highlightState: { totalCount: highlightState.totalCount, currentIndex: highlightState.currentIndex, keywords: highlightState.keywords }, ruleList, matchedRuleList, logs: debugLogs }; const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: "application/json" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `highlight-keywords-debug-${( new Date()).toISOString().slice(0, 19).replace(/:/g, "-")}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); ElementPlus.ElMessage.success("调试信息已导出"); } function copyToClipboard(text) { navigator.clipboard.writeText(text); ElementPlus.ElMessage.success("复制成功"); } function previewStyle(highlightStyle, activeStyle) { const previewHighlight = document.querySelector( ".preview-highlight" ); const previewActive = document.querySelector(".preview-active"); if (previewHighlight) { previewHighlight.style.cssText = highlightStyle; } if (previewActive) { previewActive.style.cssText = activeStyle; } ElementPlus.ElMessage.success("样式预览已更新"); } function useHighlightApp() { const ruleFormRef = vue.ref(); const dialogVisible = vue.ref(false); const ruleList = vue.ref([]); const highlightState = vue.reactive({ totalCount: 0, currentIndex: -1, highlighter: null, keywords: [] }); const panelExpanded = vue.ref(false); const panelPinned = vue.ref(_GM_getValue("panel-pinned", false)); const panelHidden = vue.ref(false); const panelHideTimeout = vue.ref(null); const isDarkMode = vue.ref( _GM_getValue( "dark-mode", window.matchMedia("(prefers-color-scheme: dark)").matches ) ); const isDebugMode = vue.ref(false); const debugDialogVisible = vue.ref(false); const activeDebugTab = vue.ref("basic"); const debugLogs = vue.ref([]); const debugInfo = vue.reactive({ currentUrl: "", pageTitle: "", userAgent: "", scriptVersion: "", pageLoadTime: 0, scriptInitTime: 0, highlightTime: 0, memoryUsage: "", domElementCount: 0, textNodeCount: 0, highlightElementCount: 0, pageHeight: 0 }); const pageState = vue.reactive({ globalStyle: void 0 }); const form = vue.reactive(defaultFormData); const matchedRuleList = vue.computed(() => { return ruleList.value.filter((rule) => { var urlPattern = new RegExp(rule.matchUrl); console.log({ match: rule.matchUrl, href: window.location.href, isMatch: urlPattern.test(window.location.href) }); return urlPattern.test(window.location.href); }); }); const matchedKeywords = vue.computed(() => { const keywordsLists = matchedRuleList.value.map((item) => { return item.keywords; }); console.log({ keywordsLists, matchedRuleList: matchedRuleList.value }); return [...new Set(keywordsLists.flat())]; }); const dynamicColors = vue.computed( () => generateDynamicColors(isDarkMode.value) ); const handlePanelHover = (isHover) => { if (!panelPinned.value && !panelHidden.value) { panelExpanded.value = isHover; } }; const togglePanelPin = () => { panelPinned.value = !panelPinned.value; _GM_setValue("panel-pinned", panelPinned.value); if (panelPinned.value) { panelExpanded.value = true; } else { panelExpanded.value = false; } }; const toggleDarkMode = () => { isDarkMode.value = !isDarkMode.value; _GM_setValue("dark-mode", isDarkMode.value); }; const handleClosePanel = () => { panelHidden.value = true; panelExpanded.value = false; panelPinned.value = false; if (panelHideTimeout.value) { clearTimeout(panelHideTimeout.value); } panelHideTimeout.value = setTimeout( () => { panelHidden.value = false; }, 60 * 60 * 1e3 ); }; function loadGlobalStyle(styleText) { if (pageState.globalStyle) { pageState.globalStyle.remove(); } const style = document.createElement("style"); style.textContent = styleText; document.head.appendChild(style); pageState.globalStyle = style; } function updateHighlightStyle() { const highlightStyle = generateHighlightStyle(form.highlightStyle); loadGlobalStyle(highlightStyle); } const handlePrevious = () => { if (highlightState.totalCount === 0) { addDebugLog( debugLogs.value, isDebugMode.value, "warn", "没有高亮项,无法导航到上一个" ); return; } const highlighter = getHighlighter(); highlighter.jumpToPreviousOffscreen(); highlightState.currentIndex = highlighter.getCurrentIndex(); addDebugLog( debugLogs.value, isDebugMode.value, "info", `导航到上一个高亮项,当前索引: ${highlightState.currentIndex + 1}/${highlightState.totalCount}` ); }; const handleNext = () => { if (highlightState.totalCount === 0) { addDebugLog( debugLogs.value, isDebugMode.value, "warn", "没有高亮项,无法导航到下一个" ); return; } const highlighter = getHighlighter(); highlighter.jumpToNextOffscreen(); highlightState.currentIndex = highlighter.getCurrentIndex(); addDebugLog( debugLogs.value, isDebugMode.value, "info", `导航到下一个高亮项,当前索引: ${highlightState.currentIndex + 1}/${highlightState.totalCount}` ); }; const handleEnableHighlight = async () => { if (matchedKeywords.value.length === 0) { ElementPlus.ElMessage.warning("当前页面没有匹配的关键词规则"); return; } try { if (!pageState.globalStyle) { loadGlobalStyle(generateHighlightStyle(form.highlightStyle)); } if (!highlightState.highlighter) { initHighlighter(document.body); } await highlightMatchedKeywords(); ElementPlus.ElMessage.success( `已启用高亮,找到 ${highlightState.totalCount} 个匹配项` ); } catch (error) { console.error("启用高亮时出错:", error); ElementPlus.ElMessage.error("启用高亮失败"); } }; const handleClearHighlight = () => { const highlighter = getHighlighter(); highlighter.remove(); highlightState.totalCount = 0; highlightState.currentIndex = -1; highlightState.keywords = []; addDebugLog(debugLogs.value, isDebugMode.value, "info", "已清除所有高亮"); ElementPlus.ElMessage.success("已清除所有高亮"); }; const handleThemeChange = (theme) => { if (themePresets[theme]) { const preset = themePresets[theme]; form.highlightStyle = preset.highlight; form.activeStyle = preset.active; } }; const toggleDebugDialog = () => { debugDialogVisible.value = !debugDialogVisible.value; if (debugDialogVisible.value) { refreshDebugInfo(debugInfo); } }; const handleCloseDebug = () => { debugDialogVisible.value = false; }; const clearDebugLogs = () => { debugLogs.value = []; addDebugLog(debugLogs.value, isDebugMode.value, "info", "调试日志已清空"); }; const handlePreviewStyle = () => { previewStyle(form.highlightStyle, form.activeStyle); }; const handleCopyJson = () => { copyToClipboard(form.configJson); }; function loadRuleList() { const vv = _GM_getValue(CONFIG_NAME, []); ruleList.value = vv; form.configJson = JSON.stringify(ruleList.value); } function handleOpenPanel() { dialogVisible.value = true; } function handleClose() { dialogVisible.value = false; } const handleUpdateConfig = async () => { try { const configList = JSON.parse(form.configJson); const [isValid, errorMessage] = validateConfig(configList); if (!isValid) { ElementPlus.ElMessage.error(errorMessage); addDebugLog(debugLogs.value, isDebugMode.value, "error", errorMessage); return; } _GM_setValue(CONFIG_NAME, configList); ElementPlus.ElMessage.success("更新成功"); loadRuleList(); dialogVisible.value = false; addDebugLog(debugLogs.value, isDebugMode.value, "info", "配置更新成功"); } catch (error) { console.error(error); ElementPlus.ElMessage.error("配置格式错误"); addDebugLog( debugLogs.value, isDebugMode.value, "error", `配置更新失败:${error}` ); } }; async function highlightMatchedKeywords() { const startTime = performance.now(); console.log({ matchedKeywords: matchedKeywords.value }); addDebugLog( debugLogs.value, isDebugMode.value, "info", `开始高亮匹配的关键词: ${matchedKeywords.value.join(", ")}` ); if (matchedKeywords.value.length < 1) { addDebugLog( debugLogs.value, isDebugMode.value, "info", "没有匹配的关键词" ); return; } try { const highlighter = getHighlighter(); highlightState.highlighter = highlighter; addDebugLog( debugLogs.value, isDebugMode.value, "info", "高亮器实例获取成功" ); const count = await highlighter.apply(matchedKeywords.value, { caseSensitive: false, wholeWord: false }); highlightState.totalCount = count; highlightState.currentIndex = count > 0 ? 0 : -1; highlightState.keywords = matchedKeywords.value; const endTime = performance.now(); debugInfo.highlightTime = Math.round(endTime - startTime); const message = `成功高亮 ${count} 个匹配项,耗时 ${debugInfo.highlightTime}ms`; console.log(message); addDebugLog(debugLogs.value, isDebugMode.value, "info", message); } catch (error) { const errorMessage = `高亮关键词时出错: ${error instanceof Error ? error.message : String(error)}`; console.error(errorMessage, error); addDebugLog(debugLogs.value, isDebugMode.value, "error", errorMessage); } } vue.onMounted(async () => { const initStartTime = performance.now(); const defaultDebugMode = false; isDebugMode.value = _GM_getValue("debugMode", defaultDebugMode); _GM_setValue("debugMode", isDebugMode.value); addDebugLog(debugLogs.value, isDebugMode.value, "info", "脚本开始初始化"); console.log("init"); loadRuleList(); addDebugLog( debugLogs.value, isDebugMode.value, "info", `规则列表加载完成,共 ${ruleList.value.length} 条规则` ); if (panelPinned.value) { panelExpanded.value = true; } addDebugLog( debugLogs.value, isDebugMode.value, "info", `面板固定状态: ${panelPinned.value ? "固定" : "浮动"}` ); console.log({ matchedKeywords: matchedKeywords.value }); if (matchedKeywords.value.length > 0) { loadGlobalStyle(generateHighlightStyle(form.highlightStyle)); initHighlighter(document.body); addDebugLog( debugLogs.value, isDebugMode.value, "info", "高亮器初始化完成" ); await highlightMatchedKeywords(); } _GM_registerMenuCommand("打开配置面板", handleOpenPanel); _GM_registerMenuCommand("切换调试模式", () => { isDebugMode.value = !isDebugMode.value; _GM_setValue("debugMode", isDebugMode.value); ElementPlus.ElMessage.success(`调试模式已${isDebugMode.value ? "开启" : "关闭"}`); addDebugLog( debugLogs.value, isDebugMode.value, "info", `调试模式已${isDebugMode.value ? "开启" : "关闭"}` ); }); const initEndTime = performance.now(); debugInfo.scriptInitTime = Math.round(initEndTime - initStartTime); addDebugLog( debugLogs.value, isDebugMode.value, "info", `脚本初始化完成,耗时 ${debugInfo.scriptInitTime}ms` ); }); vue.onUnmounted(() => { addDebugLog( debugLogs.value, isDebugMode.value, "info", "组件卸载,清理资源" ); if (highlightState.highlighter) { highlightState.highlighter.remove(); addDebugLog(debugLogs.value, isDebugMode.value, "info", "高亮已清理"); } if (pageState.globalStyle) { pageState.globalStyle.remove(); addDebugLog(debugLogs.value, isDebugMode.value, "info", "全局样式已清理"); } if (panelHideTimeout.value) { clearTimeout(panelHideTimeout.value); addDebugLog(debugLogs.value, isDebugMode.value, "info", "定时器已清理"); } }); return { ruleFormRef, dialogVisible, ruleList, highlightState, panelExpanded, panelPinned, panelHidden, panelHideTimeout, isDarkMode, isDebugMode, debugDialogVisible, activeDebugTab, debugLogs, debugInfo, pageState, form, matchedRuleList, matchedKeywords, dynamicColors, handlePanelHover, togglePanelPin, toggleDarkMode, handleClosePanel, loadGlobalStyle, updateHighlightStyle, handlePrevious, handleNext, handleEnableHighlight, handleClearHighlight, handleThemeChange, toggleDebugDialog, handleCloseDebug, clearDebugLogs, handlePreviewStyle, handleCopyJson, loadRuleList, handleOpenPanel, handleClose, handleUpdateConfig, highlightMatchedKeywords, refreshDebugInfo, exportDebugInfo }; } const _hoisted_1 = { class: "flex" }; const _sfc_main$1 = vue.defineComponent({ __name: "index", setup(__props) { const { ruleFormRef, dialogVisible, ruleList, highlightState, panelExpanded, panelPinned, panelHidden, isDarkMode, isDebugMode, debugDialogVisible, activeDebugTab, debugLogs, debugInfo, form, matchedRuleList, matchedKeywords, dynamicColors, handlePanelHover, togglePanelPin, toggleDarkMode, handleClosePanel, handlePrevious, handleNext, handleEnableHighlight, handleClearHighlight, handleThemeChange, toggleDebugDialog, handleCloseDebug, clearDebugLogs, handlePreviewStyle, handleCopyJson, handleOpenPanel, handleClose, handleUpdateConfig, refreshDebugInfo: refreshDebugInfo2, exportDebugInfo: exportDebugInfo2 } = useHighlightApp(); return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [ vue.unref(matchedKeywords).length > 0 && !vue.unref(panelHidden) ? (vue.openBlock(), vue.createElementBlock("div", { key: 0, class: vue.normalizeClass([ "fixed top-1/2 right-0 -translate-y-1/2 z-[9999] text-sm shadow-2xl transition-all duration-300 ease-out min-h-[350px] overflow-hidden rounded-l-xl backdrop-blur-md", vue.unref(cn)( "highlight-nav-panel", { "panel-expanded": vue.unref(panelExpanded), "panel-pinned": vue.unref(panelPinned) }, vue.unref(panelExpanded) || vue.unref(panelPinned) ? "w-[280px]" : "w-[50px]", vue.unref(dynamicColors).borderColor, vue.unref(dynamicColors).textPrimary, vue.unref(isDarkMode) ? "dark" : "" ) ]), onMouseenter: _cache[0] || (_cache[0] = ($event) => vue.unref(handlePanelHover)(true)), onMouseleave: _cache[1] || (_cache[1] = ($event) => vue.unref(handlePanelHover)(false)), style: vue.normalizeStyle({ background: vue.unref(dynamicColors).panelBg, boxShadow: vue.unref(isDarkMode) ? "-6px 0 20px rgba(0, 0, 0, 0.6)" : "-6px 0 20px rgba(0, 0, 0, 0.15)" }) }, [ vue.createElementVNode("div", _hoisted_1, [ vue.createVNode(_sfc_main$5, { "is-dark-mode": vue.unref(isDarkMode), "panel-pinned": vue.unref(panelPinned), "is-debug-mode": vue.unref(isDebugMode), "dynamic-colors": vue.unref(dynamicColors), onToggleDarkMode: vue.unref(toggleDarkMode), onTogglePanelPin: vue.unref(togglePanelPin), onToggleDebugDialog: vue.unref(toggleDebugDialog), onClosePanel: vue.unref(handleClosePanel) }, null, 8, ["is-dark-mode", "panel-pinned", "is-debug-mode", "dynamic-colors", "onToggleDarkMode", "onTogglePanelPin", "onToggleDebugDialog", "onClosePanel"]), vue.createVNode(_sfc_main$4, { "panel-expanded": vue.unref(panelExpanded), "panel-pinned": vue.unref(panelPinned), "highlight-state": vue.unref(highlightState), "matched-keywords": vue.unref(matchedKeywords), "dynamic-colors": vue.unref(dynamicColors), "is-dark-mode": vue.unref(isDarkMode), onPrevious: vue.unref(handlePrevious), onNext: vue.unref(handleNext), onEnableHighlight: vue.unref(handleEnableHighlight), onClearHighlight: vue.unref(handleClearHighlight), onOpenConfig: vue.unref(handleOpenPanel) }, null, 8, ["panel-expanded", "panel-pinned", "highlight-state", "matched-keywords", "dynamic-colors", "is-dark-mode", "onPrevious", "onNext", "onEnableHighlight", "onClearHighlight", "onOpenConfig"]) ]) ], 38)) : vue.createCommentVNode("", true), vue.createVNode(ConfigDialog, { visible: vue.unref(dialogVisible), "onUpdate:visible": _cache[2] || (_cache[2] = ($event) => vue.isRef(dialogVisible) ? dialogVisible.value = $event : null), form: vue.unref(form), "rule-form-ref": vue.unref(ruleFormRef), onClose: vue.unref(handleClose), onCopyJson: vue.unref(handleCopyJson), onPreviewStyle: vue.unref(handlePreviewStyle), onUpdateConfig: vue.unref(handleUpdateConfig), onThemeChange: vue.unref(handleThemeChange) }, null, 8, ["visible", "form", "rule-form-ref", "onClose", "onCopyJson", "onPreviewStyle", "onUpdateConfig", "onThemeChange"]), vue.createVNode(DebugDialog, { visible: vue.unref(debugDialogVisible), "onUpdate:visible": _cache[3] || (_cache[3] = ($event) => vue.isRef(debugDialogVisible) ? debugDialogVisible.value = $event : null), "active-tab": vue.unref(activeDebugTab), "debug-info": vue.unref(debugInfo), "highlight-state": vue.unref(highlightState), "rule-list": vue.unref(ruleList), "matched-rule-list": vue.unref(matchedRuleList), "matched-keywords": vue.unref(matchedKeywords), "debug-logs": vue.unref(debugLogs), onClose: vue.unref(handleCloseDebug), onClearLogs: vue.unref(clearDebugLogs), onExportDebug: _cache[4] || (_cache[4] = () => vue.unref(exportDebugInfo2)( vue.unref(debugInfo), vue.unref(highlightState), vue.unref(ruleList), vue.unref(matchedRuleList), vue.unref(debugLogs) )), onRefreshInfo: _cache[5] || (_cache[5] = () => vue.unref(refreshDebugInfo2)(vue.unref(debugInfo))) }, null, 8, ["visible", "active-tab", "debug-info", "highlight-state", "rule-list", "matched-rule-list", "matched-keywords", "debug-logs", "onClose", "onClearLogs"]) ], 64); }; } }); const app$1 = _export_sfc(_sfc_main$1, [["__scopeId", "data-v-e0b7c8bd"]]); const styleCss = '@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-500:oklch(63.7% .237 25.331);--color-yellow-500:oklch(79.5% .184 86.047);--color-blue-50:oklch(97% .014 254.604);--color-blue-500:oklch(62.3% .214 259.815);--color-purple-500:oklch(62.7% .265 303.9);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-800:oklch(27.8% .033 256.848);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--font-weight-medium:500;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--blur-md:12px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1)}}@layer base,components;@layer utilities{.visible{visibility:visible}.fixed{position:fixed}.top-1\\/2{top:50%}.right-0{right:calc(var(--spacing)*0)}.z-\\[9999\\]{z-index:9999}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.block{display:block}.contents{display:contents}.flex{display:flex}.h-\\[140px\\]{height:140px}.min-h-\\[350px\\]{min-height:350px}.w-\\[50px\\]{width:50px}.w-\\[260px\\]{width:260px}.w-\\[280px\\]{width:280px}.w-full{width:100%}.flex-1{flex:1}.-translate-y-1\\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1\\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-4{gap:calc(var(--spacing)*4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*2)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-x-reverse)))}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-l-xl{border-top-left-radius:var(--radius-xl);border-bottom-left-radius:var(--radius-xl)}.rounded-r-xl{border-top-right-radius:var(--radius-xl);border-bottom-right-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-gray-200\\/50{border-color:#e5e7eb80}@supports (color:color-mix(in lab,red,red)){.border-gray-200\\/50{border-color:color-mix(in oklab,var(--color-gray-200)50%,transparent)}}.border-slate-600\\/30{border-color:#45556c4d}@supports (color:color-mix(in lab,red,red)){.border-slate-600\\/30{border-color:color-mix(in oklab,var(--color-slate-600)30%,transparent)}}.bg-blue-50\\/50{background-color:#eff6ff80}@supports (color:color-mix(in lab,red,red)){.bg-blue-50\\/50{background-color:color-mix(in oklab,var(--color-blue-50)50%,transparent)}}.bg-blue-500\\/30{background-color:#3080ff4d}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\\/30{background-color:color-mix(in oklab,var(--color-blue-500)30%,transparent)}}.bg-purple-500\\/20{background-color:#ac4bff33}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\\/20{background-color:color-mix(in oklab,var(--color-purple-500)20%,transparent)}}.bg-red-500\\/20{background-color:#fb2c3633}@supports (color:color-mix(in lab,red,red)){.bg-red-500\\/20{background-color:color-mix(in oklab,var(--color-red-500)20%,transparent)}}.bg-slate-600\\/20{background-color:#45556c33}@supports (color:color-mix(in lab,red,red)){.bg-slate-600\\/20{background-color:color-mix(in oklab,var(--color-slate-600)20%,transparent)}}.bg-slate-700\\/30{background-color:#3141584d}@supports (color:color-mix(in lab,red,red)){.bg-slate-700\\/30{background-color:color-mix(in oklab,var(--color-slate-700)30%,transparent)}}.bg-slate-800\\/20{background-color:#1d293d33}@supports (color:color-mix(in lab,red,red)){.bg-slate-800\\/20{background-color:color-mix(in oklab,var(--color-slate-800)20%,transparent)}}.bg-white\\/10{background-color:#ffffff1a}@supports (color:color-mix(in lab,red,red)){.bg-white\\/10{background-color:color-mix(in oklab,var(--color-white)10%,transparent)}}.bg-white\\/20{background-color:#fff3}@supports (color:color-mix(in lab,red,red)){.bg-white\\/20{background-color:color-mix(in oklab,var(--color-white)20%,transparent)}}.bg-white\\/40{background-color:#fff6}@supports (color:color-mix(in lab,red,red)){.bg-white\\/40{background-color:color-mix(in oklab,var(--color-white)40%,transparent)}}.bg-yellow-500\\/30{background-color:#edb2004d}@supports (color:color-mix(in lab,red,red)){.bg-yellow-500\\/30{background-color:color-mix(in oklab,var(--color-yellow-500)30%,transparent)}}.p-1\\.5{padding:calc(var(--spacing)*1.5)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-800{color:var(--color-gray-800)}.text-slate-100{color:var(--color-slate-100)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-white{color:var(--color-white)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.backdrop-blur-\\[10px\\]{--tw-backdrop-blur:blur(10px);-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.backdrop-blur-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}@media(hover:hover){.hover\\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.hover\\:scale-110:hover{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x)var(--tw-scale-y)}}.active\\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x)var(--tw-scale-y)}.disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:opacity-50:disabled{opacity:.5}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}'; importCSS(styleCss); const cssLoader = (e) => _GM_addStyle(_GM_getResourceText(e)); cssLoader("element-plus/dist/index.css"); const _sfc_main = vue.defineComponent({ __name: "App", setup(__props) { const config = vue.reactive({ zIndex: 100 }); return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElConfigProvider), { locale: vue.unref(zhCn), zIndex: config.zIndex }, { default: vue.withCtx(() => [ vue.createVNode(app$1) ]), _: 1 }, 8, ["locale", "zIndex"]); }; } }); const app = vue.createApp(_sfc_main); const appContainer = (() => { const app2 = document.createElement("div"); app2.classList.add("tailwind"); document.documentElement.append(app2); return app2; })(); app.use(ElementPlus); app.mount(appContainer); })(Vue, ElementPlus);