feat(web): 记录抽屉与两层导航标准
控制台导航最多两层(侧栏一项 = 一页,页内最多一层页签 / 分段);从列表打开的
记录改成列表页上的右侧抽屉,打开的记录写在 ?open=,刷新、分享、前进后退都能还原,
后退就是关抽屉。标准写在 docs/design/console-ia.md §9,ui-controls.md 引用。
- DetailSheet 加 xl 宽度、标题下操作行;抽屉里再开的 DetailSheet 在同一抽屉里换成子视图(返回 / Esc)
- record-sheet.tsx:useRecordSheet / RecordLink / useOpenRecord / recordPath / taskPath
- 整理记录、订阅、站点(含页签)、下载、日志任务改成抽屉;旧业务任务 / 下载任务 id 在任务抽屉里换算
- 回收站并进文件管理右侧视图(?view=trash);设置左栏只列分区
- 规则组、策略版本、媒体库未识别 / 外部身份、设置实例编辑走 ?open=
- 旧地址 /console/{organize,subscriptions,sites,downloads}/:id、/tasks/:id、/files/trash 跳到列表页抽屉
- 站内链接、铃铛、命令面板、任务时间线改拼新地址;冒烟按 ?open= 检查抽屉
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
dd0f6e2c09
commit
21c55dfb3a
60 files changed
+2768
-2461
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { settingsSectionForLegacyTab } from "@umt/contracts";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Link, redirect, useLocation, useNavigate } from "react-router";
|
||||
import { PageHeader } from "~/components/console/page-header.tsx";
|
||||
import { parseSettingsHash, SECTION_GROUPS, settingsHash } from "~/components/settings/sections.tsx";
|
||||
@@ -45,9 +45,13 @@ export default function SettingsPage() {
|
||||
|
||||
// 切分区回到顶部;带节锚点时对齐到该节(有字段时对齐到字段并聚焦)。节内容多是异步加载的(上游列表、能力清单),
|
||||
// 上方内容变高会把目标挤下去,所以在 2.5 秒内反复校正,直到用户自己滚动为止。
|
||||
// 打开 / 关闭记录抽屉(?open=,console-ia.md §9)只改 search,不滚动
|
||||
const lastSearch = useRef(location.search);
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: location.key 让重复点同一锚点也能再跳一次
|
||||
useEffect(() => {
|
||||
if (moved) return;
|
||||
const searchChanged = lastSearch.current !== location.search;
|
||||
lastSearch.current = location.search;
|
||||
if (moved || searchChanged) return;
|
||||
if (!anchor) {
|
||||
window.scrollTo({ top: 0 });
|
||||
return;
|
||||
@@ -91,7 +95,7 @@ export default function SettingsPage() {
|
||||
<>
|
||||
<PageHeader title="设置" description="密钥保存后不再显示。" />
|
||||
<div className="grid gap-6 lg:grid-cols-[14rem_minmax(0,1fr)] lg:gap-8">
|
||||
{/* 窄屏:搜索 + 分区下拉 + 节横排 */}
|
||||
{/* 窄屏:搜索 + 分区下拉。左栏只有一层(console-ia.md §9):节是页面里的小标题,搜索与 #分区/节 深链仍能定位 */}
|
||||
<div className="grid gap-3 lg:hidden">
|
||||
<SettingsSearch />
|
||||
<Select value={section.id} onValueChange={(id) => navigate({ hash: settingsHash(id) })}>
|
||||
@@ -113,30 +117,9 @@ export default function SettingsPage() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-caption text-muted-foreground">{section.description}</p>
|
||||
{section.anchors.length > 1 ? (
|
||||
<nav aria-label="本分区目录" className="scroll-bleed -mx-1 overflow-x-auto px-1 pb-1">
|
||||
<ul className="flex w-max gap-1.5">
|
||||
{section.anchors.map((a) => (
|
||||
<li key={a.id}>
|
||||
<Link
|
||||
to={{ hash: settingsHash(section.id, a.id) }}
|
||||
className={cn(
|
||||
"block rounded-full border px-3 py-1 text-caption whitespace-nowrap transition-colors duration-micro",
|
||||
anchor === a.id
|
||||
? "pill-selected text-foreground"
|
||||
: "border-border/70 text-muted-foreground hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
{a.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{/* 宽屏:搜索 + 左侧分组导航 */}
|
||||
{/* 宽屏:搜索 + 左侧分组导航(只列分区,不展开节) */}
|
||||
<div className="hidden lg:block">
|
||||
<div className="sticky top-20 grid max-h-[calc(100dvh-6rem)] gap-3 overflow-y-auto pb-2">
|
||||
<SettingsSearch />
|
||||
@@ -164,23 +147,6 @@ export default function SettingsPage() {
|
||||
<s.icon className="size-4 shrink-0" aria-hidden />
|
||||
{s.label}
|
||||
</Link>
|
||||
{active && s.anchors.length > 1 ? (
|
||||
<ul className="mt-0.5 mb-1.5 ml-[1.375rem] grid gap-0.5 border-l border-border/60 pl-3">
|
||||
{s.anchors.map((a) => (
|
||||
<li key={a.id}>
|
||||
<Link
|
||||
to={{ hash: settingsHash(s.id, a.id) }}
|
||||
className={cn(
|
||||
"block rounded-md px-2 py-1 text-caption transition-colors duration-micro hover:text-foreground",
|
||||
anchor === a.id ? "text-foreground" : "text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{a.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : null}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in new issue
Block a user