Greasy Fork

Greasy Fork is available in English.

全局快捷平台跳转·收藏+导出+位置记忆

收藏当前页、导出全部站点配置、位置记忆、可删除

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         全局快捷平台跳转·收藏+导出+位置记忆
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  收藏当前页、导出全部站点配置、位置记忆、可删除
// @match        *://*/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    const SITE_KEY = "quick_nav_all_sites";
    const POS_KEY = "quick_nav_panel_position";

    // 初始默认站点
    const DEFAULT_SITES = [
        { name: "B站", url: "https://www.bilibili.com/" },
        { name: "X/Twitter", url: "https://x.com/" },
        { name: "YouTube", url: "https://www.youtube.com/" },
        { name: "Pinterest", url: "https://www.pinterest.com/" },
        { name: "TikTok", url: "https://www.tiktok.com/" },
        { name: "Kimi", url: "https://kimi.moonshot.cn/" },
        { name: "豆包", url: "https://www.doubao.com/" },
        { name: "百度", url: "https://www.baidu.com/" },
        { name: "Github", url: "https://github.com/" },
        { name: "知乎", url: "https://www.zhihu.com/" }
    ];

    if (document.getElementById('quick-nav-panel')) return;

    // 数据读写
    function getSiteList() {
        try {
            const data = localStorage.getItem(SITE_KEY);
            return data ? JSON.parse(data) : DEFAULT_SITES;
        } catch {
            return DEFAULT_SITES;
        }
    }
    function saveSiteList(arr) {
        localStorage.setItem(SITE_KEY, JSON.stringify(arr));
    }

    // 位置读写
    function getPos() {
        try {
            return JSON.parse(localStorage.getItem(POS_KEY)) || { left: 20, top: 320 };
        } catch {
            return { left: 20, top: 320 };
        }
    }
    function savePos(left, top) {
        localStorage.setItem(POS_KEY, JSON.stringify({ left, top }));
    }

    // 容器初始化
    const root = document.createElement('div');
    root.id = 'quick-nav-panel';
    const initPos = getPos();
    root.style.cssText = `
        all: initial;
        position: fixed;
        z-index: 9999998;
        left: ${initPos.left}px;
        top: ${initPos.top}px;
        width: 180px;
        font-family: system-ui, sans-serif;
        user-select: none;
    `;
    document.body.appendChild(root);

    // 顶部标题栏
    const bar = document.createElement('div');
    bar.style.cssText = `
        background: #ff4081;
        color: #fff;
        padding: 10px 12px;
        border-radius: 10px 10px 0 0;
        font-size: 14px;
        font-weight: 500;
        display: flex;
        justify-content: space-between;
        align-items: center;
        cursor: move;
    `;
    bar.innerHTML = `<span>快捷跳转</span><span id="nav-fold">−</span>`;
    root.appendChild(bar);

    // 内容面板
    const panel = document.createElement('div');
    panel.style.cssText = `
        background: #fff;
        border-radius: 0 0 10px 10px;
        padding: 10px;
        box-shadow: 0 4px 16px rgba(0,0,0,0.15);
        max-height: 320px;
        overflow-y: auto;
        ::-webkit-scrollbar { width: 5px; }
        ::-webkit-scrollbar-thumb { background: #ddd; border-radius: 5px; }
        ::-webkit-scrollbar-track { background: #f7f7f7; }
    `;
    root.appendChild(panel);

    // 渲染列表
    function renderList() {
        panel.innerHTML = "";
        const list = getSiteList();

        list.forEach((item, idx) => {
            const wrap = document.createElement('div');
            wrap.style.display = "flex";
            wrap.style.gap = "4px";
            wrap.style.marginBottom = "6px";

            const btn = document.createElement('div');
            btn.style.cssText = `
                flex:1; padding:8px 10px;
                background:#f5f5f5; border-radius:6px;
                font-size:13px; text-align:center; cursor:pointer;
            `;
            btn.textContent = item.name;
            btn.onmouseover = () => btn.style.background = "#eaeaea";
            btn.onmouseout = () => btn.style.background = "#f5f5f5";
            btn.onclick = () => window.open(item.url, "_blank");

            const del = document.createElement('span');
            del.textContent = "×";
            del.style.cssText = "color:#999; font-size:12px; cursor:pointer;";
            del.onclick = (e) => {
                e.stopPropagation();
                list.splice(idx, 1);
                saveSiteList(list);
                renderList();
            };

            wrap.append(btn, del);
            panel.appendChild(wrap);
        });

        // 功能按钮区
        const toolBox = document.createElement('div');
        toolBox.style.cssText = "margin-top:10px; display:flex; flex-direction:column; gap:6px;";

        // 1.收藏当前页面
        const collectBtn = document.createElement('button');
        collectBtn.textContent = "收藏当前页面";
        collectBtn.style.cssText = `
            padding:7px; border:none; border-radius:6px;
            background:#22c55e; color:#fff; font-size:12px; cursor:pointer;
        `;
        collectBtn.onclick = () => {
            const name = document.title.substring(0, 20);
            const url = location.href;
            const arr = getSiteList();
            arr.push({ name, url });
            saveSiteList(arr);
            renderList();
            tip("已收藏当前页面");
        };

        // 2.导出全部站点(格式化JS数组,自动复制)
        const exportBtn = document.createElement('button');
        exportBtn.textContent = "导出全部站点";
        exportBtn.style.cssText = `
            padding:7px; border:none; border-radius:6px;
            background:#1677ff; color:#fff; font-size:12px; cursor:pointer;
        `;
        exportBtn.onclick = () => {
            const arr = getSiteList();
            // 格式化为你脚本直接能用的 JS 数组格式
            const code = `const SITES = ` + JSON.stringify(arr, null, 4) + `;`;
            // 复制到剪贴板
            navigator.clipboard.writeText(code).then(() => {
                tip("已复制全部站点配置");
            });
        };

        toolBox.appendChild(collectBtn);
        toolBox.appendChild(exportBtn);
        panel.appendChild(toolBox);
    }

    // 轻提示
    function tip(text) {
        const t = document.createElement('div');
        t.textContent = text;
        t.style.cssText = `
            position:fixed; bottom:60px; left:50%;
            transform:translateX(-50%); background:rgba(0,0,0,0.7);
            color:#fff; padding:5px 12px; border-radius:4px;
            font-size:12px; z-index:999999;
        `;
        document.body.appendChild(t);
        setTimeout(() => t.remove(), 1500);
    }

    // 折叠
    const foldBtn = document.getElementById('nav-fold');
    foldBtn.style.cursor = "pointer";
    foldBtn.onclick = () => {
        const hide = panel.style.display === "none";
        panel.style.display = hide ? "block" : "none";
        foldBtn.textContent = hide ? "−" : "+";
        bar.style.borderRadius = hide ? "10px" : "10px 10px 0 0";
    };

    // 拖拽+保存位置
    let isDrag = false, startX, startY, lx, ly;
    bar.addEventListener('mousedown', e => {
        if (e.target === foldBtn) return;
        isDrag = false;
        startX = e.clientX;
        startY = e.clientY;
        lx = root.offsetLeft;
        ly = root.offsetTop;

        function move(e) {
            const dx = e.clientX - startX;
            const dy = e.clientY - startY;
            if (Math.abs(dx) > 4 || Math.abs(dy) > 4) isDrag = true;
            root.style.left = lx + dx + "px";
            root.style.top = ly + dy + "px";
        }
        function up() {
            document.removeEventListener('mousemove', move);
            document.removeEventListener('mouseup', up);
            if (isDrag) savePos(root.offsetLeft, root.offsetTop);
        }
        document.addEventListener('mousemove', move);
        document.addEventListener('mouseup', up);
    });

    // 初始化
    renderList();
// 默认永久折叠
panel.style.display = "none";
foldBtn.textContent = "+";
bar.style.borderRadius = "10px";
})();