From 4ece453f008c755dcf77bdec5eab0735d71effc1 Mon Sep 17 00:00:00 2001 From: bwstudio Date: Mon, 7 Sep 2026 20:38:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(public):=20=E9=A6=96=E9=A1=B5=E5=8D=A1?= =?UTF-8?q?=E7=89=87/=E4=B8=BB=E9=A2=98=E8=8F=9C=E5=8D=95/=E4=BE=A7?= =?UTF-8?q?=E6=A0=8F/=E7=A7=BB=E5=8A=A8=E7=AB=AF=E5=A4=9A=E9=A1=B9?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 卡片 - 描述与网址共用一行(.meta-line + grid 同格),默认显示描述、悬停交叉淡出为网址; 触屏 (hover:none) 直接显示网址,卡片不再被两行文字撑高 主题菜单 - 修复「暗色」项与其他项不一致:主题变量块原用裸属性选择器 [data-theme="dark"], 会连菜单里的
  • 一起命中导致颜色被局部覆盖; 全部改为 html[data-theme="…"](8 个主题 + 关于页 dark 特例) - 每项加统一色块标识 + 选中对勾,宽高与对齐方式一致 左侧菜单栏 - 「我常访问」「热门网址」合并为一个「常用 & 热门」分区(侧栏 + 移动端抽屉), 标题随数据动态切换;右侧内容区两个 section 保持独立不变 - addSideNavEntry/addDrawerEntry 改为往合并分区插 li,removeEntries 只摘单条, 避免整块删除把热门入口一起干掉 - 新增 retitleFeatured():JS 补入/移除个人榜后同步标题与图标 PC 侧栏 - 修复滚轮无响应:overscroll-behavior 由 contain 改为 auto(contain 会阻断滚动链接, 内容未溢出时侧栏上滚轮完全没反应) - 滚动条加宽到 6px 并使用 --text-soft,加 scrollbar-gutter: stable 移动端顶栏 - 修复 360px 小屏三个控件挤成两行:.topbar-actions 改 flex: 1 1 0 + min-width: 0 (flex 换行先于收缩,basis auto 会先按固有宽度判定放不下而换行) - 恢复显示站点名与副标题作为第二行,消除顶部空白 - 手机端隐藏「搜索」按钮,改由左侧放大镜提交,input 加 enterkeyhint - placeholder 按视口自适应:手机「搜索书签」 抽屉 - 主题菜单在窄屏改为内联展开(280px 抽屉放不下 160px fixed 浮层, 原逻辑会算出负数 left 飞出屏幕) - positionThemeMenu 增加边界兜底:两侧都放不下时贴可视区右边缘 - 面板补 width: min(280px,84vw) + overflow-y:auto(原被内容撑成 173px) --- templates/public/base.html | 487 +++++++++++++++++++++++++++------ templates/public/category.html | 7 +- templates/public/index.html | 9 +- 3 files changed, 419 insertions(+), 84 deletions(-) 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 %}