From 6c0f151f6e680d412e4a4e5ae017349c42d47ffd Mon Sep 17 00:00:00 2001 From: chengyongru Date: Thu, 23 Jul 2026 18:18:34 +0800 Subject: [PATCH] fix(webui): polish responsive layout --- .../src/components/settings/SettingsView.tsx | 128 ++++++++++++------ .../src/components/thread/ThreadComposer.tsx | 38 ++++-- webui/src/components/thread/ThreadShell.tsx | 74 +++++++++- .../src/components/thread/ThreadViewport.tsx | 2 +- .../components/thread/WorkspaceControls.tsx | 25 +++- webui/src/globals.css | 95 +++++++++++++ webui/src/i18n/locales/en/common.json | 4 +- webui/src/i18n/locales/es/common.json | 4 +- webui/src/i18n/locales/fr/common.json | 4 +- webui/src/i18n/locales/id/common.json | 4 +- webui/src/i18n/locales/ja/common.json | 4 +- webui/src/i18n/locales/ko/common.json | 4 +- webui/src/i18n/locales/pt-BR/common.json | 4 +- webui/src/i18n/locales/vi/common.json | 4 +- webui/src/i18n/locales/zh-CN/common.json | 4 +- webui/src/i18n/locales/zh-TW/common.json | 4 +- webui/src/tests/app-layout.test.tsx | 11 +- webui/src/tests/settings-view.test.tsx | 5 +- webui/src/tests/thread-composer.test.tsx | 30 +++- webui/src/tests/thread-shell.test.tsx | 4 +- 20 files changed, 372 insertions(+), 80 deletions(-) diff --git a/webui/src/components/settings/SettingsView.tsx b/webui/src/components/settings/SettingsView.tsx index 205cffd7..ab863191 100644 --- a/webui/src/components/settings/SettingsView.tsx +++ b/webui/src/components/settings/SettingsView.tsx @@ -270,6 +270,11 @@ const DEFERRED_MODEL_LIST_PROVIDERS = new Set([ const DEFERRED_MODEL_LIST_QUERY_MIN_LENGTH = 2; const CLI_APPS_REFRESH_RETRY_MS = 2_000; const CLI_APPS_REFRESH_MAX_RETRIES = 30; +const SETTINGS_SEARCH_INPUT_CLASS = cn( + "border-border/45 bg-settings-surface transition-colors hover:border-border/70", + "focus-visible:border-border/70 focus-visible:bg-background", + "focus-visible:ring-0 focus-visible:ring-offset-0", +); const FALLBACK_TIMEZONES = [ "UTC", @@ -2200,23 +2205,12 @@ function SettingsSidebar({ hostChromeInset?: boolean; }) { const { t } = useTranslation(); - const navRef = useRef(null); - const activeItemRef = useRef(null); - - useEffect(() => { - const nav = navRef.current; - const activeItem = activeItemRef.current; - if (!nav || !activeItem || nav.scrollWidth <= nav.clientWidth) return; - const navRect = nav.getBoundingClientRect(); - const itemRect = activeItem.getBoundingClientRect(); - const itemCenter = itemRect.left - navRect.left + nav.scrollLeft + itemRect.width / 2; - const targetLeft = Math.max( - 0, - Math.min(nav.scrollWidth - nav.clientWidth, itemCenter - nav.clientWidth / 2), - ); - const reducedMotion = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches; - nav.scrollTo({ left: targetLeft, behavior: reducedMotion ? "auto" : "smooth" }); - }, [activeSection]); + const activeItem = SETTINGS_NAV_ITEMS.find((item) => item.key === activeSection) + ?? SETTINGS_NAV_ITEMS[0]; + const ActiveIcon = activeItem.icon; + const activeLabel = t(`settings.nav.${activeItem.key}`, { + defaultValue: activeItem.fallback, + }); return (