From 3c21d4c28ccfa66c4cf72e982f042ded69f2aad2 Mon Sep 17 00:00:00 2001 From: Turtle Date: Tue, 8 Sep 2026 20:38:10 +0800 Subject: [PATCH] fix(client): name collapsed Settings trigger --- .../ui-settings-general/README.i18n.yaml | 4 +-- packages/client/ui-settings-general/README.md | 2 +- .../client/ui-settings-general/README.zh.md | 2 +- .../src/client/SettingsRoot.tsx | 5 +-- .../tests/settings-root.client.spec.tsx | 33 +++++++++++-------- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/packages/client/ui-settings-general/README.i18n.yaml b/packages/client/ui-settings-general/README.i18n.yaml index e86cb10e45..f5d7229b25 100644 --- a/packages/client/ui-settings-general/README.i18n.yaml +++ b/packages/client/ui-settings-general/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/client/ui-settings-general/README.md -README.md: c5bf1c1ccf0215e5902e65e66aea465a94350b9c -README.zh.md: 8fa4b48640374f414162a4f129d2ef177efb6287 +README.md: 845d9c48dce2264d478f0ac854ef85a480828a14 +README.zh.md: 4a96e78a13dd8e6aefd759926f6e2cb153f0b259 diff --git a/packages/client/ui-settings-general/README.md b/packages/client/ui-settings-general/README.md index c5bf1c1ccf..845d9c48dc 100644 --- a/packages/client/ui-settings-general/README.md +++ b/packages/client/ui-settings-general/README.md @@ -25,7 +25,7 @@ Use this package to give the dsh web client a Settings panel, connection-recover ## Use this package -Users reach the shell through the sidebar's bottom Settings control; feature plugins contribute their pages and onboarding steps through the slot ledgers this shell projects. A pale-yellow **Disconnected** action beside Settings indicates browser offline suspension. Automatic recovery shows **Reconnecting** with one to three dots advancing every 500ms. Hover or keyboard focus changes either yellow label to **Reconnect now** without changing its background; press feedback stays within the warning palette, and selecting it starts retry 1 immediately. Recovery changes the region to pale-green **Connected** for two seconds before it disappears. The icon, left-aligned text origin, height, and width remain fixed across every visible state. Initial startup and uninterrupted healthy operation remain silent. The shell renders the modal panel, the navigation built from `settings.section` entries, and exactly one mounted onboarding step at a time. +Users reach the shell through the sidebar's bottom Settings control; feature plugins contribute their pages and onboarding steps through the slot ledgers this shell projects. In both the expanded sidebar and collapsed rail, the control exposes the localized Settings label as its accessible name. A pale-yellow **Disconnected** action beside Settings indicates browser offline suspension. Automatic recovery shows **Reconnecting** with one to three dots advancing every 500ms. Hover or keyboard focus changes either yellow label to **Reconnect now** without changing its background; press feedback stays within the warning palette, and selecting it starts retry 1 immediately. Recovery changes the region to pale-green **Connected** for two seconds before it disappears. The icon, left-aligned text origin, height, and width remain fixed across every visible state. Initial startup and uninterrupted healthy operation remain silent. The shell renders the modal panel, the navigation built from `settings.section` entries, and exactly one mounted onboarding step at a time. ### The General section diff --git a/packages/client/ui-settings-general/README.zh.md b/packages/client/ui-settings-general/README.zh.md index 8fa4b48640..4a96e78a13 100644 --- a/packages/client/ui-settings-general/README.zh.md +++ b/packages/client/ui-settings-general/README.zh.md @@ -25,7 +25,7 @@ kind: "package-reference" ## 使用本包 -用户通过侧边栏底部的 Settings 控件进入外壳;功能插件通过本外壳所投影的 slot 账本贡献自己的页面与引导步骤。Settings 右侧浅黄色的**连接异常**操作表示浏览器离线暂停;自动恢复期间显示**自动重连中**,其后一至三个点每 500ms 前进一次。鼠标悬浮或键盘聚焦任一黄色状态时,只有文案变为**立即重连**,背景保持不变;按压反馈留在黄色色阶内,选中后立即从 retry 1 开始。恢复后该区域变为浅绿色的**连接成功**,驻留 2 秒再消失。所有可见状态的文字都左对齐,且图标、文字起点、高度和宽度保持固定。首次启动与未曾中断的健康连接保持静默。外壳渲染模态面板、由 `settings.section` 条目构建的导航,以及每次只挂载一个的引导步骤。 +用户通过侧边栏底部的 Settings 控件进入外壳;功能插件通过本外壳所投影的 slot 账本贡献自己的页面与引导步骤。在展开侧边栏和收起轨道中,该控件都会把本地化的 Settings 文案作为其可访问名称。Settings 右侧浅黄色的**连接异常**操作表示浏览器离线暂停;自动恢复期间显示**自动重连中**,其后一至三个点每 500ms 前进一次。鼠标悬浮或键盘聚焦任一黄色状态时,只有文案变为**立即重连**,背景保持不变;按压反馈留在黄色色阶内,选中后立即从 retry 1 开始。恢复后该区域变为浅绿色的**连接成功**,驻留 2 秒再消失。所有可见状态的文字都左对齐,且图标、文字起点、高度和宽度保持固定。首次启动与未曾中断的健康连接保持静默。外壳渲染模态面板、由 `settings.section` 条目构建的导航,以及每次只挂载一个的引导步骤。 ### 「通用」分区 diff --git a/packages/client/ui-settings-general/src/client/SettingsRoot.tsx b/packages/client/ui-settings-general/src/client/SettingsRoot.tsx index d5b1df190a..e0b20dceed 100644 --- a/packages/client/ui-settings-general/src/client/SettingsRoot.tsx +++ b/packages/client/ui-settings-general/src/client/SettingsRoot.tsx @@ -1,9 +1,9 @@ /** * Settings shell root: the sidebar-foot trigger row plus the centered modal * panel (figma 501:29947, 1080x700) with the section nav rail. The shell is - * a pure composition face — every piece of text (trigger label, panel title, + * a pure composition face — slot-owned text (trigger label, panel title, * close label, sections) arrives from registrants through slots; accessible - * names resolve to that content (trigger: its own text; dialog: + * names resolve from localized content (trigger: shell locale; dialog: * aria-labelledby the title node; close: visually-hidden slot text). Modal * open state and the active section id are component-local viewing state; * the onboarding coordinator mounts exactly one ordered registrant while the @@ -184,6 +184,7 @@ export function SettingsRoot(props: SettingsRootComponentProps) { ref={triggerButton} type="button" className={clsx(css.trigger, !wide && css.rail)} + aria-label={t('trigger')} aria-haspopup="dialog" aria-expanded={open} onClick={() => { setOpen(true) }} diff --git a/packages/client/ui-settings-general/tests/settings-root.client.spec.tsx b/packages/client/ui-settings-general/tests/settings-root.client.spec.tsx index 3ebce030b4..18d96544a0 100644 --- a/packages/client/ui-settings-general/tests/settings-root.client.spec.tsx +++ b/packages/client/ui-settings-general/tests/settings-root.client.spec.tsx @@ -6,7 +6,7 @@ import { act, cleanup, fireEvent, render, screen } from '@testing-library/react' import { makeTranslate } from '@deepseek-ai/dsh-client-test-runtime' import type { SettingsRootComponentProps } from '../src/client/shell-contract.ts' import { SettingsRoot } from '../src/client/SettingsRoot.tsx' -import { en } from '../src/client/locales.ts' +import { en, zh } from '../src/client/locales.ts' // Every fixture carries the resource hook the resources plugin merges into GlobalStandardProps. const useResource = (() => ({ status: 'none' as const, value: undefined, failure: undefined, reload: () => {} })) as GlobalStandardProps['useResource'] @@ -34,6 +34,7 @@ const useSessionPendingInteraction: SettingsRootComponentProps['useSessionPendin function mount({ wide = true, + dictionary = en, connectionState = 'connected', onboardingActive = true, rows = [ @@ -47,6 +48,7 @@ function mount({ ], }: { wide?: boolean + dictionary?: typeof en | typeof zh connectionState?: ConnectionSnapshot onboardingActive?: boolean rows?: Row[] @@ -80,7 +82,7 @@ function mount({ useWorkspaces: unusedHook, wide, reconnect, - t: makeTranslate(en), + t: makeTranslate(dictionary), useConnectionState: (select) => { const [, force] = useState(0) useEffect(() => { @@ -126,20 +128,23 @@ function openPanel() { } describe('SettingsRoot trigger', () => { - it('renders the trigger seat content as the accessible name (no aria-label of its own)', () => { - const { renderSlot } = mount() - const trigger = screen.getByRole('button', { name: 'Settings' }) - expect(trigger.hasAttribute('aria-label')).toBe(false) - expect(renderSlot).toHaveBeenCalledWith('settings.trigger', { wide: true }) + it.each([ + { column: 'expanded English', wide: true, dictionary: en, name: 'Settings' }, + { column: 'collapsed English', wide: false, dictionary: en, name: 'Settings' }, + { column: 'expanded Chinese', wide: true, dictionary: zh, name: '设置' }, + { column: 'collapsed Chinese', wide: false, dictionary: zh, name: '设置' }, + ])('uses the locale name and accepts keyboard-style activation for the $column trigger', ({ + wide, dictionary, name, + }) => { + const { renderSlot } = mount({ wide, dictionary }) + const trigger = screen.getByRole('button', { name }) + expect(trigger.getAttribute('aria-label')).toBe(name) + expect(renderSlot).toHaveBeenCalledWith('settings.trigger', { wide }) expect(trigger.getAttribute('aria-expanded')).toBe('false') - fireEvent.click(trigger) + trigger.focus() + fireEvent.click(trigger, { detail: 0 }) expect(screen.getByRole('dialog')).toBeTruthy() - expect(screen.getByRole('button', { name: 'Settings', expanded: true })).toBeTruthy() - }) - - it('hands the rail state to the trigger seat', () => { - const { renderSlot } = mount({ wide: false }) - expect(renderSlot).toHaveBeenCalledWith('settings.trigger', { wide: false }) + expect(screen.getByRole('button', { name, expanded: true })).toBeTruthy() }) it('shows outage, retry progress, and a two-second recovery confirmation', () => {