Greasy Fork

Greasy Fork is available in English.

网页划词高亮工具

提供网页划词高亮功能

当前为 2025-03-13 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         网页划词高亮工具
// @namespace    http://tampermonkey.net/
// @version      0.1.1
// @description  提供网页划词高亮功能
// @author       sunny43
// @license      MIT
// @match        *://*/*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// ==/UserScript==

(function () {
    'use strict';

    const STYLE_PREFIX = 'sunny43-';

    // 全局变量
    let highlights = [];
    let currentPageUrl = window.location.href;
    let currentDomain = window.location.hostname;
    let settings = GM_getValue('highlight_settings', {
        colors: ['#ff909c', '#b89fff', '#74b4ff', '#70d382', '#ffcb7e'],
        activeColor: '#ff909c',
        minTextLength: 1,
        enableFuzzyMatch: true,
        maxContextDistance: 50,
        sidebarDescription: '高亮工具',
        sidebarWidth: 320,
        showFloatingButton: true
    });
    let savedRange = null; // 保存选区范围
    let ignoreNextClick = false; // 忽略下一次点击的标志
    let menuDisplayTimer = null; // 菜单显示定时器
    let menuOperationInProgress = false; // 添加菜单操作锁定
    // 禁用列表
    let disabledList = GM_getValue('disabled_list', {
        domains: [],
        urls: []
    });
    // 检查当前页面是否禁用高亮功能
    let isHighlightDisabled = disabledList.domains.includes(currentDomain) ||
        disabledList.urls.includes(currentPageUrl);
    let updateSidebarHighlights = null;

    GM_addStyle(`
        /* 高亮菜单样式 */
        .${STYLE_PREFIX}highlight-menu {
            position: absolute;
            background: #333336;
            border: none;
            border-radius: 24px;
            box-shadow: 0 4px 16px rgba(0,0,0,0.3);
            padding: 10px 8px;
            z-index: 9999;
            display: flex;
            flex-direction: row;
            align-items: center;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            color: #fff;
            opacity: 0; /* 初始隐藏 */
            transition: opacity 0.2s ease-in;
            pointer-events: none; /* 隐藏时不响应事件 */
        }
        .${STYLE_PREFIX}highlight-menu.${STYLE_PREFIX}show {
            opacity: 1;
            pointer-events: auto; /* 显示时响应事件 */
        }

        /* 菜单箭头样式 */
        .${STYLE_PREFIX}highlight-menu::after {
            content: '';
            position: absolute;
            bottom: -6px;
            left: var(--arrow-left, 50%);
            width: 12px;
            height: 6px;
            background-color: #333336;
            clip-path: polygon(0 0, 100% 0, 50% 100%);
            margin-left: -6px;
        }
        .${STYLE_PREFIX}highlight-menu.${STYLE_PREFIX}arrow-top::after {
            top: -6px;
            bottom: auto;
            clip-path: polygon(0 100%, 100% 100%, 50% 0);
        }

        /* 颜色选择区域 */
        .${STYLE_PREFIX}highlight-menu-colors {
            display: flex;
            flex-direction: row;
            align-items: center;
            margin: 0 2px;
            flex-wrap: nowrap;
            flex: 0 0 auto;
        }

        /* 颜色选择按钮 */
        .${STYLE_PREFIX}highlight-menu-color {
            width: 22px;
            height: 22px;
            border-radius: 50%;
            margin: 0 3px;
            cursor: pointer;
            position: relative;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: transform 0.15s ease;
            box-shadow: inset 0 0 0 1px rgba(255,255,255,0.12);
            flex-shrink: 0;
        }
        .${STYLE_PREFIX}highlight-menu-color:hover {
            transform: scale(1.12);
        }
        .${STYLE_PREFIX}highlight-menu-color.active::after {
            content: "";
            width: 12px;
            height: 12px;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23333336' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");
            background-repeat: no-repeat;
            background-position: center;
            background-size: contain;
        }

        /* 菜单按钮通用样式 */
        .${STYLE_PREFIX}highlight-menu-action {
            height: 22px;
            margin: 0 2px;
            cursor: pointer;
            padding: 0 10px;
            border-radius: 12px;
            color: #fff;
            font-size: 13px;
            background: rgba(255,255,255,0.1);
            border: none;
            transition: all 0.15s ease;
            white-space: nowrap;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
        }
        .${STYLE_PREFIX}highlight-menu-action:hover {
            background: rgba(255,255,255,0.2);
        }

        /* 删除按钮样式 */
        .${STYLE_PREFIX}highlight-action-delete {
            color: #f0f0f0;
            font-weight: 500;
            position: relative;
            overflow: hidden;
            transition: all 0.25s cubic-bezier(0.2, 0.8, 0.2, 1);
            margin-left: 3px;
        }
        .${STYLE_PREFIX}highlight-action-delete:hover {
            background: rgba(255,82,82,0.12);
            color: #ff6b6b;
            transform: translateY(-1px);
            box-shadow: 0 2px 8px rgba(255,82,82,0.25);
        }
        .${STYLE_PREFIX}highlight-action-delete:active {
            transform: translateY(0px);
            background: rgba(255,82,82,0.2);
        }

        /* 闪烁效果用于高亮跳转 */
        @keyframes ${STYLE_PREFIX}highlightFlash {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.3; }
        }
        .${STYLE_PREFIX}highlight-flash {
            animation: ${STYLE_PREFIX}highlightFlash 0.5s ease 4;
            box-shadow: 0 0 0 3px rgba(255, 255, 0, 0.7) !important;
            position: relative;
            z-index: 10;
        }

        /* 浮动按钮样式 */
        #${STYLE_PREFIX}floating-button {
            position: fixed;
            bottom: 20px;
            right: 20px;
            z-index: 10000;
            width: 33px;
            height: 33px;
            border: none;
            border-radius: 50%;
            cursor: pointer;
            background-color: #333336; /* 与菜单一致的背景 */
            color: #fff;
            font-size: 16px;
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
            transition: background-color 0.2s ease, transform 0.2s ease;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #${STYLE_PREFIX}floating-button:hover {
            background-color: #4a4a4a;
            transform: scale(1.05);
        }
        #${STYLE_PREFIX}floating-button:active {
            transform: scale(0.95);
        }
        /* 侧边栏样式 */
        #${STYLE_PREFIX}sidebar {
            position: fixed;
            top: 0;
            right: -300px;
            width: 300px;
            height: 100%;
            background: linear-gradient(to bottom, #2c2c30, #1e1e22);
            box-shadow: -2px 0 8px rgba(0, 0, 0, 0.3);
            transition: right 0.3s ease;
            z-index: 9999;
        }
        /* 侧边栏打开时 */
        #${STYLE_PREFIX}sidebar.open {
            right: 0;
        }
    `);

    // 保存禁用列表
    function saveDisabledList() {
        GM_setValue('disabled_list', disabledList);
        // 刷新当前状态
        isHighlightDisabled = disabledList.domains.includes(currentDomain) ||
            disabledList.urls.includes(currentPageUrl);

        // 更新浮动按钮显示状态
        const floatingButton = document.getElementById(`${STYLE_PREFIX}floating-button`);
        if (floatingButton) {
            floatingButton.style.display = (settings.showFloatingButton && !isHighlightDisabled) ? 'flex' : 'none';
        }
    }

    // 禁用域名
    function disableDomain(domain) {
        if (!disabledList.domains.includes(domain)) {
            disabledList.domains.push(domain);
            saveDisabledList();
        }
    }

    // 启用域名
    function enableDomain(domain) {
        disabledList.domains = disabledList.domains.filter(d => d !== domain);
        saveDisabledList();
    }

    // 禁用URL
    function disableUrl(url) {
        if (!disabledList.urls.includes(url)) {
            disabledList.urls.push(url);
            saveDisabledList();
        }
    }

    // 启用URL
    function enableUrl(url) {
        disabledList.urls = disabledList.urls.filter(u => u !== url);
        saveDisabledList();
    }

    // 加载当前页面的高亮
    function loadHighlights() {
        const allHighlights = GM_getValue('highlights', {});
        highlights = allHighlights[currentPageUrl] || [];
        return highlights;
    }

    // 保存高亮到存储
    function saveHighlights() {
        const allHighlights = GM_getValue('highlights', {});
        allHighlights[currentPageUrl] = highlights;
        GM_setValue('highlights', allHighlights);
    }

    // 保存设置
    function saveSettings() {
        GM_setValue('highlight_settings', settings);
    }

    // 移除高亮菜单
    function removeHighlightMenu() {
        if (window.currentMenuCloseHandler) {
            document.removeEventListener('click', window.currentMenuCloseHandler);
            window.currentMenuCloseHandler = null;
        }
        const existingMenus = document.querySelectorAll(`.${STYLE_PREFIX}highlight-menu`);
        if (existingMenus.length) {
            existingMenus.forEach(menu => {
                menu.classList.remove(`${STYLE_PREFIX}show`);
                setTimeout(() => {
                    if (menu && menu.parentNode) {
                        menu.parentNode.removeChild(menu);
                    }
                }, 200);
            });
        }
        clearTimeout(menuDisplayTimer);
        ignoreNextClick = false;
        menuOperationInProgress = false;
    }

    // 高亮选中文本
    function highlightSelection(color) {
        if (isHighlightDisabled) {
            return null;
        }
        const selection = window.getSelection();
        if (!selection.rangeCount) return null;
        const range = selection.getRangeAt(0);
        const selectedText = selection.toString().trim();
        if (!selectedText || selectedText.length < settings.minTextLength) {
            return null;
        }
        const highlightId = 'highlight-' + Date.now() + '-' + Math.floor(Math.random() * 10000);
        const highlightElement = document.createElement('span');
        highlightElement.className = `${STYLE_PREFIX}highlight-marked`;
        highlightElement.dataset.highlightId = highlightId;
        highlightElement.style.backgroundColor = color;

        // ★ 先从未修改前的文本中提取上下文
        let prefix = '', suffix = '';
        if (range.startContainer.nodeType === Node.TEXT_NODE) {
            const originalText = range.startContainer.textContent;
            const startOffset = range.startOffset;
            const endOffset = startOffset + selectedText.length;
            prefix = extractValidContext(originalText, startOffset, 20, "backward");
            suffix = extractValidContext(originalText, endOffset, 20, "forward");
        }

        try {
            // 再进行DOM操作前,提取上下文后才调用 extractContents
            const fragment = range.extractContents();
            highlightElement.appendChild(fragment);
            range.insertNode(highlightElement);

            const highlight = {
                id: highlightId,
                text: selectedText,
                color: color,
                timestamp: Date.now(),
                url: currentPageUrl,
                prefix: prefix,    // 前置上下文
                suffix: suffix     // 后置上下文
            };

            highlights.push(highlight);
            saveHighlights();

            highlightElement.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();
                removeHighlightMenu();
                setTimeout(() => {
                    showHighlightEditMenu(e, highlightId);
                }, 10);
            });

            // 检查侧边栏是否打开,如果打开则刷新高亮列表
            const sidebar = document.getElementById(`${STYLE_PREFIX}sidebar`);
            if (sidebar && sidebar.style.right === '0px' && updateSidebarHighlights) {
                updateSidebarHighlights();
            }

            selection.removeAllRanges();
            return highlightId;
        } catch (e) {
            console.warn('高亮失败:', e);
            try {
                findAndHighlight(selectedText, color, highlightId);

                // 检查侧边栏是否打开,如果打开则刷新高亮列表
                const sidebar = document.getElementById(`${STYLE_PREFIX}sidebar`);
                if (sidebar && sidebar.style.right === '0px' && updateSidebarHighlights) {
                    updateSidebarHighlights();
                }

                return highlightId;
            } catch (error) {
                console.error('替代高亮方法也失败:', error);
                return null;
            }
        }
    }

    // 根据ID删除高亮
    function removeHighlightById(highlightId) {
        const highlightElement = document.querySelector(`.${STYLE_PREFIX}highlight-marked[data-highlight-id="${highlightId}"]`);
        if (highlightElement) {
            const textNode = document.createTextNode(highlightElement.textContent);
            highlightElement.parentNode.replaceChild(textNode, highlightElement);
        }
        highlights = highlights.filter(h => h.id !== highlightId);
        saveHighlights();

        // 检查侧边栏是否打开,如果打开则刷新高亮列表
        const sidebar = document.getElementById(`${STYLE_PREFIX}sidebar`);
        if (sidebar && sidebar.style.right === '0px' && updateSidebarHighlights) {
            updateSidebarHighlights();
        }
    }

    // 使用 MutationObserver 监听 DOM 变化,动态恢复高亮
    function observeDomChanges() {
        let debounceTimer;  // 新增变量用于防抖
        const observer = new MutationObserver((mutations) => {
            clearTimeout(debounceTimer);
            debounceTimer = setTimeout(() => {
                applyHighlights();
            }, 300);
        });
        observer.observe(document.body, {
            childList: true,
            subtree: true,
            characterData: true
        });
    }

    // 更改高亮颜色
    function changeHighlightColor(highlightId, newColor) {
        const highlightElement = document.querySelector(`.${STYLE_PREFIX}highlight-marked[data-highlight-id="${highlightId}"]`);
        if (highlightElement) {
            highlightElement.style.backgroundColor = newColor;
        }
        const index = highlights.findIndex(h => h.id === highlightId);
        if (index !== -1) {
            highlights[index].color = newColor;
            saveHighlights();
        }

        // 检查侧边栏是否打开,如果打开则刷新高亮列表
        const sidebar = document.getElementById(`${STYLE_PREFIX}sidebar`);
        if (sidebar && sidebar.style.right === '0px' && updateSidebarHighlights) {
            updateSidebarHighlights();
        }
    }

    // 显示/隐藏侧边栏
    function toggleSidebar(forceShow = true) {
        const sidebar = document.getElementById(`${STYLE_PREFIX}sidebar`);
        const floatingButton = document.getElementById(`${STYLE_PREFIX}floating-button`);
        if (!sidebar) return;

        if (forceShow) {
            sidebar.style.right = '0px';
            // 显示侧边栏时隐藏浮动按钮
            if (floatingButton) {
                floatingButton.style.display = 'none';
            }
            if (updateSidebarHighlights) {
                updateSidebarHighlights();
            }
        } else {
            const width = sidebar.style.width || '300px';
            const wasVisible = sidebar.style.right === '0px';
            sidebar.style.right = wasVisible ? `-${width}` : '0px';

            // 更新浮动按钮显示状态
            if (floatingButton) {
                if (wasVisible) {
                    // 关闭侧边栏时,根据设置和禁用状态决定是否显示浮动按钮
                    floatingButton.style.display = (settings.showFloatingButton && !isHighlightDisabled) ? 'flex' : 'none';
                } else {
                    // 打开侧边栏时,隐藏浮动按钮
                    floatingButton.style.display = 'none';
                }
            }

            if (sidebar.style.right === '0px' && updateSidebarHighlights) {
                updateSidebarHighlights();
            }
        }
    }

    // 切换浮动按钮显示/隐藏
    function toggleFloatingButton() {
        const floatingButton = document.getElementById(`${STYLE_PREFIX}floating-button`);
        if (!floatingButton) return;

        settings.showFloatingButton = !settings.showFloatingButton;
        // 即使设置为显示,在禁用页面也不显示按钮
        floatingButton.style.display = (settings.showFloatingButton && !isHighlightDisabled) ? 'flex' : 'none';
        saveSettings();
    }

    // 显示高亮编辑菜单
    function showHighlightEditMenu(event, highlightId) {
        if (isHighlightDisabled) {
            return;
        }
        removeHighlightMenu();
        if (menuOperationInProgress) return;
        menuOperationInProgress = true;
        event.preventDefault();
        event.stopPropagation();
        ignoreNextClick = true;
        const highlight = highlights.find(h => h.id === highlightId);
        if (!highlight) {
            menuOperationInProgress = false;
            return;
        }
        const menu = createHighlightMenu(false);
        menu.dataset.currentHighlightId = highlightId;
        menu.querySelectorAll(`.${STYLE_PREFIX}highlight-menu-color`).forEach(colorBtn => {
            colorBtn.classList.remove('active');
        });
        const activeColorButton = menu.querySelector(`.${STYLE_PREFIX}highlight-menu-color[data-color="${highlight.color}"]`);
        if (activeColorButton) {
            activeColorButton.classList.add('active');
        }
        const menuHeight = 50;
        let menuTop = event.clientY + window.scrollY - menuHeight - 10;
        let showAbove = true;
        if (event.clientY < menuHeight + 10) {
            menuTop = event.clientY + window.scrollY + 10;
            showAbove = false;
        }
        menu.style.top = `${menuTop}px`;
        const menuWidth = menu.offsetWidth || 200;
        let menuLeft;
        if (event.clientX - (menuWidth / 2) < 5) {
            menuLeft = 5;
        } else if (event.clientX + (menuWidth / 2) > window.innerWidth - 5) {
            menuLeft = window.innerWidth - menuWidth - 5;
        } else {
            menuLeft = event.clientX - (menuWidth / 2);
        }
        menu.style.left = `${menuLeft}px`;
        const arrowLeft = event.clientX - menuLeft;
        const minArrowLeft = 12;
        const maxArrowLeft = menuWidth - 12;
        const safeArrowLeft = Math.max(minArrowLeft, Math.min(arrowLeft, maxArrowLeft));
        menu.style.setProperty('--arrow-left', `${safeArrowLeft}px`);
        if (!showAbove) {
            menu.classList.add(`${STYLE_PREFIX}arrow-top`);
        } else {
            menu.classList.remove(`${STYLE_PREFIX}arrow-top`);
        }
        requestAnimationFrame(() => {
            menu.classList.add(`${STYLE_PREFIX}show`);
            // 使用 once:true 来自动清理事件监听
            document.addEventListener('click', function closeMenu(e) {
                if (ignoreNextClick) {
                    ignoreNextClick = false;
                    return;
                }
                if (!menu.contains(e.target)) {
                    removeHighlightMenu();
                }
            }, { once: true });
            setTimeout(() => {
                ignoreNextClick = false;
                menuOperationInProgress = false;
            }, 50);
        });
    }

    // 查找并高亮文本
    function findAndHighlight(searchText, color, highlightId) {
        // 遍历所有文本节点查找匹配内容
        const treeWalker = document.createTreeWalker(
            document.body,
            NodeFilter.SHOW_TEXT,
            null
        );
        while (treeWalker.nextNode()) {
            const node = treeWalker.currentNode;
            const textContent = node.textContent;
            if (!textContent || textContent.trim().length === 0) continue;
            const idx = textContent.indexOf(searchText);
            if (idx !== -1) {
                const range = document.createRange();
                range.setStart(node, idx);
                range.setEnd(node, idx + searchText.length);
                const highlightElement = document.createElement('span');
                highlightElement.className = `${STYLE_PREFIX}highlight-marked`;
                highlightElement.dataset.highlightId = highlightId;
                highlightElement.style.backgroundColor = color;
                try {
                    const fragment = range.extractContents();
                    highlightElement.appendChild(fragment);
                    range.insertNode(highlightElement);
                    highlightElement.addEventListener('click', (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        showHighlightEditMenu(e, highlightId);
                    });
                    // 新高亮直接返回 true
                    return true;
                } catch (e) {
                    console.warn('应用高亮失败:', e);
                }
            }
        }
        return false;
    }

    // 应用页面上的所有高亮
    function applyHighlights() {
        // 按 timestamp 降序排序(从后向前恢复)
        highlights.sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));
        highlights.forEach(highlight => {
            const restored = advancedRestoreHighlight(highlight);
            if (!restored) {
                console.warn('多步恢复失败:', highlight.id);
            }
        });
    }

    // 创建高亮菜单
    function createHighlightMenu(isNewHighlight = true) {
        removeHighlightMenu();
        ignoreNextClick = true;
        const menu = document.createElement('div');
        menu.className = `${STYLE_PREFIX}highlight-menu`;
        menu.innerHTML = `
        <div class="${STYLE_PREFIX}highlight-menu-colors">
            ${settings.colors.map(color => `
                <div class="${STYLE_PREFIX}highlight-menu-color"
                    style="background-color: ${color};"
                    data-color="${color}">
                </div>
            `).join('')}
        </div>
    `;
        // 无论如何先置空操作ID
        menu.dataset.currentHighlightId = '';
        document.body.appendChild(menu);

        // 如果是新建高亮,确保所有颜色块没有激活状态
        if (isNewHighlight) {
            menu.querySelectorAll(`.${STYLE_PREFIX}highlight-menu-color`).forEach(el => {
                el.classList.remove('active');
            });
        }

        menu.querySelectorAll(`.${STYLE_PREFIX}highlight-menu-color`).forEach(el => {
            el.addEventListener('click', (e) => {
                const color = el.dataset.color;
                const isActive = el.classList.contains('active');
                const currentHighlightId = menu.dataset.currentHighlightId;
                if (isActive) {
                    if (currentHighlightId) {
                        removeHighlightById(currentHighlightId);
                        menu.dataset.currentHighlightId = '';
                        menu.querySelectorAll(`.${STYLE_PREFIX}highlight-menu-color`)
                            .forEach(colorEl => colorEl.classList.remove('active'));
                        const sel = window.getSelection();
                        sel.removeAllRanges();
                        if (savedRange) {
                            sel.addRange(savedRange.cloneRange());
                        }
                    } else {
                        window.getSelection().removeAllRanges();
                        menu.querySelectorAll(`.${STYLE_PREFIX}highlight-menu-color`)
                            .forEach(colorEl => colorEl.classList.remove('active'));
                    }
                    removeHighlightMenu();
                } else {
                    settings.activeColor = color;
                    saveSettings();
                    if (currentHighlightId) {
                        changeHighlightColor(currentHighlightId, color);
                    } else {
                        const selection = window.getSelection();
                        if (selection.toString().trim() === '' && savedRange) {
                            selection.removeAllRanges();
                            selection.addRange(savedRange.cloneRange());
                        }
                        const newHighlightId = highlightSelection(color);
                        if (newHighlightId) {
                            menu.dataset.currentHighlightId = newHighlightId;
                        }
                    }
                    menu.querySelectorAll(`.${STYLE_PREFIX}highlight-menu-color`)
                        .forEach(colorEl => colorEl.classList.toggle('active', colorEl.dataset.color === color));
                }
                e.stopPropagation();
            });
        });
        return menu;
    }

    // 显示高亮菜单
    function showHighlightMenu() {
        if (isHighlightDisabled) {
            return;
        }
        if (menuOperationInProgress) return;
        menuOperationInProgress = true;
        const selection = window.getSelection();
        const selectedText = selection.toString().trim();
        if (selectedText === '') {
            menuOperationInProgress = false;
            return;
        }
        const menu = createHighlightMenu(true);
        const range = selection.getRangeAt(0);
        const rects = range.getClientRects();
        if (rects.length === 0) {
            menuOperationInProgress = false;
            return;
        }
        const targetRect = rects[0];
        const menuHeight = 50;
        let initialTop = window.scrollY + targetRect.top - menuHeight - 8;
        let showAbove = true;
        if (targetRect.top < menuHeight + 10) {
            initialTop = window.scrollY + targetRect.bottom + 8;
            showAbove = false;
        }
        menu.style.top = `${initialTop}px`;
        setTimeout(() => {
            const menuWidth = menu.offsetWidth;
            const textCenterX = targetRect.left + (targetRect.width / 2);
            let menuLeft;
            if (textCenterX - (menuWidth / 2) < 5) {
                menuLeft = 5;
            } else if (textCenterX + (menuWidth / 2) > window.innerWidth - 5) {
                menuLeft = window.innerWidth - menuWidth - 5;
            } else {
                menuLeft = textCenterX - (menuWidth / 2);
            }
            menu.style.left = `${menuLeft}px`;
            menu.style.transform = 'none';
            const arrowLeft = textCenterX - menuLeft;
            const minArrowLeft = 12;
            const maxArrowLeft = menuWidth - 12;
            const safeArrowLeft = Math.max(minArrowLeft, Math.min(arrowLeft, maxArrowLeft));
            menu.style.setProperty('--arrow-left', `${safeArrowLeft}px`);
            if (!showAbove) {
                menu.classList.add(`${STYLE_PREFIX}arrow-top`);
            } else {
                menu.classList.remove(`${STYLE_PREFIX}arrow-top`);
            }
            requestAnimationFrame(() => {
                menu.classList.add(`${STYLE_PREFIX}show`);
            });
        }, 0);
        document.addEventListener('click', function closeMenu(e) {
            if (ignoreNextClick) {
                ignoreNextClick = false;
                return;
            }
            if (!menu.contains(e.target)) {
                removeHighlightMenu();
            }
        }, { once: true });
        setTimeout(() => {
            ignoreNextClick = false;
            menuOperationInProgress = false;
        }, 100);
    }

    // 注册事件
    function registerEvents() {
        document.addEventListener('mouseup', function (e) {
            if (isHighlightDisabled) {
                return;
            }
            if (e.target.closest(`.${STYLE_PREFIX}highlight-menu`)) {
                return;
            }
            const selection = window.getSelection();
            const selectedText = selection.toString().trim();
            if (selectedText.length < (settings.minTextLength || 1)) {
                return;
            }
            if (selection.rangeCount > 0) {
                savedRange = selection.getRangeAt(0).cloneRange();
            }
            removeHighlightMenu();
            clearTimeout(menuDisplayTimer);
            ignoreNextClick = true;
            menuDisplayTimer = setTimeout(() => {
                showHighlightMenu();
            }, 10);
        });
    }

    function fuzzyContextMatch(highlight) {
        // 如果未启用模糊匹配,则直接返回 false
        if (!settings.enableFuzzyMatch) return false;

        if (!highlight.text) return false;
        const textNodes = document.createTreeWalker(
            document.body,
            NodeFilter.SHOW_TEXT,
            null
        );
        const pattern = highlight.text.trim();

        // 预处理前缀和后缀
        const storedPrefix = highlight.prefix ? highlight.prefix.trim() : '';
        const storedSuffix = highlight.suffix ? highlight.suffix.trim() : '';

        // 存储所有匹配项及其上下文评分
        const matches = [];

        // 记录匹配的总数,以便特殊处理单一匹配的情况
        let matchCount = 0;

        while (textNodes.nextNode()) {
            const node = textNodes.currentNode;
            const textContent = node.textContent;
            if (!textContent || textContent.trim().length === 0) continue;

            // 查找所有可能的匹配位置
            let startIdx = 0;
            while (startIdx < textContent.length) {
                const idx = textContent.indexOf(pattern, startIdx);
                if (idx === -1) break;

                matchCount++;

                // 获取上下文
                const actualPrefix = textContent.substring(Math.max(0, idx - 40), idx).trim();
                const actualSuffix = textContent.substring(idx + pattern.length,
                    idx + pattern.length + 40).trim();

                // 计算上下文匹配分数
                let score = 0;

                // 前缀匹配分数计算 (更宽松版)
                if (storedPrefix && actualPrefix) {
                    if (actualPrefix.includes(storedPrefix)) {
                        score += 10; // 前缀完全包含加10分
                    } else {
                        // 尝试寻找部分匹配
                        for (let i = 1; i <= Math.min(storedPrefix.length, 12); i++) {
                            const prefixEnd = storedPrefix.slice(-i);
                            if (actualPrefix.endsWith(prefixEnd)) {
                                score += i / 2; // 匹配前缀尾部,加分
                                break;
                            }
                        }

                        // 尝试在前缀中查找关键片段
                        if (storedPrefix.length > 6) {
                            for (let i = 0; i < storedPrefix.length - 5; i++) {
                                const fragment = storedPrefix.substring(i, i + 5);
                                if (actualPrefix.includes(fragment)) {
                                    score += 2.5; // 找到显著片段加2.5分
                                    break;
                                }
                            }
                        }
                    }
                }

                // 后缀匹配分数计算 (更宽松版)
                if (storedSuffix && actualSuffix) {
                    if (actualSuffix.includes(storedSuffix)) {
                        score += 10; // 后缀完全包含加10分
                    } else {
                        // 尝试寻找部分匹配
                        for (let i = 1; i <= Math.min(storedSuffix.length, 12); i++) {
                            const suffixStart = storedSuffix.slice(0, i);
                            if (actualSuffix.startsWith(suffixStart)) {
                                score += i / 2; // 匹配后缀头部,加分
                                break;
                            }
                        }

                        // 尝试在后缀中查找关键片段
                        if (storedSuffix.length > 6) {
                            for (let i = 0; i < storedSuffix.length - 5; i++) {
                                const fragment = storedSuffix.substring(i, i + 5);
                                if (actualSuffix.includes(fragment)) {
                                    score += 2.5; // 找到显著片段加2.5分
                                    break;
                                }
                            }
                        }
                    }
                }

                // 如果是单个字符的高亮,给予额外分数,避免完全相同的短文本被错过
                if (pattern.length <= 3 && (actualPrefix.includes(storedPrefix) || actualSuffix.includes(storedSuffix))) {
                    score += 5;
                }

                // 记录匹配项
                matches.push({
                    node,
                    idx,
                    score,
                    actualPrefix,
                    actualSuffix
                });

                startIdx = idx + 1; // 继续搜索下一个匹配
            }
        }

        // 特殊情况:如果页面上只有一个匹配,直接使用它
        if (matchCount === 1 && matches.length === 1) {
            const match = matches[0];
            try {
                const range = document.createRange();
                range.setStart(match.node, match.idx);
                range.setEnd(match.node, match.idx + pattern.length);

                const highlightElement = document.createElement('span');
                highlightElement.className = `${STYLE_PREFIX}highlight-marked`;
                highlightElement.dataset.highlightId = highlight.id;
                highlightElement.style.backgroundColor = highlight.color;

                const fragment = range.extractContents();
                highlightElement.appendChild(fragment);
                range.insertNode(highlightElement);

                highlightElement.addEventListener('click', (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    showHighlightEditMenu(e, highlight.id);
                });

                return true;
            } catch (e) {
                console.warn('唯一模糊匹配高亮失败:', e);
            }
        }

        // 如果有多个匹配项,选择分数最高的
        if (matches.length > 0) {
            // 按分数降序排序
            matches.sort((a, b) => b.score - a.score);
            const bestMatch = matches[0];

            // 降低得分阈值到2,使更多匹配可以被接受
            const threshold = matchCount > 1 ? 2 : 0.5;

            if (bestMatch.score >= threshold) {
                // 构造高亮
                try {
                    const range = document.createRange();
                    range.setStart(bestMatch.node, bestMatch.idx);
                    range.setEnd(bestMatch.node, bestMatch.idx + pattern.length);

                    const highlightElement = document.createElement('span');
                    highlightElement.className = `${STYLE_PREFIX}highlight-marked`;
                    highlightElement.dataset.highlightId = highlight.id;
                    highlightElement.style.backgroundColor = highlight.color;

                    const fragment = range.extractContents();
                    highlightElement.appendChild(fragment);
                    range.insertNode(highlightElement);

                    highlightElement.addEventListener('click', (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        showHighlightEditMenu(e, highlight.id);
                    });

                    return true;
                } catch (e) {
                    console.warn('模糊匹配插入高亮失败:', e);
                }
            } else {
                console.log('模糊匹配分数过低,尝试进一步降低要求:', {
                    text: pattern,
                    bestScore: bestMatch.score
                });

                // 如果分数太低但至少有一个匹配,可以考虑用最后的回退机制
                if (matches.length > 0 && pattern.length <= 5) {
                    // 对于短文本,如果我们有任何匹配并且上下文也有一些匹配,就使用它
                    const bestMatch = matches[0];
                    try {
                        const range = document.createRange();
                        range.setStart(bestMatch.node, bestMatch.idx);
                        range.setEnd(bestMatch.node, bestMatch.idx + pattern.length);

                        const highlightElement = document.createElement('span');
                        highlightElement.className = `${STYLE_PREFIX}highlight-marked`;
                        highlightElement.dataset.highlightId = highlight.id;
                        highlightElement.style.backgroundColor = highlight.color;

                        console.log('使用回退机制恢复短文本高亮:', pattern);

                        const fragment = range.extractContents();
                        highlightElement.appendChild(fragment);
                        range.insertNode(highlightElement);

                        highlightElement.addEventListener('click', (e) => {
                            e.preventDefault();
                            e.stopPropagation();
                            showHighlightEditMenu(e, highlight.id);
                        });

                        return true;
                    } catch (e) {
                        console.warn('回退机制高亮失败:', e);
                    }
                }
            }
        }

        return false;
    }

    function advancedRestoreHighlight(highlight) {
        // 检查是否已经有相同ID的高亮存在
        const existingHighlight = document.querySelector(`.${STYLE_PREFIX}highlight-marked[data-highlight-id="${highlight.id}"]`);
        if (existingHighlight) {
            // 高亮已存在,不需要重复恢复
            return true;
        }

        // 使用文本上下文匹配恢复高亮
        const contextRestored = restoreHighlightUsingContext(highlight);
        if (contextRestored) {
            // 只保存最新一次恢复记录
            highlight.recoveryHistory = {
                timestamp: Date.now(),
                method: 'contextMatch',
                success: true
            };
            saveHighlights(); // 保存更新后的恢复历史
            return true;
        }

        // 尝试模糊匹配
        if (fuzzyContextMatch(highlight)) {
            highlight.recoveryHistory = {
                timestamp: Date.now(),
                method: 'fuzzyContext',
                success: true
            };
            saveHighlights();
            return true;
        }

        // 记录失败状态
        highlight.recoveryHistory = {
            timestamp: Date.now(),
            method: 'fallback',
            success: false
        };
        saveHighlights();
        return false;
    }

    function restoreHighlightUsingContext(highlight) {
        // 遍历页面中所有文本节点
        const treeWalker = document.createTreeWalker(
            document.body,
            NodeFilter.SHOW_TEXT,
            null
        );

        // 如果存在前缀和后缀信息,预处理它们以便于比较
        const storedPrefix = highlight.prefix ? highlight.prefix.trim() : '';
        const storedSuffix = highlight.suffix ? highlight.suffix.trim() : '';

        // 存储所有可能的匹配及其得分
        const matches = [];

        // 记录找到多少个完全相同的文本
        let exactTextMatches = 0;

        while (treeWalker.nextNode()) {
            const node = treeWalker.currentNode;
            const textContent = node.textContent;
            if (!textContent || textContent.trim().length === 0) continue;

            const idx = textContent.indexOf(highlight.text);
            if (idx !== -1) {
                // 记录找到了一个文本匹配
                exactTextMatches++;

                // 获取当前节点中匹配区域前后的上下文
                const actualPrefix = textContent.substring(Math.max(0, idx - 30), idx).trim();
                const actualSuffix = textContent.substring(idx + highlight.text.length,
                    idx + highlight.text.length + 30).trim();

                // 计算上下文匹配得分
                let score = 1; // 基础分:找到了文本

                // 前缀匹配得分计算 (改进版)
                if (storedPrefix && actualPrefix) {
                    if (actualPrefix.includes(storedPrefix)) {
                        score += 10; // 前缀完全包含加10分
                    } else if (storedPrefix.length > 3) {
                        // 尝试匹配前缀的尾部
                        for (let i = Math.min(storedPrefix.length, actualPrefix.length); i >= 3; i--) {
                            if (storedPrefix.slice(-i) === actualPrefix.slice(-i)) {
                                score += i / 2; // 匹配长度越长分数越高
                                break;
                            }
                        }

                        // 另外尝试寻找前缀中的部分匹配
                        if (storedPrefix.length >= 8) {
                            for (let i = 0; i < storedPrefix.length - 6; i++) {
                                const fragment = storedPrefix.substring(i, i + 6);
                                if (actualPrefix.includes(fragment)) {
                                    score += 3; // 找到部分匹配加3分
                                    break;
                                }
                            }
                        }
                    }
                }

                // 后缀匹配得分计算 (改进版)
                if (storedSuffix && actualSuffix) {
                    if (actualSuffix.includes(storedSuffix)) {
                        score += 10; // 后缀完全包含加10分
                    } else if (storedSuffix.length > 3) {
                        // 尝试匹配后缀的开头
                        for (let i = Math.min(storedSuffix.length, actualSuffix.length); i >= 3; i--) {
                            if (storedSuffix.slice(0, i) === actualSuffix.slice(0, i)) {
                                score += i / 2; // 匹配长度越长分数越高
                                break;
                            }
                        }

                        // 另外尝试寻找后缀中的部分匹配
                        if (storedSuffix.length >= 8) {
                            for (let i = 0; i < storedSuffix.length - 6; i++) {
                                const fragment = storedSuffix.substring(i, i + 6);
                                if (actualSuffix.includes(fragment)) {
                                    score += 3; // 找到部分匹配加3分
                                    break;
                                }
                            }
                        }
                    }
                }

                matches.push({
                    node,
                    idx,
                    score,
                    actualPrefix,
                    actualSuffix
                });
            }
        }

        // 特殊情况处理:如果页面上只有一个文本匹配,直接使用它
        if (exactTextMatches === 1 && matches.length === 1) {
            const match = matches[0];
            try {
                const range = document.createRange();
                range.setStart(match.node, match.idx);
                range.setEnd(match.node, match.idx + highlight.text.length);

                const highlightElement = document.createElement('span');
                highlightElement.className = `${STYLE_PREFIX}highlight-marked`;
                highlightElement.dataset.highlightId = highlight.id;
                highlightElement.style.backgroundColor = highlight.color;

                const fragment = range.extractContents();
                highlightElement.appendChild(fragment);
                range.insertNode(highlightElement);

                highlightElement.addEventListener('click', (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    showHighlightEditMenu(e, highlight.id);
                });

                return true;
            } catch (e) {
                console.warn('唯一文本匹配恢复高亮失败:', e);
            }
        }

        // 如果找到多个匹配项,选择得分最高的
        if (matches.length > 0) {
            // 按得分降序排序
            matches.sort((a, b) => b.score - a.score);
            const bestMatch = matches[0];

            // 降低匹配阈值,从5降到3,使得更多的匹配可以被接受
            const minScore = exactTextMatches > 1 ? 3 : 1;

            if (bestMatch.score >= minScore) {
                try {
                    const range = document.createRange();
                    range.setStart(bestMatch.node, bestMatch.idx);
                    range.setEnd(bestMatch.node, bestMatch.idx + highlight.text.length);

                    const highlightElement = document.createElement('span');
                    highlightElement.className = `${STYLE_PREFIX}highlight-marked`;
                    highlightElement.dataset.highlightId = highlight.id;
                    highlightElement.style.backgroundColor = highlight.color;

                    const fragment = range.extractContents();
                    highlightElement.appendChild(fragment);
                    range.insertNode(highlightElement);

                    highlightElement.addEventListener('click', (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        showHighlightEditMenu(e, highlight.id);
                    });

                    return true;
                } catch (e) {
                    console.warn('上下文匹配恢复高亮失败:', e);
                }
            } else {
                console.log('匹配分数过低,尝试模糊匹配:', {
                    text: highlight.text,
                    bestScore: bestMatch.score,
                    matchCount: matches.length
                });
            }
        }

        return false;
    }

    function extractValidContext(text, start, count, direction) {
        // direction: "backward" 从 start 往前提取, "forward" 从 start 往后提取
        let result = "";
        let processedChars = 0;

        // 对于短文本或单个字符,我们提取更多上下文
        const adjustedCount = count * (text.length <= 3 ? 2 : 1);

        if (direction === "backward") {
            for (let i = start - 1; i >= 0 && processedChars < adjustedCount * 2; i--) {
                const ch = text.charAt(i);
                // 只计算有效字符(中文、英文、数字)
                if (/[\u4e00-\u9fffA-Za-z0-9]/.test(ch)) {
                    result = ch + result;
                    processedChars++;
                    if (processedChars >= adjustedCount) break;
                } else {
                    // 空格和标点也记录,但不计入有效字符数
                    result = ch + result;
                }
            }
        } else { // forward
            for (let i = start; i < text.length && processedChars < adjustedCount * 2; i++) {
                const ch = text.charAt(i);
                // 只计算有效字符(中文、英文、数字)
                if (/[\u4e00-\u9fffA-Za-z0-9]/.test(ch)) {
                    result += ch;
                    processedChars++;
                    if (processedChars >= adjustedCount) break;
                } else {
                    // 空格和标点也记录,但不计入有效字符数
                    result += ch;
                }
            }
        }
        return result;
    }

    // 添加浮动按钮和侧边栏功能
    function createFloatingButtonAndSidebar() {
        // 创建浮动按钮
        const floatingButton = document.createElement('button');
        floatingButton.id = `${STYLE_PREFIX}floating-button`;
        // 使用 SVG 图标,代表"汉堡菜单"
        floatingButton.innerHTML = `
            <svg viewBox="0 0 100 80" width="16" height="16" fill="#ccc" xmlns="http://www.w3.org/2000/svg">
                <rect width="100" height="10"></rect>
                <rect y="30" width="100" height="10"></rect>
                <rect y="60" width="100" height="10"></rect>
            </svg>
        `;
        // 根据设置和禁用状态决定是否显示
        floatingButton.style.display = (settings.showFloatingButton && !isHighlightDisabled) ? 'flex' : 'none';
        document.body.appendChild(floatingButton);
        // 创建侧边栏(初始隐藏)
        const sidebar = document.createElement('div');
        sidebar.id = `${STYLE_PREFIX}sidebar`;
        Object.assign(sidebar.style, {
            position: 'fixed',
            top: '0',
            right: '-300px',
            width: '300px',
            height: '100%',
            boxShadow: '-2px 0 8px rgba(0, 0, 0, 0.3)',
            transition: 'none',
            zIndex: '9999',
            overflow: 'hidden', // 改为hidden,内部内容区域单独设置overflow
            display: 'flex',
            flexDirection: 'column',
            color: '#f0f0f0',
            fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
            background: 'linear-gradient(to bottom, #262630, #1a1a22)', // 更暗、更专业的渐变色
            boxShadow: '-4px 0 20px rgba(0, 0, 0, 0.25)', // 增强阴影深度感
            borderLeft: '1px solid rgba(255, 255, 255, 0.06)', // 添加微妙的边框
        });

        // 构建侧边栏内部结构
        sidebar.innerHTML = `
            <div class="${STYLE_PREFIX}sidebar-header">
                <div class="${STYLE_PREFIX}sidebar-title" title="双击修改标题">
                    ${settings.sidebarDescription || '网页划词高亮工具'}
                </div>
                <div class="${STYLE_PREFIX}sidebar-controls">
                    <button class="${STYLE_PREFIX}sidebar-close" title="关闭侧边栏">
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                            <path d="M18 6L6 18M6 6l12 12"></path>
                        </svg>
                    </button>
                </div>
            </div>

            <div class="${STYLE_PREFIX}sidebar-tabs">
                <button class="${STYLE_PREFIX}sidebar-tab active" data-tab="highlights">高亮列表</button>
                <button class="${STYLE_PREFIX}sidebar-tab" data-tab="disabled">禁用管理</button>
            </div>

            <div class="${STYLE_PREFIX}sidebar-content">
                <div class="${STYLE_PREFIX}tab-panel active" data-panel="highlights">
                    <div class="${STYLE_PREFIX}highlights-list"></div>
                </div>

                <div class="${STYLE_PREFIX}tab-panel" data-panel="disabled">
                    <div class="${STYLE_PREFIX}disabled-container"></div>
                </div>
            </div>
        `;

        document.body.appendChild(sidebar);
        setTimeout(() => {
            sidebar.style.transition = 'right 0.3s ease';
        }, 10);

        // 设置侧边栏内部元素样式
        const header = sidebar.querySelector(`.${STYLE_PREFIX}sidebar-header`);
        Object.assign(header.style, {
            display: 'flex',
            justifyContent: 'space-between',
            alignItems: 'center',
            boxSizing: 'border-box',
            borderBottom: '1px solid rgba(255, 255, 255, 0.08)', // 更微妙的边框
            height: '42px', // 增加高度使其更易于点击
            background: 'rgba(0, 0, 0, 0.15)', // 轻微的背景色调
            padding: '0 16px', // 更合理的内边距
        });

        const title = sidebar.querySelector(`.${STYLE_PREFIX}sidebar-title`);
        Object.assign(title.style, {
            fontSize: '13px',
            fontWeight: '600',
            flex: '1',
            overflow: 'hidden',
            textOverflow: 'ellipsis',
            whiteSpace: 'nowrap',
            cursor: 'default',
            letterSpacing: '0.3px', // 增加字母间距提高可读性
            opacity: '0.9',
        });

        const controls = sidebar.querySelector(`.${STYLE_PREFIX}sidebar-controls`);
        Object.assign(controls.style, {
            display: 'flex',
            gap: '8px'
        });

        // 设置按钮样式
        sidebar.querySelectorAll(`.${STYLE_PREFIX}sidebar-controls button`).forEach(btn => {
            Object.assign(btn.style, {
                background: 'none',
                border: 'none',
                cursor: 'pointer',
                padding: '3px',         // 从5px减小到3px
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                color: '#ccc',
                borderRadius: '3px',
                transition: 'background-color 0.2s'
            });

            // 添加按钮悬停效果
            btn.addEventListener('mouseenter', () => {
                btn.style.backgroundColor = 'rgba(255, 255, 255, 0.1)';
            });

            btn.addEventListener('mouseleave', () => {
                btn.style.backgroundColor = 'transparent';
            });
        });

        // 设置标签页样式
        const tabs = sidebar.querySelector(`.${STYLE_PREFIX}sidebar-tabs`);
        Object.assign(tabs.style, {
            display: 'flex',
            borderBottom: '1px solid rgba(255, 255, 255, 0.08)',
            padding: '0',
            justifyContent: 'center',
            backgroundColor: 'rgba(0, 0, 0, 0.12)',
            height: '38px'
        });

        sidebar.querySelectorAll(`.${STYLE_PREFIX}sidebar-tab`).forEach(tab => {
            Object.assign(tab.style, {
                height: '100%', // 占满容器高度
                cursor: 'pointer',
                fontWeight: '500', // 稍微加粗
                background: 'none',
                border: 'none',
                color: '#ccc',
                borderBottom: '2px solid transparent',
                margin: '0',
                transition: 'all 0.2s ease',
                flex: '1',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                letterSpacing: '0.3px', // 增加字母间距提高可读性
                fontSize: '12px', // 减小字体
                padding: '0 12px', // 添加水平内边距
                borderRadius: '0',  // 移除边角圆角
                opacity: '0.75', // 非激活状态降低不透明度
            });
        });

        // 激活的标签页样式
        const activeTab = sidebar.querySelector(`.${STYLE_PREFIX}sidebar-tab.active`);
        if (activeTab) {
            Object.assign(activeTab.style, {
                color: '#fff',
                borderBottom: '2px solid rgba(190, 60, 60, 0.8)', // 改为指定颜色
                backgroundColor: 'rgba(255, 144, 156, 0.08)', // 使用主色的半透明版本
                opacity: '1',
            });
        }

        // 内容区域样式
        const contentArea = sidebar.querySelector(`.${STYLE_PREFIX}sidebar-content`);
        Object.assign(contentArea.style, {
            flex: '1',
            overflow: 'hidden',
            position: 'relative'
        });

        // 设置面板样式
        sidebar.querySelectorAll(`.${STYLE_PREFIX}tab-panel`).forEach(panel => {
            Object.assign(panel.style, {
                height: '100%',
                width: '100%',
                position: 'absolute',
                top: '0',
                left: '0',
                padding: '14px 14px 14px 14px',  // 修改为:上右下左,底部padding设为0
                boxSizing: 'border-box',
                overflow: 'auto',
                display: 'none'
            });
        });

        // 显示当前活动面板
        const activePanel = sidebar.querySelector(`.${STYLE_PREFIX}tab-panel.active`);
        if (activePanel) {
            activePanel.style.display = 'block';
        }

        // 添加侧边栏拖拽调整区域(位于侧边栏的最左侧)
        const resizer = document.createElement('div');
        Object.assign(resizer.style, {
            position: 'absolute',
            left: '0',
            top: '0',
            width: '5px',
            height: '100%',
            cursor: 'ew-resize',
            backgroundColor: 'transparent'
        });
        sidebar.appendChild(resizer);

        // 拖拽事件逻辑
        resizer.addEventListener('mousedown', initResize);

        function initResize(e) {
            e.preventDefault();
            window.addEventListener('mousemove', resizeSidebar);
            window.addEventListener('mouseup', stopResize);
        }

        function resizeSidebar(e) {
            // 计算出新的宽度:侧边栏右对齐,宽度 = 窗口宽度 - 鼠标水平位置
            const newWidth = window.innerWidth - e.clientX;
            // 限制最小宽度为 150px,最大宽度为窗口 80%
            if (newWidth >= 150 && newWidth <= window.innerWidth * 0.8) {
                sidebar.style.width = newWidth + 'px';
                // 更新设置中的宽度
                settings.sidebarWidth = newWidth;
                saveSettings();
            }
        }

        function stopResize(e) {
            window.removeEventListener('mousemove', resizeSidebar);
            window.removeEventListener('mouseup', stopResize);
        }

        // 标签页切换事件
        sidebar.querySelectorAll(`.${STYLE_PREFIX}sidebar-tab`).forEach(tab => {
            tab.addEventListener('click', () => {
                // 移除所有标签页和面板的活动状态
                sidebar.querySelectorAll(`.${STYLE_PREFIX}sidebar-tab`).forEach(t => {
                    t.classList.remove('active');
                    t.style.color = '#ccc';
                    t.style.borderBottom = '2px solid transparent';
                    t.style.backgroundColor = 'transparent';
                });

                sidebar.querySelectorAll(`.${STYLE_PREFIX}tab-panel`).forEach(p => {
                    p.classList.remove('active');
                    p.style.display = 'none';
                });

                // 激活当前标签和面板
                tab.classList.add('active');
                tab.style.color = '#fff';
                tab.style.borderBottom = '2px solid rgba(190, 60, 60, 0.8)'; // 改为指定颜色

                const panelId = tab.getAttribute('data-tab');
                const panel = sidebar.querySelector(`.${STYLE_PREFIX}tab-panel[data-panel="${panelId}"]`);
                if (panel) {
                    panel.classList.add('active');
                    panel.style.display = 'block';
                }
            });

            // 添加悬停效果
            tab.addEventListener('mouseenter', () => {
                if (!tab.classList.contains('active')) {
                    tab.style.backgroundColor = 'rgba(255, 144, 156, 0.05)'; // 轻微的主色背景
                    tab.style.borderBottom = '2px solid'; // 淡化的主色边框
                }
            });

            tab.addEventListener('mouseleave', () => {
                if (!tab.classList.contains('active')) {
                    tab.style.backgroundColor = 'transparent';
                    tab.style.borderBottom = '2px solid transparent';
                }
            });
        });

        // 标题双击编辑功能
        const titleElement = sidebar.querySelector(`.${STYLE_PREFIX}sidebar-title`);
        titleElement.addEventListener('dblclick', () => {
            const currentTitle = titleElement.textContent.trim() || '高亮工具';
            const input = document.createElement('input');
            input.type = 'text';
            input.value = currentTitle;

            // 美化输入框样式
            Object.assign(input.style, {
                width: '100%',
                fontSize: '14px',           // 从16px减小到14px
                fontWeight: '500',
                padding: '2px 6px',         // 调整内边距使其更美观
                boxSizing: 'border-box',
                border: '1px solid rgba(116, 180, 255, 0.5)',
                borderRadius: '3px',        // 添加圆角
                outline: 'none',
                background: 'rgba(0, 0, 0, 0.2)',
                color: '#fff',
                transition: 'all 0.15s ease', // 添加过渡效果
                boxShadow: '0 0 0 1px rgba(116, 180, 255, 0.3)'
            });

            // 替换标题内容为输入框
            titleElement.innerHTML = '';
            titleElement.appendChild(input);
            input.focus();
            input.select();

            // 添加输入框聚焦样式
            input.addEventListener('focus', () => {
                input.style.background = 'rgba(20, 20, 20, 0.4)';
                input.style.boxShadow = '0 0 0 2px rgba(116, 180, 255, 0.4)';
            });

            // 确认修改:输入框失焦或按下 Enter 键时更新标题
            const confirmChange = () => {
                const newTitle = input.value.trim() || '高亮工具';
                settings.sidebarDescription = newTitle;
                titleElement.textContent = newTitle;
                saveSettings();
            };

            input.addEventListener('blur', confirmChange);
            input.addEventListener('keydown', (event) => {
                if (event.key === 'Enter') {
                    input.blur();
                } else if (event.key === 'Escape') {
                    // 按ESC键取消编辑
                    titleElement.textContent = currentTitle;
                    input.blur();
                }
            });
        });

        // 关闭按钮事件
        const closeButton = sidebar.querySelector(`.${STYLE_PREFIX}sidebar-close`);
        closeButton.addEventListener('click', () => {
            sidebar.style.right = `-${parseInt(sidebar.style.width)}px`;

            // 侧边栏关闭时,如果设置允许显示浮动按钮且当前页面未禁用,则恢复显示浮动按钮
            if (settings.showFloatingButton && !isHighlightDisabled) {
                floatingButton.style.display = 'flex';
            }
        });

        // 浮动按钮点击后切换侧边栏的显示和隐藏
        floatingButton.addEventListener('click', () => {
            if (sidebar.style.right === '0px') {
                sidebar.style.right = `-${parseInt(sidebar.style.width)}px`;
                // 如果设置允许显示浮动按钮且当前页面未禁用,则显示浮动按钮
                if (settings.showFloatingButton && !isHighlightDisabled) {
                    floatingButton.style.display = 'flex';
                }
            } else {
                sidebar.style.right = '0px';
                // 当侧边栏显示时,隐藏浮动按钮
                floatingButton.style.display = 'none';
                // 刷新高亮列表
                if (updateSidebarHighlights) {
                    updateSidebarHighlights();
                }
            }
        });

        // 初始设置宽度
        if (settings.sidebarWidth) {
            sidebar.style.width = `${settings.sidebarWidth}px`;
            sidebar.style.right = `-${settings.sidebarWidth}px`; // 确保初始位置与实际宽度匹配
        } else {
            sidebar.style.right = '-300px'; // 默认宽度的对应位置
        }

        // 渲染高亮列表面板
        function renderHighlightsList() {
            const highlightsListContainer = sidebar.querySelector(`.${STYLE_PREFIX}highlights-list`);
            if (!highlightsListContainer) return;

            // 清空容器
            highlightsListContainer.innerHTML = '';
            Object.assign(highlightsListContainer.style, {
                height: 'calc(100vh - 120px)', // 调整合适高度,减去顶栏和标签栏高度
                overflow: 'hidden',
                display: 'flex',    // 添加flex布局
                flexDirection: 'column', // 确保子元素垂直排列
                paddingBottom: '0'  // 确保底部无padding
            });

            // 创建高亮列表
            const listContainer = document.createElement('div');
            listContainer.className = `${STYLE_PREFIX}highlights-items`;
            Object.assign(listContainer.style, {
                display: 'flex',
                flexDirection: 'column',
                gap: '8px',
                height: 'calc(100% - 22px)', // 从12px调整到22px,给上移的底部按钮腾出额外空间
                overflow: 'auto',
                paddingRight: '8px',
                paddingBottom: '4px' // 已经是5px,保持不变
            });

            // 自定义滚动条样式
            const styleEl = document.createElement('style');
            styleEl.textContent = `
                .${STYLE_PREFIX}highlights-items::-webkit-scrollbar {
                    width: 5px; /* 更细的滚动条 */
                }
                .${STYLE_PREFIX}highlights-items::-webkit-scrollbar-track {
                    background: rgba(255, 255, 255, 0.03); /* 更微妙的轨道 */
                    border-radius: 3px;
                }
                .${STYLE_PREFIX}highlights-items::-webkit-scrollbar-thumb {
                    background: rgba(255, 255, 255, 0.15); /* 更微妙的滑块 */
                    border-radius: 3px;
                }
                .${STYLE_PREFIX}highlights-items::-webkit-scrollbar-thumb:hover {
                    background: rgba(255, 255, 255, 0.25);
                }
            `;
            document.head.appendChild(styleEl);

            // 排序高亮,按时间倒序
            const sortedHighlights = [...highlights].sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));

            if (sortedHighlights.length === 0) {
                // 显示空状态
                const emptyState = document.createElement('div');
                Object.assign(emptyState.style, {
                    display: 'flex',
                    flexDirection: 'column',
                    alignItems: 'center',
                    justifyContent: 'center',
                    padding: '60px 20px',
                    textAlign: 'center',
                    color: '#999',
                    fontSize: '14px'
                });

                // 使用SVG图标作为空状态图标
                emptyState.innerHTML = `
                    <svg width="60" height="60" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.15)"
                        stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"></path>
                    </svg>
                    <p style="margin-top:16px;">暂无高亮内容<br>选中文本并点击颜色进行高亮</p>
                `;
                listContainer.appendChild(emptyState);
            } else {
                // 渲染所有高亮项目
                sortedHighlights.forEach((highlight, index) => {
                    const highlightItem = createHighlightItem(highlight, index);
                    listContainer.appendChild(highlightItem);
                });
            }

            highlightsListContainer.appendChild(listContainer);

            // 创建底部固定按钮栏
            const bottomActionBar = document.createElement('div');
            bottomActionBar.className = `${STYLE_PREFIX}highlights-bottom-actions`;
            Object.assign(bottomActionBar.style, {
                display: 'flex',
                position: 'absolute',
                bottom: '0',
                left: '0',
                right: '0',
                padding: '10px 16px', // 调整内边距
                borderTop: '1px solid rgba(255, 255, 255, 0.06)', // 更微妙的分隔线
                background: 'rgba(26, 26, 32, 0.9)', // 半透明背景
                backdropFilter: 'blur(10px)', // 磨砂玻璃效果
                zIndex: '1',
                gap: '10px',
            });

            // 创建刷新按钮
            const refreshBtn = document.createElement('button');
            refreshBtn.textContent = '刷新列表';
            Object.assign(refreshBtn.style, {
                flex: '1',
                background: 'rgba(255, 255, 255, 0.06)', // 保持原来的背景色
                border: '1px solid rgba(255, 255, 255, 0.08)', // 保持原来的边框
                borderRadius: '4px',
                padding: '8px 12px', // 添加水平内边距与清除按钮一致
                color: '#e0e0e0',
                fontSize: '13px', // 增大字体与清除按钮一致
                fontWeight: '500',
                cursor: 'pointer', // 添加指针样式
                transition: 'all 0.2s ease' // 添加过渡效果
            });

            // 添加悬停效果
            refreshBtn.addEventListener('mouseenter', () => {
                refreshBtn.style.background = 'rgba(255, 255, 255, 0.15)';
            });
            refreshBtn.addEventListener('mouseleave', () => {
                refreshBtn.style.background = 'rgba(255, 255, 255, 0.06)';
            });

            refreshBtn.addEventListener('click', () => {
                // 刷新高亮列表
                loadHighlights();
                applyHighlights();
                renderHighlightsList();
            });

            // 创建清除按钮
            const clearBtn = document.createElement('button');
            clearBtn.textContent = '清除全部';
            Object.assign(clearBtn.style, {
                flex: '1',
                background: 'rgba(190, 60, 60, 0.8)', // 更和谐的深红色
                border: '1px solid rgba(190, 60, 60, 0.2)', // 淡化边框
                color: '#f5e0e0', // 更柔和的白色文字
                borderRadius: '4px',
                padding: '8px 12px',
                fontSize: '13px',
                fontWeight: '500',
                cursor: 'pointer',
                transition: 'all 0.2s ease'
            });

            // 添加悬停效果
            clearBtn.addEventListener('mouseenter', () => {
                clearBtn.style.background = 'rgba(205, 70, 70, 0.85)';
                clearBtn.style.color = '#f7e7e7';
            });
            clearBtn.addEventListener('mouseleave', () => {
                clearBtn.style.background = 'rgba(190, 60, 60, 0.8)';
                clearBtn.style.color = '#f5e0e0';
            });

            clearBtn.addEventListener('click', () => {
                if (highlights.length === 0) return;

                // 确认删除
                if (confirm('确定要删除所有高亮吗?此操作不可撤销。')) {
                    // 移除DOM中的高亮元素
                    document.querySelectorAll(`.${STYLE_PREFIX}highlight-marked`).forEach(el => {
                        const textNode = document.createTextNode(el.textContent);
                        el.parentNode.replaceChild(textNode, el);
                    });

                    // 清空高亮数组
                    highlights = [];
                    saveHighlights();
                    renderHighlightsList();
                }
            });

            bottomActionBar.appendChild(refreshBtn);
            bottomActionBar.appendChild(clearBtn);
            highlightsListContainer.appendChild(bottomActionBar);
        }

        updateSidebarHighlights = renderHighlightsList;

        // 创建单个高亮项目
        function createHighlightItem(highlight, index) {
            const item = document.createElement('div');
            item.className = `${STYLE_PREFIX}highlight-item`;
            item.dataset.highlightId = highlight.id;

            Object.assign(item.style, {
                backgroundColor: 'rgba(30, 30, 36, 0.6)', // 更深、更专业的卡片背景
                borderRadius: '5px', // 更小的圆角
                padding: '10px 12px', // 增加水平内边距
                position: 'relative',
                transition: 'all 0.2s cubic-bezier(0.1, 0.9, 0.2, 1)', // 更平滑的过渡动画
                border: '1px solid rgba(255, 255, 255, 0.04)', // 更微妙的边框
                backdropFilter: 'blur(8px)', // 添加磨砂玻璃效果 (现代浏览器)
            })

            // 颜色指示器
            const colorIndicator = document.createElement('div');
            Object.assign(colorIndicator.style, {
                position: 'absolute',
                top: '0',
                left: '0',
                width: '3px',
                height: '100%',
                backgroundColor: highlight.color,
                borderTopLeftRadius: '12px',
                borderBottomLeftRadius: '12px'
            });

            // 高亮内容
            const content = document.createElement('div');
            Object.assign(content.style, {
                paddingLeft: '3px',
                color: '#fff',
                fontSize: '14px',
                lineHeight: '1.4',
                marginBottom: '8px',
                wordBreak: 'break-word',
                display: '-webkit-box',
                WebkitBoxOrient: 'vertical',
                WebkitLineClamp: '2',
                overflow: 'hidden',
                textOverflow: 'ellipsis'
            });

            // 处理高亮文本,避免XSS
            const textNode = document.createTextNode(highlight.text);
            content.appendChild(textNode);

            // 底部信息栏
            const infoBar = document.createElement('div');
            Object.assign(infoBar.style, {
                display: 'flex',
                justifyContent: 'space-between',
                alignItems: 'center',
                fontSize: '12px',
                marginTop: '6px',
                paddingLeft: '3px'  // 与内容区域左边距统一
            });

            // 时间信息
            const timeInfo = document.createElement('div');
            Object.assign(timeInfo.style, {
                color: '#999',
                fontSize: '12px'
            });

            // 格式化时间
            const date = new Date(highlight.timestamp);
            const formattedDate = `${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
            timeInfo.textContent = formattedDate;

            // 操作按钮容器
            const actionButtons = document.createElement('div');
            Object.assign(actionButtons.style, {
                display: 'flex',
                gap: '10px'
            });

            // 跳转按钮
            const jumpButton = document.createElement('button');
            Object.assign(jumpButton.style, {
                background: 'none',
                border: 'none',
                padding: '3px',
                cursor: 'pointer',
                color: '#74b4ff',
                display: 'flex',
                alignItems: 'center',
                fontSize: '12px',
                transition: 'color 0.15s ease'
            });
            jumpButton.title = '跳转到此高亮';
            jumpButton.innerHTML = `
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                    stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M15 3h6v6M14 10l6.16-6.16M9 21H3v-6M10 14l-6.16 6.16"></path>
                </svg>
            `;

            jumpButton.addEventListener('mouseenter', () => {
                jumpButton.style.color = '#a0cfff';
            });

            jumpButton.addEventListener('mouseleave', () => {
                jumpButton.style.color = '#74b4ff';
            });

            jumpButton.addEventListener('click', (e) => {
                e.stopPropagation();
                scrollToHighlight(highlight.id);
            });

            // 删除按钮
            const deleteButton = document.createElement('button');
            Object.assign(deleteButton.style, {
                background: 'none',
                border: 'none',
                padding: '3px',
                cursor: 'pointer',
                color: 'rgba(190, 60, 60, 0.8)',
                display: 'flex',
                alignItems: 'center',
                fontSize: '12px',
                transition: 'color 0.15s ease'
            });
            deleteButton.title = '删除此高亮';
            deleteButton.innerHTML = `
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                    stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"></path>
                </svg>
            `;

            deleteButton.addEventListener('mouseenter', () => {
                deleteButton.style.color = 'rgba(255, 80, 80, 0.95)'; // 更亮、更饱和的红色
            });

            deleteButton.addEventListener('mouseleave', () => {
                deleteButton.style.color = 'rgba(190, 60, 60, 0.8)'; // 恢复原来的颜色
            });

            deleteButton.addEventListener('click', (e) => {
                e.stopPropagation();
                removeHighlightById(highlight.id);
                item.style.opacity = '0';
                item.style.height = '0';
                item.style.padding = '0';
                item.style.margin = '0';
                item.style.overflow = 'hidden';

                setTimeout(() => {
                    renderHighlightsList();
                }, 300);
            });

            actionButtons.appendChild(jumpButton);
            actionButtons.appendChild(deleteButton);

            infoBar.appendChild(timeInfo);
            infoBar.appendChild(actionButtons);

            // 添加项目悬停效果
            item.addEventListener('mouseenter', () => {
                item.style.backgroundColor = 'rgba(40, 40, 50, 0.75)'; // 更微妙的变化
                item.style.transform = 'translateY(-2px)'; // 轻微上浮
                item.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.2), 0 1px 3px rgba(0, 0, 0, 0.1)'; // 分层阴影
            });
            item.addEventListener('mouseleave', () => {
                item.style.backgroundColor = 'rgba(0, 0, 0, 0.2)';
                item.style.transform = 'translateY(0)';
                item.style.boxShadow = 'none';
            });

            item.appendChild(colorIndicator);
            item.appendChild(content);
            item.appendChild(infoBar);

            return item;
        }

        // 滚动到指定高亮
        function scrollToHighlight(highlightId) {
            const highlightElement = document.querySelector(`.${STYLE_PREFIX}highlight-marked[data-highlight-id="${highlightId}"]`);
            if (highlightElement) {
                // 平滑滚动到元素
                highlightElement.scrollIntoView({ behavior: 'smooth', block: 'center' });

                // 添加闪烁效果,并设置临时样式使其更加明显
                highlightElement.classList.add(`${STYLE_PREFIX}highlight-flash`);

                // 保存原有的样式以便恢复
                const originalTransition = highlightElement.style.transition;

                // 添加过渡效果使视觉反馈更平滑
                highlightElement.style.transition = 'all 0.3s ease';

                setTimeout(() => {
                    highlightElement.classList.remove(`${STYLE_PREFIX}highlight-flash`);
                    highlightElement.style.transition = originalTransition;
                }, 2500);
            }
        }

        // 初始渲染高亮列表
        renderHighlightsList();

        // 渲染禁用管理面板内容
        function renderDisabledPanel() {
            const container = sidebar.querySelector(`.${STYLE_PREFIX}disabled-container`);
            if (!container) return;

            // 清空容器
            container.innerHTML = '';

            // 添加当前页面管理区域
            const currentPageSection = document.createElement('div');
            currentPageSection.className = `${STYLE_PREFIX}disabled-section`;
            Object.assign(currentPageSection.style, {
                marginBottom: '20px'
            });

            const currentPageTitle = document.createElement('div');
            currentPageTitle.className = `${STYLE_PREFIX}disabled-title`;
            currentPageTitle.innerHTML = `<span>当前页面</span>`;
            Object.assign(currentPageTitle.style, {
                fontSize: '14px',
                fontWeight: '600',
                color: '#eee',
                marginBottom: '10px',
                display: 'flex',
                alignItems: 'center',
                gap: '8px'
            });

            // 当前页面状态
            const currentStatus = document.createElement('div');
            currentStatus.className = `${STYLE_PREFIX}current-status`;
            currentStatus.innerHTML = renderCurrentPageStatus();

            currentPageSection.appendChild(currentPageTitle);
            currentPageSection.appendChild(currentStatus);
            container.appendChild(currentPageSection);

            // 禁用域名列表区域
            const domainsSection = document.createElement('div');
            domainsSection.className = `${STYLE_PREFIX}disabled-section`;
            Object.assign(domainsSection.style, {
                marginBottom: '20px'
            });

            const domainsTitle = document.createElement('div');
            domainsTitle.className = `${STYLE_PREFIX}disabled-title`;
            domainsTitle.innerHTML = `<span>禁用域名列表</span>`;
            Object.assign(domainsTitle.style, {
                fontSize: '14px',
                fontWeight: '600',
                color: '#eee',
                marginBottom: '10px',
                display: 'flex',
                alignItems: 'center',
                gap: '8px'
            });

            const domainsList = document.createElement('div');
            domainsList.className = `${STYLE_PREFIX}domains-list`;
            domainsList.innerHTML = renderDisabledDomains();

            // 添加域名表单
            const addDomainForm = document.createElement('div');
            addDomainForm.className = `${STYLE_PREFIX}add-disabled-form`;
            Object.assign(addDomainForm.style, {
                display: 'flex',
                marginTop: '12px',
                gap: '0'
            });

            const domainInput = document.createElement('input');
            domainInput.className = `${STYLE_PREFIX}add-disabled-input`;
            domainInput.id = 'add-domain-input';
            domainInput.placeholder = '输入域名...';
            Object.assign(domainInput.style, {
                flex: '1',
                backgroundColor: 'rgba(255, 255, 255, 0.07)',
                border: '1px solid rgba(255, 255, 255, 0.1)',
                borderRadius: '4px 0 0 4px',
                padding: '8px 12px',
                fontSize: '13px',
                color: '#fff',
                outline: 'none'
            });

            const addDomainBtn = document.createElement('button');
            addDomainBtn.className = `${STYLE_PREFIX}add-disabled-button`;
            addDomainBtn.id = 'add-domain-btn';
            addDomainBtn.textContent = '添加';
            Object.assign(addDomainBtn.style, {
                backgroundColor: 'rgba(190, 60, 60, 0.8)',
                color: '#f5e0e0',
                border: 'none',
                borderRadius: '0 4px 4px 0',
                padding: '8px 16px',
                fontSize: '13px',
                fontWeight: '500',
                cursor: 'pointer',
                transition: 'all 0.2s ease'
            });

            addDomainForm.appendChild(domainInput);
            addDomainForm.appendChild(addDomainBtn);

            domainsSection.appendChild(domainsTitle);
            domainsSection.appendChild(domainsList);
            domainsSection.appendChild(addDomainForm);
            container.appendChild(domainsSection);

            // 禁用URL列表区域
            const urlsSection = document.createElement('div');
            urlsSection.className = `${STYLE_PREFIX}disabled-section`;

            const urlsTitle = document.createElement('div');
            urlsTitle.className = `${STYLE_PREFIX}disabled-title`;
            urlsTitle.innerHTML = `<span>禁用网址列表</span>`;
            Object.assign(urlsTitle.style, {
                fontSize: '14px',
                fontWeight: '600',
                color: '#eee',
                marginBottom: '10px',
                display: 'flex',
                alignItems: 'center',
                gap: '8px'
            });

            const urlsList = document.createElement('div');
            urlsList.className = `${STYLE_PREFIX}urls-list`;
            urlsList.innerHTML = renderDisabledUrls();

            // 添加URL表单
            const addUrlForm = document.createElement('div');
            addUrlForm.className = `${STYLE_PREFIX}add-disabled-form`;
            Object.assign(addUrlForm.style, {
                display: 'flex',
                marginTop: '12px',
                gap: '0'
            });

            const urlInput = document.createElement('input');
            urlInput.className = `${STYLE_PREFIX}add-disabled-input`;
            urlInput.id = 'add-url-input';
            urlInput.placeholder = '输入网址...';
            Object.assign(urlInput.style, {
                flex: '1',
                backgroundColor: 'rgba(255, 255, 255, 0.07)',
                border: '1px solid rgba(255, 255, 255, 0.1)',
                borderRadius: '4px 0 0 4px',
                padding: '8px 12px',
                fontSize: '13px',
                color: '#fff',
                outline: 'none'
            });

            const addUrlBtn = document.createElement('button');
            addUrlBtn.className = `${STYLE_PREFIX}add-disabled-button`;
            addUrlBtn.id = 'add-url-btn';
            addUrlBtn.textContent = '添加';
            Object.assign(addUrlBtn.style, {
                backgroundColor: 'rgba(190, 60, 60, 0.8)',
                color: '#f5e0e0',
                border: 'none',
                borderRadius: '0 4px 4px 0',
                padding: '8px 16px',
                fontSize: '13px',
                fontWeight: '500',
                cursor: 'pointer',
                transition: 'all 0.2s ease'
            });

            addUrlForm.appendChild(urlInput);
            addUrlForm.appendChild(addUrlBtn);

            urlsSection.appendChild(urlsTitle);
            urlsSection.appendChild(urlsList);
            urlsSection.appendChild(addUrlForm);
            container.appendChild(urlsSection);

            // 绑定事件
            bindDisabledPanelEvents();
        }

        // 渲染当前页面状态
        function renderCurrentPageStatus() {
            const isDomainDisabled = disabledList.domains.includes(currentDomain);
            const isUrlDisabled = disabledList.urls.includes(currentPageUrl);

            if (isDomainDisabled || isUrlDisabled) {
                return `
                    <div class="${STYLE_PREFIX}disabled-item">
                        <div class="${STYLE_PREFIX}disabled-info">
                            <span>${isDomainDisabled ? `此域名 (${currentDomain}) 已禁用高亮` : '此网址已禁用高亮'}</span>
                        </div>
                        <span class="${STYLE_PREFIX}disabled-action" data-type="${isDomainDisabled ? 'domain' : 'url'}" data-value="${isDomainDisabled ? currentDomain : currentPageUrl}">
                            启用
                        </span>
                    </div>
                `;
            } else {
                return `
                    <div class="${STYLE_PREFIX}current-page-actions">
                        <button class="${STYLE_PREFIX}disable-btn" id="disable-domain-btn">
                            禁用此域名
                        </button>
                        <button class="${STYLE_PREFIX}disable-btn" id="disable-url-btn">
                            禁用此网址
                        </button>
                    </div>
                `;
            }
        }

        // 渲染禁用域名列表
        function renderDisabledDomains() {
            if (disabledList.domains.length === 0) {
                return `<div class="${STYLE_PREFIX}empty-list">没有禁用的域名</div>`;
            }

            return disabledList.domains.map(domain => `
                <div class="${STYLE_PREFIX}disabled-item">
                    <div class="${STYLE_PREFIX}disabled-info">
                        <span>${domain}</span>
                    </div>
                    <span class="${STYLE_PREFIX}disabled-action" data-type="domain" data-value="${domain}">
                        删除
                    </span>
                </div>
            `).join('');
        }


        // 渲染禁用URL列表
        function renderDisabledUrls() {
            if (disabledList.urls.length === 0) {
                return `<div class="${STYLE_PREFIX}empty-list">没有禁用的网址</div>`;
            }

            return disabledList.urls.map(url => {
                // 为了美观,截断过长的URL
                const displayUrl = url.length > 40 ? url.substring(0, 37) + '...' : url;

                return `
                    <div class="${STYLE_PREFIX}disabled-item" title="${url}">
                        <div class="${STYLE_PREFIX}disabled-info">
                            <span>${displayUrl}</span>
                        </div>
                        <span class="${STYLE_PREFIX}disabled-action" data-type="url" data-value="${url}">
                            删除
                        </span>
                    </div>
                `;
            }).join('');
        }

        // 绑定禁用管理面板事件
        function bindDisabledPanelEvents() {
            // 禁用当前域名按钮
            const disableDomainBtn = document.getElementById('disable-domain-btn');
            if (disableDomainBtn) {
                disableDomainBtn.addEventListener('click', () => {
                    if (confirm(`确定要禁用域名 "${currentDomain}" 上的高亮功能吗?`)) {
                        disableDomain(currentDomain);
                        renderDisabledPanel();
                    }
                });
            }

            // 禁用当前网址按钮
            const disableUrlBtn = document.getElementById('disable-url-btn');
            if (disableUrlBtn) {
                disableUrlBtn.addEventListener('click', () => {
                    if (confirm('确定要禁用当前网址的高亮功能吗?')) {
                        disableUrl(currentPageUrl);
                        renderDisabledPanel();
                    }
                });
            }

            // 添加样式
            const styleSheet = document.createElement('style');
            styleSheet.textContent = `
                .${STYLE_PREFIX}disabled-item {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    padding: 8px 12px; // 增加水平内边距
                    background-color: rgba(40, 40, 50, 0.4); // 更深的背景
                    border-radius: 4px;
                    margin-bottom: 6px; // 减少垂直间距
                    transition: all 0.2s ease;
                    border: 1px solid rgba(255, 255, 255, 0.03); // 添加微妙的边框
                }

                .${STYLE_PREFIX}disabled-item:hover {
                    background-color: rgba(60, 60, 70, 0.4); // 更微妙的悬停效果
                    transform: translateX(2px); // 添加轻微的位移感
                }

                .${STYLE_PREFIX}disabled-info {
                    display: flex;
                    align-items: center;
                    gap: 8px;
                    font-size: 13px;
                    color: #ddd;
                    flex: 1;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    white-space: nowrap;
                }

                .${STYLE_PREFIX}disabled-action {
                    color: #ff8f8f;
                    font-size: 12px;
                    cursor: pointer;
                    padding: 2px 6px;
                    border-radius: 3px;
                    transition: all 0.2s;
                    opacity: 0.8;
                }

                .${STYLE_PREFIX}disabled-action:hover {
                    background-color: rgba(255, 82, 82, 0.15); // 更和谐的悬停效果
                    opacity: 1; // 悬停时完全不透明
                }

                .${STYLE_PREFIX}empty-list {
                    padding: 10px;
                    color: #888;
                    font-style: italic;
                    font-size: 13px;
                    text-align: center;
                    background-color: rgba(0, 0, 0, 0.15);
                    border-radius: 4px;
                }

                .${STYLE_PREFIX}current-page-actions {
                    display: flex;
                    gap: 10px;
                }

                .${STYLE_PREFIX}disable-btn {
                    flex: 1;
                    background: rgba(255, 255, 255, 0.08);
                    border: none;
                    border-radius: 4px;
                    padding: 8px 12px;
                    color: #e0e0e0;
                    font-size: 14px;
                    font-weight: 500;
                    cursor: pointer;
                    transition: all 0.2s ease;
                }

                .${STYLE_PREFIX}disable-btn:hover {
                    background-color: rgba(255, 255, 255, 0.15);
                }

                .${STYLE_PREFIX}add-disabled-input:focus {
                    border-color: #74b4ff;
                    background-color: rgba(255, 255, 255, 0.1);
                }

                .${STYLE_PREFIX}add-disabled-button:hover {
                    background-color: rgba(205, 70, 70, 0.85);
                    color: #f7e7e7;
                }
            `;
            document.head.appendChild(styleSheet);

            // 删除按钮事件
            document.querySelectorAll(`.${STYLE_PREFIX}disabled-action`).forEach(btn => {
                btn.addEventListener('click', (e) => {
                    const type = e.target.dataset.type;
                    const value = e.target.dataset.value;

                    if (e.target.textContent.trim() === '删除') {
                        if (type === 'domain') {
                            disabledList.domains = disabledList.domains.filter(d => d !== value);
                        } else if (type === 'url') {
                            disabledList.urls = disabledList.urls.filter(u => u !== value);
                        }
                        saveDisabledList();
                        renderDisabledPanel();
                    } else if (e.target.textContent.trim() === '启用') {
                        if (type === 'domain') {
                            enableDomain(value);
                        } else if (type === 'url') {
                            enableUrl(value);
                        }
                        renderDisabledPanel();
                    }
                });
            });

            // 添加域名按钮
            const addDomainBtn = document.getElementById('add-domain-btn');
            if (addDomainBtn) {
                addDomainBtn.addEventListener('click', () => {
                    const input = document.getElementById('add-domain-input');
                    const domain = input.value.trim();

                    if (domain) {
                        if (!disabledList.domains.includes(domain)) {
                            disabledList.domains.push(domain);
                            saveDisabledList();
                            input.value = '';
                            renderDisabledPanel();
                        } else {
                            alert('该域名已在禁用列表中');
                        }
                    }
                });
            }

            // 添加URL按钮
            const addUrlBtn = document.getElementById('add-url-btn');
            if (addUrlBtn) {
                addUrlBtn.addEventListener('click', () => {
                    const input = document.getElementById('add-url-input');
                    const url = input.value.trim();

                    if (url) {
                        if (!disabledList.urls.includes(url)) {
                            disabledList.urls.push(url);
                            saveDisabledList();
                            input.value = '';
                            renderDisabledPanel();
                        } else {
                            alert('该网址已在禁用列表中');
                        }
                    }
                });
            }

            // 输入框回车事件
            const domainInput = document.getElementById('add-domain-input');
            if (domainInput) {
                domainInput.addEventListener('keydown', (e) => {
                    if (e.key === 'Enter') {
                        document.getElementById('add-domain-btn').click();
                    }
                });
            }

            const urlInput = document.getElementById('add-url-input');
            if (urlInput) {
                urlInput.addEventListener('keydown', (e) => {
                    if (e.key === 'Enter') {
                        document.getElementById('add-url-btn').click();
                    }
                });
            }
        }

        // 初始渲染禁用管理面板
        renderDisabledPanel();
    }

    function init() {
        loadHighlights();
        registerEvents();
        if (document.readyState === 'complete') {
            setTimeout(() => {
                applyHighlights();
                observeDomChanges();
            }, 500);
        } else {
            window.addEventListener('load', () => {
                setTimeout(() => {
                    applyHighlights();
                    observeDomChanges();
                }, 500);
            });
        }
        // 注册油猴菜单命令
        GM_registerMenuCommand('打开侧边栏', () => {
            toggleSidebar(true);
        });
        GM_registerMenuCommand('切换浮动按钮显示/隐藏', toggleFloatingButton);
    }

    init();
    createFloatingButtonAndSidebar();
})();