Floating Link Menu

Customizable link menu.

当前为 2025-08-26 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Floating Link Menu
// @namespace    http://tampermonkey.net/
// @version      2.5 universal
// @description  Customizable link menu.
// @author       echoZ
// @license      MIT
// @match        *://*/*
// @exclude      *://*routerlogin.net/*
// @exclude      *://*192.168.1.1/*
// @exclude      *://*192.168.0.1/*
// @exclude      *://*my.bankofamerica.com/*
// @exclude      *://*wellsfargo.com/*
// @exclude      *://*chase.com/*
// @exclude      *://*citibank.com/*
// @exclude      *://*online.citi.com/*
// @exclude      *://*capitalone.com/*
// @exclude      *://*usbank.com/*
// @exclude      *://*paypal.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==
(async function() {
    'use strict';

    // --- SCRIPT EXCLUSION LOGIC ---
    const excludedDomainsStorageKey = 'excludedUniversalDomains';
    const currentUrl = window.location.href;
    const excludedDomains = await GM_getValue(excludedDomainsStorageKey, []);
    const isExcluded = excludedDomains.some(domain => currentUrl.includes(domain));
    if (isExcluded) {
        return;
    }
    // --- END EXCLUSION LOGIC ---

    // --- Data Management using Tampermonkey's GM_ API ---
    const storageKey = 'universalLinkManagerLinks';
    const isBubbleHiddenStorageKey = 'isBubbleHidden';
    const buttonPositionStorageKey = 'bubblePosition';
    const themeStorageKey = 'universalLinkManagerTheme';

    const defaultLinks = [
        { label: 'Google', url: 'https://www.google.com/' },
        { label: 'Gemini AI', url: 'https://gemini.google.com/' },
        { label: 'OpenAI', url: 'https://www.openai.com/' }
    ];

    let isDeleteMode = false;
    let isExcludeDeleteMode = false;

    async function getLinks() {
        return await GM_getValue(storageKey, defaultLinks);
    }

    async function saveLinks(links) {
        await GM_setValue(storageKey, links);
    }

    async function getExcludedDomains() {
        return await GM_getValue(excludedDomainsStorageKey, []);
    }

    async function saveExcludedDomains(domains) {
        await GM_setValue(excludedDomainsStorageKey, domains);
    }

    async function getBubbleHiddenState() {
        return await GM_getValue(isBubbleHiddenStorageKey, false);
    }

    async function saveBubbleHiddenState(isHidden) {
        await GM_setValue(isBubbleHiddenStorageKey, isHidden);
    }

    async function getButtonPosition() {
        return await GM_getValue(buttonPositionStorageKey, { vertical: 'bottom', horizontal: 'right' });
    }

    async function saveButtonPosition(position) {
        await GM_setValue(buttonPositionStorageKey, position);
    }

    async function getTheme() {
        return await GM_getValue(themeStorageKey, 'default');
    }

    async function saveTheme(theme) {
        await GM_setValue(themeStorageKey, theme);
    }

    // --- Style and Themes ---
    const themes = {
        default: `
            #floatingMenu, #universalLinkManagerUI, #bubbleMenu { background-color: #222; border: 2px solid #0ff; box-shadow: 0 0 10px rgba(0,255,255,0.7); }
            #linkList a, .exclude-wrapper span { color: #fff; background-color: #333; border: 1px solid #0ff; }
            #linkList a:hover { background-color: #0ff; color: #000; }
            #menuControls button, #backupSection button, #positionControls button, .modal-button, #bubbleMenu button { color: #0ff; border: 1px solid #0ff; background-color: #444; }
            #menuControls button:hover, #backupSection button:hover, #positionControls button:hover, .modal-button:hover, #bubbleMenu button:hover { background-color: #0ff; color: #000; }
            #linkForm input, #excludeSection input { border: 1px solid #0ff; background-color: #333; color: #fff; }
            #linkForm h3, #excludeSection h3, #backupSection h3, #positionControls h3 { color: #fff; }
            .delete-link-button, .delete-exclude-button { background-color: #a00; border: 1px solid #f00; color: #fff; }
            .delete-link-button:hover, .delete-exclude-button:hover { background-color: #f00; }
            .active { background-color: #0ff; color: #000 !important; }
        `,
        highContrast: `
            #floatingMenu, #universalLinkManagerUI, #bubbleMenu { background-color: #000; border: 2px solid #ffff00; box-shadow: 0 0 15px rgba(255,255,0,0.9); }
            #linkList a, .exclude-wrapper span { color: #ffff00; background-color: #000; border: 1px solid #ffff00; text-shadow: 0 0 5px #ffff00; font-weight: bold; }
            #linkList a:hover { background-color: #ffff00; color: #000; text-shadow: none; }
            #menuControls button, #backupSection button, #positionControls button, .modal-button, #bubbleMenu button { color: #ffff00; border: 1px solid #ffff00; background-color: #333; }
            #menuControls button:hover, #backupSection button:hover, #positionControls button:hover, .modal-button:hover, #bubbleMenu button:hover { background-color: #ffff00; color: #000; }
            #linkForm input, #excludeSection input { border: 1px solid #ffff00; background-color: #000; color: #ffff00; }
            #linkForm h3, #excludeSection h3, #backupSection h3, #positionControls h3 { color: #ffff00; }
            .delete-link-button, .delete-exclude-button { background-color: #ff0000; border: 1px solid #ff0000; color: #ffff00; }
            .delete-link-button:hover, .delete-exclude-button:hover { background-color: #ff5555; }
            .active { background-color: #ffff00; color: #000 !important; }
        `
    };

    const baseStyle = `
        @keyframes pulse {
            0% { transform: scale(1); box-shadow: 0 0 15px 3px #0ff, 0 0 30px 10px #0ff; }
            50% { transform: scale(1.05); box-shadow: 0 0 20px 5px #0ff, 0 0 40px 15px #0ff; }
            100% { transform: scale(1); box-shadow: 0 0 15px 3px #0ff, 0 0 30px 10px #0ff; }
        }
        @keyframes neonGlow {
            0% { box-shadow: 0 0 10px rgba(0,255,255,0.7); }
            50% { box-shadow: 0 0 15px rgba(0,255,255,0.9), 0 0 25px rgba(0,255,255,0.6); }
            100% { box-shadow: 0 0 10px rgba(0,255,255,0.7); }
        }

        #customFloatingBubble {
            position: fixed;
            width: 60px;
            height: 60px;
            background-color: #0ff;
            border-radius: 50%;
            box-shadow: 0 0 15px 3px #0ff, 0 0 30px 10px #0ff;
            cursor: pointer;
            z-index: 9999999;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 36px;
            font-weight: 900;
            color: #001f3f;
            user-select: none;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            transition: transform 0.2s ease, box-shadow 0.2s ease, top 0.2s ease, bottom 0.2s ease, left 0.2s ease, right 0.2s ease;
            animation: pulse 3s infinite ease-in-out;
        }
        #customFloatingBubble:hover {
            transform: scale(1.15);
            box-shadow: 0 0 20px 5px #0ff, 0 0 40px 15px #0ff;
        }
        #universalLinkManagerUI {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 350px;
            border-radius: 8px;
            padding: 15px;
            z-index: 9999998;
            display: none;
            flex-direction: column;
            gap: 15px;
            max-height: 90vh;
            overflow-y: auto;
            animation: neonGlow 4s infinite ease-in-out;
        }
        #bubbleMenu {
            position: fixed;
            z-index: 9999999;
            padding: 10px;
            border-radius: 8px;
            display: none;
            flex-direction: column;
            gap: 8px;
            animation: neonGlow 4s infinite ease-in-out;
        }
        #bubbleMenu button {
            transition: background-color 0.2s, color 0.2s;
        }
        #ui-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px solid #555;
            padding-bottom: 10px;
        }
        #ui-header h2 {
            margin: 0;
            color: #0ff;
            text-shadow: 0 0 5px #0ff;
        }
        #closeUI {
            background: none;
            border: none;
            color: #fff;
            font-size: 24px;
            cursor: pointer;
            padding: 0;
            width: 30px;
            height: 30px;
            border-radius: 50%;
            transition: all 0.2s ease;
        }
        #closeUI:hover {
            background-color: #f00;
            transform: scale(1.1);
        }
        #linkList, #excludeList {
            display: flex;
            flex-direction: column;
            gap: 5px;
        }
        .link-wrapper, .exclude-wrapper {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        #linkList a, .exclude-wrapper span {
            flex-grow: 1;
            padding: 8px;
            text-align: center;
            text-decoration: none;
            border-radius: 5px;
            transition: background-color 0.2s ease, color 0.2s ease;
            text-shadow: 0 0 3px currentColor;
            font-size: 14px;
        }
        .delete-link-button, .delete-exclude-button {
            width: 30px;
            height: 30px;
            border-radius: 50%;
            cursor: pointer;
            font-weight: bold;
            transition: background-color 0.2s ease;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 0;
        }
        #menuControls {
            display: flex;
            flex-wrap: wrap;
            justify-content: space-between;
            gap: 5px;
        }
        #menuControls button, .modal-button {
            padding: 8px 12px;
            border-radius: 5px;
            cursor: pointer;
            flex: 1 1 45%;
            font-size: 12px;
            text-align: center;
        }
        #linkForm, #excludeSection, #backupSection, #positionControls {
            display: flex;
            flex-direction: column;
            gap: 5px;
            padding-top: 10px;
            border-top: 1px solid #444;
        }
        #linkForm h3, #excludeSection h3, #backupSection h3, #positionControls h3 {
            margin: 0;
            text-align: center;
        }
        #linkForm input, #excludeSection input {
            padding: 8px;
            border-radius: 5px;
        }
        #backupSection button {
            flex: 1;
            font-size: 14px;
        }
        #showBubbleButton {
            position: fixed;
            width: 60px;
            height: 60px;
            cursor: pointer;
            z-index: 9999997;
            background-color: transparent;
            border: none;
            user-select: none;
        }
        #positionControls .position-buttons {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 5px;
        }
        .import-buttons {
            display: flex;
            gap: 5px;
        }
        .import-buttons button {
            flex: 1;
        }
    `;

    GM_addStyle(baseStyle);

    let bubble = null;
    let mainUI = null;
    let showBubbleButton = null;
    let bubbleMenu = null;

    function populateLinkList(links, linkListElement) {
        linkListElement.innerHTML = '';
        links.forEach((linkData, index) => {
            const linkWrapper = document.createElement('div');
            linkWrapper.className = 'link-wrapper';

            const link = document.createElement('a');
            link.href = linkData.url;
            link.textContent = linkData.label;
            link.target = '_blank';

            linkWrapper.appendChild(link);

            if (isDeleteMode) {
                const deleteButton = document.createElement('button');
                deleteButton.className = 'delete-link-button';
                deleteButton.textContent = 'x';
                deleteButton.addEventListener('click', async (event) => {
                    event.preventDefault();
                    links.splice(index, 1);
                    await saveLinks(links);
                    populateLinkList(links, linkListElement);
                });
                linkWrapper.appendChild(deleteButton);
            }
            linkListElement.appendChild(linkWrapper);
        });
    }

    function populateExcludeList(domains, excludeListElement) {
        excludeListElement.innerHTML = '';
        domains.forEach((domain, index) => {
            const domainWrapper = document.createElement('div');
            domainWrapper.className = 'exclude-wrapper';

            const domainLabel = document.createElement('span');
            domainLabel.textContent = domain;
            domainWrapper.appendChild(domainLabel);

            if (isExcludeDeleteMode) {
                const deleteButton = document.createElement('button');
                deleteButton.className = 'delete-exclude-button';
                deleteButton.textContent = 'x';
                deleteButton.addEventListener('click', async (event) => {
                    event.preventDefault();
                    domains.splice(index, 1);
                    await saveExcludedDomains(domains);
                    populateExcludeList(domains, excludeListElement);
                });
                domainWrapper.appendChild(deleteButton);
            }
            excludeListElement.appendChild(domainWrapper);
        });
    }

    function applyButtonPosition(position) {
        if (bubble) {
            bubble.style.top = '';
            bubble.style.left = '';
            bubble.style.bottom = '';
            bubble.style.right = '';
            bubble.style[position.vertical] = '30px';
            bubble.style[position.horizontal] = '30px';
        }
        if (showBubbleButton) {
            showBubbleButton.style.top = '';
            showBubbleButton.style.left = '';
            showBubbleButton.style.bottom = '';
            showBubbleButton.style.right = '';
            showBubbleButton.style[position.vertical] = '30px';
            showBubbleButton.style[position.horizontal] = '30px';
        }
        if (bubbleMenu) {
            bubbleMenu.style.top = '';
            bubbleMenu.style.left = '';
            bubbleMenu.style.bottom = '';
            bubbleMenu.style.right = '';

            if (position.vertical === 'top') {
                bubbleMenu.style.top = '100px';
            } else {
                bubbleMenu.style.bottom = '100px';
            }

            if (position.horizontal === 'left') {
                bubbleMenu.style.left = '30px';
            } else {
                bubbleMenu.style.right = '30px';
            }
        }

        const positionButtons = document.querySelectorAll('#positionControls button');
        positionButtons.forEach(btn => {
            btn.classList.remove('active');
        });
        const activeBtnId = `position-${position.vertical}-${position.horizontal}`;
        const activeBtn = document.getElementById(activeBtnId);
        if (activeBtn) {
            activeBtn.classList.add('active');
        }
    }

    function applyTheme(themeName) {
        const styleElement = document.getElementById('universalLinkManagerStyle');
        if (styleElement) {
            styleElement.innerHTML = `${baseStyle}\n${themes[themeName]}\n`;
        }
    }

    async function initializeScript() {
        if (document.getElementById('customFloatingBubble')) {
            return;
        }

        const buttonPosition = await getButtonPosition();
        const currentTheme = await getTheme();
        
        const style = document.createElement('style');
        style.id = 'universalLinkManagerStyle';
        document.head.appendChild(style);
        applyTheme(currentTheme);

        // Create the bubble
        bubble = document.createElement('div');
        bubble.id = 'customFloatingBubble';
        bubble.textContent = 'λ';
        document.body.appendChild(bubble);

        // Create the mini bubble menu
        bubbleMenu = document.createElement('div');
        bubbleMenu.id = 'bubbleMenu';
        bubbleMenu.innerHTML = `
            <button id="instantAddButton">Add This Site</button>
            <button id="showFullMenuButton">Settings</button>
        `;
        document.body.appendChild(bubbleMenu);

        // Create the main modal UI
        mainUI = document.createElement('div');
        mainUI.id = 'universalLinkManagerUI';
        mainUI.innerHTML = `
            <div id="ui-header">
                <h2>Universal Links</h2>
                <button id="closeUI">X</button>
            </div>
            <div id="ui-content">
                <div id="linkList"></div>
                <div id="linkForm">
                    <h3>Add New Link</h3>
                    <input type="text" id="linkLabel" placeholder="Label (e.g. My Site)">
                    <input type="text" id="linkUrl" placeholder="URL (e.g. https://example.com)">
                    <button id="saveLinkButton" class="modal-button">Save</button>
                </div>
                <div id="excludeSection">
                    <h3>Excluded Websites</h3>
                    <div id="excludeList"></div>
                    <input type="text" id="excludeUrl" placeholder="Domain (e.g. example.com)">
                    <button id="saveExcludeButton" class="modal-button">Add Exclude</button>
                    <button id="deleteExcludeButton" class="modal-button">Delete Excludes</button>
                </div>
                <div id="backupSection">
                    <h3>Backup & Restore</h3>
                    <div id="exportWrapper">
                        <button id="exportButton" class="modal-button">Export</button>
                    </div>
                    <div id="importWrapper">
                        <button id="importButton" class="modal-button">Import</button>
                    </div>
                </div>
                <div id="positionControls">
                    <h3>Button Position</h3>
                    <div class="position-buttons">
                        <button id="position-top-left" class="modal-button">Top-Left</button>
                        <button id="position-top-right" class="modal-button">Top-Right</button>
                        <button id="position-bottom-left" class="modal-button">Bottom-Left</button>
                        <button id="position-bottom-right" class="modal-button">Bottom-Right</button>
                    </div>
                </div>
                <div id="menuControls">
                    <button id="deleteLinksButton" class="modal-button">Delete Links</button>
                    <button id="themeButton" class="modal-button">Theme</button>
                    <button id="hideButton" class="modal-button">Hide Button</button>
                </div>
            </div>
        `;
        document.body.appendChild(mainUI);
        
        // Create the invisible show bubble button
        showBubbleButton = document.createElement('div');
        showBubbleButton.id = 'showBubbleButton';
        document.body.appendChild(showBubbleButton);

        // Load initial state and position
        applyButtonPosition(buttonPosition);
        const isHidden = await getBubbleHiddenState();
        bubble.style.display = isHidden ? 'none' : 'flex';
        showBubbleButton.style.display = isHidden ? 'block' : 'none';

        // --- Event Listeners ---
        // Bubble click to toggle the mini-menu
        bubble.addEventListener('click', async () => {
            const isVisible = bubbleMenu.style.display === 'flex';
            bubbleMenu.style.display = isVisible ? 'none' : 'flex';
        });

        // Triple-click logic for bubble
        let bubbleClickCount = 0;
        let bubbleClickTimer = null;
        bubble.addEventListener('click', () => {
            bubbleClickCount++;
            if (bubbleClickTimer) clearTimeout(bubbleClickTimer);
            bubbleClickTimer = setTimeout(() => {
                bubbleClickCount = 0;
            }, 300);

            if (bubbleClickCount === 3) {
                clearTimeout(bubbleClickTimer);
                bubble.style.display = 'none';
                showBubbleButton.style.display = 'block';
                mainUI.style.display = 'none';
                bubbleMenu.style.display = 'none';
                saveBubbleHiddenState(true);
                bubbleClickCount = 0;
            }
        });

        // Triple-click logic for showBubbleButton
        let restoreClickCount = 0;
        let restoreClickTimer = null;
        showBubbleButton.addEventListener('click', () => {
            restoreClickCount++;
            if (restoreClickTimer) clearTimeout(restoreClickTimer);
            restoreClickTimer = setTimeout(() => {
                restoreClickCount = 0;
            }, 400);

            if (restoreClickCount === 3) {
                clearTimeout(restoreClickTimer);
                bubble.style.display = 'flex';
                showBubbleButton.style.display = 'none';
                saveBubbleHiddenState(false);
                restoreClickCount = 0;
            }
        });
        
        // Instant Add Button
        bubbleMenu.querySelector('#instantAddButton').addEventListener('click', async () => {
            const title = document.title;
            const url = window.location.href;
            const links = await getLinks();
            
            links.push({ label: title, url: url });
            await saveLinks(links);
            
            bubbleMenu.style.display = 'none';
            const excluded = await getExcludedDomains();
            populateLinkList(links, mainUI.querySelector('#linkList'));
            populateExcludeList(excluded, mainUI.querySelector('#excludeList'));
            mainUI.style.display = 'flex';
        });

        // Show Full Menu Button
        bubbleMenu.querySelector('#showFullMenuButton').addEventListener('click', async () => {
            bubbleMenu.style.display = 'none';
            const links = await getLinks();
            const excluded = await getExcludedDomains();
            populateLinkList(links, mainUI.querySelector('#linkList'));
            populateExcludeList(excluded, mainUI.querySelector('#excludeList'));
            mainUI.style.display = 'flex';
        });

        mainUI.querySelector('#closeUI').addEventListener('click', () => {
            mainUI.style.display = 'none';
        });

        mainUI.querySelector('#hideButton').addEventListener('click', () => {
            bubble.style.display = 'none';
            showBubbleButton.style.display = 'block';
            mainUI.style.display = 'none';
            bubbleMenu.style.display = 'none';
            saveBubbleHiddenState(true);
        });

        mainUI.querySelector('#saveLinkButton').addEventListener('click', async () => {
            const labelInput = mainUI.querySelector('#linkLabel');
            const urlInput = mainUI.querySelector('#linkUrl');
            const label = labelInput.value.trim();
            const url = urlInput.value.trim();
            if (label && url) {
                try {
                    new URL(url);
                    const links = await getLinks();
                    links.push({ label, url });
                    await saveLinks(links);
                    populateLinkList(links, mainUI.querySelector('#linkList'));
                    labelInput.value = '';
                    urlInput.value = '';
                } catch (e) {
                    alert('Please enter a valid URL (e.g., https://example.com).');
                }
            } else {
                alert('Please enter both a label and a URL.');
            }
        });

        mainUI.querySelector('#deleteLinksButton').addEventListener('click', async () => {
            isDeleteMode = !isDeleteMode;
            const deleteButton = mainUI.querySelector('#deleteLinksButton');
            deleteButton.textContent = isDeleteMode ? 'Exit Delete' : 'Delete Links';
            const links = await getLinks();
            populateLinkList(links, mainUI.querySelector('#linkList'));
        });

        mainUI.querySelector('#themeButton').addEventListener('click', async () => {
            const currentTheme = await getTheme();
            const newTheme = currentTheme === 'default' ? 'highContrast' : 'default';
            await saveTheme(newTheme);
            applyTheme(newTheme);
            const themeButton = mainUI.querySelector('#themeButton');
            themeButton.textContent = newTheme === 'default' ? 'Theme' : 'Default';
        });

        mainUI.querySelector('#saveExcludeButton').addEventListener('click', async () => {
            const domainInput = mainUI.querySelector('#excludeUrl');
            const domain = domainInput.value.trim();
            if (domain) {
                const excluded = await getExcludedDomains();
                if (!excluded.includes(domain)) {
                    excluded.push(domain);
                    await saveExcludedDomains(excluded);
                    populateExcludeList(excluded, mainUI.querySelector('#excludeList'));
                    domainInput.value = '';
                } else {
                    alert('This domain is already on the exclusion list.');
                }
            } else {
                alert('Please enter a domain to exclude.');
            }
        });

        mainUI.querySelector('#deleteExcludeButton').addEventListener('click', async () => {
            isExcludeDeleteMode = !isExcludeDeleteMode;
            const deleteExcludeButton = mainUI.querySelector('#deleteExcludeButton');
            deleteExcludeButton.textContent = isExcludeDeleteMode ? 'Exit Exclude Delete' : 'Delete Excludes';
            const excluded = await getExcludedDomains();
            populateExcludeList(excluded, mainUI.querySelector('#excludeList'));
        });

        mainUI.querySelector('#positionControls').querySelectorAll('button').forEach(button => {
            button.addEventListener('click', async (event) => {
                const id = event.target.id;
                const parts = id.split('-');
                const newPosition = { vertical: parts[1], horizontal: parts[2] };
                await saveButtonPosition(newPosition);
                applyButtonPosition(newPosition);
            });
        });

        mainUI.querySelector('#exportWrapper').addEventListener('click', async (event) => {
            const button = event.target;
            if (button.id === 'exportButton') {
                if (button.textContent === 'Export') {
                    const links = await getLinks();
                    const exportData = JSON.stringify(links, null, 2);
                    mainUI.querySelector('#exportWrapper').innerHTML = `
                        <textarea readonly style="width:100%; height:100px;">${exportData}</textarea>
                        <button id="exportButton" class="modal-button">Close</button>
                    `;
                } else {
                    mainUI.querySelector('#exportWrapper').innerHTML = `<button id="exportButton" class="modal-button">Export</button>`;
                }
            }
        });

        mainUI.querySelector('#importWrapper').addEventListener('click', async (event) => {
            const button = event.target;
            if (button.id === 'importButton') {
                if (button.textContent === 'Import') {
                    mainUI.querySelector('#importWrapper').innerHTML = `
                        <textarea placeholder="Paste your link data here..." style="width:100%; height:100px;"></textarea>
                        <div class="import-buttons">
                            <button id="loadButton" class="modal-button">Load</button>
                            <button id="importButton" class="modal-button">Cancel</button>
                        </div>
                    `;
                } else {
                    mainUI.querySelector('#importWrapper').innerHTML = `<button id="importButton" class="modal-button">Import</button>`;
                }
            } else if (button.id === 'loadButton') {
                const dataTextarea = mainUI.querySelector('textarea');
                if (dataTextarea) {
                    const data = dataTextarea.value.trim();
                    if (!data) {
                        alert('Please paste the link data.');
                        return;
                    }
                    try {
                        const importedLinks = JSON.parse(data);
                        if (Array.isArray(importedLinks)) {
                            await saveLinks(importedLinks);
                            const links = await getLinks();
                            populateLinkList(links, mainUI.querySelector('#linkList'));
                            alert('Links imported successfully!');
                            mainUI.querySelector('#importWrapper').innerHTML = `<button id="importButton" class="modal-button">Import</button>`;
                        } else {
                            alert('Invalid data format. Please paste the correct JSON data.');
                        }
                    } catch (e) {
                        alert('Invalid JSON format. Error: ' + e.message);
                    }
                }
            }
        });
    }

    if (document.body) {
        initializeScript();
    } else {
        document.addEventListener('DOMContentLoaded', initializeScript);
    }
})();