Skip to content

Commit 32508c7

Browse files
committed
feat: regroup mobile settings homepage
1 parent 032a3f0 commit 32508c7

4 files changed

Lines changed: 88 additions & 24 deletions

File tree

packages/web/src/features/settings/components/settings-page.test.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,36 @@ describe("SettingsPage", () => {
272272
).toBeTruthy();
273273
});
274274

275+
it("renders the mobile settings homepage as grouped sections without the legacy hero", async () => {
276+
viewportMocks.viewport = "mobile";
277+
const store = createConnectedStore(vi.fn().mockResolvedValue({}));
278+
279+
renderSettingsPage(store);
280+
281+
expect(await screen.findByText("工作区与运行")).toBeInTheDocument();
282+
expect(screen.getByText("界面与交互")).toBeInTheDocument();
283+
expect(document.querySelector(".settings-mobile-root-hero")).toBeNull();
284+
285+
const buttons = screen.getAllByRole("button");
286+
const labels = buttons.map((button) => button.getAttribute("aria-label")).filter(Boolean);
287+
288+
expect(labels).toEqual(expect.arrayContaining(["通用", "Agents", "外观", "快捷键"]));
289+
expect(labels.indexOf("通用")).toBeLessThan(labels.indexOf("Agents"));
290+
expect(labels.indexOf("Agents")).toBeLessThan(labels.indexOf("外观"));
291+
expect(labels.indexOf("外观")).toBeLessThan(labels.indexOf("快捷键"));
292+
});
293+
294+
it("localizes the new mobile settings homepage section headings", async () => {
295+
viewportMocks.viewport = "mobile";
296+
window.localStorage.setItem("ui.locale", JSON.stringify("en"));
297+
const store = createConnectedStore(vi.fn().mockResolvedValue({}));
298+
299+
renderSettingsPage(store);
300+
301+
expect(await screen.findByText("Workspace & Runtime")).toBeInTheDocument();
302+
expect(screen.getByText("Interface & Interaction")).toBeInTheDocument();
303+
});
304+
275305
it("does not render default Agent Provider selection in general settings", async () => {
276306
const sendCommand = vi.fn().mockImplementation(async (op: string) => {
277307
if (op === "settings.get") {

packages/web/src/features/settings/components/settings-page.tsx

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@ function getMobileSectionHintKey(section: SettingsSection) {
138138
}
139139
}
140140

141+
const MOBILE_SETTINGS_GROUPS = [
142+
{
143+
titleKey: "settings.mobile_groups.workspace_runtime",
144+
sections: ["general", "providers"],
145+
},
146+
{
147+
titleKey: "settings.mobile_groups.interface_interaction",
148+
sections: ["appearance", "shortcuts"],
149+
},
150+
] as const satisfies readonly {
151+
titleKey: string;
152+
sections: readonly SettingsSection[];
153+
}[];
154+
141155
/**
142156
* Settings Page
143157
*
@@ -449,30 +463,42 @@ export function SettingsPage() {
449463

450464
const renderMobileRoot = () => (
451465
<main className="settings-content settings-content--mobile-root">
452-
<section className="settings-mobile-root-hero">
453-
<div className="settings-mobile-root-hero__eyebrow">{t("settings.title")}</div>
454-
<p className="settings-mobile-root-hero__body">{t("settings.autosave_hint")}</p>
455-
</section>
456-
<div className="settings-mobile-list">
457-
{availableSections.map(({ id, labelKey, iconSemantic }) => (
458-
<button
459-
key={id}
460-
type="button"
461-
className="settings-mobile-item"
462-
aria-label={t(labelKey)}
463-
onClick={() => setNavigationState({ kind: "detail", section: id })}
464-
>
465-
<span className="settings-mobile-item__icon-shell" aria-hidden="true">
466-
<span className="settings-mobile-item__icon">
467-
<ThemedIcon semantic={iconSemantic} size={18} />
468-
</span>
469-
</span>
470-
<span className="settings-mobile-item__copy">
471-
<span className="settings-mobile-item__label">{t(labelKey)}</span>
472-
<span className="settings-mobile-item__hint">{t(getMobileSectionHintKey(id))}</span>
473-
</span>
474-
<ChevronRight size={16} className="settings-mobile-item__arrow" />
475-
</button>
466+
<div className="settings-mobile-root" data-testid="settings-mobile-root">
467+
{MOBILE_SETTINGS_GROUPS.map((group) => (
468+
<section key={group.titleKey} className="settings-mobile-group">
469+
<h2 className="settings-mobile-group__title">{t(group.titleKey)}</h2>
470+
<div className="settings-mobile-group__list">
471+
{group.sections.map((sectionId) => {
472+
const section = availableSections.find((entry) => entry.id === sectionId);
473+
if (!section) {
474+
return null;
475+
}
476+
477+
return (
478+
<button
479+
key={section.id}
480+
type="button"
481+
className="settings-mobile-item"
482+
aria-label={t(section.labelKey)}
483+
onClick={() => setNavigationState({ kind: "detail", section: section.id })}
484+
>
485+
<span className="settings-mobile-item__icon-shell" aria-hidden="true">
486+
<span className="settings-mobile-item__icon">
487+
<ThemedIcon semantic={section.iconSemantic} size={18} />
488+
</span>
489+
</span>
490+
<span className="settings-mobile-item__copy">
491+
<span className="settings-mobile-item__label">{t(section.labelKey)}</span>
492+
<span className="settings-mobile-item__hint">
493+
{t(getMobileSectionHintKey(section.id))}
494+
</span>
495+
</span>
496+
<ChevronRight size={16} className="settings-mobile-item__arrow" />
497+
</button>
498+
);
499+
})}
500+
</div>
501+
</section>
476502
))}
477503
</div>
478504
</main>

packages/web/src/locales/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@
489489
"general": "General",
490490
"appearance": "Appearance",
491491
"providers": "Agents",
492+
"mobile_groups": {
493+
"workspace_runtime": "Workspace & Runtime",
494+
"interface_interaction": "Interface & Interaction"
495+
},
492496
"autosave_hint": "Settings saved automatically",
493497
"load_failed": "Failed to load settings",
494498
"load_failed_unknown": "Server did not return settings data",

packages/web/src/locales/zh.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@
489489
"general": "通用",
490490
"appearance": "外观",
491491
"providers": "Agents",
492+
"mobile_groups": {
493+
"workspace_runtime": "工作区与运行",
494+
"interface_interaction": "界面与交互"
495+
},
492496
"autosave_hint": "设置已自动保存",
493497
"load_failed": "设置加载失败",
494498
"load_failed_unknown": "未收到服务端返回的设置数据",

0 commit comments

Comments
 (0)