From a3af602751850e3fa4763b6d2ad4afb4398b90c2 Mon Sep 17 00:00:00 2001 From: Jiwon Kim Date: Thu, 20 Aug 2026 23:44:24 +0000 Subject: [PATCH 1/3] Add shadcn starter add-on --- .changeset/shaggy-cats-smile.md | 5 + packages/create-sites/README.md | 15 +- packages/create-sites/src/index.ts | 27 +- .../templates/addons/shadcn/app/globals.css | 134 +++++++++ .../templates/addons/shadcn/components.json | 25 ++ .../addons/shadcn/components/ui/alert.tsx | 76 +++++ .../addons/shadcn/components/ui/badge.tsx | 52 ++++ .../addons/shadcn/components/ui/button.tsx | 58 ++++ .../addons/shadcn/components/ui/card.tsx | 103 +++++++ .../addons/shadcn/components/ui/checkbox.tsx | 28 ++ .../addons/shadcn/components/ui/dialog.tsx | 159 ++++++++++ .../shadcn/components/ui/dropdown-menu.tsx | 272 ++++++++++++++++++ .../addons/shadcn/components/ui/input.tsx | 20 ++ .../addons/shadcn/components/ui/label.tsx | 20 ++ .../addons/shadcn/components/ui/select.tsx | 202 +++++++++++++ .../addons/shadcn/components/ui/separator.tsx | 25 ++ .../addons/shadcn/components/ui/skeleton.tsx | 13 + .../addons/shadcn/components/ui/switch.tsx | 32 +++ .../addons/shadcn/components/ui/tabs.tsx | 82 ++++++ .../addons/shadcn/components/ui/textarea.tsx | 18 ++ .../addons/shadcn/components/ui/tooltip.tsx | 66 +++++ .../templates/addons/shadcn/lib/utils.ts | 6 + .../create-sites/test/create-sites.test.ts | 96 ++++++- 23 files changed, 1524 insertions(+), 10 deletions(-) create mode 100644 .changeset/shaggy-cats-smile.md create mode 100644 packages/create-sites/templates/addons/shadcn/app/globals.css create mode 100644 packages/create-sites/templates/addons/shadcn/components.json create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/alert.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/badge.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/button.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/card.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/checkbox.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/dialog.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/dropdown-menu.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/input.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/label.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/select.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/separator.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/skeleton.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/switch.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/tabs.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/textarea.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/components/ui/tooltip.tsx create mode 100644 packages/create-sites/templates/addons/shadcn/lib/utils.ts diff --git a/.changeset/shaggy-cats-smile.md b/.changeset/shaggy-cats-smile.md new file mode 100644 index 0000000..35ab0b1 --- /dev/null +++ b/.changeset/shaggy-cats-smile.md @@ -0,0 +1,5 @@ +--- +'@openai/create-sites': minor +--- + +Add a shadcn/ui add-on with a vetted set of common components. diff --git a/packages/create-sites/README.md b/packages/create-sites/README.md index 9d29e67..6f28afb 100644 --- a/packages/create-sites/README.md +++ b/packages/create-sites/README.md @@ -5,18 +5,25 @@ Create ChatGPT Sites projects. ```bash npm create @openai/sites@latest my-site -npm create @openai/sites@latest my-site -- --yes --add-ons d1,r2 +npm create @openai/sites@latest my-site -- --yes --add-ons d1,r2,shadcn -pnpm create @openai/sites@latest my-site --yes --add-ons d1,r2 +pnpm create @openai/sites@latest my-site --yes --add-ons d1,r2,shadcn ``` Use `--yes` for noninteractive generation. Dependencies are not installed by default; pass `--install` to install them. The `d1` add-on adds a D1 binding and -Drizzle, `r2` adds an R2 binding, and `auth` adds ChatGPT authentication helpers. +Drizzle, `r2` adds an R2 binding, `auth` adds ChatGPT authentication helpers, +and `shadcn` adds shadcn/ui with a vetted set of common components. + +The `shadcn` add-on uses the Base UI Nova preset with neutral colors, Geist, +Lucide icons, and CSS variables. It includes alert, badge, button, card, +checkbox, dialog, dropdown menu, input, label, select, separator, skeleton, +switch, tabs, textarea, and tooltip. Add more components later with +`npm run ui:add -- `. ```bash npx --yes @openai/create-sites@latest . \ - --yes --add-ons d1,r2 + --yes --add-ons d1,r2,shadcn ``` The generated `.openai/hosting.json` is the source of truth for Sites bindings. diff --git a/packages/create-sites/src/index.ts b/packages/create-sites/src/index.ts index 0f61862..68a90fe 100644 --- a/packages/create-sites/src/index.ts +++ b/packages/create-sites/src/index.ts @@ -14,13 +14,17 @@ import { cancel, group, multiselect, text } from '@clack/prompts'; import { Command, InvalidArgumentError, Option } from 'commander'; import { xSync } from 'tinyexec'; -type AddOn = 'd1' | 'r2' | 'auth'; +type AddOn = 'd1' | 'r2' | 'auth' | 'shadcn'; type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun'; const addOns: { name: AddOn; description: string }[] = [ { name: 'd1', description: 'Add a Cloudflare D1 database and Drizzle.' }, { name: 'r2', description: 'Add a Cloudflare R2 object storage binding.' }, { name: 'auth', description: 'Add ChatGPT authentication helpers.' }, + { + name: 'shadcn', + description: 'Add shadcn/ui with a vetted set of common components.', + }, ]; const packageManagers: PackageManager[] = ['npm', 'pnpm', 'yarn', 'bun']; const allowedExistingEntries = new Set(['.git', '.DS_Store']); @@ -171,6 +175,23 @@ async function createSite( }; } + if (selected.includes('shadcn')) { + manifest.dependencies = { + ...manifest.dependencies, + '@base-ui/react': '1.7.0', + 'class-variance-authority': '0.7.1', + clsx: '2.1.1', + 'lucide-react': '1.31.0', + shadcn: '4.18.0', + 'tailwind-merge': '3.6.0', + 'tw-animate-css': '1.4.0', + }; + manifest.scripts = { + ...manifest.scripts, + 'ui:add': 'shadcn add', + }; + } + await mkdir(destination, { recursive: true }); await cp(base, destination, { recursive: true, force: false }); await rename( @@ -181,7 +202,9 @@ async function createSite( for (const addOn of selected) { await cp(join(templates, 'addons', addOn), destination, { recursive: true, - force: false, + // The shadcn add-on intentionally replaces the base global stylesheet + // with its theme variables and Tailwind imports. + force: addOn === 'shadcn', }); } diff --git a/packages/create-sites/templates/addons/shadcn/app/globals.css b/packages/create-sites/templates/addons/shadcn/app/globals.css new file mode 100644 index 0000000..7fafef8 --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/app/globals.css @@ -0,0 +1,134 @@ +@import 'tailwindcss'; +@import 'tw-animate-css'; +@import 'shadcn/tailwind.css'; + +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --font-heading: var(--font-sans); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) * 0.6); + --radius-md: calc(var(--radius) * 0.8); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) * 1.4); + --radius-2xl: calc(var(--radius) * 1.8); + --radius-3xl: calc(var(--radius) * 2.2); + --radius-4xl: calc(var(--radius) * 2.6); +} + +body { + font-family: var(--font-geist-sans), Arial, Helvetica, sans-serif; +} + +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } + html { + @apply font-sans; + } +} diff --git a/packages/create-sites/templates/addons/shadcn/components.json b/packages/create-sites/templates/addons/shadcn/components.json new file mode 100644 index 0000000..f382eb7 --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/components.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "base-nova", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} +} diff --git a/packages/create-sites/templates/addons/shadcn/components/ui/alert.tsx b/packages/create-sites/templates/addons/shadcn/components/ui/alert.tsx new file mode 100644 index 0000000..abe04d3 --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/components/ui/alert.tsx @@ -0,0 +1,76 @@ +import * as React from 'react'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from '@/lib/utils'; + +const alertVariants = cva( + "group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4", + { + variants: { + variant: { + default: 'bg-card text-card-foreground', + destructive: + 'bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +); + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<'div'> & VariantProps) { + return ( +
+ ); +} + +function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground', + className, + )} + {...props} + /> + ); +} + +function AlertDescription({ + className, + ...props +}: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function AlertAction({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +export { Alert, AlertTitle, AlertDescription, AlertAction }; diff --git a/packages/create-sites/templates/addons/shadcn/components/ui/badge.tsx b/packages/create-sites/templates/addons/shadcn/components/ui/badge.tsx new file mode 100644 index 0000000..8e59eb1 --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/components/ui/badge.tsx @@ -0,0 +1,52 @@ +import { mergeProps } from '@base-ui/react/merge-props'; +import { useRender } from '@base-ui/react/use-render'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from '@/lib/utils'; + +const badgeVariants = cva( + 'group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80', + secondary: + 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80', + destructive: + 'bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20', + outline: + 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground', + ghost: + 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50', + link: 'text-primary underline-offset-4 hover:underline', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +); + +function Badge({ + className, + variant = 'default', + render, + ...props +}: useRender.ComponentProps<'span'> & VariantProps) { + return useRender({ + defaultTagName: 'span', + props: mergeProps<'span'>( + { + className: cn(badgeVariants({ variant }), className), + }, + props, + ), + render, + state: { + slot: 'badge', + variant, + }, + }); +} + +export { Badge, badgeVariants }; diff --git a/packages/create-sites/templates/addons/shadcn/components/ui/button.tsx b/packages/create-sites/templates/addons/shadcn/components/ui/button.tsx new file mode 100644 index 0000000..7a8a32c --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/components/ui/button.tsx @@ -0,0 +1,58 @@ +import { Button as ButtonPrimitive } from '@base-ui/react/button'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from '@/lib/utils'; + +const buttonVariants = cva( + "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/80', + outline: + 'border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground', + ghost: + 'hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50', + destructive: + 'bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: + 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2', + xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3", + sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5", + lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2', + icon: 'size-8', + 'icon-xs': + "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3", + 'icon-sm': + 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg', + 'icon-lg': 'size-9', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +); + +function Button({ + className, + variant = 'default', + size = 'default', + ...props +}: ButtonPrimitive.Props & VariantProps) { + return ( + + ); +} + +export { Button, buttonVariants }; diff --git a/packages/create-sites/templates/addons/shadcn/components/ui/card.tsx b/packages/create-sites/templates/addons/shadcn/components/ui/card.tsx new file mode 100644 index 0000000..ae29aa2 --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/components/ui/card.tsx @@ -0,0 +1,103 @@ +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +function Card({ + className, + size = 'default', + ...props +}: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }) { + return ( +
img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl', + className, + )} + {...props} + /> + ); +} + +function CardHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardTitle({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardDescription({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardAction({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardContent({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardFooter({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, +}; diff --git a/packages/create-sites/templates/addons/shadcn/components/ui/checkbox.tsx b/packages/create-sites/templates/addons/shadcn/components/ui/checkbox.tsx new file mode 100644 index 0000000..990dbaf --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/components/ui/checkbox.tsx @@ -0,0 +1,28 @@ +'use client'; + +import { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox'; + +import { cn } from '@/lib/utils'; +import { CheckIcon } from 'lucide-react'; + +function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) { + return ( + + + + + + ); +} + +export { Checkbox }; diff --git a/packages/create-sites/templates/addons/shadcn/components/ui/dialog.tsx b/packages/create-sites/templates/addons/shadcn/components/ui/dialog.tsx new file mode 100644 index 0000000..019e0eb --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/components/ui/dialog.tsx @@ -0,0 +1,159 @@ +'use client'; + +import * as React from 'react'; +import { Dialog as DialogPrimitive } from '@base-ui/react/dialog'; + +import { cn } from '@/lib/utils'; +import { Button } from '@/components/ui/button'; +import { XIcon } from 'lucide-react'; + +function Dialog({ ...props }: DialogPrimitive.Root.Props) { + return ; +} + +function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) { + return ; +} + +function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) { + return ; +} + +function DialogClose({ ...props }: DialogPrimitive.Close.Props) { + return ; +} + +function DialogOverlay({ + className, + ...props +}: DialogPrimitive.Backdrop.Props) { + return ( + + ); +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: DialogPrimitive.Popup.Props & { + showCloseButton?: boolean; +}) { + return ( + + + + {children} + {showCloseButton && ( + + } + > + + Close + + )} + + + ); +} + +function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function DialogFooter({ + className, + showCloseButton = false, + children, + ...props +}: React.ComponentProps<'div'> & { + showCloseButton?: boolean; +}) { + return ( +
+ {children} + {showCloseButton && ( + }> + Close + + )} +
+ ); +} + +function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) { + return ( + + ); +} + +function DialogDescription({ + className, + ...props +}: DialogPrimitive.Description.Props) { + return ( + + ); +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +}; diff --git a/packages/create-sites/templates/addons/shadcn/components/ui/dropdown-menu.tsx b/packages/create-sites/templates/addons/shadcn/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..1cfacf7 --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/components/ui/dropdown-menu.tsx @@ -0,0 +1,272 @@ +'use client'; + +import * as React from 'react'; +import { Menu as MenuPrimitive } from '@base-ui/react/menu'; + +import { cn } from '@/lib/utils'; +import { ChevronRightIcon, CheckIcon } from 'lucide-react'; + +function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) { + return ; +} + +function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) { + return ; +} + +function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) { + return ; +} + +function DropdownMenuContent({ + align = 'start', + alignOffset = 0, + side = 'bottom', + sideOffset = 4, + className, + ...props +}: MenuPrimitive.Popup.Props & + Pick< + MenuPrimitive.Positioner.Props, + 'align' | 'alignOffset' | 'side' | 'sideOffset' + >) { + return ( + + + + + + ); +} + +function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) { + return ; +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: MenuPrimitive.GroupLabel.Props & { + inset?: boolean; +}) { + return ( + + ); +} + +function DropdownMenuItem({ + className, + inset, + variant = 'default', + ...props +}: MenuPrimitive.Item.Props & { + inset?: boolean; + variant?: 'default' | 'destructive'; +}) { + return ( + + ); +} + +function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) { + return ; +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: MenuPrimitive.SubmenuTrigger.Props & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function DropdownMenuSubContent({ + align = 'start', + alignOffset = -3, + side = 'right', + sideOffset = 0, + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + inset, + ...props +}: MenuPrimitive.CheckboxItem.Props & { + inset?: boolean; +}) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) { + return ( + + ); +} + +function DropdownMenuRadioItem({ + className, + children, + inset, + ...props +}: MenuPrimitive.RadioItem.Props & { + inset?: boolean; +}) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuSeparator({ + className, + ...props +}: MenuPrimitive.Separator.Props) { + return ( + + ); +} + +function DropdownMenuShortcut({ + className, + ...props +}: React.ComponentProps<'span'>) { + return ( + + ); +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +}; diff --git a/packages/create-sites/templates/addons/shadcn/components/ui/input.tsx b/packages/create-sites/templates/addons/shadcn/components/ui/input.tsx new file mode 100644 index 0000000..70c195a --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/components/ui/input.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { Input as InputPrimitive } from '@base-ui/react/input'; + +import { cn } from '@/lib/utils'; + +function Input({ className, type, ...props }: React.ComponentProps<'input'>) { + return ( + + ); +} + +export { Input }; diff --git a/packages/create-sites/templates/addons/shadcn/components/ui/label.tsx b/packages/create-sites/templates/addons/shadcn/components/ui/label.tsx new file mode 100644 index 0000000..6d13a34 --- /dev/null +++ b/packages/create-sites/templates/addons/shadcn/components/ui/label.tsx @@ -0,0 +1,20 @@ +'use client'; + +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +function Label({ className, ...props }: React.ComponentProps<'label'>) { + return ( +