diff --git a/.github/workflows/prerelease-comment.yml b/.github/workflows/prerelease-comment.yml index 51a4e55da87..ad21a549f9b 100644 --- a/.github/workflows/prerelease-comment.yml +++ b/.github/workflows/prerelease-comment.yml @@ -10,7 +10,7 @@ on: jobs: comment: if: | - github.repository_owner == 'shadcn' && + github.repository_owner == 'shadcn-ui' && ${{ github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-latest name: Write comment to the PR diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index d31a8ebaa80..ea414857c6f 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -10,7 +10,7 @@ on: jobs: prerelease: if: | - github.repository_owner == 'shadcn' && + github.repository_owner == 'shadcn-ui' && contains(github.event.pull_request.labels.*.name, '🚀 autorelease') name: Build & Publish a beta release to NPM runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ba8d4a6e8e..7ec48407d95 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ on: jobs: release: - if: ${{ github.repository_owner == 'shadcn' }} + if: ${{ github.repository_owner == 'shadcn-ui' }} name: Create a PR for release workflow runs-on: ubuntu-latest steps: diff --git a/apps/www/app/docs/[[...slug]]/page.tsx b/apps/www/app/docs/[[...slug]]/page.tsx index 11443efd0cf..710e5a3a7a0 100644 --- a/apps/www/app/docs/[[...slug]]/page.tsx +++ b/apps/www/app/docs/[[...slug]]/page.tsx @@ -139,9 +139,11 @@ export default async function DocPage({ params }: DocPageProps) { {doc.toc && (
-
+
- +
+ +
diff --git a/apps/www/app/examples/cards/page.tsx b/apps/www/app/examples/cards/page.tsx index 8f3a94bfd51..2a5f91f64d7 100644 --- a/apps/www/app/examples/cards/page.tsx +++ b/apps/www/app/examples/cards/page.tsx @@ -75,7 +75,7 @@ export default function CardsPage() {
-
+
diff --git a/apps/www/app/examples/forms/account/account-form.tsx b/apps/www/app/examples/forms/account/account-form.tsx index 082d29411a9..1f21b7fdd20 100644 --- a/apps/www/app/examples/forms/account/account-form.tsx +++ b/apps/www/app/examples/forms/account/account-form.tsx @@ -184,10 +184,10 @@ export function AccountForm() { {languages.map((language) => ( { - form.setValue("language", value) + onSelect={() => { + form.setValue("language", language.value) }} > { const down = (e: KeyboardEvent) => { - if (e.key === "k" && e.metaKey) { + if (e.key === "k" && (e.metaKey || e.ctrlKey)) { + e.preventDefault() setOpen((open) => !open) } } diff --git a/apps/www/content/docs/dark-mode/index.mdx b/apps/www/content/docs/dark-mode/index.mdx new file mode 100644 index 00000000000..214118d608a --- /dev/null +++ b/apps/www/content/docs/dark-mode/index.mdx @@ -0,0 +1,37 @@ +--- +title: Dark Mode +description: Adding dark mode to your site. +--- + +
+ + + Next.js + + +

Next.js

+
+ + + Vite + + +

Vite

+
+
+ +## Other frameworks + +I'm looking for help writing guides for other frameworks. Help me write guides for Remix, Astro and Vite by [opening an PR](https://github.com/shadcn/ui). diff --git a/apps/www/content/docs/dark-mode.mdx b/apps/www/content/docs/dark-mode/next.mdx similarity index 81% rename from apps/www/content/docs/dark-mode.mdx rename to apps/www/content/docs/dark-mode/next.mdx index 2c85e38da9a..ef7489cad7f 100644 --- a/apps/www/content/docs/dark-mode.mdx +++ b/apps/www/content/docs/dark-mode/next.mdx @@ -1,9 +1,9 @@ --- -title: Dark Mode -description: Adding dark mode to your site. +title: Next.js +description: Adding dark mode to your next app. --- -## Next.js +## Dark mode @@ -51,7 +51,3 @@ Place a mode toggle on your site to toggle between light and dark mode. - -## Other frameworks - -I'm looking for help writing guides for other frameworks. Help me write guides for Remix, Astro and Vite by [opening an PR](https://github.com/shadcn/ui). diff --git a/apps/www/content/docs/dark-mode/vite.mdx b/apps/www/content/docs/dark-mode/vite.mdx new file mode 100644 index 00000000000..53afa996185 --- /dev/null +++ b/apps/www/content/docs/dark-mode/vite.mdx @@ -0,0 +1,148 @@ +--- +title: Vite +description: Adding dark mode to your vite app. +--- + +## Dark mode + + + +### Create a theme provider + +```tsx title="components/theme-provider.tsx" +import { createContext, useContext, useEffect, useState } from "react" + +type ThemeProviderProps = { + children: React.ReactNode + defaultTheme?: string + storageKey?: string +} + +type ThemeProviderState = { + theme: string + setTheme: (theme: string) => void +} + +const initialState = { + theme: "system", + setTheme: () => null, +} + +const ThemeProviderContext = createContext(initialState) + +export function ThemeProvider({ + children, + defaultTheme = "system", + storageKey = "vite-ui-theme", + ...props +}: ThemeProviderProps) { + const [theme, setTheme] = useState( + () => localStorage.getItem(storageKey) || defaultTheme + ) + + useEffect(() => { + const root = window.document.documentElement + + root.classList.remove("light", "dark") + + if (theme === "system") { + const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") + .matches + ? "dark" + : "light" + + root.classList.add(systemTheme) + return + } + + root.classList.add(theme) + }, [theme]) + + const value = { + theme, + setTheme: (theme: string) => { + localStorage.setItem(storageKey, theme) + setTheme(theme) + }, + } + + return ( + + {children} + + ) +} + +export const useTheme = () => { + const context = useContext(ThemeProviderContext) + + if (context === undefined) + throw new Error("useTheme must be used within a ThemeProvider") + + return context +} +``` + +### Wrap your root layout + +Add the `ThemeProvider` to your root layout. + +```tsx {1,5-7} title="App.tsx" +import { ThemeProvider } from "@/components/theme-provider" + +function App() { + return ( + + {children} + + ) +} + +export default App +``` + +### Add a mode toggle + +Place a mode toggle on your site to toggle between light and dark mode. + +```tsx title="components/mode-toggle.tsx" +import { Moon, Sun } from "lucide-react" + +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { useTheme } from "@/components/theme-provider" + +export function ModeToggle() { + const { setTheme } = useTheme() + + return ( + + + + + + setTheme("light")}> + Light + + setTheme("dark")}> + Dark + + setTheme("system")}> + System + + + + ) +} +``` + + diff --git a/apps/www/content/docs/installation/gatsby.mdx b/apps/www/content/docs/installation/gatsby.mdx index a680cd2fa32..cd83d6f8f6b 100644 --- a/apps/www/content/docs/installation/gatsby.mdx +++ b/apps/www/content/docs/installation/gatsby.mdx @@ -106,7 +106,7 @@ npx shadcn-ui@latest add button The command above will add the `Button` component to your project. You can then import it like this: ```tsx {1,6} showLineNumbers -import { Button } from "@/components/ui" +import { Button } from "@/components/ui/button" export default function Home() { return ( diff --git a/apps/www/content/docs/installation/next.mdx b/apps/www/content/docs/installation/next.mdx index 0fe520f5fdc..8cda7fde6fa 100644 --- a/apps/www/content/docs/installation/next.mdx +++ b/apps/www/content/docs/installation/next.mdx @@ -82,7 +82,7 @@ npx shadcn-ui@latest add button The command above will add the `Button` component to your project. You can then import it like this: ```tsx {1,6} showLineNumbers -import { Button } from "@/components/ui" +import { Button } from "@/components/ui/button" export default function Home() { return ( diff --git a/apps/www/content/docs/installation/remix.mdx b/apps/www/content/docs/installation/remix.mdx index 2b484a10094..71235ba825e 100644 --- a/apps/www/content/docs/installation/remix.mdx +++ b/apps/www/content/docs/installation/remix.mdx @@ -103,7 +103,7 @@ npx shadcn-ui@latest add button The command above will add the `Button` component to your project. You can then import it like this: ```tsx {1,6} showLineNumbers -import { Button } from "@/components/ui" +import { Button } from "~/components/ui/button" export default function Home() { return ( diff --git a/apps/www/content/docs/installation/vite.mdx b/apps/www/content/docs/installation/vite.mdx index bf1195037a7..b198b23c30b 100644 --- a/apps/www/content/docs/installation/vite.mdx +++ b/apps/www/content/docs/installation/vite.mdx @@ -93,7 +93,7 @@ npx shadcn-ui@latest add button The command above will add the `Button` component to your project. You can then import it like this: ```tsx {1,6} showLineNumbers -import { Button } from "@/components/ui" +import { Button } from "@/components/ui/button" export default function Home() { return ( diff --git a/apps/www/pages/api/components.json b/apps/www/pages/api/components.json index cf89b8f3f4f..94ff628884f 100644 --- a/apps/www/pages/api/components.json +++ b/apps/www/pages/api/components.json @@ -17,7 +17,7 @@ { "name": "alert.tsx", "dir": "components/ui", - "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"text-destructive border-destructive/50 dark:border-destructive [&>svg]:text-destructive text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes & VariantProps\n>(({ className, variant, ...props }, ref) => (\n \n))\nAlert.displayName = \"Alert\"\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertTitle.displayName = \"AlertTitle\"\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertDescription.displayName = \"AlertDescription\"\n\nexport { Alert, AlertTitle, AlertDescription }\n" + "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&>svg~*]:pl-7\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"text-destructive border-destructive/50 dark:border-destructive [&>svg]:text-destructive text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes & VariantProps\n>(({ className, variant, ...props }, ref) => (\n \n))\nAlert.displayName = \"Alert\"\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertTitle.displayName = \"AlertTitle\"\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertDescription.displayName = \"AlertDescription\"\n\nexport { Alert, AlertTitle, AlertDescription }\n" } ], "type": "ui" diff --git a/apps/www/public/registry/styles/default/alert.json b/apps/www/public/registry/styles/default/alert.json index a04a1324a74..e1bc8d0fa79 100644 --- a/apps/www/public/registry/styles/default/alert.json +++ b/apps/www/public/registry/styles/default/alert.json @@ -3,7 +3,7 @@ "files": [ { "name": "alert.tsx", - "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&:has(svg)]:pl-11 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes & VariantProps\n>(({ className, variant, ...props }, ref) => (\n \n))\nAlert.displayName = \"Alert\"\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertTitle.displayName = \"AlertTitle\"\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertDescription.displayName = \"AlertDescription\"\n\nexport { Alert, AlertTitle, AlertDescription }\n" + "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes & VariantProps\n>(({ className, variant, ...props }, ref) => (\n \n))\nAlert.displayName = \"Alert\"\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertTitle.displayName = \"AlertTitle\"\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertDescription.displayName = \"AlertDescription\"\n\nexport { Alert, AlertTitle, AlertDescription }\n" } ], "type": "components:ui" diff --git a/apps/www/public/registry/styles/new-york/alert.json b/apps/www/public/registry/styles/new-york/alert.json index 2cc9a4ea497..6ba27db1fec 100644 --- a/apps/www/public/registry/styles/new-york/alert.json +++ b/apps/www/public/registry/styles/new-york/alert.json @@ -3,7 +3,7 @@ "files": [ { "name": "alert.tsx", - "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border px-4 py-3 text-sm [&:has(svg)]:pl-11 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes & VariantProps\n>(({ className, variant, ...props }, ref) => (\n \n))\nAlert.displayName = \"Alert\"\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertTitle.displayName = \"AlertTitle\"\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertDescription.displayName = \"AlertDescription\"\n\nexport { Alert, AlertTitle, AlertDescription }\n" + "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes & VariantProps\n>(({ className, variant, ...props }, ref) => (\n \n))\nAlert.displayName = \"Alert\"\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertTitle.displayName = \"AlertTitle\"\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes\n>(({ className, ...props }, ref) => (\n \n))\nAlertDescription.displayName = \"AlertDescription\"\n\nexport { Alert, AlertTitle, AlertDescription }\n" } ], "type": "components:ui" diff --git a/apps/www/registry/default/example/combobox-form.tsx b/apps/www/registry/default/example/combobox-form.tsx index 3a778ad1c54..c1a3ea94449 100644 --- a/apps/www/registry/default/example/combobox-form.tsx +++ b/apps/www/registry/default/example/combobox-form.tsx @@ -100,10 +100,10 @@ export default function ComboboxForm() { {languages.map((language) => ( { - form.setValue("language", value) + onSelect={() => { + form.setValue("language", language.value) }} > { const down = (e: KeyboardEvent) => { - if (e.key === "j" && e.metaKey) { + if (e.key === "j" && (e.metaKey || e.ctrlKey)) { + e.preventDefault() setOpen((open) => !open) } } diff --git a/apps/www/registry/default/ui/alert.tsx b/apps/www/registry/default/ui/alert.tsx index b2730b3c45f..41fa7e0561a 100644 --- a/apps/www/registry/default/ui/alert.tsx +++ b/apps/www/registry/default/ui/alert.tsx @@ -4,7 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const alertVariants = cva( - "relative w-full rounded-lg border p-4 [&:has(svg)]:pl-11 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", + "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", { variants: { variant: { diff --git a/apps/www/registry/default/ui/card.tsx b/apps/www/registry/default/ui/card.tsx index 47dc8358051..afa13ecfa3b 100644 --- a/apps/www/registry/default/ui/card.tsx +++ b/apps/www/registry/default/ui/card.tsx @@ -70,7 +70,7 @@ const CardFooter = React.forwardRef< >(({ className, ...props }, ref) => (
)) diff --git a/apps/www/registry/new-york/example/combobox-form.tsx b/apps/www/registry/new-york/example/combobox-form.tsx index bedee428d6d..fdff7e2087d 100644 --- a/apps/www/registry/new-york/example/combobox-form.tsx +++ b/apps/www/registry/new-york/example/combobox-form.tsx @@ -103,10 +103,10 @@ export default function ComboboxForm() { {languages.map((language) => ( { - form.setValue("language", value) + onSelect={() => { + form.setValue("language", language.value) }} > {language.label} diff --git a/apps/www/registry/new-york/example/command-dialog.tsx b/apps/www/registry/new-york/example/command-dialog.tsx index abb11c67ba8..a40ff3cb9c7 100644 --- a/apps/www/registry/new-york/example/command-dialog.tsx +++ b/apps/www/registry/new-york/example/command-dialog.tsx @@ -26,7 +26,8 @@ export default function CommandDialogDemo() { React.useEffect(() => { const down = (e: KeyboardEvent) => { - if (e.key === "j" && e.metaKey) { + if (e.key === "j" && (e.metaKey || e.ctrlKey)) { + e.preventDefault() setOpen((open) => !open) } } diff --git a/apps/www/registry/new-york/ui/alert.tsx b/apps/www/registry/new-york/ui/alert.tsx index 863d8fc3d91..9188e7402d9 100644 --- a/apps/www/registry/new-york/ui/alert.tsx +++ b/apps/www/registry/new-york/ui/alert.tsx @@ -4,7 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const alertVariants = cva( - "relative w-full rounded-lg border px-4 py-3 text-sm [&:has(svg)]:pl-11 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", + "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", { variants: { variant: { diff --git a/apps/www/registry/new-york/ui/card.tsx b/apps/www/registry/new-york/ui/card.tsx index 9f7e6083b11..77e9fb789bf 100644 --- a/apps/www/registry/new-york/ui/card.tsx +++ b/apps/www/registry/new-york/ui/card.tsx @@ -67,7 +67,7 @@ const CardFooter = React.forwardRef< >(({ className, ...props }, ref) => (
)) diff --git a/templates/next-template/next.config.mjs b/templates/next-template/next.config.mjs index b561a91ebdf..94be31c3d55 100644 --- a/templates/next-template/next.config.mjs +++ b/templates/next-template/next.config.mjs @@ -1,9 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, - experimental: { - appDir: true, - }, } export default nextConfig