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(); });
})();