Files
shadcn-ui/apps/v4/app/(create)/components/preset-picker.tsx
shadcn 687f09817b feat: chartColor and fontHeading (#10115)
* feat: chart color

* fix

* fix

* fix: chart color

* chore: changeset

* chore: restore directory registry formatting

* feat: add fontHeading

* feat: rebuild registry

* fix: v0

* refactor

* fix

* fix

* fix

* fix

* fix

* fix: refactor preset handling

* fix

* fix

* fix
2026-03-19 23:35:01 +04:00

133 lines
3.7 KiB
TypeScript

"use client"
import * as React from "react"
import { STYLES, type Preset } from "@/registry/config"
import {
Picker,
PickerContent,
PickerGroup,
PickerRadioGroup,
PickerRadioItem,
PickerTrigger,
} from "@/app/(create)/components/picker"
import { useDesignSystemSearchParams } from "@/app/(create)/lib/search-params"
export function PresetPicker({
presets,
isMobile,
anchorRef,
}: {
presets: readonly Preset[]
isMobile: boolean
anchorRef: React.RefObject<HTMLDivElement | null>
}) {
const [params, setParams] = useDesignSystemSearchParams()
const currentPreset = React.useMemo(() => {
return presets.find(
(preset) =>
preset.base === params.base &&
preset.style === params.style &&
preset.baseColor === params.baseColor &&
preset.theme === params.theme &&
preset.chartColor === params.chartColor &&
preset.iconLibrary === params.iconLibrary &&
preset.font === params.font &&
preset.fontHeading === params.fontHeading &&
preset.menuAccent === params.menuAccent &&
preset.menuColor === params.menuColor &&
preset.radius === params.radius
)
}, [
presets,
params.base,
params.style,
params.baseColor,
params.theme,
params.chartColor,
params.iconLibrary,
params.font,
params.fontHeading,
params.menuAccent,
params.menuColor,
params.radius,
])
// Filter presets for current base only
const currentBasePresets = React.useMemo(() => {
return presets.filter((preset) => preset.base === params.base)
}, [presets, params.base])
const handlePresetChange = (value: string) => {
const preset = presets.find((p) => p.title === value)
if (!preset) {
return
}
// Update all params including base.
setParams({
base: preset.base,
style: preset.style,
baseColor: preset.baseColor,
theme: preset.theme,
chartColor: preset.chartColor,
iconLibrary: preset.iconLibrary,
font: preset.font,
fontHeading: preset.fontHeading,
menuAccent: preset.menuAccent,
menuColor: preset.menuColor,
radius: preset.radius,
custom: false,
})
}
return (
<Picker>
<PickerTrigger>
<div className="flex flex-col justify-start text-left">
<div className="text-xs text-muted-foreground">Preset</div>
<div className="line-clamp-1 text-sm font-medium text-foreground">
{currentPreset?.description ?? "Custom"}
</div>
</div>
</PickerTrigger>
<PickerContent
anchor={isMobile ? anchorRef : undefined}
side={isMobile ? "top" : "right"}
align={isMobile ? "center" : "start"}
className="md:w-72"
>
<PickerRadioGroup
value={currentPreset?.title ?? ""}
onValueChange={handlePresetChange}
>
<PickerGroup>
{currentBasePresets.map((preset) => {
const style = STYLES.find((s) => s.name === preset.style)
return (
<PickerRadioItem
key={preset.title}
value={preset.title}
closeOnClick={isMobile}
>
<div className="flex items-center gap-2">
{style?.icon && (
<div className="flex size-4 shrink-0 items-center justify-center">
{React.cloneElement(style.icon, {
className: "size-4",
})}
</div>
)}
{preset.description}
</div>
</PickerRadioItem>
)
})}
</PickerGroup>
</PickerRadioGroup>
</PickerContent>
</Picker>
)
}