diff --git a/templates/public/base.html b/templates/public/base.html index 874d972..c191c69 100644 --- a/templates/public/base.html +++ b/templates/public/base.html @@ -91,6 +91,62 @@ --shadow: 0 2px 12px rgba(0,0,0,0.4); --shadow-hover: 0 8px 24px rgba(22, 186, 170, 0.25); } + /* 紫韵(优雅紫色) */ + [data-theme="lavender"] { + --brand: #8b5cf6; + --brand-2: #ec4899; + --bg: #faf5ff; + --card-bg: #ffffff; + --text: #2e1065; + --text-muted: #6d28d9; + --text-soft: #a78bfa; + --border: #e9d5ff; + --topbar-text: #ffffff; + --shadow: 0 2px 12px rgba(139,92,246,0.10); + --shadow-hover: 0 8px 24px rgba(139,92,246,0.25); + } + /* 深海(深蓝 navy) */ + [data-theme="ocean"] { + --brand: #0ea5e9; + --brand-2: #06b6d4; + --bg: #f0f9ff; + --card-bg: #ffffff; + --text: #0c4a6e; + --text-muted: #0369a1; + --text-soft: #7dd3fc; + --border: #bae6fd; + --topbar-text: #ffffff; + --shadow: 0 2px 12px rgba(14,165,233,0.10); + --shadow-hover: 0 8px 24px rgba(14,165,233,0.28); + } + /* 青空(明亮天蓝) */ + [data-theme="sky"] { + --brand: #38bdf8; + --brand-2: #3b82f6; + --bg: #f0f9ff; + --card-bg: #ffffff; + --text: #0c4a6e; + --text-muted: #0284c7; + --text-soft: #7dd3fc; + --border: #e0f2fe; + --topbar-text: #ffffff; + --shadow: 0 2px 12px rgba(59,130,246,0.10); + --shadow-hover: 0 8px 24px rgba(59,130,246,0.28); + } + /* 玫红(热情玫红) */ + [data-theme="rose"] { + --brand: #f43f5e; + --brand-2: #ec4899; + --bg: #fff1f2; + --card-bg: #ffffff; + --text: #4a040c; + --text-muted: #be123c; + --text-soft: #fda4af; + --border: #fecdd3; + --topbar-text: #ffffff; + --shadow: 0 2px 12px rgba(244,63,94,0.10); + --shadow-hover: 0 8px 24px rgba(244,63,94,0.28); + } /* 系统暗色兜底:未设置 data-theme 时跟随系统 */ @media (prefers-color-scheme: dark) { :root:not([data-theme]) { @@ -157,85 +213,15 @@ .topbar { padding: 68px 0 52px; } .topbar h1 { font-size: 44px; } .topbar .sub { font-size: 17px; } - .site-search { max-width: 680px; } + .site-search { max-width: 760px; } + /* 卡片描述放宽到 2 行,提升信息密度 */ + .card .desc { -webkit-line-clamp: 2; min-height: 40px; } } @media (min-width: 2560px) { .topbar { padding: 84px 0 64px; } .topbar h1 { font-size: 52px; } + .site-search { max-width: 880px; } } - .topbar .actions { margin-top: 18px; display: flex; flex-wrap: wrap; gap: 8px; } - .topbar .actions a, .topbar .actions button { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 6px 14px; - background: rgba(255,255,255,0.18); - border: 1px solid rgba(255,255,255,0.35); - color: var(--topbar-text); - border-radius: 999px; - font-size: 13px; - text-decoration: none; - cursor: pointer; - transition: background 0.2s; - font-family: inherit; - } - .topbar .actions a:hover, .topbar .actions button:hover { background: rgba(255,255,255,0.32); } - - /* ===== 主题切换下拉 ===== */ - .theme-picker { position: relative; display: inline-block; } - .theme-picker > button { - display: inline-flex; align-items: center; gap: 4px; - } - .theme-menu { - position: absolute; - top: calc(100% + 6px); - right: 0; - min-width: 180px; - margin: 0; padding: 4px; - list-style: none; - background: var(--card-bg); - color: var(--text); - border: 1px solid var(--border); - border-radius: 10px; - box-shadow: var(--shadow-hover); - z-index: 50; - opacity: 0; - transform: translateY(-6px); - pointer-events: none; - transition: opacity 0.15s, transform 0.15s; - } - .theme-menu.open { - opacity: 1; - transform: translateY(0); - pointer-events: auto; - } - .theme-menu li { - display: flex; align-items: center; gap: 10px; - padding: 8px 12px; - font-size: 14px; - border-radius: 6px; - cursor: pointer; - transition: background 0.12s; - color: var(--text); - } - .theme-menu li:hover { background: rgba(22,186,170,0.10); } - .theme-menu li.active { background: rgba(22,186,170,0.18); font-weight: 600; } - .theme-menu li .dot { - display: inline-block; - width: 18px; height: 18px; - border-radius: 50%; - border: 2px solid var(--border); - flex-shrink: 0; - } - .dot-default { background: linear-gradient(135deg, #16baaa 0%, #2e8de8 100%); } - .dot-sunset { background: linear-gradient(135deg, #ff7043 0%, #e91e63 100%); } - .dot-forest { background: linear-gradient(135deg, #2e7d32 0%, #00897b 100%); } - .dot-dark { background: linear-gradient(135deg, #0f1419 0%, #16baaa 100%); } - .dot-auto { - background: linear-gradient(90deg, #f5f7fa 0%, #f5f7fa 50%, #0f1419 50%, #0f1419 100%); - border-color: var(--text-muted); - } - /* 手机端分类入口按钮:默认桌面隐藏 */ .cat-trigger-mobile { display: none; @@ -251,6 +237,36 @@ } .cat-trigger-mobile:active { background: rgba(255,255,255,0.32); } + /* ===== 主题下拉菜单 ===== */ + .theme-picker-trigger { position: relative; } + .theme-menu { + display: none; + position: absolute; + top: calc(100% + 6px); + left: 0; + min-width: 150px; + margin: 0; padding: 4px; + list-style: none; + background: var(--card-bg); + color: var(--text); + border: 1px solid var(--border); + border-radius: 10px; + box-shadow: var(--shadow-hover); + z-index: 50; + } + .theme-menu.open { display: block; } + .theme-menu li { + display: block; + padding: 8px 12px; + font-size: 14px; + border-radius: 6px; + cursor: pointer; + transition: background 0.12s; + color: var(--text); + } + .theme-menu li:hover { background: rgba(22,186,170,0.10); } + .theme-menu li.active { background: rgba(22,186,170,0.18); font-weight: 600; } + /* ===== 顶部全局搜索 ===== */ .site-search { position: relative; @@ -307,7 +323,7 @@ -webkit-backdrop-filter: saturate(180%) blur(8px); } .cat-nav-inner { - max-width: 1200px; + max-width: 100%; margin: 0 auto; padding: 8px 24px; display: flex; @@ -358,6 +374,17 @@ background: rgba(0,0,0,0.5); } .cat-drawer.open { display: block; } + /* 抽屉打开时锁定背景滚动 */ + body.drawer-open { overflow: hidden; } + + /* 搜索无结果空态 */ + .search-empty { + text-align: center; + color: var(--text-muted); + padding: 64px 16px; + font-size: 15px; + } + .search-empty .ico { font-size: 40px; display: block; margin-bottom: 12px; opacity: 0.6; } .cat-drawer-panel { position: absolute; left: 0; right: 0; bottom: 0; @@ -606,7 +633,7 @@ min-height: 20px; } .card .url { - font-size: 12px; color: var(--text-soft); + font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; direction: rtl; text-align: left; @@ -785,7 +812,6 @@ gap: 10px; } .topbar-brand { display: none; } /* 手机顶部只保留分类按钮+搜索 */ - .topbar .actions { display: none; } .cat-trigger-mobile { display: inline-flex; } /* 顶部搜索框更紧凑,占满剩余空间 */ @@ -966,14 +992,28 @@
  • 登录后台
  • -
  • - - 切换主题
  • +
  • + + + 切换主题 + +
  • + {% block content %}{% endblock %}
    @@ -1064,10 +1104,23 @@ 登录后台 -
  • - - 切换主题 -
  • +
  • + + + 切换主题 + + +
  • @@ -1080,13 +1133,6 @@ var THEME_KEY = 'bw-theme'; var FIXED_THEMES = ['default', 'sunset', 'forest', 'dark']; var ALL = FIXED_THEMES.concat(['auto']); - var LABEL_MAP = { - 'default': '🎨 蓝绿', - 'sunset': '🎨 暮色', - 'forest': '🎨 森林', - 'dark': '🎨 暗色', - 'auto': '🎨 跟随系统' - }; function isSystemDark(){ return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; @@ -1103,8 +1149,12 @@ if (ALL.indexOf(name) === -1) name = 'default'; var resolved = resolveTheme(name); document.documentElement.setAttribute('data-theme', resolved); - // 顶部 meta 颜色随主题变化 - var themeColor = (resolved === 'dark') ? '#0f1419' : '#16baaa'; + // 顶部 meta 颜色随主题变化(暗色用深色,其他用对应品牌色) + var themeColor = (resolved === 'dark') ? '#0f1419' : + (resolved === 'lavender') ? '#8b5cf6' : + (resolved === 'ocean') ? '#0ea5e9' : + (resolved === 'sky') ? '#38bdf8' : + (resolved === 'rose') ? '#f43f5e' : '#16baaa'; var meta = document.querySelector('meta[name="theme-color"]'); if (meta) meta.setAttribute('content', themeColor); // 高亮菜单项 @@ -1112,9 +1162,6 @@ if (li.getAttribute('data-theme') === name) li.classList.add('active'); else li.classList.remove('active'); }); - // 更新顶部按钮文字 - var label = document.getElementById('theme-toggle-label'); - if (label) label.textContent = LABEL_MAP[name] || '🎨 主题'; if (persist) localStorage.setItem(THEME_KEY, name); } @@ -1227,9 +1274,11 @@ function openDrawer(){ drawer.classList.add('open'); + document.body.classList.add('drawer-open'); // 锁背景滚动 } function closeDrawer(){ drawer.classList.remove('open'); + document.body.classList.remove('drawer-open'); } if (triggerMobile) triggerMobile.addEventListener('click', openDrawer); if (fab) fab.addEventListener('click', openDrawer); @@ -1263,32 +1312,6 @@ link.addEventListener('click', closeDrawer); }); } - - // 抽屉内"切换主题"按钮:循环到下一个主题(含 auto) - var drawerThemeBtn = document.getElementById('drawer-theme-toggle'); - if (drawerThemeBtn) { - drawerThemeBtn.addEventListener('click', function(e){ - e.preventDefault(); - var VALID = ['default', 'sunset', 'forest', 'dark', 'auto']; - var LABEL_MAP = {default:'🎨 蓝绿', sunset:'🎨 暮色', forest:'🎨 森林', dark:'🎨 暗色', auto:'🎨 跟随系统'}; - var cur = localStorage.getItem('bw-theme') || 'default'; - var idx = VALID.indexOf(cur); - var next = VALID[(idx + 1) % VALID.length]; - // 解析 next 为实际生效值 - var isSystemDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; - var resolved = (next === 'auto') ? (isSystemDark ? 'dark' : 'default') : next; - document.documentElement.setAttribute('data-theme', resolved); - var labelEl = document.getElementById('theme-toggle-label'); - if (labelEl) labelEl.textContent = LABEL_MAP[next]; - localStorage.setItem('bw-theme', next); - // 同步菜单高亮 - document.querySelectorAll('.theme-menu li').forEach(function(li){ - if (li.getAttribute('data-theme') === next) li.classList.add('active'); - else li.classList.remove('active'); - }); - closeDrawer(); - }); - } })(); // ===== 导航卡片点击埋点:sendBeacon,不影响原 href 跳转 ===== @@ -1526,10 +1549,26 @@ if (cnt) cnt.textContent = n ? String(n) : ''; li.style.display = n ? '' : 'none'; }); + + // 无结果空态 + var empty = document.getElementById('search-empty'); + if (empty) { + var totalVisible = document.querySelectorAll('.grid .card:not([style*="display: none"])').length; + if (keyword && totalVisible === 0) { + empty.innerHTML = '🔍未找到与「' + keyword + '」匹配的网址'; + empty.hidden = false; + } else { + empty.hidden = true; + } + } } + // 输入防抖,避免每次按键都遍历全部卡片 + var t; input.addEventListener('input', function(){ - filter(input.value); + clearTimeout(t); + var v = input.value; + t = setTimeout(function(){ filter(v); }, 120); }); form.addEventListener('submit', function(e){ @@ -1557,26 +1596,59 @@ filter(q || ''); })(); - // ===== 侧栏「切换主题」:循环切换到下一个主题 ===== + // ===== 侧栏「切换主题」:弹出下拉菜单 ===== (function(){ var btn = document.getElementById('side-theme-toggle'); - if (!btn) return; + var menu = document.getElementById('side-theme-menu'); + if (!btn || !menu) return; + function closeAll(){ + document.querySelectorAll('.theme-menu.open').forEach(function(m){ m.classList.remove('open'); }); + } btn.addEventListener('click', function(e){ e.preventDefault(); - var VALID = ['default', 'sunset', 'forest', 'dark', 'auto']; - var LABEL_MAP = {default:'🎨 蓝绿', sunset:'🎨 暮色', forest:'🎨 森林', dark:'🎨 暗色', auto:'🎨 跟随系统'}; - var cur = localStorage.getItem('bw-theme') || 'default'; - var next = VALID[(VALID.indexOf(cur) + 1) % VALID.length]; - var isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; - var resolved = (next === 'auto') ? (isDark ? 'dark' : 'default') : next; - document.documentElement.setAttribute('data-theme', resolved); - var label = document.getElementById('theme-toggle-label'); - if (label) label.textContent = LABEL_MAP[next]; - localStorage.setItem('bw-theme', next); - document.querySelectorAll('.theme-menu li').forEach(function(li){ - li.classList.toggle('active', li.getAttribute('data-theme') === next); - }); + e.stopPropagation(); + var wasOpen = menu.classList.contains('open'); + closeAll(); + if (!wasOpen) menu.classList.add('open'); }); + menu.addEventListener('click', function(e){ + var li = e.target.closest('li[data-theme]'); + if (!li) return; + e.stopPropagation(); + applyTheme(li.getAttribute('data-theme'), true); + closeAll(); + }); + document.addEventListener('click', closeAll); + document.addEventListener('keydown', function(e){ if (e.key === 'Escape') closeAll(); }); + })(); + + // ===== 抽屉内「切换主题」:弹出下拉菜单 ===== + (function(){ + var btn = document.getElementById('drawer-theme-toggle'); + var menu = document.getElementById('drawer-theme-menu'); + if (!btn || !menu) return; + function closeAll(){ + document.querySelectorAll('.theme-menu.open').forEach(function(m){ m.classList.remove('open'); }); + } + btn.addEventListener('click', function(e){ + e.preventDefault(); + e.stopPropagation(); + var wasOpen = menu.classList.contains('open'); + closeAll(); + if (!wasOpen) menu.classList.add('open'); + }); + menu.addEventListener('click', function(e){ + var li = e.target.closest('li[data-theme]'); + if (!li) return; + e.stopPropagation(); + applyTheme(li.getAttribute('data-theme'), true); + closeAll(); + // 关闭抽屉 + var drawer = document.getElementById('cat-drawer'); + if (drawer) drawer.classList.remove('open'); + }); + document.addEventListener('click', closeAll); + document.addEventListener('keydown', function(e){ if (e.key === 'Escape') closeAll(); }); })();