From a87041c9f62554ae71345e6c1ca1ae47aa289752 Mon Sep 17 00:00:00 2001 From: wgqqqqq Date: Fri, 4 Sep 2026 17:50:11 +0800 Subject: [PATCH 1/3] refactor(mobile-web): adopt shared mobile component system --- design-system/apps/design-lab/src/App.tsx | 53 +- .../design-lab/src/i18n/componentMetadata.ts | 24 + .../apps/design-lab/src/i18n/messages.ts | 99 + design-system/apps/design-lab/src/main.tsx | 1 + .../src/pages/ComponentDetailPage.tsx | 267 ++ .../design-lab/src/pages/ComponentsPage.tsx | 143 +- .../design-lab/vite/icon-consumers.test.mjs | 28 +- design-system/packages/ui/README.md | 40 + design-system/packages/ui/package.json | 7 +- design-system/packages/ui/src/mobile.ts | 112 + .../MobileActionSheet.meta.ts | 18 + .../MobileActionSheet.module.css | 13 + .../MobileActionSheet/MobileActionSheet.tsx | 71 + .../ui/src/mobile/MobileActionSheet/index.ts | 5 + .../mobile/MobileBadge/MobileBadge.meta.ts | 2 + .../mobile/MobileBadge/MobileBadge.module.css | 8 + .../ui/src/mobile/MobileBadge/MobileBadge.tsx | 8 + .../ui/src/mobile/MobileBadge/index.ts | 1 + .../mobile/MobileBanner/MobileBanner.meta.ts | 2 + .../MobileBanner/MobileBanner.module.css | 9 + .../src/mobile/MobileBanner/MobileBanner.tsx | 8 + .../ui/src/mobile/MobileBanner/index.ts | 1 + .../mobile/MobileButton/MobileButton.meta.ts | 16 + .../MobileButton/MobileButton.module.css | 48 + .../src/mobile/MobileButton/MobileButton.tsx | 56 + .../ui/src/mobile/MobileButton/index.ts | 1 + .../src/mobile/MobileCard/MobileCard.meta.ts | 2 + .../mobile/MobileCard/MobileCard.module.css | 10 + .../ui/src/mobile/MobileCard/MobileCard.tsx | 15 + .../ui/src/mobile/MobileCard/index.ts | 1 + .../MobileChoiceSheet.meta.ts | 25 + .../MobileChoiceSheet.module.css | 23 + .../MobileChoiceSheet/MobileChoiceSheet.tsx | 81 + .../ui/src/mobile/MobileChoiceSheet/index.ts | 5 + .../MobileComposer/MobileComposer.meta.ts | 28 + .../MobileComposer/MobileComposer.module.css | 150 + .../mobile/MobileComposer/MobileComposer.tsx | 79 + .../ui/src/mobile/MobileComposer/index.ts | 4 + .../MobileConfirmSheet.meta.ts | 26 + .../MobileConfirmSheet.module.css | 30 + .../MobileConfirmSheet/MobileConfirmSheet.tsx | 72 + .../ui/src/mobile/MobileConfirmSheet/index.ts | 4 + .../MobileDisclosure/MobileDisclosure.meta.ts | 2 + .../MobileDisclosure.module.css | 13 + .../MobileDisclosure/MobileDisclosure.tsx | 7 + .../ui/src/mobile/MobileDisclosure/index.ts | 1 + .../MobileFileButton/MobileFileButton.meta.ts | 2 + .../MobileFileButton.module.css | 11 + .../MobileFileButton/MobileFileButton.tsx | 48 + .../ui/src/mobile/MobileFileButton/index.ts | 1 + .../MobileFloatingActions.meta.ts | 14 + .../MobileFloatingActions.module.css | 38 + .../MobileFloatingActions.tsx | 29 + .../src/mobile/MobileFloatingActions/index.ts | 4 + .../MobileIconButton/MobileIconButton.meta.ts | 33 + .../MobileIconButton.module.css | 123 + .../MobileIconButton/MobileIconButton.tsx | 58 + .../ui/src/mobile/MobileIconButton/index.ts | 6 + .../src/mobile/MobileLink/MobileLink.meta.ts | 22 + .../mobile/MobileLink/MobileLink.module.css | 42 + .../ui/src/mobile/MobileLink/MobileLink.tsx | 23 + .../ui/src/mobile/MobileLink/index.ts | 5 + .../MobileListRow/MobileListRow.meta.ts | 40 + .../MobileListRow/MobileListRow.module.css | 117 + .../mobile/MobileListRow/MobileListRow.tsx | 68 + .../ui/src/mobile/MobileListRow/index.ts | 6 + .../MobileMessage/MobileMessage.meta.ts | 2 + .../MobileMessage/MobileMessage.module.css | 8 + .../mobile/MobileMessage/MobileMessage.tsx | 8 + .../ui/src/mobile/MobileMessage/index.ts | 1 + .../MobilePageHeader/MobilePageHeader.meta.ts | 2 + .../MobilePageHeader.module.css | 10 + .../MobilePageHeader/MobilePageHeader.tsx | 24 + .../ui/src/mobile/MobilePageHeader/index.ts | 1 + .../mobile/MobileScrim/MobileScrim.meta.ts | 2 + .../mobile/MobileScrim/MobileScrim.module.css | 6 + .../ui/src/mobile/MobileScrim/MobileScrim.tsx | 23 + .../ui/src/mobile/MobileScrim/index.ts | 1 + .../MobileSection/MobileSection.meta.ts | 2 + .../MobileSection/MobileSection.module.css | 8 + .../mobile/MobileSection/MobileSection.tsx | 7 + .../ui/src/mobile/MobileSection/index.ts | 1 + .../MobileSegmentedControl.meta.ts | 2 + .../MobileSegmentedControl.module.css | 9 + .../MobileSegmentedControl.tsx | 8 + .../mobile/MobileSegmentedControl/index.ts | 1 + .../mobile/MobileSheet/MobileSheet.meta.ts | 30 + .../mobile/MobileSheet/MobileSheet.module.css | 139 + .../ui/src/mobile/MobileSheet/MobileSheet.tsx | 148 + .../ui/src/mobile/MobileSheet/index.ts | 5 + .../mobile/MobileStatus/MobileStatus.meta.ts | 2 + .../MobileStatus/MobileStatus.module.css | 13 + .../src/mobile/MobileStatus/MobileStatus.tsx | 8 + .../ui/src/mobile/MobileStatus/index.ts | 1 + .../MobileTextField/MobileTextField.meta.ts | 33 + .../MobileTextField.module.css | 89 + .../MobileTextField/MobileTextField.tsx | 64 + .../ui/src/mobile/MobileTextField/index.ts | 5 + .../MobileTextarea/MobileTextarea.meta.ts | 2 + .../MobileTextarea/MobileTextarea.module.css | 9 + .../mobile/MobileTextarea/MobileTextarea.tsx | 40 + .../ui/src/mobile/MobileTextarea/index.ts | 1 + design-system/packages/ui/src/registry.ts | 46 + .../packages/ui/src/registry.types.ts | 2 +- .../packages/ui/tests/mobile.test.mjs | 145 + .../packages/ui/tests/registry.test.mjs | 23 + design-system/packages/ui/tsconfig.build.json | 2 +- .../packages/ui/vite.mobile.config.ts | 28 + pnpm-lock.yaml | 3 + src/mobile-web/package.json | 4 +- src/mobile-web/src/App.tsx | 17 +- .../src/components/ChatAskQuestionCard.tsx | 188 ++ .../src/components/ChatComposerBar.tsx | 167 + .../src/components/ChatFeedback.tsx | 20 + src/mobile-web/src/components/ChatHeader.tsx | 129 + .../src/components/ChatMarkdown.tsx | 515 ++++ .../src/components/ChatMessageActions.tsx | 42 + .../src/components/ChatModelControls.tsx | 459 +++ .../src/components/ChatTranscript.tsx | 1192 +++++++ .../src/components/CompactSettingsSheet.tsx | 134 + .../src/components/ErrorBoundary.tsx | 42 +- .../src/components/HarnessProfilePicker.tsx | 77 +- .../src/components/LanguageToggleButton.tsx | 7 +- src/mobile-web/src/components/PairingForm.tsx | 188 ++ .../src/components/QrScannerSheet.tsx | 54 +- .../src/components/RemoteHomePanel.tsx | 32 +- .../components/SessionDashboardSections.tsx | 204 ++ .../src/components/SessionOverlays.tsx | 197 ++ src/mobile-web/src/i18n/messages.ts | 3 + src/mobile-web/src/main.tsx | 1 + src/mobile-web/src/pages/ChatPage.tsx | 2742 +---------------- src/mobile-web/src/pages/DevicesPage.tsx | 95 +- src/mobile-web/src/pages/PairingPage.tsx | 252 +- src/mobile-web/src/pages/SessionListPage.tsx | 1007 ++---- src/mobile-web/src/pages/WorkspacePage.tsx | 57 +- .../src/services/CloudAccountSessionStore.ts | 130 + .../src/services/RelayHttpClient.ts | 12 +- .../src/services/RemoteSessionManager.ts | 21 +- .../src/styles/components/adaptive-shell.scss | 44 +- .../src/styles/components/chat-input.scss | 83 - .../src/styles/components/chat.scss | 113 - .../src/styles/components/devices.scss | 67 - .../src/styles/components/harmony-native.scss | 131 +- .../src/styles/components/sessions.scss | 181 -- .../src/styles/components/workspace.scss | 25 - .../tests/mobile-ui-components.test.mjs | 123 + .../MobileChatSettings.contract.test.ts | 49 + .../MobileTargetOwner.contract.test.ts | 79 + .../RemoteSessionManager.routing.test.ts | 26 + 149 files changed, 7784 insertions(+), 4398 deletions(-) create mode 100644 design-system/packages/ui/src/mobile.ts create mode 100644 design-system/packages/ui/src/mobile/MobileActionSheet/MobileActionSheet.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileActionSheet/MobileActionSheet.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileActionSheet/MobileActionSheet.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileActionSheet/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileBadge/MobileBadge.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileBadge/MobileBadge.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileBadge/MobileBadge.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileBadge/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileBanner/MobileBanner.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileBanner/MobileBanner.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileBanner/MobileBanner.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileBanner/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileButton/MobileButton.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileButton/MobileButton.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileButton/MobileButton.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileButton/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileCard/MobileCard.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileCard/MobileCard.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileCard/MobileCard.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileCard/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileChoiceSheet/MobileChoiceSheet.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileChoiceSheet/MobileChoiceSheet.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileChoiceSheet/MobileChoiceSheet.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileChoiceSheet/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileComposer/MobileComposer.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileComposer/MobileComposer.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileComposer/MobileComposer.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileComposer/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileConfirmSheet/MobileConfirmSheet.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileConfirmSheet/MobileConfirmSheet.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileConfirmSheet/MobileConfirmSheet.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileConfirmSheet/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileDisclosure/MobileDisclosure.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileDisclosure/MobileDisclosure.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileDisclosure/MobileDisclosure.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileDisclosure/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileFileButton/MobileFileButton.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileFileButton/MobileFileButton.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileFileButton/MobileFileButton.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileFileButton/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileFloatingActions/MobileFloatingActions.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileFloatingActions/MobileFloatingActions.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileFloatingActions/MobileFloatingActions.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileFloatingActions/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileIconButton/MobileIconButton.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileIconButton/MobileIconButton.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileIconButton/MobileIconButton.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileIconButton/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileLink/MobileLink.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileLink/MobileLink.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileLink/MobileLink.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileLink/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileListRow/MobileListRow.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileListRow/MobileListRow.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileListRow/MobileListRow.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileListRow/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileMessage/MobileMessage.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileMessage/MobileMessage.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileMessage/MobileMessage.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileMessage/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobilePageHeader/MobilePageHeader.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobilePageHeader/MobilePageHeader.module.css create mode 100644 design-system/packages/ui/src/mobile/MobilePageHeader/MobilePageHeader.tsx create mode 100644 design-system/packages/ui/src/mobile/MobilePageHeader/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileScrim/MobileScrim.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileScrim/MobileScrim.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileScrim/MobileScrim.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileScrim/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileSection/MobileSection.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileSection/MobileSection.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileSection/MobileSection.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileSection/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileSegmentedControl/MobileSegmentedControl.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileSegmentedControl/MobileSegmentedControl.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileSegmentedControl/MobileSegmentedControl.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileSegmentedControl/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileSheet/MobileSheet.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileSheet/MobileSheet.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileSheet/MobileSheet.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileSheet/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileStatus/MobileStatus.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileStatus/MobileStatus.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileStatus/MobileStatus.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileStatus/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileTextField/MobileTextField.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileTextField/MobileTextField.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileTextField/MobileTextField.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileTextField/index.ts create mode 100644 design-system/packages/ui/src/mobile/MobileTextarea/MobileTextarea.meta.ts create mode 100644 design-system/packages/ui/src/mobile/MobileTextarea/MobileTextarea.module.css create mode 100644 design-system/packages/ui/src/mobile/MobileTextarea/MobileTextarea.tsx create mode 100644 design-system/packages/ui/src/mobile/MobileTextarea/index.ts create mode 100644 design-system/packages/ui/tests/mobile.test.mjs create mode 100644 design-system/packages/ui/vite.mobile.config.ts create mode 100644 src/mobile-web/src/components/ChatAskQuestionCard.tsx create mode 100644 src/mobile-web/src/components/ChatComposerBar.tsx create mode 100644 src/mobile-web/src/components/ChatFeedback.tsx create mode 100644 src/mobile-web/src/components/ChatHeader.tsx create mode 100644 src/mobile-web/src/components/ChatMarkdown.tsx create mode 100644 src/mobile-web/src/components/ChatMessageActions.tsx create mode 100644 src/mobile-web/src/components/ChatModelControls.tsx create mode 100644 src/mobile-web/src/components/ChatTranscript.tsx create mode 100644 src/mobile-web/src/components/CompactSettingsSheet.tsx create mode 100644 src/mobile-web/src/components/PairingForm.tsx create mode 100644 src/mobile-web/src/components/SessionDashboardSections.tsx create mode 100644 src/mobile-web/src/components/SessionOverlays.tsx create mode 100644 src/mobile-web/src/services/CloudAccountSessionStore.ts create mode 100644 src/mobile-web/tests/mobile-ui-components.test.mjs create mode 100644 src/web-ui/src/app/components/RemoteConnectDialog/MobileChatSettings.contract.test.ts diff --git a/design-system/apps/design-lab/src/App.tsx b/design-system/apps/design-lab/src/App.tsx index 91704fbeec..b0a5aab431 100644 --- a/design-system/apps/design-lab/src/App.tsx +++ b/design-system/apps/design-lab/src/App.tsx @@ -6,7 +6,7 @@ import { } from "react"; import type { SystemTokenMode } from "@bitfun/design-tokens"; import type { ThemeDataName } from "@bitfun/theme-bitfun"; -import { AppWindow, Blocks, BookOpen, Braces, CircleDashed, FileText, House, Languages, Menu, Moon, MousePointerClick, PanelTop, PanelsTopLeft, SquareTerminal, Sun, ToggleLeft, type LucideIcon } from "lucide-react"; +import { AppWindow, Blocks, BookOpen, Braces, CircleDashed, FileText, House, Languages, Menu, Moon, MousePointerClick, PanelTop, PanelsTopLeft, Smartphone, SquareTerminal, Sun, ToggleLeft, type LucideIcon } from "lucide-react"; import { Icon as CatalogIcon, ThemeRoot, type ColorScheme, @@ -53,6 +53,7 @@ type LabRoute = | { page: "overview" } | { page: "getting-started" } | { page: "components" } + | { page: "mobile" } | { page: "patterns" } | { page: "flow-chat" } | { page: "colors" } @@ -84,8 +85,13 @@ const componentIcons: Record = { const flowChatComponents = componentRegistry.filter( (component) => component.category === "flow-chat", ); +const mobileComponents = componentRegistry.filter( + (component) => component.category === "mobile", +); const standardComponents = componentRegistry.filter( - (component) => component.category !== "flow-chat" && component.name !== "Icon", + (component) => component.category !== "flow-chat" + && component.category !== "mobile" + && component.name !== "Icon", ); function getComponentNavGroup(route: LabRoute): ComponentNavGroup | undefined { @@ -138,6 +144,9 @@ function parseRoute(hash: string): LabRoute { if (route === "components") { return { page: "components" }; } + if (route === "mobile") { + return { page: "mobile" }; + } if (route === "patterns") { return { page: "patterns" }; } @@ -234,6 +243,13 @@ export function App() { label: t("nav.components"), route: { page: "components" }, }, + { + detail: t("search.mobileDetail", { count: mobileComponents.length }), + icon: Smartphone, + keywords: `mobile touch phone foldable ${t("nav.mobile")}`, + label: t("nav.mobile"), + route: { page: "mobile" }, + }, { detail: t("search.patternsDetail"), icon: PanelsTopLeft, @@ -398,8 +414,13 @@ export function App() { const isFlowChatRoute = route.page === "flow-chat" || activeComponent?.category === "flow-chat"; const isIconRoute = activeComponent?.name === "Icon"; + const isMobileRoute = route.page === "mobile" + || activeComponent?.category === "mobile"; const isStandardComponentRoute = route.page === "components" - || Boolean(activeComponent && activeComponent.category !== "flow-chat" && !isIconRoute); + || Boolean(activeComponent + && activeComponent.category !== "flow-chat" + && activeComponent.category !== "mobile" + && !isIconRoute); return ( + { + event.preventDefault(); + navigate({ page: "mobile" }); + }} + > + )} + {route.page === "mobile" && ( + openTokenPage()} + onOpenComponent={(name) => navigate({ componentName: name, page: "component" })} + tokenOverrides={tokenOverrides} + /> + )} + {route.page === "patterns" && ( navigate({ page: activeComponent.category === "flow-chat" ? "flow-chat" + : activeComponent.category === "mobile" + ? "mobile" : "components", })} onInspectTokens={openTokenPage} diff --git a/design-system/apps/design-lab/src/i18n/componentMetadata.ts b/design-system/apps/design-lab/src/i18n/componentMetadata.ts index 819b4059f8..f5145ec5fd 100644 --- a/design-system/apps/design-lab/src/i18n/componentMetadata.ts +++ b/design-system/apps/design-lab/src/i18n/componentMetadata.ts @@ -9,6 +9,7 @@ const categoryKeys: Readonly> = { "flow-chat": "meta.category.flowChat", form: "meta.category.form", navigation: "meta.category.navigation", + mobile: "meta.category.mobile", primitive: "meta.category.primitive", }; @@ -42,6 +43,29 @@ const descriptionKeys: Readonly> = { LauncherButton: "component.LauncherButton.description", LoadingState: "component.LoadingState.description", Menu: "component.Menu.description", + MobileActionSheet: "component.MobileActionSheet.description", + MobileBadge: "component.MobileBadge.description", + MobileBanner: "component.MobileBanner.description", + MobileButton: "component.MobileButton.description", + MobileCard: "component.MobileCard.description", + MobileChoiceSheet: "component.MobileChoiceSheet.description", + MobileConfirmSheet: "component.MobileConfirmSheet.description", + MobileComposer: "component.MobileComposer.description", + MobileDisclosure: "component.MobileDisclosure.description", + MobileFileButton: "component.MobileFileButton.description", + MobileFloatingActions: "component.MobileFloatingActions.description", + MobileIconButton: "component.MobileIconButton.description", + MobileLink: "component.MobileLink.description", + MobileListRow: "component.MobileListRow.description", + MobileMessage: "component.MobileMessage.description", + MobilePageHeader: "component.MobilePageHeader.description", + MobileScrim: "component.MobileScrim.description", + MobileSection: "component.MobileSection.description", + MobileSegmentedControl: "component.MobileSegmentedControl.description", + MobileSheet: "component.MobileSheet.description", + MobileStatus: "component.MobileStatus.description", + MobileTextField: "component.MobileTextField.description", + MobileTextarea: "component.MobileTextarea.description", Dialog: "component.Dialog.description", Sheet: "component.Sheet.description", NavigationPanel: "component.NavigationPanel.description", diff --git a/design-system/apps/design-lab/src/i18n/messages.ts b/design-system/apps/design-lab/src/i18n/messages.ts index f45bf47a63..affe2484bc 100644 --- a/design-system/apps/design-lab/src/i18n/messages.ts +++ b/design-system/apps/design-lab/src/i18n/messages.ts @@ -13,6 +13,7 @@ export const enUSMessages = { "nav.colors": "Colors", "nav.library": "Library", "nav.components": "Components", + "nav.mobile": "Mobile", "nav.patterns": "Patterns", "nav.flowChat": "FlowChat", "nav.docs": "Docs", @@ -25,6 +26,7 @@ export const enUSMessages = { "search.tokensDetail": "{count} editable contracts", "search.colorsDetail": "{count} semantic color tokens and real reference scales", "search.componentsDetail": "{count} registered components", + "search.mobileDetail": "{count} touch-first mobile components", "search.patternsDetail": "Reference compositions assembled from public components", "search.flowChatDetail": "{count} shared templates and standard tool-card specimens", "search.resourcesDetail": "Package documentation and release policy", @@ -52,9 +54,33 @@ export const enUSMessages = { "meta.category.feedback": "Feedback", "meta.category.flowChat": "Flow Chat", "meta.category.navigation": "Navigation", + "meta.category.mobile": "Mobile", "meta.category.primitive": "Primitive", "meta.category.other": "Component", "component.ActionCard.description": "An actionable card with independent leading, title, description, selection, and sibling action areas.", + "component.MobileActionSheet.description": "A dismissible mobile sheet for consistent neutral and destructive action lists.", + "component.MobileBadge.description": "A compact mobile label for status, identity, and metadata.", + "component.MobileBanner.description": "An inline mobile status banner with semantic tone and an optional action.", + "component.MobileButton.description": "A touch-sized mobile text button with semantic appearances and loading state.", + "component.MobileCard.description": "A responsive mobile content surface with optional elevation and density.", + "component.MobileChoiceSheet.description": "A responsive bottom-sheet selector for short, mutually exclusive mobile choices.", + "component.MobileConfirmSheet.description": "A mobile confirmation sheet with consistent pending and destructive behavior.", + "component.MobileComposer.description": "A compact-to-expanded mobile composer with semantic editor and action slots.", + "component.MobileDisclosure.description": "A compact disclosure row for thinking, tool groups, and advanced options.", + "component.MobileFileButton.description": "An accessible touch-sized file picker presented as a mobile action button.", + "component.MobileFloatingActions.description": "A transparent floating action row that does not cover scrolling content with an opaque bar.", + "component.MobileIconButton.description": "A touch-first icon button with mobile sizing and surface elevation.", + "component.MobileLink.description": "A touch-aware mobile link with consistent inline and surfaced focus treatment.", + "component.MobileListRow.description": "A responsive touch row for mobile navigation and selection lists.", + "component.MobileMessage.description": "A responsive chat message shell for user, assistant, and system content.", + "component.MobilePageHeader.description": "A responsive mobile page header with balanced leading and trailing actions.", + "component.MobileScrim.description": "A dismissible mobile overlay scrim with consistent focus and motion behavior.", + "component.MobileSection.description": "A mobile content section with optional heading, description, and action.", + "component.MobileSegmentedControl.description": "A touch-first segmented selector for compact mode and filter choices.", + "component.MobileSheet.description": "A safe-area-aware bottom sheet with shared dismissal, focus, and scroll locking.", + "component.MobileStatus.description": "A consistent mobile loading, empty, or error state with optional recovery action.", + "component.MobileTextField.description": "A mobile text field with touch geometry and optional content slots.", + "component.MobileTextarea.description": "A touch-friendly multiline field for expanded mobile composition and forms.", "component.ActionItem.description": "A native button row with independent leading, shortcut, and sibling action areas.", "component.ActivityItem.description": "A compact activity row with independent identity, description, metadata, and sibling action areas.", "component.AgentControlToolCard.description": "A prominent subagent card with an openable identity, lifecycle state, and expandable prompt.", @@ -310,6 +336,10 @@ export const enUSMessages = { "components.preview.close": "Close", "components.preview.openDialog": "Open dialog", "components.preview.modalInteractionDemo": "Open interaction demo", + "components.preview.selectExecutionMode": "Select execution mode", + "components.preview.modeMinimal": "Minimal", + "components.preview.modeStandard": "Standard", + "components.preview.modeUltimate": "Ultimate", "components.preview.modalTitle": "Edit provider configuration", "components.preview.modalDescription": "Update the connection settings for this provider.", "components.preview.modalSectionTitle": "Basic provider parameters", @@ -378,6 +408,9 @@ export const enUSMessages = { "components.kicker": "Library", "components.title": "Components", "components.description": "Production package exports, rendered against the active theme and density contract.", + "components.mobile.kicker": "Touch-first library", + "components.mobile.title": "Mobile components", + "components.mobile.description": "Responsive controls for phone, narrow-window, and foldable layouts, published through the isolated mobile entry.", "components.flowChat.kicker": "FlowChat library", "components.flowChat.title": "FlowChat", "components.flowChat.description": "Shared attention-based card frameworks and standard tool-card specimens built from those public contracts.", @@ -716,6 +749,7 @@ export const zhCNMessages = { "nav.colors": "Colors", "nav.library": "组件库", "nav.components": "组件", + "nav.mobile": "移动端", "nav.patterns": "模式", "nav.flowChat": "FlowChat", "nav.docs": "文档", @@ -728,6 +762,7 @@ export const zhCNMessages = { "search.tokensDetail": "{count} 个可编辑契约", "search.colorsDetail": "{count} 个语义颜色 Token 与真实基础色阶", "search.componentsDetail": "{count} 个已注册组件", + "search.mobileDetail": "{count} 个触控优先的移动端组件", "search.patternsDetail": "由公开组件组合而成的参考界面模式", "search.flowChatDetail": "{count} 个通用模板及标准工具卡片样例", "search.resourcesDetail": "包文档与发布策略", @@ -755,9 +790,33 @@ export const zhCNMessages = { "meta.category.feedback": "反馈", "meta.category.flowChat": "FlowChat", "meta.category.navigation": "导航", + "meta.category.mobile": "移动端", "meta.category.primitive": "基础组件", "meta.category.other": "组件", "component.ActionCard.description": "可独立配置前置内容、标题、说明、选中状态和同级尾部操作的可交互卡片。", + "component.MobileActionSheet.description": "用于统一呈现普通和危险操作列表的可关闭移动端弹层。", + "component.MobileBadge.description": "用于状态、身份与元数据的紧凑移动端标签。", + "component.MobileBanner.description": "支持语义色调和可选操作的移动端行内状态横幅。", + "component.MobileButton.description": "具备触控尺寸、语义外观和加载状态的移动端文字按钮。", + "component.MobileCard.description": "支持不同层级与密度的响应式移动端内容表面。", + "component.MobileChoiceSheet.description": "用于少量互斥选项、具备响应式布局的移动端底部选择弹层。", + "component.MobileConfirmSheet.description": "统一处理等待态与危险操作的移动端确认弹层。", + "component.MobileComposer.description": "可在紧凑态与展开态之间切换,并提供语义化编辑区和操作插槽的移动端输入容器。", + "component.MobileDisclosure.description": "用于思考过程、工具分组和高级选项的紧凑展开控件。", + "component.MobileFileButton.description": "以移动端操作按钮呈现、具备无障碍支持和触控尺寸的文件选择器。", + "component.MobileFloatingActions.description": "不会用不透明底栏遮挡滚动内容的透明悬浮操作区。", + "component.MobileIconButton.description": "具备移动端触控尺寸和表面阴影的图标按钮。", + "component.MobileLink.description": "具备统一行内、表面样式和焦点反馈的移动端链接。", + "component.MobileListRow.description": "用于移动端导航和选择列表的响应式触控行。", + "component.MobileMessage.description": "用于用户、助手和系统内容的响应式聊天消息容器。", + "component.MobilePageHeader.description": "左右操作区保持平衡的响应式移动端页面头部。", + "component.MobileScrim.description": "具备一致焦点和动效行为、可点击关闭的移动端遮罩。", + "component.MobileSection.description": "带可选标题、说明和操作区的移动端内容分组。", + "component.MobileSegmentedControl.description": "用于紧凑模式和筛选选择的移动端分段控件。", + "component.MobileSheet.description": "适配安全区并统一关闭、焦点与滚动锁定行为的底部弹层。", + "component.MobileStatus.description": "统一呈现加载、空状态和错误恢复操作的移动端状态组件。", + "component.MobileTextField.description": "具备触控几何与可选内容插槽的移动端文本框。", + "component.MobileTextarea.description": "用于展开态输入和表单的触控友好多行文本框。", "component.ActionItem.description": "使用原生按钮语义,并拆分前置、快捷键与同级尾部操作区域的行项目。", "component.ActivityItem.description": "紧凑的活动行,可独立配置标识、描述、统计信息和同级尾部操作。", "component.AgentControlToolCard.description": "关注型子 Agent 卡片,统一呈现可打开的身份、生命周期状态和可展开提示词。", @@ -1013,6 +1072,10 @@ export const zhCNMessages = { "components.preview.close": "关闭", "components.preview.openDialog": "打开对话框", "components.preview.modalInteractionDemo": "打开交互演示", + "components.preview.selectExecutionMode": "选择执行模式", + "components.preview.modeMinimal": "极简", + "components.preview.modeStandard": "标准", + "components.preview.modeUltimate": "极致", "components.preview.modalTitle": "编辑服务商配置", "components.preview.modalDescription": "更新此服务商的连接设置。", "components.preview.modalSectionTitle": "基础服务商参数", @@ -1081,6 +1144,9 @@ export const zhCNMessages = { "components.kicker": "组件库", "components.title": "组件", "components.description": "真实的生产包导出,并使用当前主题与密度契约渲染。", + "components.mobile.kicker": "触控优先组件库", + "components.mobile.title": "移动端组件", + "components.mobile.description": "通过独立移动端入口发布,适配手机、窄窗口与折叠屏布局的响应式控件。", "components.flowChat.kicker": "FlowChat 组件库", "components.flowChat.title": "FlowChat", "components.flowChat.description": "以用户关注程度组织的通用卡片框架,以及基于这些公共契约构建的标准工具卡片样例。", @@ -1460,6 +1526,7 @@ export const zhTWMessages = { "nav.colors": "Colors", "nav.library": "元件庫", "nav.components": "元件", + "nav.mobile": "移動端", "nav.flowChat": "FlowChat", "nav.docs": "文件", "nav.resources": "資源", @@ -1471,6 +1538,7 @@ export const zhTWMessages = { "search.tokensDetail": "{count} 個可編輯契約", "search.colorsDetail": "{count} 個語意顏色 Token 與真實基礎色階", "search.componentsDetail": "{count} 個已註冊元件", + "search.mobileDetail": "{count} 個觸控優先的移動端元件", "search.flowChatDetail": "{count} 個通用模板及標準工具卡片範例", "search.resourcesDetail": "套件文件與發佈策略", "theme.switchToDark": "切換至深色模式", @@ -1496,9 +1564,33 @@ export const zhTWMessages = { "meta.category.feedback": "回饋", "meta.category.flowChat": "FlowChat", "meta.category.navigation": "導覽", + "meta.category.mobile": "移動端", "meta.category.primitive": "基礎元件", "meta.category.other": "元件", "component.ActionCard.description": "可獨立設定前置內容、標題、說明、選取狀態和同級尾端操作的可互動卡片。", + "component.MobileActionSheet.description": "用於統一呈現一般和危險操作清單的可關閉行動端彈層。", + "component.MobileBadge.description": "用於狀態、身分與中繼資料的緊湊行動端標籤。", + "component.MobileBanner.description": "支援語義色調和可選操作的行動端行內狀態橫幅。", + "component.MobileButton.description": "具備觸控尺寸、語義外觀和載入狀態的行動端文字按鈕。", + "component.MobileCard.description": "支援不同層級與密度的響應式行動端內容表面。", + "component.MobileChoiceSheet.description": "用於少量互斥選項、具備響應式佈局的行動端底部選擇彈層。", + "component.MobileConfirmSheet.description": "統一處理等待狀態與危險操作的行動端確認彈層。", + "component.MobileComposer.description": "可在緊湊態與展開態之間切換,並提供語義化編輯區和操作插槽的移動端輸入容器。", + "component.MobileDisclosure.description": "用於思考過程、工具分組和進階選項的緊湊展開控制項。", + "component.MobileFileButton.description": "以行動端操作按鈕呈現、具備無障礙支援和觸控尺寸的檔案選擇器。", + "component.MobileFloatingActions.description": "不會用不透明底欄遮擋捲動內容的透明懸浮操作區。", + "component.MobileIconButton.description": "具備移動端觸控尺寸和表面陰影的圖示按鈕。", + "component.MobileLink.description": "具備統一行內、表面樣式和焦點回饋的行動端連結。", + "component.MobileListRow.description": "用於移動端導覽和選擇清單的響應式觸控列。", + "component.MobileMessage.description": "用於使用者、助理和系統內容的響應式聊天訊息容器。", + "component.MobilePageHeader.description": "左右操作區保持平衡的響應式行動端頁面標頭。", + "component.MobileScrim.description": "具備一致焦點和動效行為、可點擊關閉的行動端遮罩。", + "component.MobileSection.description": "帶可選標題、說明和操作區的行動端內容分組。", + "component.MobileSegmentedControl.description": "用於緊湊模式和篩選選擇的行動端分段控制項。", + "component.MobileSheet.description": "適配安全區並統一關閉、焦點與捲動鎖定行為的底部彈層。", + "component.MobileStatus.description": "統一呈現載入、空狀態和錯誤恢復操作的行動端狀態元件。", + "component.MobileTextField.description": "具備觸控幾何與可選內容插槽的移動端文字欄位。", + "component.MobileTextarea.description": "用於展開態輸入和表單的觸控友好多行文字欄位。", "component.ActionItem.description": "使用原生按鈕語意,並拆分前置、快捷鍵與同級尾端操作區域的列項目。", "component.ActivityItem.description": "緊湊的活動列,可獨立設定標識、描述、統計資訊和同級尾端操作。", "component.AgentControlToolCard.description": "關注型子 Agent 卡片,統一呈現可開啟的身分、生命週期狀態和可展開提示詞。", @@ -1666,6 +1758,10 @@ export const zhTWMessages = { "components.preview.close": "關閉", "components.preview.openDialog": "開啟對話框", "components.preview.modalInteractionDemo": "開啟互動展示", + "components.preview.selectExecutionMode": "選擇執行模式", + "components.preview.modeMinimal": "極簡", + "components.preview.modeStandard": "標準", + "components.preview.modeUltimate": "極致", "components.preview.modalTitle": "編輯服務商設定", "components.preview.modalDescription": "更新此服務商的連線設定。", "components.preview.modalSectionTitle": "基礎服務商參數", @@ -1729,6 +1825,9 @@ export const zhTWMessages = { "components.kicker": "元件庫", "components.title": "元件", "components.description": "真實的正式套件匯出,並使用目前主題與密度契約呈現。", + "components.mobile.kicker": "觸控優先元件庫", + "components.mobile.title": "移動端元件", + "components.mobile.description": "透過獨立移動端入口發佈,適配手機、窄視窗與摺疊螢幕版面的響應式控制項。", "components.flowChat.kicker": "FlowChat 元件庫", "components.flowChat.title": "FlowChat", "components.flowChat.description": "依使用者關注程度組織的通用卡片框架,以及基於這些公開契約建構的標準工具卡片範例。", diff --git a/design-system/apps/design-lab/src/main.tsx b/design-system/apps/design-lab/src/main.tsx index 77fae83455..425d938331 100644 --- a/design-system/apps/design-lab/src/main.tsx +++ b/design-system/apps/design-lab/src/main.tsx @@ -2,6 +2,7 @@ import React from "react"; import ReactDOM from "react-dom/client"; import "@bitfun/theme-bitfun/default.css"; import "@bitfun/ui/styles.css"; +import "@bitfun/ui/mobile.css"; import { App } from "./App"; import { I18nProvider } from "./i18n"; import "./styles.css"; diff --git a/design-system/apps/design-lab/src/pages/ComponentDetailPage.tsx b/design-system/apps/design-lab/src/pages/ComponentDetailPage.tsx index ff889d1348..973c1aae97 100644 --- a/design-system/apps/design-lab/src/pages/ComponentDetailPage.tsx +++ b/design-system/apps/design-lab/src/pages/ComponentDetailPage.tsx @@ -93,6 +93,31 @@ import { type ToolbarSize, type TokenOverrides, } from "@bitfun/ui"; +import { + MobileActionSheet, + MobileBadge, + MobileBanner, + MobileButton, + MobileCard, + MobileChoiceSheet, + MobileConfirmSheet, + MobileComposer, + MobileDisclosure, + MobileFileButton, + MobileFloatingActions, + MobileIconButton, + MobileLink, + MobileListRow, + MobileMessage, + MobilePageHeader, + MobileScrim, + MobileSection, + MobileSegmentedControl, + MobileSheet, + MobileStatus, + MobileTextField, + MobileTextarea, +} from "@bitfun/ui/mobile"; import type { ComponentMeta } from "@bitfun/ui/registry"; import previewImage from "../assets/design-system-hero.webp"; import { IconCompositionPreview } from "../preview/IconCompositionPreview"; @@ -332,6 +357,7 @@ export function ComponentDetailPage({ const [copyStatus, setCopyStatus] = useState("idle"); const [inspectorTab, setInspectorTab] = useState("properties"); const [overlayOpen, setOverlayOpen] = useState(false); + const [mobileChoiceValue, setMobileChoiceValue] = useState("standard"); const [menuShowScrollbar, setMenuShowScrollbar] = useState(true); const [navigationPanelShowScrollbar, setNavigationPanelShowScrollbar] = useState(true); const [composerShowContext, setComposerShowContext] = useState(false); @@ -409,6 +435,18 @@ export function ComponentDetailPage({ : states; const codeSample = useMemo(() => { + if (component.name === "MobileActionSheet") return `import { MobileActionSheet } from "@bitfun/ui/mobile";\n\n setOpen(false)}\n open={open}\n title="${t("components.preview.session")}"\n/>`; + if (component.name === "MobileComposer") return `import { MobileComposer } from "@bitfun/ui/mobile";\n\n}\n startActions={}\n endActions={}\n>\n