// ==UserScript== // @name LinuxDo 收藏夹 // @namespace https://linux.do/ // @version 1.0.6 // @description 自定义收藏夹功能 // @author eamooooon // @icon data:image/png;base64,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 // @match https://linux.do/* // @match https://linux.do/t/* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_addStyle // @run-at document-idle // ==/UserScript== (function() { 'use strict'; const STORAGE_KEY = 'linux_do_favorites'; const FOLDERS_KEY = 'linux_do_folders'; const THEME_KEY = 'linux_do_theme'; const MODE_KEY = 'linux_do_mode'; const GITHUB_TOKEN_KEY = 'linux_do_github_token'; const GIST_ID_KEY = 'linux_do_gist_id'; const BUTTON_POS_KEY = 'linux_do_button_position'; const defaultFolders = ['默认收藏']; const themes = { 'orange': { name: '橙红色', color: '#e5573c' }, 'blue': { name: '蓝色', color: '#3b82f6' }, 'green': { name: '绿色', color: '#22c55e' }, 'purple': { name: '紫色', color: '#a855f7' }, 'pink': { name: '粉色', color: '#ec4899' }, 'teal': { name: '青色', color: '#14b8a6' } }; function getTheme() { return GM_getValue(THEME_KEY, 'orange'); } function saveTheme(theme) { GM_setValue(THEME_KEY, theme); } function getMode() { return GM_getValue(MODE_KEY, 'default'); } function saveMode(mode) { GM_setValue(MODE_KEY, mode); } function getButtonPosition() { return GM_getValue(BUTTON_POS_KEY, 'floor'); } function saveButtonPosition(pos) { GM_setValue(BUTTON_POS_KEY, pos); } function getGithubToken() { return GM_getValue(GITHUB_TOKEN_KEY, ''); } function saveGithubToken(token) { GM_setValue(GITHUB_TOKEN_KEY, token); } function getGistId() { return GM_getValue(GIST_ID_KEY, ''); } function saveGistId(gistId) { GM_setValue(GIST_ID_KEY, gistId); } function hexToRgba(hex, alpha) { const r = parseInt(hex.slice(1, 3), 16); const g = parseInt(hex.slice(3, 5), 16); const b = parseInt(hex.slice(5, 7), 16); return `rgba(${r}, ${g}, ${b}, ${alpha})`; } function applyTheme(theme) { const themeColor = themes[theme]?.color || themes.orange.color; document.documentElement.style.setProperty('--ld-theme-color', themeColor); document.documentElement.style.setProperty('--ld-theme-bg-light', hexToRgba(themeColor, 0.1)); document.documentElement.style.setProperty('--ld-theme-bg-dark', hexToRgba(themeColor, 0.2)); } function getFolders() { const saved = GM_getValue(FOLDERS_KEY, null); let folders = saved ? JSON.parse(saved) : [...defaultFolders]; if (!folders.includes('默认收藏')) { folders.unshift('默认收藏'); } return folders; } function saveFolders(folders) { GM_setValue(FOLDERS_KEY, JSON.stringify(folders)); } function getFavorites() { const saved = GM_getValue(STORAGE_KEY, null); const favs = saved ? JSON.parse(saved) : {}; let dirty = false; for (const [key, fav] of Object.entries(favs)) { if (fav.url && fav.url.includes('/null')) { fav.url = fav.url.replace('/null', ''); dirty = true; } if (fav.postNumber === 'null' || fav.postNumber === null) { fav.postNumber = undefined; dirty = true; } if (fav.title && fav.title.includes(' - #null')) { fav.title = fav.title.replace(' - #null', ''); dirty = true; } } if (dirty) GM_setValue(STORAGE_KEY, JSON.stringify(favs)); return favs; } function saveFavorites(favorites) { GM_setValue(STORAGE_KEY, JSON.stringify(favorites)); } function getTopicId() { const match = window.location.pathname.match(/\/t\/.*?\/(\d+)/); return match ? match[1] : null; } function getPostId(postElement) { if (!postElement) return null; const postId = postElement.getAttribute('data-post-id'); const postNumber = postElement.getAttribute('data-post-number'); return postId ? { id: postId, number: postNumber } : null; } function getTopicInfo() { const topicId = getTopicId(); if (!topicId) return null; const titleEl = document.querySelector('.header-title .topic-link span span') || document.querySelector('#topic-title h1 .topic-link') || document.querySelector('.fancy-title') || document.querySelector('.header-title'); const title = titleEl ? titleEl.textContent.trim() : document.title; const categoryEl = document.querySelector('.badge-category__name') || document.querySelector('.category-name'); const category = categoryEl ? categoryEl.textContent.trim() : '未分类'; const tagsEls = document.querySelectorAll('.discourse-tag.box, .tag'); const tags = [...new Set(Array.from(tagsEls).map(t => t.textContent.trim()))]; return { id: topicId, title: title, url: window.location.href.split('?')[0], category: category, tags: tags, addedAt: Date.now() }; } function getPostInfo(postElement) { const topicId = getTopicId(); if (!topicId || !postElement) return null; const postInfo = getPostId(postElement); if (!postInfo) return null; const titleEl = document.querySelector('.header-title .topic-link span span') || document.querySelector('#topic-title h1 .topic-link') || document.querySelector('.fancy-title') || document.querySelector('.header-title'); const topicTitle = titleEl ? titleEl.textContent.trim() : document.title; const categoryEl = document.querySelector('.badge-category__name') || document.querySelector('.category-name'); const category = categoryEl ? categoryEl.textContent.trim() : '未分类'; const tagsEls = document.querySelectorAll('.discourse-tag.box, .tag'); const tags = [...new Set(Array.from(tagsEls).map(t => t.textContent.trim()))]; const cookedEl = postElement.querySelector('.cooked'); const postContent = cookedEl ? cookedEl.textContent.trim().substring(0, 50) : ''; const uniqueId = `${topicId}_${postInfo.id}`; let postNumber = postInfo.number; if (!postNumber) { const floorEl = postElement.querySelector('#floor-button, .floor-number'); if (floorEl) { const match = floorEl.textContent.match(/(\d+)/); if (match) postNumber = match[1]; } } const isFloor1 = postNumber === '1' || postNumber === 1 || !postNumber; return { id: uniqueId, topicId: topicId, postId: postInfo.id, postNumber: postNumber, title: isFloor1 ? topicTitle : `${topicTitle} - #${postNumber}`, url: isFloor1 ? window.location.pathname.split('?')[0] : `${window.location.pathname}/${postNumber}`, category: category, tags: tags, addedAt: Date.now(), isPost: true }; } GM_addStyle(` .ld-fav-post-btn.btn { background: none !important; border: none !important; cursor: pointer !important; padding: 8px !important; color: var(--primary-high, #333) !important; font-size: 24px !important; display: inline-flex !important; align-items: center !important; gap: 4px !important; opacity: 0.7 !important; transition: opacity 0.2s !important; } .ld-fav-post-btn.btn:hover { opacity: 1 !important; color: var(--ld-theme-color, #e5573c) !important; } .ld-fav-post-btn.btn.favorited { color: var(--ld-theme-color, #e5573c) !important; opacity: 1 !important; } .ld-fav-post-btn.btn svg { width: 1.3em; height: 1.3em; } #ld-fav-modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 10000; justify-content: center; align-items: center; } #ld-fav-modal.show { display: flex; } .ld-fav-content { background: var(--secondary, #fff); color: var(--primary, #333); border-radius: 12px; width: 500px; max-height: 80vh; overflow: hidden; display: flex; flex-direction: column; } .ld-fav-header { padding: 16px 20px; border-bottom: 1px solid var(--primary-low, #eee); display: flex; justify-content: space-between; align-items: center; } .ld-fav-header h3 { margin: 0; font-size: 18px; } .ld-fav-close { background: none; border: none; font-size: 24px; cursor: pointer; color: var(--primary, #333); } .ld-fav-tabs { display: flex; border-bottom: 1px solid var(--primary-low, #eee); overflow-x: auto; } .ld-fav-tab { padding: 10px 16px; cursor: pointer; white-space: nowrap; border-bottom: 2px solid transparent; font-size: 14px; color: var(--primary-medium, #666); } .ld-fav-tab.active { color: var(--ld-theme-color, #e5573c); border-bottom-color: var(--ld-theme-color, #e5573c); } .ld-fav-tab:hover { background: var(--highlight-low, #f5f5f5); } .ld-fav-body { flex: 1; overflow-y: auto; padding: 12px; } .ld-fav-item { padding: 10px 12px; border-radius: 8px; margin-bottom: 6px; display: flex; justify-content: space-between; align-items: center; background: var(--primary-low, #f8f8f8); } .ld-fav-item:hover { background: var(--highlight-low, #f0f0f0); } .ld-fav-item a { color: var(--primary, #333); text-decoration: none; flex: 1; font-size: 14px; line-height: 1.4; } .ld-fav-item a:hover { color: var(--ld-theme-color, #e5573c); } .ld-fav-item-meta { font-size: 12px; color: var(--primary-medium, #888); margin-top: 4px; } .ld-fav-remove { background: none; border: none; color: var(--danger, var(--ld-theme-color, #e5573c)); cursor: pointer; font-size: 16px; padding: 4px 8px; border-radius: 4px; opacity: 0; transition: opacity 0.2s; } .ld-fav-item:hover .ld-fav-remove { opacity: 1; } .ld-fav-footer { padding: 12px 16px; border-top: 1px solid var(--primary-low, #eee); display: flex; gap: 8px; } .ld-fav-footer button { padding: 8px 16px; border-radius: 6px; border: 1px solid var(--primary-low, #ddd); background: var(--secondary, #fff); color: var(--primary, #333); cursor: pointer; font-size: 13px; } .ld-fav-footer button:hover { background: var(--highlight-low, #f0f0f0); } .ld-fav-empty { text-align: center; padding: 40px 20px; color: var(--primary-medium, #888); } .ld-fav-dialog { position: absolute; background: var(--secondary, #fff); padding: 0 12px; border-radius: 8px; z-index: 10001; box-shadow: 0 4px 20px rgba(0,0,0,0.15); min-width: 200px; max-height: 0; overflow: hidden; border: 2px solid transparent; pointer-events: none; opacity: 0; transition: max-height 0.25s ease, padding 0.25s ease, border-color 0.25s ease, opacity 0.15s ease 0.15s; } .ld-fav-dialog.show { pointer-events: auto; opacity: 1; max-height: 300px; padding: 12px; overflow-y: auto; border-color: var(--primary-low, #ddd); transition: max-height 0.25s ease, padding 0.25s ease, border-color 0.25s ease, opacity 0.15s ease; } #ld-fav-new-folder-dialog { overflow: hidden; } .ld-fav-folder-item { padding: 8px 12px; cursor: pointer; border-radius: 4px; display: flex; align-items: center; gap: 8px; color: var(--primary, #333); font-size: 14px; } .ld-fav-folder-item:hover { background: var(--highlight-low, #f0f0f0); } .ld-fav-folder-item.selected { background: var(--highlight-low, #e8e8e8); color: var(--ld-theme-color, #e5573c); } .ld-fav-new-folder { padding: 8px 12px; cursor: pointer; border-radius: 4px; display: flex; align-items: center; gap: 8px; color: var(--primary-medium, #888); font-size: 14px; border-top: 1px solid var(--primary-low, #eee); margin-top: 4px; } .ld-fav-new-folder:hover { background: var(--highlight-low, #f0f0f0); color: var(--primary, #333); } .ld-fav-dialog h4 { margin: 0 0 16px 0; font-size: 16px; } .ld-fav-dialog input, .ld-fav-dialog select { width: 100%; padding: 10px; border: 1px solid var(--primary-low, #ddd); border-radius: 6px; font-size: 14px; margin-bottom: 12px; background: var(--secondary, #fff); color: var(--primary, #333); box-sizing: border-box; } .ld-fav-dialog-actions { display: flex; justify-content: flex-end; gap: 8px; } .ld-fav-dialog-actions button { padding: 8px 16px; border-radius: 6px; border: none; cursor: pointer; font-size: 13px; } .ld-fav-btn-primary { background: var(--ld-theme-color, #e5573c); color: white; } .ld-fav-btn-secondary { background: var(--primary-low, #eee); color: var(--primary, #333); } .ld-fav-inline-btn { background: none; border: 1px dashed var(--primary-low, #ccc); color: var(--primary-medium, #888); padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 12px; width: 100%; margin-top: 4px; } .ld-fav-inline-btn:hover { border-color: var(--ld-theme-color, #e5573c); color: var(--ld-theme-color, #e5573c); } #ld-fav-panel { display: flex; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0); z-index: 10002; justify-content: center; align-items: center; pointer-events: none; opacity: 0; transition: background 0.3s ease, opacity 0.3s ease; } #ld-fav-panel.show { pointer-events: auto; opacity: 1; background: rgba(0,0,0,0.5); } #ld-fav-panel.show .ld-fav-panel-body { transform: scale(1) translateY(0); opacity: 1; } .ld-fav-panel-close { position: absolute; top: 16px; right: 16px; background: none; border: none; font-size: 24px; cursor: pointer; color: var(--primary-medium, #888); padding: 8px; line-height: 1; z-index: 1; } .ld-fav-panel-close:hover { color: var(--primary, #333); } .ld-fav-panel-body { display: flex; flex: 1; overflow: hidden; background: var(--secondary, #fff); border-radius: 12px; width: 80%; max-width: 1000px; height: 80vh; box-shadow: 0 10px 40px rgba(0,0,0,0.2); flex-direction: row; transform: scale(0.92) translateY(20px); opacity: 0; transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.3s ease; } .ld-fav-panel-sidebar { width: 200px; min-width: 200px; border-right: 1px solid var(--primary-low, #eee); overflow-y: auto; padding: 8px 0; background: var(--primary-low, #f0f0f0); } .ld-fav-panel-sidebar::-webkit-scrollbar { width: 6px; } .ld-fav-panel-sidebar::-webkit-scrollbar-track { background: transparent; } .ld-fav-panel-sidebar::-webkit-scrollbar-thumb { background: var(--primary-low, #ccc); border-radius: 3px; } .ld-fav-panel-sidebar::-webkit-scrollbar-thumb:hover { background: var(--primary-medium, #999); } .ld-fav-panel-folder { display: flex; justify-content: space-between; align-items: center; padding: 10px 16px; cursor: pointer; color: var(--primary, #333); font-size: 14px; position: relative; } .ld-fav-panel-folder:hover { background: var(--highlight-low, #f0f0f0); } .ld-fav-panel-folder.active { background: var(--secondary, #fff); color: var(--ld-theme-color, #e5573c); font-weight: 600; } .ld-fav-panel-folder-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ld-fav-panel-folder-count { background: var(--primary-low, #eee); color: var(--primary-medium, #888); padding: 2px 8px; border-radius: 10px; font-size: 12px; margin-left: 8px; } .ld-fav-panel-folder-actions { display: none; gap: 4px; margin-left: 8px; } .ld-fav-panel-folder:hover .ld-fav-panel-folder-actions { display: flex; } .ld-fav-panel-folder-btn { background: none; border: none; cursor: pointer; padding: 2px 4px; color: var(--primary-medium, #888); font-size: 12px; border-radius: 3px; } .ld-fav-panel-folder-btn:hover { background: var(--primary-low, #eee); color: var(--primary, #333); } .ld-fav-panel-folder-btn.delete:hover { color: var(--ld-theme-color, #e5573c); } .ld-fav-panel-folder-drag-handle { cursor: grab; color: var(--primary-medium, #888); margin-right: 8px; font-size: 12px; } .ld-fav-panel-folder.dragging { opacity: 0.5; background: var(--highlight-low, #f0f0f0); } .ld-fav-panel-folder.drag-over { border-top: 2px solid var(--ld-theme-color, #e5573c); } .ld-fav-panel-add-folder { padding: 10px 16px; cursor: pointer; color: var(--primary-medium, #888); font-size: 14px; border-top: 1px solid var(--primary-low, #eee); margin-top: 8px; } .ld-fav-panel-add-folder:hover { background: var(--highlight-low, #f0f0f0); color: var(--primary, #333); } .ld-fav-panel-settings { padding: 10px 16px; cursor: pointer; color: var(--primary-medium, #888); font-size: 14px; border-top: 1px solid var(--primary-low, #eee); margin-top: auto; } .ld-fav-panel-settings:hover { background: var(--highlight-low, #f0f0f0); color: var(--primary, #333); } .ld-fav-settings-panel { display: none; padding: 12px 16px; border-top: 1px solid var(--primary-low, #eee); background: var(--primary-low, #f0f0f0); } .ld-fav-settings-panel.show { display: block; } .ld-fav-settings-title { font-size: 13px; color: var(--primary-medium, #888); margin-bottom: 10px; } .ld-fav-mode-options { display: flex; flex-direction: column; gap: 8px; margin-bottom: 4px; } .ld-fav-mode-option { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--primary, #333); cursor: pointer; } .ld-fav-mode-option input[type="radio"] { accent-color: var(--ld-theme-color, #e5573c); } .ld-fav-theme-options { display: flex; flex-wrap: wrap; gap: 8px; } .ld-fav-theme-option { width: 28px; height: 28px; border-radius: 50%; cursor: pointer; border: 2px solid transparent; transition: transform 0.2s; } .ld-fav-theme-option:hover { transform: scale(1.1); } .ld-fav-theme-option.active { border-color: var(--primary, #333); box-shadow: 0 0 0 2px var(--secondary, #fff); } .ld-fav-settings-content { padding: 20px; max-width: 600px; } .ld-fav-settings-header { font-size: 20px; font-weight: 600; color: var(--primary, #333); margin: 0 0 24px 0; padding-bottom: 12px; border-bottom: 2px solid var(--ld-theme-color, #e5573c); } .ld-fav-settings-section { margin-bottom: 28px; padding: 16px; background: var(--primary-low, #f5f5f5); border-radius: 8px; } .ld-fav-settings-content .ld-fav-settings-title { font-size: 15px; font-weight: 600; color: var(--primary, #333); margin-bottom: 12px; } .ld-fav-settings-desc { font-size: 13px; color: var(--primary-medium, #888); margin-bottom: 16px; } .ld-fav-settings-field { margin-bottom: 16px; } .ld-fav-settings-advanced { margin-top: 12px; } .ld-fav-settings-advanced summary { font-size: 13px; color: var(--primary-medium, #888); cursor: pointer; user-select: none; } .ld-fav-settings-advanced summary:hover { color: var(--primary, #333); } .ld-fav-settings-advanced[open] summary { margin-bottom: 12px; } .ld-fav-settings-label { display: block; font-size: 13px; font-weight: 500; color: var(--primary, #333); margin-bottom: 6px; } .ld-fav-settings-input { width: 100%; padding: 10px 12px; border: 1px solid var(--primary-low, #ddd); border-radius: 6px; font-size: 14px; background: var(--secondary, #fff); color: var(--primary, #333); box-sizing: border-box; transition: border-color 0.2s; } .ld-fav-settings-input:focus { outline: none; border-color: var(--ld-theme-color, #e5573c); } .ld-fav-settings-hint { font-size: 12px; color: var(--primary-medium, #888); margin-top: 6px; } .ld-fav-settings-hint a { color: var(--ld-theme-color, #e5573c); text-decoration: none; } .ld-fav-settings-hint a:hover { text-decoration: underline; } .ld-fav-settings-actions { display: flex; gap: 10px; margin-top: 16px; } .ld-fav-settings-btn { padding: 10px 20px; border: none; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; background: var(--ld-theme-color, #e5573c); color: white; transition: opacity 0.2s; } .ld-fav-settings-btn:hover { opacity: 0.9; } .ld-fav-settings-btn.secondary { background: var(--primary-low, #eee); color: var(--primary, #333); } .ld-fav-settings-btn.secondary:hover { background: var(--primary-low, #ddd); } .ld-fav-settings-status { margin-top: 12px; padding: 10px; border-radius: 6px; font-size: 13px; display: none; } .ld-fav-settings-status.success { display: block; background: #d4edda; color: #155724; } .ld-fav-settings-status.error { display: block; background: #f8d7da; color: #721c24; } .ld-fav-settings-status.info { display: block; background: #d1ecf1; color: #0c5460; } .ld-fav-panel-rename-input { width: 100%; padding: 4px 8px; border: 1px solid var(--ld-theme-color, #e5573c); border-radius: 4px; font-size: 14px; background: var(--secondary, #fff); color: var(--primary, #333); } .ld-fav-inline-dialog { position: absolute; background: var(--secondary, #fff); border: 2px solid var(--primary-low, #ddd); border-radius: 8px; padding: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 10002; min-width: 200px; pointer-events: none; opacity: 0; transform: translateY(-8px) scale(0.96); transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1); } .ld-fav-inline-dialog.show { pointer-events: auto; opacity: 1; transform: translateY(0) scale(1); } .ld-fav-inline-dialog-title { font-size: 14px; color: var(--primary, #333); margin-bottom: 10px; } .ld-fav-inline-dialog-input { width: 100%; padding: 8px; border: 1px solid var(--primary-low, #ddd); border-radius: 4px; font-size: 14px; margin-bottom: 10px; box-sizing: border-box; outline: none !important; } .ld-fav-inline-dialog-input.error { border-color: #e5573c !important; outline: none !important; } .ld-fav-inline-dialog-actions { display: flex; justify-content: flex-end; gap: 8px; } .ld-fav-inline-dialog-btn { padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; font-size: 13px; } .ld-fav-inline-dialog-btn.confirm { background: var(--ld-theme-color, #e5573c); color: white; } .ld-fav-inline-dialog-btn.cancel { background: var(--primary-low, #eee); color: var(--primary, #333); } .ld-fav-panel-content { flex: 1; overflow-y: auto; padding: 16px; } .ld-fav-panel-content::-webkit-scrollbar { width: 6px; } .ld-fav-panel-content::-webkit-scrollbar-track { background: transparent; } .ld-fav-panel-content::-webkit-scrollbar-thumb { background: var(--primary-low, #ccc); border-radius: 3px; } .ld-fav-panel-content::-webkit-scrollbar-thumb:hover { background: var(--primary-medium, #999); } .ld-fav-panel-search { margin-bottom: 12px; } .ld-fav-panel-search input { width: 100%; padding: 8px 12px; border: 1px solid var(--primary-low, #ddd); border-radius: 6px; font-size: 14px; background: var(--secondary, #fff); color: var(--primary, #333); box-sizing: border-box; outline: none; transition: border-color 0.2s; } .ld-fav-panel-search input:focus { border-color: var(--ld-theme-color, #e5573c); } .ld-fav-panel-search input::placeholder { color: var(--primary-medium, #999); } .ld-fav-panel-empty { text-align: center; padding: 40px 20px; color: var(--primary-medium, #888); } .ld-fav-panel-more { text-align: center; padding: 12px 20px; color: var(--primary-medium, #888); font-size: 13px; } @keyframes ld-fav-item-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } .ld-fav-panel-item { padding: 12px; border-radius: 8px; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; background: var(--primary-low, #f8f8f8); position: relative; animation: ld-fav-item-in 0.25s ease both; gap: 12px; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(1) { animation-delay: 0s; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(2) { animation-delay: 0.03s; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(3) { animation-delay: 0.06s; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(4) { animation-delay: 0.09s; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(5) { animation-delay: 0.12s; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(6) { animation-delay: 0.15s; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(7) { animation-delay: 0.18s; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(8) { animation-delay: 0.21s; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(9) { animation-delay: 0.24s; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(10) { animation-delay: 0.27s; } #ld-fav-panel-list .ld-fav-panel-item:nth-child(n+11) { animation-delay: 0.3s; } .ld-fav-panel-item:hover { background: var(--highlight-low, #f0f0f0); } .ld-fav-panel-item-content { flex: 1; min-width: 0; } .ld-fav-panel-item-title { color: var(--primary, #333); text-decoration: none; font-size: 14px; line-height: 1.4; display: block; margin-bottom: 6px; } .ld-fav-panel-item-title:visited { color: var(--primary, #333); } .ld-fav-panel-item-title:hover { color: var(--ld-theme-color, #e5573c); } .ld-fav-panel-item-meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } .ld-fav-panel-item-category { font-size: 12px; color: var(--primary, #333); background: var(--primary-low, #eee); padding: 2px 8px; border-radius: 4px; border: 1px solid var(--primary-low, #ddd); } .ld-fav-panel-item-tags { font-size: 12px; color: var(--primary-medium, #888); background: var(--primary-low, #eee); padding: 2px 8px; border-radius: 4px; } .ld-fav-panel-item-folder { font-size: 12px; color: var(--ld-theme-color, #e5573c); background: var(--ld-theme-bg-light, rgba(229, 87, 60, 0.1)); padding: 2px 8px; border-radius: 4px; } .ld-fav-panel-item-date { font-size: 12px; color: var(--primary-medium, #888); } .ld-fav-panel-item-remove { background: none; border: none; color: var(--danger, var(--ld-theme-color, #e5573c)); cursor: pointer; font-size: 18px; padding: 4px 8px; border-radius: 4px; opacity: 0; transition: opacity 0.2s; margin-left: 8px; } .ld-fav-panel-item:hover .ld-fav-panel-item-remove { opacity: 1; } .ld-fav-panel-item.dragging { opacity: 0.5; background: var(--highlight-low, #f0f0f0); } .ld-fav-panel-folder.drag-over { background: var(--ld-theme-bg-dark, rgba(229, 87, 60, 0.2)); border: 2px dashed var(--ld-theme-color, #e5573c); } .ld-fav-bookmark-btn { background: none; border: none; cursor: pointer; padding: 8px 6px; color: var(--primary-medium, #888); font-size: 24px; line-height: 1; opacity: 0.6; transition: opacity 0.2s, color 0.2s; display: inline-flex; align-items: center; justify-content: center; vertical-align: middle; height: 100%; } tr.bookmark-list-item td:last-child { vertical-align: middle !important; } .ld-fav-bookmark-btn:hover { opacity: 1; color: var(--ld-theme-color, #e5573c); } .ld-fav-bookmark-btn.favorited { color: var(--ld-theme-color, #e5573c); opacity: 1; } `); function createModal() { const modal = document.createElement('div'); modal.id = 'ld-fav-modal'; modal.innerHTML = `

LinuxDo 收藏夹

`; document.body.appendChild(modal); const addDialog = document.createElement('div'); addDialog.id = 'ld-fav-add-dialog'; addDialog.className = 'ld-fav-dialog'; addDialog.innerHTML = `
+ 新建收藏夹
`; document.body.appendChild(addDialog); const newFolderDialog = document.createElement('div'); newFolderDialog.id = 'ld-fav-new-folder-dialog'; newFolderDialog.className = 'ld-fav-dialog'; newFolderDialog.innerHTML = `
`; document.body.appendChild(newFolderDialog); const manageDialog = document.createElement('div'); manageDialog.id = 'ld-fav-manage-dialog'; manageDialog.className = 'ld-fav-dialog'; manageDialog.innerHTML = `

管理收藏夹

`; document.body.appendChild(manageDialog); createFavoritesPanel(); return modal; } let currentTab = '全部'; let currentPanelFolder = '全部'; let pendingFavorite = null; let isHoverDialog = false; let newFolderBtnHandler = null; function renderTabs() { const tabs = document.getElementById('ld-fav-tabs'); const folders = getFolders(); const allTabs = ['全部', '未分类', ...folders]; tabs.innerHTML = allTabs.map(tab => `
${tab}
`).join(''); tabs.querySelectorAll('.ld-fav-tab').forEach(el => { el.addEventListener('click', () => { currentTab = el.dataset.tab; renderTabs(); renderFavorites(); }); }); } function renderFavorites() { const body = document.getElementById('ld-fav-body'); const favorites = getFavorites(); const items = Object.values(favorites); let filtered = items; if (currentTab === '未分类') { filtered = items.filter(i => !i.folder || i.folder === '未分类'); } else if (currentTab !== '全部') { filtered = items.filter(i => i.folder === currentTab); } filtered.sort((a, b) => b.addedAt - a.addedAt); if (filtered.length === 0) { body.innerHTML = `
暂无收藏
`; return; } body.innerHTML = filtered.map(item => `
${item.title}
${item.folder ? `[${item.folder}] ` : ''} ${item.category || ''} ${item.tags && item.tags.length ? ' · ' + [...new Set(item.tags)].join(', ') : ''}
`).join(''); body.querySelectorAll('.ld-fav-remove').forEach(btn => { btn.addEventListener('click', (e) => { const id = e.target.dataset.id; const favs = getFavorites(); delete favs[id]; saveFavorites(favs); renderFavorites(); insertPostFavButtons(); insertBookmarkFavButtons(); }); }); } function showModal() { const modal = document.getElementById('ld-fav-modal'); modal.classList.add('show'); renderTabs(); renderFavorites(); } function hideModal() { document.getElementById('ld-fav-modal').classList.remove('show'); } function showAddDialog(topicInfo, referenceElement) { pendingFavorite = topicInfo; isHoverDialog = false; const dialog = document.getElementById('ld-fav-add-dialog'); const btn = referenceElement; const folderList = document.getElementById('ld-fav-folder-list'); let folders = getFolders(); const mode = getMode(); let defaultFolder = '默认收藏'; if (mode === 'auto' && topicInfo.category) { const matchFolder = folders.find(f => f.includes(topicInfo.category) || topicInfo.category.includes(f) ); if (matchFolder) { defaultFolder = matchFolder; } else { folders.push(topicInfo.category); saveFolders(folders); defaultFolder = topicInfo.category; } } folderList.innerHTML = folders.map(f => `
${f}
`).join(''); folderList.querySelectorAll('.ld-fav-folder-item').forEach(item => { item.addEventListener('click', () => { const folder = item.dataset.folder; const { _triggerBtn, ...cleanInfo } = topicInfo; const favorites = getFavorites(); favorites[cleanInfo.id] = { ...cleanInfo, folder: folder }; saveFavorites(favorites); if (_triggerBtn) updateBookmarkBtnState(_triggerBtn, cleanInfo.topicId || cleanInfo.id.split('_')[0]); pendingFavorite = null; hideAddDialog(); insertPostFavButtons(); insertBookmarkFavButtons(); }); }); document.getElementById('ld-fav-new-folder-btn').onclick = () => { showNewFolderDialog(btn); }; if (btn) { const rect = btn.getBoundingClientRect(); dialog.style.position = 'fixed'; dialog.style.top = (rect.bottom + 5) + 'px'; dialog.style.right = (window.innerWidth - rect.right) + 'px'; dialog.style.left = 'auto'; } dialog.classList.add('show'); } function hideAddDialog(skipAutoSave) { const dialog = document.getElementById('ld-fav-add-dialog'); const newFolderDialog = document.getElementById('ld-fav-new-folder-dialog'); if (!skipAutoSave && !isHoverDialog && dialog.classList.contains('show') && pendingFavorite && !newFolderDialog.classList.contains('show')) { const mode = getMode(); let folder = '默认收藏'; if (mode === 'auto' && pendingFavorite.category) { const folders = getFolders(); const matchFolder = folders.find(f => f.includes(pendingFavorite.category) || pendingFavorite.category.includes(f) ); if (matchFolder) { folder = matchFolder; } else { folders.push(pendingFavorite.category); saveFolders(folders); folder = pendingFavorite.category; } } const triggerBtn = pendingFavorite._triggerBtn; const tid = pendingFavorite.topicId || pendingFavorite.id.split('_')[0]; const { _triggerBtn, ...cleanFav } = pendingFavorite; const favorites = getFavorites(); favorites[cleanFav.id] = { ...cleanFav, folder: folder }; saveFavorites(favorites); insertPostFavButtons(); insertBookmarkFavButtons(); if (triggerBtn) updateBookmarkBtnState(triggerBtn, tid); pendingFavorite = null; } dialog.classList.remove('show'); isHoverDialog = false; } function showChangeFolderDialog(favItem, referenceElement) { isHoverDialog = true; pendingFavorite = { ...favItem, _triggerBtn: referenceElement }; const dialog = document.getElementById('ld-fav-add-dialog'); const btn = referenceElement; const folderList = document.getElementById('ld-fav-folder-list'); const folders = getFolders(); folderList.innerHTML = folders.map(f => `
${f}
`).join(''); folderList.querySelectorAll('.ld-fav-folder-item').forEach(item => { item.addEventListener('click', () => { const folder = item.dataset.folder; const favorites = getFavorites(); if (favorites[favItem.id]) { favorites[favItem.id].folder = folder; saveFavorites(favorites); pendingFavorite = null; hideAddDialog(true); insertPostFavButtons(); insertBookmarkFavButtons(); } }); }); const newFolderBtn = document.getElementById('ld-fav-new-folder-btn'); newFolderBtn.onclick = () => { showNewFolderDialog(btn); }; if (btn) { const rect = btn.getBoundingClientRect(); dialog.style.position = 'fixed'; dialog.style.top = (rect.bottom + 5) + 'px'; dialog.style.right = (window.innerWidth - rect.right) + 'px'; dialog.style.left = 'auto'; } dialog.classList.add('show'); } function showNewFolderDialog(referenceElement) { const dialog = document.getElementById('ld-fav-new-folder-dialog'); const input = document.getElementById('ld-fav-new-folder-name'); input.value = ''; dialog.style.position = 'fixed'; if (referenceElement) { const rect = referenceElement.getBoundingClientRect(); dialog.style.top = (rect.bottom + 5) + 'px'; dialog.style.left = rect.left + 'px'; dialog.style.transform = 'none'; } else { dialog.style.top = '50%'; dialog.style.left = '50%'; dialog.style.transform = 'translate(-50%, -50%)'; } clearNewFolderError(); dialog.classList.add('show'); input.focus(); input.oninput = () => clearNewFolderError(); input.onkeydown = (e) => { if (e.key === 'Enter') { e.preventDefault(); createNewFolder(); } if (e.key === 'Escape') { e.preventDefault(); hideNewFolderDialog(); } }; } function hideNewFolderDialog() { document.getElementById('ld-fav-new-folder-dialog').classList.remove('show'); } function showNewFolderError(msg) { const input = document.getElementById('ld-fav-new-folder-name'); const error = document.getElementById('ld-fav-new-folder-error'); if (input) input.style.borderColor = '#e5573c'; if (error) { error.textContent = msg; error.style.display = 'block'; } } function clearNewFolderError() { const input = document.getElementById('ld-fav-new-folder-name'); const error = document.getElementById('ld-fav-new-folder-error'); if (input) input.style.borderColor = ''; if (error) error.style.display = 'none'; } function createNewFolder() { const input = document.getElementById('ld-fav-new-folder-name'); const name = input.value.trim(); if (!name) return; const folders = getFolders(); if (folders.includes(name)) { showNewFolderError('收藏夹已存在'); return; } folders.push(name); saveFolders(folders); hideNewFolderDialog(); if (pendingFavorite) { const triggerBtn = pendingFavorite._triggerBtn; const tid = pendingFavorite.topicId || pendingFavorite.id.split('_')[0]; const { _triggerBtn, ...cleanFav } = pendingFavorite; const favorites = getFavorites(); favorites[cleanFav.id] = { ...cleanFav, folder: name }; saveFavorites(favorites); if (triggerBtn) updateBookmarkBtnState(triggerBtn, tid); pendingFavorite = null; hideAddDialog(true); insertPostFavButtons(); insertBookmarkFavButtons(); } renderTabs(); } function showManageDialog() { const dialog = document.getElementById('ld-fav-manage-dialog'); const list = document.getElementById('ld-fav-manage-list'); const folders = getFolders(); const favorites = getFavorites(); list.innerHTML = folders.map(f => { const count = Object.values(favorites).filter(i => i.folder === f).length; const isDefault = defaultFolders.includes(f); return `
${f} (${count}) ${isDefault ? '' : ``}
`; }).join(''); list.querySelectorAll('.ld-fav-remove').forEach(btn => { btn.addEventListener('click', (e) => { const folder = e.target.dataset.folder; if (confirm(`确定删除收藏夹"${folder}"?其中的帖子将移到未分类。`)) { const allFolders = getFolders().filter(f => f !== folder); saveFolders(allFolders); const favs = getFavorites(); Object.values(favs).forEach(fav => { if (fav.folder === folder) fav.folder = ''; }); saveFavorites(favs); showManageDialog(); renderTabs(); } }); }); dialog.classList.add('show'); } function hideManageDialog() { document.getElementById('ld-fav-manage-dialog').classList.remove('show'); } function showConfirmDialog(title, onConfirm) { const dialog = document.getElementById('ld-fav-confirm-dialog'); const titleEl = document.getElementById('ld-fav-confirm-title'); const cancelBtn = document.getElementById('ld-fav-confirm-cancel'); const okBtn = document.getElementById('ld-fav-confirm-ok'); titleEl.textContent = title; dialog.classList.add('show'); const hideDialog = () => { dialog.classList.remove('show'); cancelBtn.removeEventListener('click', hideDialog); okBtn.removeEventListener('click', handleConfirm); }; const handleConfirm = () => { hideDialog(); onConfirm(); }; cancelBtn.addEventListener('click', hideDialog); okBtn.addEventListener('click', handleConfirm); } function showInputDialog(title, defaultValue, onConfirm) { const dialog = document.getElementById('ld-fav-input-dialog'); const titleEl = document.getElementById('ld-fav-input-title'); const input = document.getElementById('ld-fav-input-field'); const cancelBtn = document.getElementById('ld-fav-input-cancel'); const okBtn = document.getElementById('ld-fav-input-ok'); titleEl.textContent = title; input.value = defaultValue || ''; input.classList.remove('error'); const errorEl = document.getElementById('ld-fav-input-error'); if (errorEl) errorEl.style.display = 'none'; dialog.classList.add('show'); input.focus(); input.select(); const hideDialog = () => { dialog.classList.remove('show'); input.classList.remove('error'); const err = document.getElementById('ld-fav-input-error'); if (err) err.style.display = 'none'; cancelBtn.removeEventListener('click', hideDialog); okBtn.removeEventListener('click', handleConfirm); input.removeEventListener('keydown', handleKeydown); }; const handleConfirm = () => { const value = input.value.trim(); if (value) { const close = onConfirm(value); if (close !== false) hideDialog(); } }; const handleKeydown = (e) => { if (e.key === 'Enter') handleConfirm(); if (e.key === 'Escape') hideDialog(); }; cancelBtn.addEventListener('click', hideDialog); okBtn.addEventListener('click', handleConfirm); input.addEventListener('keydown', handleKeydown); } function createFavoritesPanel() { const panel = document.createElement('div'); panel.id = 'ld-fav-panel'; panel.innerHTML = `
`; document.body.appendChild(panel); document.getElementById('ld-fav-panel-close').addEventListener('click', hideFavoritesPanel); panel.addEventListener('click', (e) => { if (e.target === panel) hideFavoritesPanel(); }); return panel; } function renderPanelSidebar(activeFolder) { const sidebar = document.getElementById('ld-fav-panel-sidebar'); const folders = getFolders(); const favorites = getFavorites(); const allCount = Object.keys(favorites).length; const selected = activeFolder || currentPanelFolder || '全部'; let html = `
全部 ${allCount}
`; folders.forEach((folder) => { const count = Object.values(favorites).filter(f => f.folder === folder).length; const isDefault = defaultFolders.includes(folder); html += `
${folder} ${count}
${!isDefault ? `` : ''}
`; }); html += `
+ 新建收藏夹
⚙ 设置
`; sidebar.innerHTML = html; sidebar.querySelectorAll('.ld-fav-panel-folder').forEach(item => { item.addEventListener('click', (e) => { if (e.target.closest('.ld-fav-panel-folder-btn')) return; sidebar.querySelectorAll('.ld-fav-panel-folder').forEach(i => i.classList.remove('active')); item.classList.add('active'); currentPanelFolder = item.dataset.folder; const content = document.getElementById('ld-fav-panel-content'); content.innerHTML = ''; renderPanelContent(currentPanelFolder, ''); }); }); const folderItems = sidebar.querySelectorAll('.ld-fav-panel-folder[draggable="true"]'); let draggedItem = null; folderItems.forEach(item => { item.addEventListener('dragstart', (e) => { draggedItem = item; item.classList.add('dragging'); e.dataTransfer.effectAllowed = 'move'; }); item.addEventListener('dragend', () => { item.classList.remove('dragging'); draggedItem = null; folderItems.forEach(i => i.classList.remove('drag-over')); const newOrder = Array.from(sidebar.querySelectorAll('.ld-fav-panel-folder[draggable="true"]')) .map(i => i.dataset.folder); saveFolders(newOrder); }); item.addEventListener('dragover', (e) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; item.classList.add('drag-over'); }); item.addEventListener('dragleave', () => { item.classList.remove('drag-over'); }); item.addEventListener('drop', (e) => { e.preventDefault(); item.classList.remove('drag-over'); const favId = e.dataTransfer.getData('text/plain'); if (favId) { const favorites = getFavorites(); if (favorites[favId]) { favorites[favId].folder = item.dataset.folder; saveFavorites(favorites); const activeFolder = currentPanelFolder || '全部'; renderPanelSidebar(activeFolder); renderPanelContent(activeFolder); } return; } if (draggedItem && draggedItem !== item) { const allItems = Array.from(sidebar.querySelectorAll('.ld-fav-panel-folder[draggable="true"]')); const draggedIndex = allItems.indexOf(draggedItem); const targetIndex = allItems.indexOf(item); if (draggedIndex < targetIndex) { item.after(draggedItem); } else { item.before(draggedItem); } } }); }); sidebar.querySelectorAll('.ld-fav-panel-folder-btn.rename').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); const folder = btn.dataset.folder; const folderItem = btn.closest('.ld-fav-panel-folder'); const nameSpan = folderItem.querySelector('.ld-fav-panel-folder-name'); const input = document.createElement('input'); input.className = 'ld-fav-panel-rename-input'; input.value = folder; nameSpan.replaceWith(input); input.focus(); input.select(); const saveRename = () => { const newName = input.value.trim(); if (newName && newName !== folder) { const folders = getFolders(); const index = folders.indexOf(folder); if (index !== -1) { folders[index] = newName; saveFolders(folders); const favs = getFavorites(); Object.values(favs).forEach(fav => { if (fav.folder === folder) fav.folder = newName; }); saveFavorites(favs); if (currentPanelFolder === folder) currentPanelFolder = newName; } } renderPanelSidebar(currentPanelFolder); renderPanelContent(currentPanelFolder || '全部'); }; input.addEventListener('blur', saveRename); input.addEventListener('keydown', (e) => { if (e.key === 'Enter') saveRename(); if (e.key === 'Escape') renderPanelSidebar(currentPanelFolder); }); }); }); sidebar.querySelectorAll('.ld-fav-panel-folder-btn.delete').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); const folder = btn.dataset.folder; const folderItem = btn.closest('.ld-fav-panel-folder'); const rect = folderItem.getBoundingClientRect(); const dialog = document.getElementById('ld-fav-confirm-dialog'); dialog.style.top = (rect.bottom + 5) + 'px'; dialog.style.left = rect.left + 'px'; showConfirmDialog(`确定删除收藏夹"${folder}"?`, () => { const folders = getFolders().filter(f => f !== folder); saveFolders(folders); const favs = getFavorites(); Object.values(favs).forEach(fav => { if (fav.folder === folder) fav.folder = '默认收藏'; }); saveFavorites(favs); if (currentPanelFolder === folder) currentPanelFolder = '全部'; renderPanelSidebar(currentPanelFolder); const content = document.getElementById('ld-fav-panel-content'); content.innerHTML = ''; renderPanelContent(currentPanelFolder, ''); }); }); }); document.getElementById('ld-fav-panel-add-folder').addEventListener('click', (e) => { const rect = e.target.getBoundingClientRect(); const dialog = document.getElementById('ld-fav-input-dialog'); dialog.style.top = (rect.bottom + 5) + 'px'; dialog.style.left = rect.left + 'px'; showInputDialog('请输入收藏夹名称:', '', (name) => { const folders = getFolders(); if (folders.includes(name)) { const input = document.getElementById('ld-fav-input-field'); const errorEl = document.getElementById('ld-fav-input-error'); if (input) { input.classList.add('error'); input.oninput = () => { input.classList.remove('error'); if (errorEl) errorEl.style.display = 'none'; }; } if (errorEl) errorEl.style.display = 'block'; return false; } folders.push(name); saveFolders(folders); renderPanelSidebar(currentPanelFolder); }); }); const settingsBtn = document.getElementById('ld-fav-panel-settings'); settingsBtn.addEventListener('click', () => { sidebar.querySelectorAll('.ld-fav-panel-folder').forEach(i => i.classList.remove('active')); renderSettingsContent(); }); } function renderSettingsContent() { const content = document.getElementById('ld-fav-panel-content'); const currentTheme = getTheme(); const currentMode = getMode(); const currentPos = getButtonPosition(); const githubToken = getGithubToken(); const gistId = getGistId(); let html = `

设置

收藏模式
收藏按钮位置
主题颜色
${Object.entries(themes).map(([key, theme]) => `
`).join('')}
GitHub Gist 同步
使用 GitHub Gist 在多设备间同步收藏数据,只需填入 Token 即可自动管理
需要 gist 权限。创建 Token
高级设置
正常情况无需填写,系统会自动查找你的同步 Gist
数据同步
`; content.innerHTML = html; bindSettingsEvents(); } function bindSettingsEvents() { const themeOptions = document.getElementById('ld-fav-theme-options'); const modeOptions = document.querySelectorAll('#ld-fav-mode-options input[type="radio"]'); themeOptions.querySelectorAll('.ld-fav-theme-option').forEach(option => { option.addEventListener('click', () => { const theme = option.dataset.theme; saveTheme(theme); applyTheme(theme); themeOptions.querySelectorAll('.ld-fav-theme-option').forEach(o => o.classList.remove('active')); option.classList.add('active'); }); }); modeOptions.forEach(option => { option.addEventListener('change', () => { saveMode(option.value); }); }); const posOptions = document.querySelectorAll('#ld-fav-pos-options input[type="radio"]'); posOptions.forEach(option => { option.addEventListener('change', () => { saveButtonPosition(option.value); insertPostFavButtons(); }); }); document.getElementById('ld-fav-save-token').addEventListener('click', () => { const token = document.getElementById('ld-fav-github-token').value.trim(); const gistId = document.getElementById('ld-fav-gist-id').value.trim(); saveGithubToken(token); saveGistId(gistId); showSyncStatus('设置已保存', 'success'); }); document.getElementById('ld-fav-test-sync').addEventListener('click', async () => { const token = document.getElementById('ld-fav-github-token').value.trim(); if (!token) { showSyncStatus('请先填写 Token', 'error'); return; } showSyncStatus('测试中...', 'info'); try { const response = await fetch('https://api.github.com/user', { headers: { 'Authorization': `token ${token}` } }); if (response.ok) { const user = await response.json(); showSyncStatus(`连接成功: ${user.login}`, 'success'); } else { showSyncStatus('Token 无效或已过期', 'error'); } } catch (e) { showSyncStatus('网络错误', 'error'); } }); document.getElementById('ld-fav-upload-data').addEventListener('click', uploadToGist); document.getElementById('ld-fav-download-data').addEventListener('click', downloadFromGist); } function showSyncStatus(message, type) { const status = document.getElementById('ld-fav-sync-status'); if (status) { status.textContent = message; status.className = `ld-fav-settings-status ${type}`; } } const GIST_DESCRIPTION = 'LinuxDo-Favorites-Sync'; async function findGistByDescription(token) { try { const response = await fetch('https://api.github.com/gists?per_page=100', { headers: { 'Authorization': `token ${token}` } }); if (response.ok) { const gists = await response.json(); const found = gists.find(g => g.description === GIST_DESCRIPTION); return found ? found.id : null; } } catch (e) { console.error('查找 Gist 失败:', e); } return null; } async function getOrCreateGistId(token) { let gistId = getGistId(); if (gistId) return gistId; gistId = await findGistByDescription(token); if (gistId) { saveGistId(gistId); const gistIdInput = document.getElementById('ld-fav-gist-id'); if (gistIdInput) gistIdInput.value = gistId; } return gistId; } async function uploadToGist() { const token = getGithubToken(); if (!token) { showSyncStatus('请先填写 GitHub Token', 'error'); return; } showSyncStatus('上传中...', 'info'); const data = { favorites: getFavorites(), folders: getFolders(), theme: getTheme(), mode: getMode(), updatedAt: new Date().toISOString() }; const gistId = await getOrCreateGistId(token); const body = { description: GIST_DESCRIPTION, public: false, files: { 'linux-do-favorites.json': { content: JSON.stringify(data, null, 2) } } }; try { const url = gistId ? `https://api.github.com/gists/${gistId}` : 'https://api.github.com/gists'; const method = gistId ? 'PATCH' : 'POST'; const response = await fetch(url, { method: method, headers: { 'Authorization': `token ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); if (response.ok) { const result = await response.json(); if (!gistId) { saveGistId(result.id); const gistIdInput = document.getElementById('ld-fav-gist-id'); if (gistIdInput) gistIdInput.value = result.id; } showSyncStatus(`上传成功! Gist ID: ${result.id}`, 'success'); } else { const error = await response.json(); showSyncStatus(`上传失败: ${error.message || '未知错误'}`, 'error'); } } catch (e) { showSyncStatus(`网络错误: ${e.message}`, 'error'); } } async function downloadFromGist() { const token = getGithubToken(); if (!token) { showSyncStatus('请先填写 GitHub Token', 'error'); return; } showSyncStatus('下载中...', 'info'); const gistId = await getOrCreateGistId(token); if (!gistId) { showSyncStatus('未找到同步数据,请先上传', 'error'); return; } try { const response = await fetch(`https://api.github.com/gists/${gistId}`, { headers: { 'Authorization': `token ${token}` } }); if (response.ok) { const gist = await response.json(); const file = gist.files['linux-do-favorites.json']; if (file) { const data = JSON.parse(file.content); if (data.favorites) saveFavorites(data.favorites); if (data.folders) saveFolders(data.folders); if (data.theme) { saveTheme(data.theme); applyTheme(data.theme); } if (data.mode) saveMode(data.mode); showSyncStatus('下载成功! 数据已同步', 'success'); currentPanelFolder = '全部'; renderPanelSidebar('全部'); renderPanelContent('全部'); } else { showSyncStatus('Gist 中未找到数据文件', 'error'); } } else { showSyncStatus('下载失败: Gist 不存在或无权访问', 'error'); } } catch (e) { showSyncStatus(`网络错误: ${e.message}`, 'error'); } } function formatDate(timestamp) { const date = new Date(timestamp); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } function renderPanelContent(folder, searchQuery) { const content = document.getElementById('ld-fav-panel-content'); const searchInput = document.getElementById('ld-fav-search-input'); const currentQuery = searchQuery !== undefined ? searchQuery : (searchInput ? searchInput.value : ''); const favorites = getFavorites(); let items = Object.values(favorites); if (folder !== '全部') { items = items.filter(f => f.folder === folder); } if (currentQuery) { const query = currentQuery.toLowerCase(); items = items.filter(item => item.title.toLowerCase().includes(query) || (item.category && item.category.toLowerCase().includes(query)) || (item.tags && item.tags.some(tag => tag.toLowerCase().includes(query))) ); } items.sort((a, b) => b.addedAt - a.addedAt); if (!searchInput) { let html = `
`; content.innerHTML = html; bindSearchEvent(folder); document.getElementById('ld-fav-search-input').focus(); } const listContainer = document.getElementById('ld-fav-panel-list'); if (items.length === 0) { listContainer.innerHTML = `
${currentQuery ? '没有找到匹配的收藏' : '暂无收藏'}
`; return; } const LIMIT = 50; const displayed = items.slice(0, LIMIT); const fragments = []; for (let i = 0; i < displayed.length; i++) { const item = displayed[i]; fragments.push(`
${item.title}
${item.folder || '默认收藏'}${item.category || '未分类'}${item.tags && item.tags.length > 0 ? `${[...new Set(item.tags)].join(', ')}` : ''}
${formatDate(item.addedAt)}
`); } listContainer.innerHTML = fragments.join('') + (items.length > LIMIT ? `
显示前 ${LIMIT} 条,共 ${items.length} 条收藏
` : ''); if (!content._delegated) { content._delegated = true; let draggedItem = null; content.addEventListener('dragstart', (e) => { const item = e.target.closest('.ld-fav-panel-item'); if (!item) return; draggedItem = item; item.classList.add('dragging'); e.dataTransfer.setData('text/plain', item.dataset.id); e.dataTransfer.effectAllowed = 'move'; }); content.addEventListener('dragend', (e) => { const item = e.target.closest('.ld-fav-panel-item'); if (item) item.classList.remove('dragging'); draggedItem = null; }); content.addEventListener('click', (e) => { const removeBtn = e.target.closest('.ld-fav-panel-item-remove'); if (removeBtn) { e.preventDefault(); e.stopPropagation(); const id = removeBtn.dataset.id; const favorites = getFavorites(); delete favorites[id]; saveFavorites(favorites); const activeFolder = currentPanelFolder || '全部'; renderPanelSidebar(activeFolder); renderPanelContent(activeFolder); insertPostFavButtons(); insertBookmarkFavButtons(); return; } const link = e.target.closest('.ld-fav-panel-item-title'); if (link) { const postId = link.getAttribute('data-post-id'); if (postId) { e.preventDefault(); hideFavoritesPanel(); const postElement = document.querySelector(`article[data-post-id="${postId}"]`); if (postElement) { postElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); postElement.style.transition = 'background-color 0.3s'; postElement.style.backgroundColor = 'var(--ld-theme-bg-light, rgba(229, 87, 60, 0.1))'; setTimeout(() => { postElement.style.backgroundColor = ''; }, 2000); } else { window.location.href = link.href; } } } }); } } function bindSearchEvent(folder) { const searchInput = document.getElementById('ld-fav-search-input'); if (!searchInput) return; let searchTimer = null; searchInput.addEventListener('input', () => { if (searchTimer) clearTimeout(searchTimer); searchTimer = setTimeout(() => { renderPanelContent(folder); }, 150); }); } function showFavoritesPanel() { const panel = document.getElementById('ld-fav-panel'); if (!panel) return; const content = document.getElementById('ld-fav-panel-content'); content.innerHTML = ''; currentPanelFolder = '全部'; renderPanelSidebar('全部'); renderPanelContent('全部', ''); panel.classList.add('show'); } function hideFavoritesPanel() { const panel = document.getElementById('ld-fav-panel'); if (panel) panel.classList.remove('show'); } function insertSidebarButton() { const existingBtn = document.getElementById('ld-fav-sidebar-btn'); if (existingBtn) return; const sidebarList = document.querySelector('#sidebar-section-content-community'); if (!sidebarList) return; const li = document.createElement('li'); li.className = 'sidebar-section-link-wrapper'; li.setAttribute('data-list-item-name', 'favorites'); li.innerHTML = ` 收藏 `; const moreBtn = sidebarList.querySelector('.sidebar-more-section-trigger'); if (moreBtn) { sidebarList.insertBefore(li, moreBtn.parentElement); } else { sidebarList.appendChild(li); } li.querySelector('a').addEventListener('click', (e) => { e.preventDefault(); showFavoritesPanel(); }); } function insertPostFavButtons() { const posts = document.querySelectorAll('.topic-post, article[data-post-id]'); const pos = getButtonPosition(); posts.forEach(post => { const postId = post.getAttribute('data-post-id'); if (!postId) return; const existingBtn = post.querySelector('.ld-fav-post-btn'); if (existingBtn) { if (existingBtn.dataset.pos !== pos) { existingBtn.remove(); } else { updatePostBtnState(existingBtn, postId); return; } } const btn = document.createElement('button'); btn.className = 'btn no-text btn-icon btn-flat ld-fav-post-btn'; btn.setAttribute('data-post-id', postId); btn.type = 'button'; updatePostBtnState(btn, postId); btn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); if (hoverTimer) { clearTimeout(hoverTimer); hoverTimer = null; } if (btn._hideTimer) { clearTimeout(btn._hideTimer); btn._hideTimer = null; } const topicId = getTopicId(); const uniqueId = `${topicId}_${postId}`; const bookmarkId = `${topicId}_${topicId}`; const favorites = getFavorites(); const existingFav = favorites[uniqueId] || favorites[bookmarkId]; if (existingFav) { delete favorites[existingFav.id]; saveFavorites(favorites); updatePostBtnState(btn, postId); hideAddDialog(true); } else { const postInfo = getPostInfo(post); if (postInfo) { showAddDialog(postInfo, btn); } } }); let hoverTimer = null; btn.addEventListener('mouseenter', () => { const topicId = getTopicId(); const uniqueId = `${topicId}_${postId}`; const bookmarkId = `${topicId}_${topicId}`; const favorites = getFavorites(); const existingFav = favorites[uniqueId] || favorites[bookmarkId]; if (!existingFav) return; if (btn._hideTimer) { clearTimeout(btn._hideTimer); btn._hideTimer = null; } hoverTimer = setTimeout(() => { showChangeFolderDialog(existingFav, btn); }, 300); }); btn.addEventListener('mouseleave', () => { if (hoverTimer) { clearTimeout(hoverTimer); hoverTimer = null; } btn._hideTimer = setTimeout(() => { const dialog = document.getElementById('ld-fav-add-dialog'); if (!dialog.matches(':hover') && !btn.matches(':hover')) { hideAddDialog(isHoverDialog); } }, 300); }); btn.dataset.pos = pos; if (pos === 'like-left') { const likeBtn = post.querySelector('.discourse-reactions-reaction-button, .btn-toggle-reaction-like'); if (likeBtn) { likeBtn.parentNode.insertBefore(btn, likeBtn); } else { post.querySelector('.post-controls .actions')?.prepend(btn); } } else if (pos === 'reply-right') { const replyBtn = post.querySelector('.post-action-menu__reply'); if (replyBtn) { replyBtn.parentNode.insertBefore(btn, replyBtn.nextSibling); } else { post.querySelector('.post-controls .actions')?.appendChild(btn); } } else { const floorButton = post.querySelector('#floor-button, .floor-number'); if (floorButton) { floorButton.parentNode.insertBefore(btn, floorButton.nextSibling); } } }); } function updateBookmarkBtnState(btn, topicId) { const uniqueId = `${topicId}_${topicId}`; const favorites = getFavorites(); const hasFav = favorites[uniqueId] || Object.keys(favorites).some(k => k.startsWith(`${topicId}_`)); if (hasFav) { btn.classList.add('favorited'); btn.innerHTML = '★'; btn.title = '取消收藏'; } else { btn.classList.remove('favorited'); btn.innerHTML = '☆'; btn.title = '收藏此话题'; } } function insertBookmarkFavButtons() { if (!window.location.pathname.includes('/activity/bookmarks')) return; const rows = document.querySelectorAll('tr.bookmark-list-item'); rows.forEach(row => { const titleLink = row.querySelector('a.title'); if (!titleLink) return; const topicId = titleLink.getAttribute('data-topic-id'); if (!topicId) return; let btn = row.querySelector('.ld-fav-bookmark-btn'); if (btn) { updateBookmarkBtnState(btn, topicId); return; } const categoryEl = row.querySelector('.badge-category__name'); const category = categoryEl ? categoryEl.textContent.trim() : ''; const tagsEls = row.querySelectorAll('.discourse-tag'); const tags = [...new Set(Array.from(tagsEls).map(t => t.textContent.trim()))]; btn = document.createElement('button'); btn.className = 'ld-fav-bookmark-btn'; btn.type = 'button'; updateBookmarkBtnState(btn, topicId); const uniqueId = `${topicId}_${topicId}`; btn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); if (bmLeaveTimer) { clearTimeout(bmLeaveTimer); bmLeaveTimer = null; } if (bmHoverTimer) { clearTimeout(bmHoverTimer); bmHoverTimer = null; } const favs = getFavorites(); const existingFav = favs[uniqueId] || Object.values(favs).find(f => f.topicId == topicId); if (existingFav) { delete favs[existingFav.id]; saveFavorites(favs); updateBookmarkBtnState(btn, topicId); hideAddDialog(true); insertPostFavButtons(); } else { const topicInfo = { id: uniqueId, topicId: topicId, title: titleLink.textContent.trim(), url: titleLink.getAttribute('href').split('?')[0], category: category, tags: tags, addedAt: Date.now(), _triggerBtn: btn }; showAddDialog(topicInfo, btn); } }); let bmLeaveTimer = null; let bmHoverTimer = null; btn.addEventListener('mouseenter', () => { if (bmLeaveTimer) { clearTimeout(bmLeaveTimer); bmLeaveTimer = null; } const favs = getFavorites(); const existingFav = favs[uniqueId] || Object.values(favs).find(f => f.topicId == topicId); if (!existingFav) return; bmHoverTimer = setTimeout(() => { showChangeFolderDialog(existingFav, btn); }, 300); }); btn.addEventListener('mouseleave', () => { if (bmHoverTimer) { clearTimeout(bmHoverTimer); bmHoverTimer = null; } bmLeaveTimer = setTimeout(() => { const newFolderDialog = document.getElementById('ld-fav-new-folder-dialog'); if (newFolderDialog.classList.contains('show')) return; const dialog = document.getElementById('ld-fav-add-dialog'); if (!dialog.matches(':hover') && !btn.matches(':hover')) { hideAddDialog(isHoverDialog); } }, 300); }); const actionsTd = row.querySelector('td:last-child'); if (actionsTd) { const details = actionsTd.querySelector('details'); if (details) { actionsTd.insertBefore(btn, details); } else { actionsTd.insertBefore(btn, actionsTd.firstChild); } } }); } function updatePostBtnState(btn, postId) { const topicId = getTopicId(); const uniqueId = `${topicId}_${postId}`; const favorites = getFavorites(); const bookmarkId = `${topicId}_${topicId}`; const hasFav = favorites[uniqueId] || favorites[bookmarkId]; if (hasFav) { btn.classList.add('favorited'); btn.innerHTML = '★'; btn.title = '取消收藏此回复'; btn.setAttribute('aria-label', '取消收藏此回复'); } else { btn.classList.remove('favorited'); btn.innerHTML = '☆'; btn.title = '收藏此回复'; btn.setAttribute('aria-label', '收藏此回复'); } } function init() { const modal = createModal(); insertSidebarButton(); insertPostFavButtons(); insertBookmarkFavButtons(); applyTheme(getTheme()); document.getElementById('ld-fav-close').addEventListener('click', hideModal); document.getElementById('ld-fav-add-folder').addEventListener('click', showNewFolderDialog); document.getElementById('ld-fav-manage').addEventListener('click', showManageDialog); document.getElementById('ld-fav-new-folder-cancel').addEventListener('click', hideNewFolderDialog); document.getElementById('ld-fav-new-folder-confirm').addEventListener('click', createNewFolder); document.getElementById('ld-fav-manage-close').addEventListener('click', hideManageDialog); modal.addEventListener('click', (e) => { if (e.target === modal) hideModal(); }); document.addEventListener('click', (e) => { const addDialog = document.getElementById('ld-fav-add-dialog'); const newFolderDialog = document.getElementById('ld-fav-new-folder-dialog'); const isFavBtn = e.target.closest('.ld-fav-post-btn, .ld-fav-bookmark-btn'); if (!addDialog.contains(e.target) && !newFolderDialog.contains(e.target) && !isFavBtn) { hideAddDialog(); hideNewFolderDialog(); } }); window.addEventListener('scroll', () => { const addDialog = document.getElementById('ld-fav-add-dialog'); const newFolderDialog = document.getElementById('ld-fav-new-folder-dialog'); if (addDialog.classList.contains('show') && !newFolderDialog.classList.contains('show')) { hideAddDialog(); } }); const addDialog = document.getElementById('ld-fav-add-dialog'); addDialog.addEventListener('mouseenter', () => { const hoveredBtn = document.querySelector('.ld-fav-post-btn:hover, .ld-fav-bookmark-btn:hover'); if (hoveredBtn && hoveredBtn._hideTimer) { clearTimeout(hoveredBtn._hideTimer); hoveredBtn._hideTimer = null; } }); addDialog.addEventListener('mouseleave', () => { const newFolderDialog = document.getElementById('ld-fav-new-folder-dialog'); if (newFolderDialog.classList.contains('show')) return; const hoveredBtn = document.querySelector('.ld-fav-post-btn:hover, .ld-fav-bookmark-btn:hover'); if (hoveredBtn) { hoveredBtn._hideTimer = setTimeout(() => { hideAddDialog(isHoverDialog); }, 200); } else { hideAddDialog(isHoverDialog); } }); insertPostFavButtons(); let lastUrl = ''; const panel = document.getElementById('ld-fav-panel'); const observer = new MutationObserver((mutations) => { let hasOutsideChange = false; for (const m of mutations) { const target = m.target.nodeType === 1 ? m.target : m.target.parentElement; if (target && target.closest && target.closest('#ld-fav-panel')) continue; let insidePanel = false; for (const node of m.addedNodes) { if (node.nodeType === 1 && node.closest && node.closest('#ld-fav-panel')) { insidePanel = true; break; } } if (!insidePanel) hasOutsideChange = true; } if (!hasOutsideChange) return; if (window.location.href !== lastUrl) { lastUrl = window.location.href; setTimeout(insertSidebarButton, 500); setTimeout(insertPostFavButtons, 500); setTimeout(insertBookmarkFavButtons, 500); } else { setTimeout(insertPostFavButtons, 100); setTimeout(insertBookmarkFavButtons, 100); } }); observer.observe(document.body, { childList: true, subtree: true }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();