fix(web): settings page layout pass (FE-7)
- Section header (h2 + description) and section blocks as h3; unified block padding and title size - Global settings forms use label-left / control-right rows, stacked below md; control width fixed by type (number short, text/select medium, wide/textarea full) - Per-block SaveBar pinned at the block end with dirty hint; naming template saves moved from the header to the bar - Console shell uses overflow-x-clip so the sticky header and sticky section nav actually stick; anchor jumps re-align while async content loads and land below the header - Section content uses a single minmax(0,1fr) column so wide tables scroll inside their card instead of widening the page - useSettings fills missing keys from DEFAULT_SETTINGS so an older backend no longer crashes the metadata section Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
04cffcd1f1
commit
639fdeacae
13 files changed
+254
-111
No files matched your search
@@ -12,7 +12,7 @@ import { Button } from "~/components/ui/button.tsx";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/components/ui/select.tsx";
|
||||
import { Switch } from "~/components/ui/switch.tsx";
|
||||
import { errorMessage } from "~/lib/api.ts";
|
||||
import { SettingsBlock } from "./settings-block.tsx";
|
||||
import { SaveBar, SettingsBlock } from "./settings-block.tsx";
|
||||
|
||||
// 设置 → 媒体库与目录 → 命名模板:全局模板 + 库根覆盖(作品覆盖在作品详情)。
|
||||
|
||||
@@ -61,19 +61,7 @@ function GlobalNaming() {
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingsBlock
|
||||
section="library"
|
||||
anchor="naming"
|
||||
title="命名模板"
|
||||
description={NAMING_NOTE}
|
||||
dirty={dirty}
|
||||
actions={
|
||||
<Button size="sm" onClick={onSave} disabled={!dirty || save.isPending || !draft}>
|
||||
<Save />
|
||||
{save.isPending ? "保存中…" : "保存"}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<SettingsBlock section="library" anchor="naming" title="命名模板" description={NAMING_NOTE} dirty={dirty}>
|
||||
{!q.data || !draft ? (
|
||||
q.isError ? (
|
||||
<ErrorState plain error={q.error} onRetry={() => q.refetch()} />
|
||||
@@ -110,6 +98,12 @@ function GlobalNaming() {
|
||||
aria-label="已有目录的作品固定文件名"
|
||||
/>
|
||||
</label>
|
||||
<SaveBar dirty={dirty}>
|
||||
<Button size="sm" onClick={onSave} disabled={!dirty || save.isPending || !draft}>
|
||||
<Save />
|
||||
{save.isPending ? "保存中…" : "保存"}
|
||||
</Button>
|
||||
</SaveBar>
|
||||
</div>
|
||||
)}
|
||||
</SettingsBlock>
|
||||
@@ -199,22 +193,6 @@ function RootNamingEditor({ root }: { root: LibraryRoot }) {
|
||||
{NAMING_KIND_LABEL[k]}:{saved[k] ? "库根覆盖" : "沿用全局"}
|
||||
</StatusBadge>
|
||||
))}
|
||||
<div className="ml-auto flex items-center gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="hover:text-destructive"
|
||||
disabled={!hasOverride || save.isPending}
|
||||
onClick={() => put(null)}
|
||||
>
|
||||
<Trash2 />
|
||||
清除覆盖
|
||||
</Button>
|
||||
<Button size="sm" disabled={!dirty || save.isPending} onClick={() => put(overrideBody(draft))}>
|
||||
<Save />
|
||||
{save.isPending ? "保存中…" : "保存覆盖"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<NamingTemplateEditor
|
||||
kinds={KINDS}
|
||||
@@ -229,6 +207,22 @@ function RootNamingEditor({ root }: { root: LibraryRoot }) {
|
||||
saveErrors={errors}
|
||||
dirtyKinds={dirtyKinds}
|
||||
/>
|
||||
<SaveBar dirty={dirty}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="hover:text-destructive"
|
||||
disabled={!hasOverride || save.isPending}
|
||||
onClick={() => put(null)}
|
||||
>
|
||||
<Trash2 />
|
||||
清除覆盖
|
||||
</Button>
|
||||
<Button size="sm" disabled={!dirty || save.isPending} onClick={() => put(overrideBody(draft))}>
|
||||
<Save />
|
||||
{save.isPending ? "保存中…" : "保存覆盖"}
|
||||
</Button>
|
||||
</SaveBar>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user