"use client" import * as React from "react" import { ComputerTerminal01Icon, Copy01Icon, Tick02Icon, } from "@hugeicons/core-free-icons" import { HugeiconsIcon } from "@hugeicons/react" import { useQueryStates } from "nuqs" import { toast } from "sonner" import { useConfig } from "@/hooks/use-config" import { copyToClipboardWithMeta } from "@/components/copy-button" import { Button } from "@/registry/new-york-v4/ui/button" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/registry/new-york-v4/ui/dialog" import { Field, FieldGroup, FieldLabel, FieldTitle, } from "@/registry/new-york-v4/ui/field" import { RadioGroup, RadioGroupItem, } from "@/registry/new-york-v4/ui/radio-group" import { Tabs, TabsContent, TabsList, TabsTrigger, } from "@/registry/new-york-v4/ui/tabs" import { Tooltip, TooltipContent, TooltipTrigger, } from "@/registry/new-york-v4/ui/tooltip" import { designSystemSearchParams } from "@/app/(create)/lib/search-params" const TEMPLATES = [ { value: "next", title: "Next.js", logo: 'Next.js', }, { value: "start", title: "TanStack Start", logo: 'TanStack', }, { value: "vite", title: "Vite", logo: '', }, ] as const export function ToolbarControls() { const [open, setOpen] = React.useState(false) const [params, setParams] = useQueryStates(designSystemSearchParams, { shallow: false, history: "push", }) const [config, setConfig] = useConfig() const [hasCopied, setHasCopied] = React.useState(false) const packageManager = config.packageManager || "pnpm" const commands = React.useMemo(() => { const origin = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000" const url = `${origin}/init?base=${params.base}&style=${params.style}&baseColor=${params.baseColor}&theme=${params.theme}&iconLibrary=${params.iconLibrary}&font=${params.font}&menuAccent=${params.menuAccent}&menuColor=${params.menuColor}&radius=${params.radius}&template=${params.template}` const templateFlag = params.template ? ` --template ${params.template}` : "" return { pnpm: `pnpm dlx shadcn@latest create --preset ${url}${templateFlag}`, npm: `npx shadcn@latest create --preset ${url}${templateFlag}`, yarn: `yarn dlx shadcn@latest create --preset ${url}${templateFlag}`, bun: `bunx --bun shadcn@latest create --preset ${url}${templateFlag}`, } }, [ params.base, params.style, params.baseColor, params.theme, params.iconLibrary, params.font, params.menuAccent, params.menuColor, params.radius, params.template, ]) const command = commands[packageManager] React.useEffect(() => { if (hasCopied) { const timer = setTimeout(() => setHasCopied(false), 2000) return () => clearTimeout(timer) } }, [hasCopied]) const handleCopy = React.useCallback(() => { const properties: Record = { command, } if (params.template) { properties.template = params.template } copyToClipboardWithMeta(command, { name: "copy_npm_command", properties, }) setOpen(false) setHasCopied(true) toast("Command copied to clipboard.", { description: "Paste and run the command in your terminal to create a new shadcn/ui project.", position: "bottom-center", classNames: { content: "rounded-xl", toast: "rounded-xl!", description: "text-sm/leading-normal!", }, }) }, [command, params.template, setOpen]) const handleCopyFromTabs = React.useCallback(() => { const properties: Record = { command, } if (params.template) { properties.template = params.template } copyToClipboardWithMeta(command, { name: "copy_npm_command", properties, }) setHasCopied(true) }, [command, params.template]) const selectedTemplate = TEMPLATES.find( (template) => template.value === params.template ) return ( Create Project Select a template and run this command to create a{" "} {selectedTemplate?.title} + shadcn/ui project. Template { setParams({ template: value as "next" | "start" | "vite", }) }} className="grid grid-cols-3 gap-2" > {TEMPLATES.map((template) => ( {template.logo && (
)} {template.title} ))} { setConfig({ ...config, packageManager: value as "pnpm" | "npm" | "yarn" | "bun", }) }} className="bg-surface min-w-0 gap-0 overflow-hidden rounded-lg border" >
pnpm npm yarn bun {hasCopied ? "Copied!" : "Copy command"}
{Object.entries(commands).map(([key, cmd]) => { return (
{cmd}
) })}
) }