From d01d0faf7a7ed4e5eb3c284d74065236473d9d19 Mon Sep 17 00:00:00 2001 From: Yaowei Zheng Date: Thu, 23 Jul 2026 01:07:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(web):=20settings=20form=20polish=20?= =?UTF-8?q?=E2=80=94=20dialog=20layout,=20homepage=20button,=20no=20defaul?= =?UTF-8?q?t=20rows,=20unified=20dropdown=20text=20(#39)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alice Co-authored-by: Claude Fable 5 --- .../web/src/components/ui/option-menu.tsx | 11 +- packages/web/src/components/ui/select.tsx | 5 +- packages/web/src/components/ui/switch.tsx | 44 +++ .../features/agents/agent-settings-page.tsx | 90 ++++-- .../web/src/features/chat/thinking-level.ts | 33 ++- .../web/src/features/models/models-page.tsx | 262 ++++++++++-------- packages/web/src/lib/strings-en.ts | 23 +- packages/web/src/lib/strings.ts | 28 +- .../web/test/agent-settings-options.test.ts | 34 +++ packages/web/test/thinking-level.test.ts | 16 +- 10 files changed, 363 insertions(+), 183 deletions(-) create mode 100644 packages/web/src/components/ui/switch.tsx create mode 100644 packages/web/test/agent-settings-options.test.ts diff --git a/packages/web/src/components/ui/option-menu.tsx b/packages/web/src/components/ui/option-menu.tsx index f2bf3d4..8f81764 100644 --- a/packages/web/src/components/ui/option-menu.tsx +++ b/packages/web/src/components/ui/option-menu.tsx @@ -43,6 +43,11 @@ export interface OptionMenuChoice { const PANEL_WIDTH = 288; // w-72 +/** Row-title text follows the control's size tier, so the dropdown reads exactly like an Input of the same tier (review: dropdown text = input text); descriptions stay text-xs secondary. */ +const rowTextClass: Record = { base: "text-base", sm: "text-xs" }; +/** Descriptions keep one step below the row title at every tier, so the title/description hierarchy survives the sm tier's text-xs titles. */ +const rowDescClass: Record = { base: "text-xs", sm: "text-[11px]" }; + export function OptionMenu({ options, value, @@ -143,7 +148,7 @@ export function OptionMenu({ > ({ )} - + {opt.description} diff --git a/packages/web/src/components/ui/select.tsx b/packages/web/src/components/ui/select.tsx index 3f9738a..f0f166a 100644 --- a/packages/web/src/components/ui/select.tsx +++ b/packages/web/src/components/ui/select.tsx @@ -48,6 +48,9 @@ const CONTROL_CLASS = "dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:hover:border-gray-600 " + "dark:focus:border-gray-400 dark:focus:ring-gray-500/30"; +/** Menu-row text follows the control's size tier, so the dropdown reads exactly like an Input of the same tier (review: dropdown text = input text). */ +const menuTextClass: Record = { base: "text-base", sm: "text-xs" }; + export function Select({ label, hint, @@ -169,7 +172,7 @@ export function Select({ aria-selected={o.value === current} disabled={o.disabled} onClick={() => pick(o.value)} - className={`flex w-full items-center px-3 py-1.5 text-left text-sm transition-colors duration-150 disabled:opacity-50 ${ + className={`flex w-full items-center px-3 py-1.5 text-left ${menuTextClass[size]} transition-colors duration-150 disabled:opacity-50 ${ o.value === current ? "bg-gray-100 font-medium text-gray-900 dark:bg-gray-800 dark:text-gray-100" : "text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800" diff --git a/packages/web/src/components/ui/switch.tsx b/packages/web/src/components/ui/switch.tsx new file mode 100644 index 0000000..f3a6af7 --- /dev/null +++ b/packages/web/src/components/ui/switch.tsx @@ -0,0 +1,44 @@ +/** + * iOS-style toggle switch: a `button` with `role="switch"` + `aria-checked` (a native + * button is keyboard-operable out of the box — Space/Enter activate it — and is labelable + * content, so clicking an enclosing `