diff --git a/docs/src/content/registry.ts b/docs/src/content/registry.ts index 4311648..ad4ca2f 100644 --- a/docs/src/content/registry.ts +++ b/docs/src/content/registry.ts @@ -35,6 +35,14 @@ const packageDefinitions: readonly PackageDefinition[] = [ us: "Build an application shell and add navigation, notifications, chat, and appearance controls.", }, }, + { + key: "appearance", + label: "Appearance", + description: { + zh: "使用原子化控件、主题词典和可组合偏好副作用构建应用外观设置。", + us: "Build application appearance settings with atomic controls, theme tokens, and composable preference effects.", + }, + }, { key: "i18n", label: "I18n", diff --git a/packages/appearance/docs/en-US/advanced/atomic-composition.mdx b/packages/appearance/docs/en-US/advanced/atomic-composition.mdx new file mode 100644 index 0000000..7b508e5 --- /dev/null +++ b/packages/appearance/docs/en-US/advanced/atomic-composition.mdx @@ -0,0 +1,41 @@ +--- +title: Atomic composition +description: Build a custom appearance surface from controlled components without the preset dialog. +order: 1 +toc: + - id: controlled-atoms + title: Controlled atoms + - id: compose-card + title: Compose a theme card + - id: connected-layer + title: State bindings +--- + +## Controlled atoms {#controlled-atoms} + +`ThemeModeField`, `CompactLayoutField`, `ThemeColorPicker`, and `ThemeToggle` are driven by values and callbacks. They do not require preference context, so they can work with forms, preview tools, or another state library. + +```tsx + + +``` + +## Compose a theme card {#compose-card} + +`ThemeConfigCard` combines a preview with base and accent color controls while keeping the configuration owned by the caller. + +```tsx + +``` + +For a more granular layout, compose `ThemePreview`, `baseColorSwatches`, `accentColorSwatches`, and `ThemeColorSwatchButton` directly. + +## State bindings {#connected-layer} + +`AppearanceSettings` is the default binding layer between the atoms and the shared `PreferencesProvider`. A custom surface can call `usePreference` from `@workspace/preferences` for individual values without reusing the default layout. diff --git a/packages/appearance/docs/en-US/examples/settings-dialog.mdx b/packages/appearance/docs/en-US/examples/settings-dialog.mdx new file mode 100644 index 0000000..8c19e62 --- /dev/null +++ b/packages/appearance/docs/en-US/examples/settings-dialog.mdx @@ -0,0 +1,49 @@ +--- +title: Appearance settings dialog +description: Compose a trigger, controller, and hotkeys into a complete appearance settings flow. +order: 1 +toc: + - id: controller + title: Mount the controller + - id: trigger + title: Add a trigger + - id: custom-handle + title: Independent dialog instance +--- + +## Mount the controller {#controller} + +Mount one `AppearanceController` inside the application's shared `PreferencesProvider`. It composes the default settings content and registers `Mod+,` to open the dialog and `Mod+D` to toggle the theme. + +```tsx + + + + +``` + +## Add a trigger {#trigger} + +Place `AppearanceDialogTrigger` in a user menu, settings button, or command palette. By default it connects to the handle used by the default controller. + +```tsx +}> + Appearance + +``` + +## Independent dialog instance {#custom-handle} + +When a page needs an isolated appearance dialog, pass the same new handle to its trigger and controller. + +```tsx +const handle = createAppearanceDialogHandle() + +}> + Open theme settings + + +``` diff --git a/packages/appearance/docs/en-US/guide/setup.mdx b/packages/appearance/docs/en-US/guide/setup.mdx new file mode 100644 index 0000000..38088c5 --- /dev/null +++ b/packages/appearance/docs/en-US/guide/setup.mdx @@ -0,0 +1,89 @@ +--- +title: Set up appearance preferences +description: Aggregate appearance definitions and effects with the application's shared preferences. +order: 1 +toc: + - id: provider + title: Aggregate preferences + - id: effects + title: Register effects + - id: theme-style + title: Inject theme variables + - id: persistence + title: Persist updates +--- + +## Aggregate preferences {#provider} + +Build one complete preference definition map at the application boundary. Spread definitions from appearance, locale, keyboard, and other feature packages into this map, then create or load the initial values. + +```tsx +import { + createDefaultPreferences, + PreferencesProvider, +} from "@workspace/preferences" +import { + appearancePreferenceDefinitions, + appearancePreferenceEffect, +} from "@workspace/appearance" + +const preferenceDefinitions = { + ...appearancePreferenceDefinitions, + ...localePreferenceDefinitions, +} + +const initialPreferences = createDefaultPreferences(preferenceDefinitions) +const preferenceEffects = [ + appearancePreferenceEffect, + localePreferenceEffect, +] as const + +export function Root({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} +``` + +`defaultAppearancePreferences` remains available when only the appearance slice is needed, but the definition map is the preferred source when several packages are combined. + +## Register effects {#effects} + +`appearancePreferenceEffect` combines two exported callbacks: `applyAppearancePreferenceEffect` updates document classes and theme variables before paint, while `subscribeSystemThemePreferenceEffect` watches the operating-system theme after paint. Register the composed effect in the stable `effects` array passed to `PreferencesProvider`. + +## Inject theme variables {#theme-style} + +Use `buildThemeStyleSheet` to generate the CSS variables for light, dark, and system modes. Keep the stable element ID so the appearance effect can update the same node when color preferences change. + +```tsx +import { + buildThemeStyleSheet, + THEME_STYLE_ELEMENT_ID, +} from "@workspace/appearance" + +;