feat(settings): Group page description, collapsed page tree and a seamless title bar

- Group pages open with a short description and list their pages as
  indented links.
- The page tree starts collapsed, expanding only the current page's
  ancestors.
- The Settings window title bar sits on the dialog surface without a
  hairline.
This commit is contained in:
l0ng-ai
2026-10-28 10:20:26 +08:00
parent c6a4361513
commit b3b4cbbe1a
5 changed files with 66 additions and 17 deletions
@@ -147,24 +147,37 @@
}
.groupPage {
padding-top: 8px;
}
.groupDescription {
margin: 0 0 14px;
max-width: 720px;
color: var(--fg);
line-height: 1.45;
}
.groupLinks {
display: flex;
flex-direction: column;
max-width: 420px;
align-items: flex-start;
gap: 2px;
padding-left: 32px;
}
.groupLink {
display: flex;
align-items: center;
justify-content: space-between;
height: 28px;
padding: 0 8px;
border-radius: var(--radius-row);
height: 20px;
padding: 0;
border: 0;
background: none;
color: var(--link);
font: inherit;
text-align: left;
cursor: pointer;
}
.groupLink:hover {
background: var(--bg-hover);
color: var(--link-hover);
text-decoration: underline;
}
.groupLink:focus-visible {
outline: 2px solid var(--focus-ring, var(--accent));
}
.footerStatus {
@@ -42,20 +42,46 @@ import { PageErrorBoundary } from "./PageErrorBoundary";
import styles from "./SettingsDialog.module.css";
import { tx } from "@/platform/i18n";
/** Keys of the nodes above `key`, root first. */
function ancestorKeys(nodes: readonly PageNode[], key: string): string[] {
for (const n of nodes) {
if (n.key === key) return [];
const sub = ancestorKeys(n.children, key);
if (sub.length || n.children.some((c) => c.key === key)) return [n.key, ...sub];
}
return [];
}
function firstPage(nodes: readonly PageNode[]): string | null {
const list = flatten(nodes).filter((n) => n.page);
return (list.find((n) => n.matched) ?? list[0])?.key ?? null;
}
const GROUP_DESCRIPTIONS: Record<string, string> = {
"Appearance & Behavior":
"Customize IDE appearance and behavior: change themes and font size, configure system settings and notifications.",
Editor: "Configure code editing: completion, folding, tabs, fonts, colors, code style and inspections.",
"Build, Execution, Deployment": "Configure build tools, run configurations, debugger and deployment.",
"Languages & Frameworks": "Configure language servers, interpreters, SDKs and framework support.",
Tools: "Configure external tools, terminal, database and other integrations.",
};
function GroupPage({ node }: { node: PageNode }) {
const description = GROUP_DESCRIPTIONS[node.title];
return (
<div className={styles.groupPage}>
{node.children.map((c) => (
<button key={c.key} type="button" className={styles.groupLink} onClick={() => selectPage(c.key)}>
<SearchLabel text={c.title} />
<Icon name="chevron-right" size={12} />
</button>
))}
{description && (
<p className={styles.groupDescription}>
<T>{description}</T>
</p>
)}
<div className={styles.groupLinks}>
{node.children.map((c) => (
<button key={c.key} type="button" className={styles.groupLink} onClick={() => selectPage(c.key)}>
<SearchLabel text={c.title} />
</button>
))}
</div>
</div>
);
}
@@ -263,7 +289,7 @@ export function SettingsLayout() {
getLabel={(n) => tx(n.title)}
getChildren={(n) => (n.children.length ? n.children : undefined)}
isExpandable={(n) => n.children.length > 0}
defaultExpanded={all.filter((n) => n.children.length).map((n) => n.key)}
defaultExpanded={current ? ancestorKeys(tree, current.key) : []}
expanded={query ? expanded : undefined}
selected={current ? new Set([current.key]) : new Set()}
onSelectionChange={(_sel, node) => node && selectPage(node.key)}
+6 -1
View File
@@ -4198,5 +4198,10 @@
"0 results": "0 个结果",
"Time the agent took to answer": "智能体回答所用的时间",
"Edit and Resend": "编辑后重新发送",
"Send Again": "再次发送"
"Send Again": "再次发送",
"Customize IDE appearance and behavior: change themes and font size, configure system settings and notifications.": "自定义 IDE 的外观和行为:更改主题和字号,配置系统设置和通知。",
"Configure code editing: completion, folding, tabs, fonts, colors, code style and inspections.": "配置代码编辑:补全、折叠、标签页、字体、配色、代码样式和检查。",
"Configure build tools, run configurations, debugger and deployment.": "配置构建工具、运行配置、调试器和部署。",
"Configure language servers, interpreters, SDKs and framework support.": "配置语言服务器、解释器、SDK 和框架支持。",
"Configure external tools, terminal, database and other integrations.": "配置外部工具、终端、数据库和其他集成。"
}
+5
View File
@@ -19,6 +19,11 @@
background: var(--bg-elev);
box-shadow: inset 0 -1px 0 var(--border);
}
/* Dialog window (Settings): the title sits on the dialog surface, no hairline. */
.dialogBar {
background: var(--bg-dialog, var(--bg-elev));
box-shadow: none;
}
.windowTitle {
min-width: 0;
overflow: hidden;
+1 -1
View File
@@ -292,7 +292,7 @@ export function TitleBar({
const entry = (id: string) => <ToolbarEntry key={id} id={id} items={map} />;
return (
<header
className={clsx(className, minimal && styles.minimal)}
className={clsx(className, minimal && styles.minimal, dialog && styles.dialogBar)}
data-tauri-drag-region
onContextMenu={(e) => {
if (minimal || e.defaultPrevented) return;