diff --git a/HANDOFF.md b/HANDOFF.md index 6cd2c37..7465aa6 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -167,7 +167,7 @@ GET /api/backup SQLite 快照附件 需登录 - 当前 `PRAGMA user_version = 22`;`schema::migrate` 逐级升级:0 建全量、15→16→17→18→19→20→21→22、更高版本拒绝启动。 - 格式在 `entry.format`(apps / posters / articles),同组可混合;`node` 的旧 `view_mode` 仅保留兼容,不再决定渲染。 - `settings.sidebar.show_profile / show_service` 控制侧栏两张卡片显隐(默认 true)。 -- 首页滚动:`#page-scroll`(Layout 的 body)是唯一滚动容器,搜索框固定在其上方;左右两栏顶部对齐,左侧到底后通过 `translateY` 吸底,右侧继续滚动;滚动条隐藏;页头实底,搜索框悬浮,顶部与内容之间没有独立填充块。 +- 首页滚动:`#page-scroll`(Layout 的 body)是唯一滚动容器,搜索框固定在其上方;左右两栏顶部对齐,左侧到底后通过 `translateY` 吸底,右侧继续滚动;滚动条隐藏;页头实底,搜索框 50% 透明,顶部另有一层上下渐隐的软虚化(`blur(8px)`)。 - 本地服务是运行时卡片,但 `card` 表里有一行 `local-service` 只用于排序;内容来自 `/api/projects`,后端禁止删除/改名/配置分组。 - `node` 是统一分组树(根节点 `kind='section'`,子节点 `kind='group'` 可多层);`enabled` 控制启停;`icon` 可为空。 - 主要表:`node`、`entry`、`entry_tag`、`section_block`、`admin`、`session`、`setting`、`audit`。 diff --git a/docs/ADMIN-PLAN.md b/docs/ADMIN-PLAN.md index ccb8723..541a509 100644 --- a/docs/ADMIN-PLAN.md +++ b/docs/ADMIN-PLAN.md @@ -147,6 +147,13 @@ DELETE /api/items/:id ## 11. 实施记录 +### P27(2026-10-31,分类块圆角与顶部软虚化) + +- 侧栏导航 `.nav-card` 是普通 div(不是 Card),之前没有圆角;补 `border-radius: 12px` + `overflow: hidden`,和资料/服务卡一致; +- 搜索框透明度提到 50%,模糊提到 14px; +- 新增 `.top-blur`:固定在 header 下方(top 60、height 120),`blur(8px)` + 18% 页面色渐变,并用上下 `mask-image` 渐隐,避免再次出现分割线; +- 验证:nav 圆角 12px、top-blur 存在且 blur 生效、搜索框仍可点击、滚动时顶部软虚化无硬边。 + ### P26(2026-10-31,顶部留白加高) - 首页顶部偏移 `TOP_OFFSET` 从 88 调到 104,搜索框与内容卡片之间的空白从 28px 增加到 44px; diff --git a/stash-web/src/App.css b/stash-web/src/App.css index 7701c2a..860ba3d 100644 --- a/stash-web/src/App.css +++ b/stash-web/src/App.css @@ -151,8 +151,33 @@ /* 搜索框半透明,顶部区域透出背景 */ .search-row > *:first-child { - background-color: color-mix(in srgb, var(--su-bg-card) 60%, transparent); - backdrop-filter: blur(10px); + background-color: color-mix(in srgb, var(--su-bg-card) 50%, transparent); + backdrop-filter: blur(14px); +} + +/* 搜索区域软虚化:上下都用 mask 渐隐,不出现横向分割线 */ +.top-blur { + position: fixed; + top: 60px; + right: 0; + left: 0; + z-index: 4; + height: 120px; + pointer-events: none; + background: linear-gradient( + to bottom, + color-mix(in srgb, var(--su-bg-page) 22%, transparent) 0%, + transparent 80% + ); + backdrop-filter: blur(8px); + mask-image: linear-gradient(to bottom, transparent 0%, #000 28%, #000 62%, transparent 100%); + -webkit-mask-image: linear-gradient( + to bottom, + transparent 0%, + #000 28%, + #000 62%, + transparent 100% + ); } /* ---------- 两栏骨架 ---------- */ @@ -1339,6 +1364,11 @@ a.entry-href:hover { backdrop-filter: blur(14px) saturate(1.15); } +.sidebar-home .nav-card { + overflow: hidden; + border-radius: var(--su-radius-md); +} + .sidebar-divider { margin: var(--su-space-2) 0; border-top: 1px dashed var(--su-border-strong); diff --git a/stash-web/src/AppNext.tsx b/stash-web/src/AppNext.tsx index bd177d6..ef20199 100644 --- a/stash-web/src/AppNext.tsx +++ b/stash-web/src/AppNext.tsx @@ -223,6 +223,13 @@ export default function AppNext() { const onScroll = () => setScrolled(body.scrollTop > 4) + // 顶部软虚化层:覆盖搜索区域与内容顶部,边缘用 mask 渐隐,避免硬分割线 + const blur = document.createElement('div') + blur.className = 'top-blur' + blur.setAttribute('aria-hidden', 'true') + const appRoot = document.querySelector('.app') + appRoot?.appendChild(blur) + const updateSticky = () => { const viewport = body.clientHeight const maxLeft = Math.max(0, sider instanceof HTMLElement ? sider.offsetHeight - viewport : 0) @@ -246,6 +253,7 @@ export default function AppNext() { body.removeEventListener('scroll', updateSticky) window.removeEventListener('resize', updateSticky) observer.disconnect() + blur.remove() body.id = '' body.style.overflowY = '' body.style.overflowX = ''