From e327cef2c102da86cbf90326383c3e1e4b923944 Mon Sep 17 00:00:00 2001 From: shadcn Date: Fri, 20 Mar 2026 16:46:40 +0400 Subject: [PATCH] feat: update customizer (#10129) --- .../app/(create)/components/accent-picker.tsx | 36 +- .../(create)/components/base-color-picker.tsx | 54 +-- .../app/(create)/components/base-picker.tsx | 4 +- .../components/chart-color-picker.tsx | 62 ++-- .../app/(create)/components/copy-preset.tsx | 48 ++- .../(create)/components/customizer-layout.tsx | 50 +++ .../v4/app/(create)/components/customizer.tsx | 325 +++++++++++++++--- .../app/(create)/components/font-picker.tsx | 53 +-- .../components/icon-library-picker.tsx | 36 +- apps/v4/app/(create)/components/main-menu.tsx | 87 ++++- .../app/(create)/components/menu-picker.tsx | 37 +- apps/v4/app/(create)/components/picker.tsx | 137 +++++++- apps/v4/app/(create)/components/preview.tsx | 12 + .../app/(create)/components/radius-picker.tsx | 39 ++- .../app/(create)/components/random-button.tsx | 38 +- .../app/(create)/components/style-picker.tsx | 45 +-- .../app/(create)/components/theme-picker.tsx | 60 ++-- apps/v4/app/(create)/components/tooltip.tsx | 12 + apps/v4/app/(create)/create/page.tsx | 29 +- apps/v4/app/(create)/lib/customizer.ts | 21 ++ .../(create)/preview/[base]/[name]/page.tsx | 2 + 21 files changed, 922 insertions(+), 265 deletions(-) create mode 100644 apps/v4/app/(create)/components/customizer-layout.tsx create mode 100644 apps/v4/app/(create)/components/tooltip.tsx create mode 100644 apps/v4/app/(create)/lib/customizer.ts diff --git a/apps/v4/app/(create)/components/accent-picker.tsx b/apps/v4/app/(create)/components/accent-picker.tsx index 7ac45b58e7..e0821f09e5 100644 --- a/apps/v4/app/(create)/components/accent-picker.tsx +++ b/apps/v4/app/(create)/components/accent-picker.tsx @@ -1,6 +1,7 @@ "use client" import { MENU_ACCENTS, type MenuAccentValue } from "@/registry/config" +import { useCustomizerLayout } from "@/app/(create)/components/customizer-layout" import { LockButton } from "@/app/(create)/components/lock-button" import { Picker, @@ -8,18 +9,21 @@ import { PickerGroup, PickerRadioGroup, PickerRadioItem, - PickerTrigger, + PickerValueTrigger, } from "@/app/(create)/components/picker" import { useDesignSystemSearchParams } from "@/app/(create)/lib/search-params" export function MenuAccentPicker({ isMobile, anchorRef, + collapsed = false, }: { isMobile: boolean anchorRef: React.RefObject + collapsed?: boolean }) { const [params, setParams] = useDesignSystemSearchParams() + const { desktopPickerSide } = useCustomizerLayout() const currentAccent = MENU_ACCENTS.find( (accent) => accent.value === params.menuAccent @@ -28,14 +32,11 @@ export function MenuAccentPicker({ return (
- -
-
Menu Accent
-
- {currentAccent?.label} -
-
-
+ -
-
+ } + collapsed={collapsed} + />
- + {!collapsed ? ( + + ) : null}
) } diff --git a/apps/v4/app/(create)/components/base-color-picker.tsx b/apps/v4/app/(create)/components/base-color-picker.tsx index e0d1ec1d7d..9ea72a5b65 100644 --- a/apps/v4/app/(create)/components/base-color-picker.tsx +++ b/apps/v4/app/(create)/components/base-color-picker.tsx @@ -4,6 +4,7 @@ import * as React from "react" import { useMounted } from "@/hooks/use-mounted" import { BASE_COLORS, type BaseColorName } from "@/registry/config" +import { useCustomizerLayout } from "@/app/(create)/components/customizer-layout" import { LockButton } from "@/app/(create)/components/lock-button" import { Picker, @@ -11,50 +12,51 @@ import { PickerGroup, PickerRadioGroup, PickerRadioItem, - PickerTrigger, + PickerValueTrigger, } from "@/app/(create)/components/picker" import { useDesignSystemSearchParams } from "@/app/(create)/lib/search-params" export function BaseColorPicker({ isMobile, anchorRef, + collapsed = false, }: { isMobile: boolean anchorRef: React.RefObject + collapsed?: boolean }) { const mounted = useMounted() const [params, setParams] = useDesignSystemSearchParams() + const { desktopPickerSide } = useCustomizerLayout() const currentBaseColor = React.useMemo( () => BASE_COLORS.find((baseColor) => baseColor.name === params.baseColor), [params.baseColor] ) + const baseColorIndicator = mounted ? ( +
+ ) : null return (
- -
-
Base Color
-
- {currentBaseColor?.title} -
-
- {mounted && ( -
- )} - + - + {!collapsed ? ( + + ) : null}
) } diff --git a/apps/v4/app/(create)/components/base-picker.tsx b/apps/v4/app/(create)/components/base-picker.tsx index f43b11460d..d77299e670 100644 --- a/apps/v4/app/(create)/components/base-picker.tsx +++ b/apps/v4/app/(create)/components/base-picker.tsx @@ -3,6 +3,7 @@ import * as React from "react" import { BASES } from "@/registry/config" +import { useCustomizerLayout } from "@/app/(create)/components/customizer-layout" import { Picker, PickerContent, @@ -21,6 +22,7 @@ export function BasePicker({ anchorRef: React.RefObject }) { const [params, setParams] = useDesignSystemSearchParams() + const { desktopPickerSide } = useCustomizerLayout() const currentBase = React.useMemo( () => BASES.find((base) => base.name === params.base), @@ -60,7 +62,7 @@ export function BasePicker({
+ collapsed?: boolean }) { const mounted = useMounted() const [params, setParams] = useDesignSystemSearchParams() + const { desktopPickerSide } = useCustomizerLayout() const availableChartColors = React.useMemo( () => getThemesForBaseColor(params.baseColor), @@ -52,35 +56,33 @@ export function ChartColorPicker({ } }, [currentChartColor, availableChartColors, setParams]) + const chartColorIndicator = mounted ? ( +
+ ) : null + return (
- -
-
Chart Color
-
- {currentChartColor?.title} -
-
- {mounted && ( -
- )} - + @@ -127,10 +129,12 @@ export function ChartColorPicker({ - + {!collapsed ? ( + + ) : null}
) } diff --git a/apps/v4/app/(create)/components/copy-preset.tsx b/apps/v4/app/(create)/components/copy-preset.tsx index 7e94c8aec3..f08d2badb1 100644 --- a/apps/v4/app/(create)/components/copy-preset.tsx +++ b/apps/v4/app/(create)/components/copy-preset.tsx @@ -2,12 +2,24 @@ import * as React from "react" import { Button } from "@/examples/base/ui/button" +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/examples/base/ui/tooltip" +import { Copy01Icon, Tick02Icon } from "@hugeicons/core-free-icons" +import { HugeiconsIcon } from "@hugeicons/react" import { cn } from "@/lib/utils" import { copyToClipboardWithMeta } from "@/components/copy-button" import { usePresetCode } from "@/app/(create)/hooks/use-design-system" -export function CopyPreset({ className }: React.ComponentProps) { +export function CopyPreset({ + className, + collapsed = false, +}: React.ComponentProps & { + collapsed?: boolean +}) { const presetCode = usePresetCode() const [hasCopied, setHasCopied] = React.useState(false) @@ -28,6 +40,40 @@ export function CopyPreset({ className }: React.ComponentProps) { setHasCopied(true) }, [presetCode]) + const tooltipLabel = hasCopied + ? "Copied preset" + : `Copy --preset ${presetCode}` + + if (collapsed) { + return ( + + + } + > + + {tooltipLabel} + + + {tooltipLabel} + + + ) + } + return (