fix(web): 控制台界面细节与 uhd_web 控件规范对齐

- 顶栏搜索移进右侧玻璃胶囊;输入框改淡玻璃(边线 0.46 → 0.16,悬停加深,聚焦 / 出错保留光晕)
- 新增 SegmentedControl(滑动 seg-thumb),替换站点、下载、订阅、文件、智能体列表及对话框里的实心选中块;Tabs 改为同一枚滑块
- 开关型按钮统一 outline + aria-pressed 选中外观;页头 / 工具栏次操作描边、图标钮描边圆;文件排序改 Select;下载总速度加标签
- 分页一页放得下时只留总数、空列表不渲染、按容器宽度收起按钮
- 运行状态存储区重排;智能体列表页与会话页共用外壳路由,标题与左栏不再重挂载
- 站点卡片「⋯」不再单独换行;设置导航、状态计数、多选条件改玻璃选中态

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-08 12:02:48 +08:00
1 parent 8ff1817845
commit c9b4ceb301
32 files changed
+753 -639

No files matched your search

+6 -42
View File
@@ -12,7 +12,7 @@ import { SiteCard, SiteTable } from "~/components/sites/site-card.tsx";
import { type SiteDialog, SiteDialogHost, useSiteChecks } from "~/components/sites/site-dialogs.tsx";
import { needsAttention, type SortKey, sortSites } from "~/components/sites/site-fields.ts";
import { Button } from "~/components/ui/button.tsx";
import { cn } from "~/lib/utils.ts";
import { SegmentedControl } from "~/components/ui/segmented.tsx";
// 获取 → 站点:站点、凭证、健康、账号数据、RSS 的唯一入口(docs/design/site-center.md §4);
// 按类型分组显示:PT 站 / 公开 BT 站(旧的自定义 RSS 源有的话单列);?new=<类型> 直接打开添加。
@@ -143,13 +143,13 @@ export default function SitesPage() {
{all.length ? (
<div className="mb-4 flex flex-wrap items-center justify-between gap-3">
<div className="flex flex-wrap items-center gap-2">
<Segmented
<SegmentedControl
label="筛选"
value={filter}
onChange={(v) => setParam("filter", v === "all" ? null : v)}
options={FILTERS.map((f) => ({
...f,
label: f.value === "attention" && attention ? `${f.label} ${attention}` : f.label,
count: f.value === "attention" && attention ? attention : undefined,
}))}
/>
<FilterSelect
@@ -160,13 +160,13 @@ export default function SitesPage() {
options={SORTS.filter((x) => x.value !== "name")}
/>
</div>
<Segmented
<SegmentedControl
label="视图"
value={view}
onChange={(v) => setView(v as View)}
options={[
{ value: "cards", label: "卡片", icon: <LayoutGrid className="h-3.5 w-3.5" /> },
{ value: "list", label: "列表", icon: <List className="h-3.5 w-3.5" /> },
{ value: "cards", label: "卡片", icon: <LayoutGrid /> },
{ value: "list", label: "列表", icon: <List /> },
]}
/>
</div>
@@ -224,39 +224,3 @@ export default function SitesPage() {
</>
);
}
function Segmented({
label,
value,
onChange,
options,
}: {
label: string;
value: string;
onChange: (v: string) => void;
options: { value: string; label: string; icon?: React.ReactNode }[];
}) {
return (
<div role="radiogroup" aria-label={label} className="inline-flex gap-0.5 rounded-xl border border-border p-0.5">
{options.map((o) => (
// biome-ignore lint/a11y/useSemanticElements: 分段按钮
<button
key={o.value}
type="button"
role="radio"
aria-checked={value === o.value}
onClick={() => onChange(o.value)}
className={cn(
"inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1 text-caption transition-colors",
value === o.value
? "bg-foreground text-background"
: "text-muted-foreground hover:bg-accent hover:text-foreground",
)}
>
{o.icon}
{o.label}
</button>
))}
</div>
);
}