Files
shadcn-ui/apps/v4/app/(create)/components/menu-picker.tsx
shadcn 86d9b00084 chore: update deps (#9022)
* feat: init

* fix

* fix

* fix

* feat

* feat

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* feat: implement icons

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* feat: update init command

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* feat: dialog

* feat

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* feat: add registry:base item type

* feat: rename frame to canva

* fix

* feat

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fi

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* feat: add all colors

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* feat: add outfit font

* fix

* fix

* fix

* fix

* fix

* chore: changeset

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix
2025-12-12 21:01:44 +04:00

168 lines
4.8 KiB
TypeScript

"use client"
import * as React from "react"
import { useTheme } from "next-themes"
import { useQueryStates } from "nuqs"
import { useMounted } from "@/hooks/use-mounted"
import { type MenuColorValue } from "@/registry/config"
import { LockButton } from "@/app/(create)/components/lock-button"
import {
Picker,
PickerContent,
PickerGroup,
PickerRadioGroup,
PickerRadioItem,
PickerTrigger,
} from "@/app/(create)/components/picker"
import { designSystemSearchParams } from "@/app/(create)/lib/search-params"
const MENU_OPTIONS = [
{
value: "default" as const,
label: "Default",
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
width="128"
height="128"
viewBox="0 0 24 24"
fill="none"
role="img"
stroke="currentColor"
className="text-foreground"
>
<path
d="M2 11.5C2 7.02166 2 4.78249 3.39124 3.39124C4.78249 2 7.02166 2 11.5 2C15.9783 2 18.2175 2 19.6088 3.39124C21 4.78249 21 7.02166 21 11.5C21 15.9783 21 18.2175 19.6088 19.6088C18.2175 21 15.9783 21 11.5 21C7.02166 21 4.78249 21 3.39124 19.6088C2 18.2175 2 15.9783 2 11.5Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M8.5 11.5L14.5001 11.5"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M9.5 15H13.5"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M7.5 8H15.5"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
),
},
{
value: "inverted" as const,
label: "Inverted",
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
width="128"
height="128"
viewBox="0 0 24 24"
fill="none"
role="img"
className="fill-foreground text-foreground"
>
<path
d="M2 11.5C2 7.02166 2 4.78249 3.39124 3.39124C4.78249 2 7.02166 2 11.5 2C15.9783 2 18.2175 2 19.6088 3.39124C21 4.78249 21 7.02166 21 11.5C21 15.9783 21 18.2175 19.6088 19.6088C18.2175 21 15.9783 21 11.5 21C7.02166 21 4.78249 21 3.39124 19.6088C2 18.2175 2 15.9783 2 11.5Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M8.5 11.5L14.5001 11.5"
stroke="var(--background)"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M9.5 15H13.5"
stroke="var(--background)"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M7.5 8H15.5"
stroke="var(--background)"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
),
},
] as const
export function MenuColorPicker({
isMobile,
anchorRef,
}: {
isMobile: boolean
anchorRef: React.RefObject<HTMLDivElement | null>
}) {
const { resolvedTheme } = useTheme()
const mounted = useMounted()
const [params, setParams] = useQueryStates(designSystemSearchParams, {
shallow: false,
history: "push",
})
const currentMenu = MENU_OPTIONS.find(
(menu) => menu.value === params.menuColor
)
return (
<Picker>
<div className="group/picker relative">
<PickerTrigger disabled={mounted && resolvedTheme === "dark"}>
<div className="flex flex-col justify-start text-left">
<div className="text-muted-foreground text-xs">Menu Color</div>
<div className="text-foreground text-sm font-medium">
{currentMenu?.label}
</div>
</div>
<div className="text-foreground absolute top-1/2 right-4 flex size-4 -translate-y-1/2 items-center justify-center text-base">
{currentMenu?.icon}
</div>
</PickerTrigger>
<LockButton
param="menuColor"
className="absolute top-1/2 right-10 -translate-y-1/2"
/>
</div>
<PickerContent
anchor={isMobile ? anchorRef : undefined}
side={isMobile ? "top" : "right"}
align={isMobile ? "center" : "start"}
>
<PickerRadioGroup
value={currentMenu?.value}
onValueChange={(value) => {
setParams({ menuColor: value as MenuColorValue })
}}
>
<PickerGroup>
{MENU_OPTIONS.map((menu) => (
<PickerRadioItem key={menu.value} value={menu.value}>
{menu.icon}
{menu.label}
</PickerRadioItem>
))}
</PickerGroup>
</PickerRadioGroup>
</PickerContent>
</Picker>
)
}