From b9d1923f15b2d47cb9f6b2052b6404a361b22502 Mon Sep 17 00:00:00 2001 From: jackwener Date: Fri, 26 Jun 2026 02:43:48 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ui,settings):=20Round=20C=20=E2=80=94?= =?UTF-8?q?=20ChoiceCard=20primitive=20+=20Theme/Palette=20pickers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @WAWQAQ msg `4f598b19` 「没做完你就继续呀」 — finally takes the hand-rolled Theme/Palette native-button radiogroups off SettingsModal.tsx and onto a Base UI-backed primitive. **Why this was a contract-test-protected migration.** Commit b40d097 (WAWQAQ msg `5f75daf6`) once routed these cards through the shared ` + ))} - +

调色板

{/* PR-PALETTE-PICKER-GROUPS-0: 11 palettes in a flat grid is @@ -2835,41 +2827,27 @@ function ThemeSettingsPage(props: { {PALETTE_GROUPS.map((group) => (

{group.label}

-
onSettingsRadioGroupKeyDown( - event, - group.palettes, - currentPalette, - (next) => void setPalette(next), - )} + value={currentPalette} + onValueChange={(next) => void setPalette(next as ThemePalette)} > {group.palettes.map((palette) => ( - // Native + ))} -
+
))} diff --git a/apps/desktop/src/renderer/styles.css b/apps/desktop/src/renderer/styles.css index da2217c129..674d2c9c8d 100644 --- a/apps/desktop/src/renderer/styles.css +++ b/apps/desktop/src/renderer/styles.css @@ -8149,7 +8149,7 @@ button:active { background: var(--foreground-3); } -.settingsThemeOption[data-active="true"] { +.settingsThemeOption[data-checked] { border-color: oklch(from var(--accent) l c h / 0.45); background: oklch(from var(--accent) l c h / 0.06); } diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 9fe1ae951a..05059cde2f 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -34,6 +34,7 @@ export * from './primitives/kbd.js'; export * from './primitives/menu.js'; export * from './primitives/group.js'; export * from './primitives/frame.js'; +export * from './primitives/choice-card.js'; export * from './primitives/preview-card.js'; export * from './primitives/settings-select.js'; export * from './primitives/input-group.js'; diff --git a/packages/ui/src/primitives/choice-card.tsx b/packages/ui/src/primitives/choice-card.tsx new file mode 100644 index 0000000000..c7cf9c8343 --- /dev/null +++ b/packages/ui/src/primitives/choice-card.tsx @@ -0,0 +1,84 @@ +"use client"; + +import { Radio as BaseRadio } from "@base-ui/react/radio"; +import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group"; +import { forwardRef } from "react"; +import type { ComponentPropsWithoutRef, ReactNode } from "react"; +import { cn } from "../utils.js"; + +/** + * Card-style radio primitive for "pick one of N richly-laid-out options" + * surfaces — Settings → 外观 theme picker (3 vertically-stacked preview + * tiles), palette picker (round swatches + label), provider model + * "default" picker, etc. + * + * Why a separate primitive (not the existing dot-style `Radio`): + * - Each card has rich body content (preview mocks, swatches, + * descriptions). It needs to be the FULL clickable target, not a + * small leading indicator. + * - Earlier attempts to route the card through the shared `Button` + * primitive baked in `h-9 inline-flex bg-primary text-white` + * utilities that collapsed each card to a 36px black pill (WAWQAQ + * msg `5f75daf6`, reverted in commit b40d097). The contract test + * locked the regression by pinning native `