feat(appearance): add composable theme package

This commit is contained in:
Maofeng
2026-09-21 16:05:05 +08:00
parent 71c416caab
commit e2dbbcb884
29 changed files with 2877 additions and 0 deletions
@@ -0,0 +1,82 @@
import { LocalizedText } from "@workspace/i18n"
import { Badge } from "@workspace/ui/components/badge"
import { MoonIcon, SunIcon } from "@workspace/ui/components/icon"
import { cn } from "@workspace/ui/lib/utils"
import { appearanceMessages } from "../messages"
import type { ThemeColorConfig, ThemeScheme } from "../theme"
import {
accentColorSwatches,
baseColorSwatches,
ThemeColorPicker,
} from "./theme-color-picker"
import { ThemePreview } from "./theme-preview"
export interface ThemeConfigCardProps {
active?: boolean
className?: string
compacted?: boolean
config: ThemeColorConfig
onConfigChange: (config: ThemeColorConfig) => void
scheme: ThemeScheme
}
export function ThemeConfigCard({
active = false,
className,
compacted = false,
config,
onConfigChange,
scheme,
}: ThemeConfigCardProps) {
const titleMessage =
scheme === "light"
? appearanceMessages.lightTheme
: appearanceMessages.darkTheme
const descriptionMessage =
scheme === "light"
? appearanceMessages.lightThemeDescription
: appearanceMessages.darkThemeDescription
return (
<section className={cn("w-md rounded-xl border", className)}>
<header className="flex gap-4 border-b p-3">
{scheme === "light" ? (
<SunIcon className="size-5" />
) : (
<MoonIcon className="size-5" />
)}
<h2>
<LocalizedText message={titleMessage} />
</h2>
{active && (
<Badge className="ml-auto">
<LocalizedText message={appearanceMessages.active} />
</Badge>
)}
</header>
<div className="space-y-4 p-4">
<p>
<LocalizedText message={descriptionMessage} />
</p>
<ThemePreview compacted={compacted} config={config} scheme={scheme} />
<ThemeColorPicker
swatches={baseColorSwatches}
title={<LocalizedText message={appearanceMessages.baseColor} />}
value={config.baseColor}
onValueChange={(baseColor) =>
onConfigChange({ ...config, baseColor })
}
/>
<ThemeColorPicker
swatches={accentColorSwatches}
title={<LocalizedText message={appearanceMessages.primaryColor} />}
value={config.accentColor}
onValueChange={(accentColor) =>
onConfigChange({ ...config, accentColor })
}
/>
</div>
</section>
)
}