snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
138
apps/v4/app/(app)/(create)/components/theme-picker.tsx
Normal file
138
apps/v4/app/(app)/(create)/components/theme-picker.tsx
Normal file
@@ -0,0 +1,138 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { useMounted } from "@/hooks/use-mounted"
|
||||
import { BASE_COLORS, type Theme, type ThemeName } from "@/registry/config"
|
||||
import { LockButton } from "@/app/(app)/(create)/components/lock-button"
|
||||
import {
|
||||
Picker,
|
||||
PickerContent,
|
||||
PickerGroup,
|
||||
PickerRadioGroup,
|
||||
PickerRadioItem,
|
||||
PickerSeparator,
|
||||
PickerTrigger,
|
||||
} from "@/app/(app)/(create)/components/picker"
|
||||
import { usePreviewOverride } from "@/app/(app)/(create)/components/preview-override"
|
||||
import { useDesignSystemSearchParams } from "@/app/(app)/(create)/lib/search-params"
|
||||
|
||||
export function ThemePicker({
|
||||
themes,
|
||||
isMobile,
|
||||
anchorRef,
|
||||
}: {
|
||||
themes: readonly Theme[]
|
||||
isMobile: boolean
|
||||
anchorRef: React.RefObject<HTMLDivElement | null>
|
||||
}) {
|
||||
const mounted = useMounted()
|
||||
const [params, setParams] = useDesignSystemSearchParams()
|
||||
const { setOverride, clearOverride } = usePreviewOverride()
|
||||
|
||||
const currentTheme = React.useMemo(
|
||||
() => themes.find((theme) => theme.name === params.theme),
|
||||
[themes, params.theme]
|
||||
)
|
||||
|
||||
const currentThemeIsBaseColor = React.useMemo(
|
||||
() => BASE_COLORS.find((baseColor) => baseColor.name === params.theme),
|
||||
[params.theme]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="group/picker relative">
|
||||
<Picker
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
clearOverride()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<PickerTrigger>
|
||||
<div className="flex flex-col justify-start text-left">
|
||||
<div className="text-xs text-muted-foreground">Theme</div>
|
||||
<div className="text-sm font-medium text-foreground">
|
||||
{currentTheme?.title}
|
||||
</div>
|
||||
</div>
|
||||
{mounted && (
|
||||
<div
|
||||
style={
|
||||
{
|
||||
"--color":
|
||||
currentTheme?.cssVars?.dark?.[
|
||||
currentThemeIsBaseColor ? "muted-foreground" : "primary"
|
||||
],
|
||||
} as React.CSSProperties
|
||||
}
|
||||
className="pointer-events-none absolute top-1/2 right-4 size-4 -translate-y-1/2 rounded-full bg-(--color) select-none md:right-2.5"
|
||||
/>
|
||||
)}
|
||||
</PickerTrigger>
|
||||
<PickerContent
|
||||
anchor={isMobile ? anchorRef : undefined}
|
||||
side={isMobile ? "top" : "right"}
|
||||
align={isMobile ? "center" : "start"}
|
||||
className="max-h-92"
|
||||
onMouseLeave={clearOverride}
|
||||
>
|
||||
<PickerRadioGroup
|
||||
value={currentTheme?.name}
|
||||
onValueChange={(value) => {
|
||||
setParams({ theme: value as ThemeName })
|
||||
}}
|
||||
onItemPreview={
|
||||
isMobile
|
||||
? undefined
|
||||
: (value) => setOverride({ theme: value as ThemeName })
|
||||
}
|
||||
>
|
||||
<PickerGroup>
|
||||
{themes
|
||||
.filter((theme) =>
|
||||
BASE_COLORS.find((baseColor) => baseColor.name === theme.name)
|
||||
)
|
||||
.map((theme) => {
|
||||
return (
|
||||
<PickerRadioItem
|
||||
key={theme.name}
|
||||
value={theme.name}
|
||||
closeOnClick={isMobile}
|
||||
>
|
||||
{theme.title}
|
||||
</PickerRadioItem>
|
||||
)
|
||||
})}
|
||||
</PickerGroup>
|
||||
<PickerSeparator />
|
||||
<PickerGroup>
|
||||
{themes
|
||||
.filter(
|
||||
(theme) =>
|
||||
!BASE_COLORS.find(
|
||||
(baseColor) => baseColor.name === theme.name
|
||||
)
|
||||
)
|
||||
.map((theme) => {
|
||||
return (
|
||||
<PickerRadioItem
|
||||
key={theme.name}
|
||||
value={theme.name}
|
||||
closeOnClick={isMobile}
|
||||
>
|
||||
{theme.title}
|
||||
</PickerRadioItem>
|
||||
)
|
||||
})}
|
||||
</PickerGroup>
|
||||
</PickerRadioGroup>
|
||||
</PickerContent>
|
||||
</Picker>
|
||||
<LockButton
|
||||
param="theme"
|
||||
className="absolute top-1/2 right-8 -translate-y-1/2"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user