diff --git a/templates/public/base.html b/templates/public/base.html index 846dafe..7bb2142 100644 --- a/templates/public/base.html +++ b/templates/public/base.html @@ -36,7 +36,7 @@ * forest 墨绿 + 青绿 * dark 深色背景 */ - :root, [data-theme="default"] { + :root, html[data-theme="default"] { --brand: #16baaa; --brand-2: #2e8de8; --bg: #f5f7fa; @@ -50,7 +50,7 @@ --shadow-hover: 0 8px 24px rgba(22, 186, 170, 0.18); } /* 暮色橙(暖色系) */ - [data-theme="sunset"] { + html[data-theme="sunset"] { --brand: #ff7043; --brand-2: #e91e63; --bg: #fff8f3; @@ -64,7 +64,7 @@ --shadow-hover: 0 8px 24px rgba(255,112,67,0.25); } /* 森林绿(自然系) */ - [data-theme="forest"] { + html[data-theme="forest"] { --brand: #2e7d32; --brand-2: #00897b; --bg: #f3f8f4; @@ -78,7 +78,7 @@ --shadow-hover: 0 8px 24px rgba(46,125,50,0.22); } /* 暗色(深色背景) */ - [data-theme="dark"] { + html[data-theme="dark"] { --brand: #16baaa; --brand-2: #2e8de8; --bg: #0f1419; @@ -92,7 +92,7 @@ --shadow-hover: 0 8px 24px rgba(22, 186, 170, 0.25); } /* 紫韵(优雅紫色) */ - [data-theme="lavender"] { + html[data-theme="lavender"] { --brand: #8b5cf6; --brand-2: #ec4899; --bg: #faf5ff; @@ -106,7 +106,7 @@ --shadow-hover: 0 8px 24px rgba(139,92,246,0.25); } /* 深海(深蓝 navy) */ - [data-theme="ocean"] { + html[data-theme="ocean"] { --brand: #0ea5e9; --brand-2: #06b6d4; --bg: #f0f9ff; @@ -120,7 +120,7 @@ --shadow-hover: 0 8px 24px rgba(14,165,233,0.28); } /* 青空(明亮天蓝) */ - [data-theme="sky"] { + html[data-theme="sky"] { --brand: #38bdf8; --brand-2: #3b82f6; --bg: #f0f9ff; @@ -134,7 +134,7 @@ --shadow-hover: 0 8px 24px rgba(59,130,246,0.28); } /* 玫红(热情玫红) */ - [data-theme="rose"] { + html[data-theme="rose"] { --brand: #f43f5e; --brand-2: #ec4899; --bg: #fff1f2; @@ -205,7 +205,38 @@ padding: 56px 0 40px; position: relative; } - .topbar-inner { max-width: 100%; margin: 0 auto; padding: 0 24px; } + .topbar-inner { + max-width: 100%; + margin: 0 auto; + padding: 0 24px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 24px; + flex-wrap: wrap; + } + .topbar-brand { flex: 1 1 auto; min-width: 220px; } + .topbar-actions { + display: flex; + align-items: center; + gap: 14px; + flex: 0 1 auto; + justify-content: flex-end; + } + /* 顶栏右侧主题切换按钮(让原本藏在侧栏的入口在顶栏也可见,填充右侧空白) */ + .top-theme-trigger { position: relative; } + .top-theme-toggle { + width: 44px; height: 44px; + border-radius: 50%; + border: 1px solid rgba(255,255,255,0.4); + background: rgba(255,255,255,0.18); + color: #fff; font-size: 20px; + cursor: pointer; + display: flex; align-items: center; justify-content: center; + flex-shrink: 0; + transition: background .2s; + } + .top-theme-toggle:hover { background: rgba(255,255,255,0.30); } .topbar h1 { font-size: 36px; margin: 0 0 8px; font-weight: 600; line-height: 1.2; } .topbar .sub { font-size: 15px; opacity: 0.92; } /* 宽屏:标题与内边距同步放大,避免头重脚轻 */ @@ -213,7 +244,7 @@ .topbar { padding: 68px 0 52px; } .topbar h1 { font-size: 44px; } .topbar .sub { font-size: 17px; } - .site-search { max-width: 760px; } + .site-search { max-width: 560px; } /* 卡片描述放宽到 2 行,提升信息密度 */ .card .desc { -webkit-line-clamp: 2; min-height: 40px; } } @@ -256,7 +287,9 @@ } .theme-menu.open { display: block; } .theme-menu li { - display: block; + display: flex; + align-items: center; + gap: 8px; padding: 8px 12px; font-size: 14px; border-radius: 6px; @@ -264,14 +297,39 @@ transition: background 0.12s; color: var(--text); } + /* 每项都带一枚同规格色块,保证「暗色」这类深底项不会视觉上落单 */ + .theme-menu li::before { + content: ''; + width: 12px; height: 12px; + border-radius: 50%; + flex-shrink: 0; + background: var(--sw, var(--brand)); + box-shadow: 0 0 0 1px rgba(0,0,0,0.12) inset; + } + .theme-menu li[data-theme="default"] { --sw: #16baaa; } + .theme-menu li[data-theme="sunset"] { --sw: #ff7043; } + .theme-menu li[data-theme="forest"] { --sw: #2e7d32; } + .theme-menu li[data-theme="dark"] { --sw: #1a1f29; } + .theme-menu li[data-theme="lavender"] { --sw: #8b5cf6; } + .theme-menu li[data-theme="ocean"] { --sw: #0ea5e9; } + .theme-menu li[data-theme="sky"] { --sw: #38bdf8; } + .theme-menu li[data-theme="rose"] { --sw: #f43f5e; } + .theme-menu li[data-theme="auto"] { --sw: linear-gradient(135deg, #f5f7fa 50%, #1a1f29 50%); } .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.active::after { + content: '✓'; + margin-left: auto; + color: var(--brand); + font-weight: 700; + } /* ===== 顶部全局搜索 ===== */ .site-search { position: relative; - max-width: 560px; - margin-top: 22px; + max-width: 460px; + flex: 1 1 320px; + margin-top: 0; display: flex; align-items: center; background: rgba(255,255,255,0.95); @@ -433,11 +491,28 @@ top: 20px; max-height: calc(100vh - 40px); overflow-y: auto; - overscroll-behavior: contain; - padding: 8px 0 20px; + /* 不用 contain:contain 会阻断滚动链接,侧栏滚到底(或内容没超出)时 + 鼠标在侧栏上滚轮会完全没反应,表现为"上下滚动没有呼应"。 + 保持默认的 auto,滚到底后自然接力给页面滚动。 */ + overscroll-behavior: auto; + /* 预留滚动条位置,出现滚动条时内容不横向抖动 */ + scrollbar-gutter: stable; + scrollbar-width: thin; + scrollbar-color: var(--text-soft) transparent; + padding: 8px 6px 20px 0; + /* 关键:侧栏本身是 sticky,会生成独立层叠上下文。 + 若不提升层级,内部弹出的主题菜单(z-index:50)会被锁在该上下文里, + 而内容区卡片图标带 z-index:1,反而会画到菜单之上。提到 20 即可压过内容区。 */ + z-index: 20; } - .side-nav::-webkit-scrollbar { width: 4px; } - .side-nav::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } + /* 滚动条要看得见,否则内容被截断时用户不知道还能往下滚 */ + .side-nav::-webkit-scrollbar { width: 6px; } + .side-nav::-webkit-scrollbar-track { background: transparent; } + .side-nav::-webkit-scrollbar-thumb { + background: var(--text-soft); + border-radius: 3px; + } + .side-nav::-webkit-scrollbar-thumb:hover { background: var(--brand); } .side-block { background: var(--card-bg); @@ -597,8 +672,12 @@ box-shadow: 0 6px 20px rgba(139, 92, 246, 0.18); } .card-mine .visit-count { color: #8b5cf6; } + .cat-nav-inner a.cat-nav-mine { color: #8b5cf6; font-weight: 600; } - .cat-drawer-list a.cat-drawer-mine { color: #8b5cf6; font-weight: 600; } + .cat-drawer-list a.cat-drawer-mine, + .cat-drawer-list a.cat-drawer-mine .cat-icon { color: #8b5cf6; font-weight: 600; } + .cat-drawer-list a.cat-drawer-hot, + .cat-drawer-list a.cat-drawer-hot .cat-icon { color: #ff6b35; font-weight: 600; } .card .icon-wrap { position: relative; @@ -647,12 +726,39 @@ -webkit-box-orient: vertical; min-height: 20px; } + /* 描述与网址共用同一行:默认显示描述,悬停时交叉淡出为网址。 + 两者用 grid 叠在同一格,卡片高度不再被两行文字撑开。 */ + .card .meta-line { + display: grid; + min-height: 20px; + margin-top: 2px; + } + .card .meta-line > .desc, + .card .meta-line > .url { + grid-area: 1 / 1; + min-width: 0; + align-self: center; + transition: opacity 0.18s ease; + } + .card .meta-line > .url { + opacity: 0; + pointer-events: none; + } + .card:hover .meta-line > .desc, + .card:focus-visible .meta-line > .desc { opacity: 0; } + .card:hover .meta-line > .url, + .card:focus-visible .meta-line > .url { opacity: 1; } .card .url { - font-size: 12px; color: var(--text-muted); + font-size: 12px; color: var(--brand-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; direction: rtl; text-align: left; } + /* 触屏设备没有 hover,直接展示网址,避免描述永远盖住它 */ + @media (hover: none) { + .card .meta-line > .desc { opacity: 0; } + .card .meta-line > .url { opacity: 1; } + } .card .visit-count { margin-top: auto; font-size: 11px; @@ -721,7 +827,7 @@ border-radius: 6px; overflow-x: auto; } - [data-theme="dark"] .about-content pre { background: rgba(255,255,255,0.06); } + html[data-theme="dark"] .about-content pre { background: rgba(255,255,255,0.06); } .about-content blockquote { border-left: 4px solid var(--brand); margin: 12px 0; @@ -819,26 +925,58 @@ @media (max-width: 600px) { body { font-size: 14px; } .container { padding: 0 14px; } - .topbar { padding: 12px 0; } + .topbar { padding: 10px 0 12px; } .topbar-inner { padding: 0 14px; display: flex; align-items: center; - gap: 10px; + gap: 8px; + } + /* 手机顶栏:第一行 = 分类 + 搜索 + 主题;第二行 = 站点名 + 副标题。 + 注意 flex 的换行发生在收缩之前,所以 .topbar-actions 必须用 + flex-basis: 0 + min-width: 0;否则它会先按搜索框的固有宽度(约 280px) + 判定"放不下"而整块换行,之后再缩小——表现就是三个控件挤成两行。 */ + .cat-trigger-mobile { + display: inline-flex; + width: 38px; height: 38px; + font-size: 18px; + order: 1; + } + .topbar-actions { flex: 1 1 0; min-width: 0; order: 2; gap: 8px; } + .topbar-brand { + display: flex; + align-items: baseline; + flex-wrap: nowrap; + gap: 8px; + flex: 1 1 100%; + min-width: 0; + order: 3; + margin-top: 8px; + } + .topbar h1 { + font-size: 17px; margin: 0; line-height: 1.3; + white-space: nowrap; flex-shrink: 0; + } + .topbar .sub { + font-size: 12px; opacity: 0.9; line-height: 1.3; + min-width: 0; + overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } - .topbar-brand { display: none; } /* 手机顶部只保留分类按钮+搜索 */ - .cat-trigger-mobile { display: inline-flex; } /* 顶部搜索框更紧凑,占满剩余空间 */ .site-search { - flex: 1; + flex: 1 1 auto; + min-width: 0; margin-top: 0; max-width: none; - padding: 3px 4px 3px 12px; + padding: 2px 2px 2px 12px; } - .site-search i { font-size: 16px; margin-right: 8px; } - .site-search input[type="search"] { font-size: 14px; padding: 8px 0; } - .site-search .search-btn { padding: 7px 14px; font-size: 13px; } + .site-search i { font-size: 16px; margin-right: 8px; cursor: pointer; } + .site-search input[type="search"] { font-size: 14px; padding: 8px 0; width: 100%; } + /* 手机端靠键盘的「搜索」键或左侧放大镜提交,把横向空间全留给输入框 */ + .site-search .search-btn { display: none; } + .top-theme-trigger { flex-shrink: 0; } + .top-theme-toggle { width: 38px; height: 38px; font-size: 17px; } /* 手机端:横向分类 Tab 隐藏(用抽屉替代) */ .cat-nav { display: none; } @@ -883,8 +1021,12 @@ .cat-drawer-panel { left: 0; right: auto; top: 0; bottom: 0; border-radius: 0 16px 16px 0; + /* 必须给显式宽度:只写 max-width 时面板会被内容撑成一条窄条(实测 173px)。 */ + width: min(280px, 84vw); + max-width: none; max-height: 100vh; - max-width: 280px; + overflow-y: auto; + overscroll-behavior: contain; transform: translateX(-100%); padding: 20px 16px 28px; } @@ -905,6 +1047,20 @@ } .cat-drawer-list li a .arrow { margin-left: auto; } + /* 抽屉宽 280px,主题菜单(min-width 160px)作为 fixed 浮层无论贴左还是贴右 + 都会被挤出可视区,所以手机端改成在「切换主题」父项下方内联展开。 */ + .cat-drawer .theme-menu { + position: static !important; + top: auto !important; + left: auto !important; + width: auto; + min-width: 0; + max-width: none; + margin: 4px 10px 10px; + background: var(--bg); + box-shadow: none; + } + /* 抽屉分区 */ .cat-drawer-section { margin-bottom: 18px; } .cat-drawer-title { @@ -935,12 +1091,33 @@
{% block subtitle %}精选优质站点,按分类聚合展示 · 共 {{ total|default(0) }} 个链接{% endblock %}
- {# 全局搜索框(OneNav 风格) #} - +
+ {# 全局搜索框(OneNav 风格) #} + + + {# 顶栏主题切换:把原本藏在侧栏/抽屉的入口放到顶栏右侧,填充空白 #} +
+ + +
+
@@ -954,26 +1131,32 @@
{# ===== 左侧分类侧栏:桌面常驻(≥1025px);平板/手机隐藏,改用顶部横条 + 抽屉 ===== #}
-
{{ item.description or '暂无描述' }}
-
{{ item.url }}
+ {# 描述与网址共用同一行:默认显示描述,悬停时交叉淡出为网址 #} +
+
{{ item.description or '暂无描述' }}
+
{{ item.url }}
+
{%- set vc = item.visit_count or 0 -%} {%- if vc >= 3 -%}访问 {{ '{:,}'.format(vc) }} diff --git a/templates/public/index.html b/templates/public/index.html index f8e2de5..604c30f 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -23,8 +23,11 @@ {% endif %}
-
{{ item.description or '暂无描述' }}
-
{{ item.url }}
+ {# 描述与网址共用同一行:默认显示描述,悬停时交叉淡出为网址,避免两行同时占用卡片空间 #} +
+
{{ item.description or '暂无描述' }}
+
{{ item.url }}
+
{%- if mine is not none -%} 我点过 {{ item.mine_count or 0 }} 次 @@ -69,7 +72,7 @@

我常访问

-
只在这台设备上统计 · 清除
+
只在这台设备上统计 · 清除我的记录
{% for item in my_navs %}