diff --git a/apps/v4/app/(app)/(root)/components/appearance-settings.tsx b/apps/v4/app/(app)/(root)/components/appearance-settings.tsx index ea0df5091a..782129ec70 100644 --- a/apps/v4/app/(app)/(root)/components/appearance-settings.tsx +++ b/apps/v4/app/(app)/(root)/components/appearance-settings.tsx @@ -1,10 +1,8 @@ "use client" import * as React from "react" -import { IconMinus, IconPlus } from "@tabler/icons-react" - -import { Button } from "@/registry/new-york-v4/ui/button" -import { ButtonGroup } from "@/registry/new-york-v4/ui/button-group" +import { Button } from "@/examples/radix/ui/button" +import { ButtonGroup } from "@/examples/radix/ui/button-group" import { Field, FieldContent, @@ -15,13 +13,11 @@ import { FieldSeparator, FieldSet, FieldTitle, -} from "@/registry/new-york-v4/ui/field" -import { Input } from "@/registry/new-york-v4/ui/input" -import { - RadioGroup, - RadioGroupItem, -} from "@/registry/new-york-v4/ui/radio-group" -import { Switch } from "@/registry/new-york-v4/ui/switch" +} from "@/examples/radix/ui/field" +import { Input } from "@/examples/radix/ui/input" +import { RadioGroup, RadioGroupItem } from "@/examples/radix/ui/radio-group" +import { Switch } from "@/examples/radix/ui/switch" +import { IconMinus, IconPlus } from "@tabler/icons-react" export function AppearanceSettings() { const [gpuCount, setGpuCount] = React.useState(8) diff --git a/apps/v4/app/(app)/(root)/components/button-group-demo.tsx b/apps/v4/app/(app)/(root)/components/button-group-demo.tsx index 2f50d8ac8f..bdf259d1d5 100644 --- a/apps/v4/app/(app)/(root)/components/button-group-demo.tsx +++ b/apps/v4/app/(app)/(root)/components/button-group-demo.tsx @@ -1,20 +1,8 @@ "use client" import * as React from "react" -import { - ArchiveIcon, - ArrowLeftIcon, - CalendarPlusIcon, - ClockIcon, - ListFilterIcon, - MailCheckIcon, - MoreHorizontalIcon, - TagIcon, - Trash2Icon, -} from "lucide-react" - -import { Button } from "@/registry/new-york-v4/ui/button" -import { ButtonGroup } from "@/registry/new-york-v4/ui/button-group" +import { Button } from "@/examples/radix/ui/button" +import { ButtonGroup } from "@/examples/radix/ui/button-group" import { DropdownMenu, DropdownMenuContent, @@ -27,7 +15,18 @@ import { DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, -} from "@/registry/new-york-v4/ui/dropdown-menu" +} from "@/examples/radix/ui/dropdown-menu" +import { + ArchiveIcon, + ArrowLeftIcon, + CalendarPlusIcon, + ClockIcon, + ListFilterIcon, + MailCheckIcon, + MoreHorizontalIcon, + TagIcon, + Trash2Icon, +} from "lucide-react" export function ButtonGroupDemo() { const [label, setLabel] = React.useState("personal") diff --git a/apps/v4/app/(app)/(root)/components/button-group-input-group.tsx b/apps/v4/app/(app)/(root)/components/button-group-input-group.tsx index 0120a22901..4fd4a4d964 100644 --- a/apps/v4/app/(app)/(root)/components/button-group-input-group.tsx +++ b/apps/v4/app/(app)/(root)/components/button-group-input-group.tsx @@ -1,21 +1,20 @@ "use client" import * as React from "react" -import { AudioLinesIcon, PlusIcon } from "lucide-react" - -import { Button } from "@/registry/new-york-v4/ui/button" -import { ButtonGroup } from "@/registry/new-york-v4/ui/button-group" +import { Button } from "@/examples/radix/ui/button" +import { ButtonGroup } from "@/examples/radix/ui/button-group" import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, -} from "@/registry/new-york-v4/ui/input-group" +} from "@/examples/radix/ui/input-group" import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/registry/new-york-v4/ui/tooltip" +} from "@/examples/radix/ui/tooltip" +import { AudioLinesIcon, PlusIcon } from "lucide-react" export function ButtonGroupInputGroup() { const [voiceEnabled, setVoiceEnabled] = React.useState(false) diff --git a/apps/v4/app/(app)/(root)/components/button-group-nested.tsx b/apps/v4/app/(app)/(root)/components/button-group-nested.tsx index 44718e472e..e612ea740f 100644 --- a/apps/v4/app/(app)/(root)/components/button-group-nested.tsx +++ b/apps/v4/app/(app)/(root)/components/button-group-nested.tsx @@ -1,10 +1,9 @@ "use client" +import { Button } from "@/examples/radix/ui/button" +import { ButtonGroup } from "@/examples/radix/ui/button-group" import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react" -import { Button } from "@/registry/new-york-v4/ui/button" -import { ButtonGroup } from "@/registry/new-york-v4/ui/button-group" - export function ButtonGroupNested() { return ( diff --git a/apps/v4/app/(app)/(root)/components/button-group-popover.tsx b/apps/v4/app/(app)/(root)/components/button-group-popover.tsx index 972aa0b4ce..cbc11df9dc 100644 --- a/apps/v4/app/(app)/(root)/components/button-group-popover.tsx +++ b/apps/v4/app/(app)/(root)/components/button-group-popover.tsx @@ -1,14 +1,13 @@ -import { BotIcon, ChevronDownIcon } from "lucide-react" - -import { Button } from "@/registry/new-york-v4/ui/button" -import { ButtonGroup } from "@/registry/new-york-v4/ui/button-group" +import { Button } from "@/examples/radix/ui/button" +import { ButtonGroup } from "@/examples/radix/ui/button-group" import { Popover, PopoverContent, PopoverTrigger, -} from "@/registry/new-york-v4/ui/popover" -import { Separator } from "@/registry/new-york-v4/ui/separator" -import { Textarea } from "@/registry/new-york-v4/ui/textarea" +} from "@/examples/radix/ui/popover" +import { Separator } from "@/examples/radix/ui/separator" +import { Textarea } from "@/examples/radix/ui/textarea" +import { BotIcon, ChevronDownIcon } from "lucide-react" export function ButtonGroupPopover() { return ( diff --git a/apps/v4/app/(app)/(root)/components/empty-avatar-group.tsx b/apps/v4/app/(app)/(root)/components/empty-avatar-group.tsx index fdc0b96060..1fb96e4731 100644 --- a/apps/v4/app/(app)/(root)/components/empty-avatar-group.tsx +++ b/apps/v4/app/(app)/(root)/components/empty-avatar-group.tsx @@ -1,11 +1,5 @@ -import { PlusIcon } from "lucide-react" - -import { - Avatar, - AvatarFallback, - AvatarImage, -} from "@/registry/new-york-v4/ui/avatar" -import { Button } from "@/registry/new-york-v4/ui/button" +import { Avatar, AvatarFallback, AvatarImage } from "@/examples/radix/ui/avatar" +import { Button } from "@/examples/radix/ui/button" import { Empty, EmptyContent, @@ -13,7 +7,8 @@ import { EmptyHeader, EmptyMedia, EmptyTitle, -} from "@/registry/new-york-v4/ui/empty" +} from "@/examples/radix/ui/empty" +import { PlusIcon } from "lucide-react" export function EmptyAvatarGroup() { return ( diff --git a/apps/v4/app/(app)/(root)/components/field-checkbox.tsx b/apps/v4/app/(app)/(root)/components/field-checkbox.tsx index e7d9778ad0..595cac1f41 100644 --- a/apps/v4/app/(app)/(root)/components/field-checkbox.tsx +++ b/apps/v4/app/(app)/(root)/components/field-checkbox.tsx @@ -1,5 +1,5 @@ -import { Checkbox } from "@/registry/new-york-v4/ui/checkbox" -import { Field, FieldLabel } from "@/registry/new-york-v4/ui/field" +import { Checkbox } from "@/examples/radix/ui/checkbox" +import { Field, FieldLabel } from "@/examples/radix/ui/field" export function FieldCheckbox() { return ( diff --git a/apps/v4/app/(app)/(root)/components/field-demo.tsx b/apps/v4/app/(app)/(root)/components/field-demo.tsx index 426f09a146..795129225d 100644 --- a/apps/v4/app/(app)/(root)/components/field-demo.tsx +++ b/apps/v4/app/(app)/(root)/components/field-demo.tsx @@ -1,5 +1,5 @@ -import { Button } from "@/registry/new-york-v4/ui/button" -import { Checkbox } from "@/registry/new-york-v4/ui/checkbox" +import { Button } from "@/examples/radix/ui/button" +import { Checkbox } from "@/examples/radix/ui/checkbox" import { Field, FieldDescription, @@ -8,16 +8,16 @@ import { FieldLegend, FieldSeparator, FieldSet, -} from "@/registry/new-york-v4/ui/field" -import { Input } from "@/registry/new-york-v4/ui/input" +} from "@/examples/radix/ui/field" +import { Input } from "@/examples/radix/ui/input" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/registry/new-york-v4/ui/select" -import { Textarea } from "@/registry/new-york-v4/ui/textarea" +} from "@/examples/radix/ui/select" +import { Textarea } from "@/examples/radix/ui/textarea" export function FieldDemo() { return ( diff --git a/apps/v4/app/(app)/(root)/components/field-hear.tsx b/apps/v4/app/(app)/(root)/components/field-hear.tsx index 824df31cc9..ad28d31289 100644 --- a/apps/v4/app/(app)/(root)/components/field-hear.tsx +++ b/apps/v4/app/(app)/(root)/components/field-hear.tsx @@ -1,5 +1,5 @@ -import { Card, CardContent } from "@/registry/new-york-v4/ui/card" -import { Checkbox } from "@/registry/new-york-v4/ui/checkbox" +import { Card, CardContent } from "@/examples/radix/ui/card" +import { Checkbox } from "@/examples/radix/ui/checkbox" import { Field, FieldDescription, @@ -8,7 +8,7 @@ import { FieldLegend, FieldSet, FieldTitle, -} from "@/registry/new-york-v4/ui/field" +} from "@/examples/radix/ui/field" const options = [ { diff --git a/apps/v4/app/(app)/(root)/components/field-slider.tsx b/apps/v4/app/(app)/(root)/components/field-slider.tsx index 20dec76e3f..b2ab12306c 100644 --- a/apps/v4/app/(app)/(root)/components/field-slider.tsx +++ b/apps/v4/app/(app)/(root)/components/field-slider.tsx @@ -1,13 +1,8 @@ "use client" import { useState } from "react" - -import { - Field, - FieldDescription, - FieldTitle, -} from "@/registry/new-york-v4/ui/field" -import { Slider } from "@/registry/new-york-v4/ui/slider" +import { Field, FieldDescription, FieldTitle } from "@/examples/radix/ui/field" +import { Slider } from "@/examples/radix/ui/slider" export function FieldSlider() { const [value, setValue] = useState([200, 800]) diff --git a/apps/v4/app/(app)/(root)/components/index.tsx b/apps/v4/app/(app)/(root)/components/index.tsx index 6439367be6..4c8bc44880 100644 --- a/apps/v4/app/(app)/(root)/components/index.tsx +++ b/apps/v4/app/(app)/(root)/components/index.tsx @@ -1,4 +1,4 @@ -import { FieldSeparator } from "@/registry/new-york-v4/ui/field" +import { FieldSeparator } from "@/examples/radix/ui/field" import { AppearanceSettings } from "./appearance-settings" import { ButtonGroupDemo } from "./button-group-demo" diff --git a/apps/v4/app/(app)/(root)/components/input-group-button.tsx b/apps/v4/app/(app)/(root)/components/input-group-button.tsx index dfe639afe5..f6fcf4db60 100644 --- a/apps/v4/app/(app)/(root)/components/input-group-button.tsx +++ b/apps/v4/app/(app)/(root)/components/input-group-button.tsx @@ -1,20 +1,19 @@ "use client" import * as React from "react" -import { IconInfoCircle, IconStar } from "@tabler/icons-react" - import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, -} from "@/registry/new-york-v4/ui/input-group" -import { Label } from "@/registry/new-york-v4/ui/label" +} from "@/examples/radix/ui/input-group" +import { Label } from "@/examples/radix/ui/label" import { Popover, PopoverContent, PopoverTrigger, -} from "@/registry/new-york-v4/ui/popover" +} from "@/examples/radix/ui/popover" +import { IconInfoCircle, IconStar } from "@tabler/icons-react" export function InputGroupButtonExample() { const [isFavorite, setIsFavorite] = React.useState(false) diff --git a/apps/v4/app/(app)/(root)/components/input-group-demo.tsx b/apps/v4/app/(app)/(root)/components/input-group-demo.tsx index f0bab1fdd4..1321c001e0 100644 --- a/apps/v4/app/(app)/(root)/components/input-group-demo.tsx +++ b/apps/v4/app/(app)/(root)/components/input-group-demo.tsx @@ -1,12 +1,9 @@ -import { IconCheck, IconInfoCircle, IconPlus } from "@tabler/icons-react" -import { ArrowUpIcon, Search } from "lucide-react" - import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from "@/registry/new-york-v4/ui/dropdown-menu" +} from "@/examples/radix/ui/dropdown-menu" import { InputGroup, InputGroupAddon, @@ -14,13 +11,15 @@ import { InputGroupInput, InputGroupText, InputGroupTextarea, -} from "@/registry/new-york-v4/ui/input-group" -import { Separator } from "@/registry/new-york-v4/ui/separator" +} from "@/examples/radix/ui/input-group" +import { Separator } from "@/examples/radix/ui/separator" import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/registry/new-york-v4/ui/tooltip" +} from "@/examples/radix/ui/tooltip" +import { IconCheck, IconInfoCircle, IconPlus } from "@tabler/icons-react" +import { ArrowUpIcon, Search } from "lucide-react" export function InputGroupDemo() { return ( diff --git a/apps/v4/app/(app)/(root)/components/item-demo.tsx b/apps/v4/app/(app)/(root)/components/item-demo.tsx index 75d125f473..2c97c53e99 100644 --- a/apps/v4/app/(app)/(root)/components/item-demo.tsx +++ b/apps/v4/app/(app)/(root)/components/item-demo.tsx @@ -1,6 +1,4 @@ -import { BadgeCheckIcon, ChevronRightIcon } from "lucide-react" - -import { Button } from "@/registry/new-york-v4/ui/button" +import { Button } from "@/examples/radix/ui/button" import { Item, ItemActions, @@ -8,7 +6,8 @@ import { ItemDescription, ItemMedia, ItemTitle, -} from "@/registry/new-york-v4/ui/item" +} from "@/examples/radix/ui/item" +import { BadgeCheckIcon, ChevronRightIcon } from "lucide-react" export function ItemDemo() { return ( diff --git a/apps/v4/app/(app)/(root)/components/notion-prompt-form.tsx b/apps/v4/app/(app)/(root)/components/notion-prompt-form.tsx index cd56c7bf10..242878f8a3 100644 --- a/apps/v4/app/(app)/(root)/components/notion-prompt-form.tsx +++ b/apps/v4/app/(app)/(root)/components/notion-prompt-form.tsx @@ -1,24 +1,8 @@ "use client" import { useMemo, useState } from "react" -import { - IconApps, - IconArrowUp, - IconAt, - IconBook, - IconCircleDashedPlus, - IconPaperclip, - IconPlus, - IconWorld, - IconX, -} from "@tabler/icons-react" - -import { - Avatar, - AvatarFallback, - AvatarImage, -} from "@/registry/new-york-v4/ui/avatar" -import { Badge } from "@/registry/new-york-v4/ui/badge" +import { Avatar, AvatarFallback, AvatarImage } from "@/examples/radix/ui/avatar" +import { Badge } from "@/examples/radix/ui/badge" import { Command, CommandEmpty, @@ -26,7 +10,7 @@ import { CommandInput, CommandItem, CommandList, -} from "@/registry/new-york-v4/ui/command" +} from "@/examples/radix/ui/command" import { DropdownMenu, DropdownMenuCheckboxItem, @@ -39,25 +23,36 @@ import { DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, -} from "@/registry/new-york-v4/ui/dropdown-menu" -import { Field, FieldLabel } from "@/registry/new-york-v4/ui/field" +} from "@/examples/radix/ui/dropdown-menu" +import { Field, FieldLabel } from "@/examples/radix/ui/field" import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea, -} from "@/registry/new-york-v4/ui/input-group" +} from "@/examples/radix/ui/input-group" import { Popover, PopoverContent, PopoverTrigger, -} from "@/registry/new-york-v4/ui/popover" -import { Switch } from "@/registry/new-york-v4/ui/switch" +} from "@/examples/radix/ui/popover" +import { Switch } from "@/examples/radix/ui/switch" import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/registry/new-york-v4/ui/tooltip" +} from "@/examples/radix/ui/tooltip" +import { + IconApps, + IconArrowUp, + IconAt, + IconBook, + IconCircleDashedPlus, + IconPaperclip, + IconPlus, + IconWorld, + IconX, +} from "@tabler/icons-react" const SAMPLE_DATA = { mentionable: [ diff --git a/apps/v4/app/(app)/(root)/components/spinner-badge.tsx b/apps/v4/app/(app)/(root)/components/spinner-badge.tsx index b6116547b9..3bff547115 100644 --- a/apps/v4/app/(app)/(root)/components/spinner-badge.tsx +++ b/apps/v4/app/(app)/(root)/components/spinner-badge.tsx @@ -1,5 +1,5 @@ -import { Badge } from "@/registry/new-york-v4/ui/badge" -import { Spinner } from "@/registry/new-york-v4/ui/spinner" +import { Badge } from "@/examples/radix/ui/badge" +import { Spinner } from "@/examples/radix/ui/spinner" export function SpinnerBadge() { return ( diff --git a/apps/v4/app/(app)/(root)/components/spinner-empty.tsx b/apps/v4/app/(app)/(root)/components/spinner-empty.tsx index b1f1a6f540..1ff6b0b8b2 100644 --- a/apps/v4/app/(app)/(root)/components/spinner-empty.tsx +++ b/apps/v4/app/(app)/(root)/components/spinner-empty.tsx @@ -1,4 +1,4 @@ -import { Button } from "@/registry/new-york-v4/ui/button" +import { Button } from "@/examples/radix/ui/button" import { Empty, EmptyContent, @@ -6,8 +6,8 @@ import { EmptyHeader, EmptyMedia, EmptyTitle, -} from "@/registry/new-york-v4/ui/empty" -import { Spinner } from "@/registry/new-york-v4/ui/spinner" +} from "@/examples/radix/ui/empty" +import { Spinner } from "@/examples/radix/ui/spinner" export function SpinnerEmpty() { return ( diff --git a/apps/v4/app/(app)/charts/layout.tsx b/apps/v4/app/(app)/charts/layout.tsx index 3c5746b7f0..52bfd82dc4 100644 --- a/apps/v4/app/(app)/charts/layout.tsx +++ b/apps/v4/app/(app)/charts/layout.tsx @@ -64,7 +64,7 @@ export default function ChartsLayout({ -
+
{children}
diff --git a/apps/v4/app/(app)/docs/[[...slug]]/page.tsx b/apps/v4/app/(app)/docs/[[...slug]]/page.tsx index f700a3c5b7..34aa1e0f05 100644 --- a/apps/v4/app/(app)/docs/[[...slug]]/page.tsx +++ b/apps/v4/app/(app)/docs/[[...slug]]/page.tsx @@ -1,21 +1,15 @@ import Link from "next/link" import { notFound } from "next/navigation" import { mdxComponents } from "@/mdx-components" -import { - IconArrowLeft, - IconArrowRight, - IconArrowUpRight, -} from "@tabler/icons-react" -import fm from "front-matter" +import { IconArrowLeft, IconArrowRight } from "@tabler/icons-react" import { findNeighbour } from "fumadocs-core/page-tree" -import z from "zod" import { source } from "@/lib/source" import { absoluteUrl } from "@/lib/utils" +import { DocsBaseSwitcher } from "@/components/docs-base-switcher" import { DocsCopyPage } from "@/components/docs-copy-page" import { DocsTableOfContents } from "@/components/docs-toc" import { OpenInV0Cta } from "@/components/open-in-v0-cta" -import { Badge } from "@/registry/new-york-v4/ui/badge" import { Button } from "@/registry/new-york-v4/ui/button" export const revalidate = false @@ -86,126 +80,110 @@ export default async function Page(props: { const doc = page.data const MDX = doc.body const neighbours = findNeighbour(source.pageTree, page.url) - const raw = await page.data.getText("raw") - const { attributes } = fm(raw) - const { links } = z - .object({ - links: z - .object({ - doc: z.string().optional(), - api: z.string().optional(), - }) - .optional(), - }) - .parse(attributes) return ( -
+
-
+
-

+

{doc.title}

-
+
- {neighbours.previous && ( - - )} - {neighbours.next && ( - - )} +
+ {neighbours.previous && ( + + )} + {neighbours.next && ( + + )} +
{doc.description && ( -

+

{doc.description}

)}
- {links ? ( -
- {links?.doc && ( - - - Docs - - - )} - {links?.api && ( - - - API Reference - - - )} -
- ) : null}
-
+
+ {params.slug && + params.slug[0] === "components" && + params.slug[1] && + params.slug[2] && ( + + )}
-
-
- {neighbours.previous && ( - - )} - {neighbours.next && ( - - )} +
+ {neighbours.previous && ( + + )} + {neighbours.next && ( + + )} +
-
-
+
+
{doc.toc?.length ? ( -
+
-
) : null} -
+
diff --git a/apps/v4/app/(app)/docs/layout.tsx b/apps/v4/app/(app)/docs/layout.tsx index 65e202a987..339c2ca804 100644 --- a/apps/v4/app/(app)/docs/layout.tsx +++ b/apps/v4/app/(app)/docs/layout.tsx @@ -9,7 +9,10 @@ export default function DocsLayout({ }) { return (
- +
{children}
diff --git a/apps/v4/app/(app)/llm/[[...slug]]/route.ts b/apps/v4/app/(app)/llm/[[...slug]]/route.ts index b50339de4d..78390a5d1f 100644 --- a/apps/v4/app/(app)/llm/[[...slug]]/route.ts +++ b/apps/v4/app/(app)/llm/[[...slug]]/route.ts @@ -3,10 +3,23 @@ import { NextResponse, type NextRequest } from "next/server" import { processMdxForLLMs } from "@/lib/llm" import { source } from "@/lib/source" -import { getActiveStyle } from "@/registry/_legacy-styles" +import { getActiveStyle, type Style } from "@/registry/_legacy-styles" export const revalidate = false +function getStyleFromSlug(slug: string[] | undefined, fallbackStyle: string) { + // Detect base from URL: /docs/components/base/... or /docs/components/radix/... + if (slug && slug[0] === "components" && slug[1]) { + if (slug[1] === "base") { + return "base-nova" + } + if (slug[1] === "radix") { + return "new-york-v4" + } + } + return fallbackStyle +} + export async function GET( _req: NextRequest, { params }: { params: Promise<{ slug?: string[] }> } @@ -19,9 +32,11 @@ export async function GET( notFound() } + const effectiveStyle = getStyleFromSlug(slug, activeStyle.name) + const processedContent = processMdxForLLMs( await page.data.getText("raw"), - activeStyle.name + effectiveStyle as Style["name"] ) return new NextResponse(processedContent, { diff --git a/apps/v4/app/(create)/components/item-picker.tsx b/apps/v4/app/(create)/components/item-picker.tsx index 7dcf9bd73d..e742c11a8f 100644 --- a/apps/v4/app/(create)/components/item-picker.tsx +++ b/apps/v4/app/(create)/components/item-picker.tsx @@ -99,7 +99,7 @@ export function ItemPicker({ variant="outline" aria-label="Select item" size="sm" - className="data-popup-open:bg-muted dark:data-popup-open:bg-muted/50 bg-muted/50 sm:bg-background md:dark:bg-background border-foreground/10 dark:bg-muted/50 h-[calc(--spacing(13.5))] flex-1 touch-manipulation justify-between gap-2 rounded-xl pr-4! pl-2.5 text-left shadow-none select-none *:data-[slot=combobox-trigger-icon]:hidden sm:h-8 sm:max-w-56 sm:rounded-lg sm:pr-2! xl:max-w-md" + className="data-popup-open:bg-muted dark:data-popup-open:bg-muted/50 bg-muted/50 sm:bg-background md:dark:bg-background border-foreground/10 dark:bg-muted/50 h-[calc(--spacing(13.5))] flex-1 touch-manipulation justify-between gap-2 rounded-xl pr-4! pl-2.5 text-left shadow-none select-none *:data-[slot=combobox-trigger-icon]:hidden sm:h-8 sm:max-w-56 sm:rounded-lg sm:pr-2! xl:max-w-64" /> } > @@ -123,9 +123,9 @@ export function ItemPicker({ {hasCopied ? ( @@ -64,7 +64,7 @@ export function ShareButton() { ) : ( )} - Share + Share Copy Link diff --git a/apps/v4/app/(create)/components/v0-button.tsx b/apps/v4/app/(create)/components/v0-button.tsx index cdf7ea36b7..f716e31ca0 100644 --- a/apps/v4/app/(create)/components/v0-button.tsx +++ b/apps/v4/app/(create)/components/v0-button.tsx @@ -14,7 +14,7 @@ import { import { useDesignSystemSearchParams } from "@/app/(create)/lib/search-params" export function V0Button({ className }: { className?: string }) { - const [params, setParams] = useDesignSystemSearchParams() + const [params] = useDesignSystemSearchParams() const isMobile = useIsMobile() const isMounted = useMounted() @@ -32,7 +32,7 @@ export function V0Button({ className }: { className?: string }) { size="sm" variant={isMobile ? "default" : "outline"} className={cn( - "w-24 rounded-lg shadow-none data-[variant=default]:h-[31px]", + "w-24 rounded-lg shadow-none data-[variant=default]:h-[31px] lg:w-8 xl:w-24", className )} asChild @@ -41,7 +41,8 @@ export function V0Button({ className }: { className?: string }) { href={`${process.env.NEXT_PUBLIC_V0_URL}/chat/api/open?url=${encodeURIComponent(url)}&title=${params.item}`} target="_blank" > - Open in + Open in + diff --git a/apps/v4/app/(create)/create/page.tsx b/apps/v4/app/(create)/create/page.tsx index 81887852b9..b3d69ac579 100644 --- a/apps/v4/app/(create)/create/page.tsx +++ b/apps/v4/app/(create)/create/page.tsx @@ -4,7 +4,11 @@ import { ArrowLeftIcon } from "lucide-react" import type { SearchParams } from "nuqs/server" import { siteConfig } from "@/lib/config" +import { source } from "@/lib/source" import { absoluteUrl } from "@/lib/utils" +import { Icons } from "@/components/icons" +import { MainNav } from "@/components/main-nav" +import { MobileNav } from "@/components/mobile-nav" import { ModeSwitcher } from "@/components/mode-switcher" import { SiteConfig } from "@/components/site-config" import { BASES } from "@/registry/config" @@ -64,6 +68,7 @@ export default async function CreatePage({ const params = await loadDesignSystemSearchParams(searchParams) const base = BASES.find((b) => b.name === params.base) ?? BASES[0] + const pageTree = source.pageTree const items = await getItemsForBase(base.name) const filteredItems = items @@ -82,38 +87,34 @@ export default async function CreatePage({
-
+
+ - -
- New Project -
+
-
+
- +
-
+
diff --git a/apps/v4/app/(view)/view/[style]/[name]/page.tsx b/apps/v4/app/(view)/view/[style]/[name]/page.tsx index 77761346df..f0ee545d50 100644 --- a/apps/v4/app/(view)/view/[style]/[name]/page.tsx +++ b/apps/v4/app/(view)/view/[style]/[name]/page.tsx @@ -4,7 +4,11 @@ import { type Metadata } from "next" import { notFound } from "next/navigation" import { siteConfig } from "@/lib/config" -import { getRegistryComponent, getRegistryItem } from "@/lib/registry" +import { + getDemoItem, + getRegistryComponent, + getRegistryItem, +} from "@/lib/registry" import { absoluteUrl } from "@/lib/utils" import { getStyle, legacyStyles, type Style } from "@/registry/_legacy-styles" @@ -18,7 +22,12 @@ export const dynamicParams = false const getCachedRegistryItem = React.cache( async (name: string, styleName: Style["name"]) => { - return await getRegistryItem(name, styleName) + // Try registry item first, then fallback to demo item (for examples). + const item = await getRegistryItem(name, styleName) + if (item) { + return item + } + return await getDemoItem(name, styleName) } ) @@ -75,9 +84,54 @@ export async function generateMetadata({ export async function generateStaticParams() { const { Index } = await import("@/registry/__index__") + // const { Index: BasesIndex } = await import("@/registry/bases/__index__") + const { ExamplesIndex } = await import("@/examples/__index__") const params: Array<{ style: string; name: string }> = [] for (const style of legacyStyles) { + // Check if this is a base-prefixed style (e.g., base-nova, radix-nova). + const baseMatch = style.name.match(/^(base|radix)-/) + if (baseMatch) { + const baseName = baseMatch[1] + + // Add examples from ExamplesIndex. + const examples = ExamplesIndex[baseName] + if (examples) { + for (const exampleName of Object.keys(examples)) { + if (exampleName.startsWith("sidebar-")) { + params.push({ + style: style.name, + name: exampleName, + }) + } + } + } + + // // Add UI components from BasesIndex. + // const baseIndex = BasesIndex[baseName] + // if (baseIndex) { + // for (const itemName in baseIndex) { + // const item = baseIndex[itemName] + // if ( + // [ + // "registry:block", + // "registry:component", + // "registry:example", + // "registry:internal", + // ].includes(item.type) + // ) { + // params.push({ + // style: style.name, + // name: item.name, + // }) + // } + // } + // } + + continue + } + + // Handle legacy styles (e.g., new-york-v4). if (!Index[style.name]) { continue } diff --git a/apps/v4/components/announcement.tsx b/apps/v4/components/announcement.tsx index bf85673ede..34d6e0e2b4 100644 --- a/apps/v4/components/announcement.tsx +++ b/apps/v4/components/announcement.tsx @@ -3,12 +3,27 @@ import { ArrowRightIcon } from "lucide-react" import { Badge } from "@/registry/new-york-v4/ui/badge" +function BaseUILogo() { + return ( + + + + + ) +} + export function Announcement() { return ( - - npx shadcn create + + Base UI Documentation ) diff --git a/apps/v4/components/chart-display.tsx b/apps/v4/components/chart-display.tsx index 26bc60fa16..637da1c87f 100644 --- a/apps/v4/components/chart-display.tsx +++ b/apps/v4/components/chart-display.tsx @@ -35,7 +35,7 @@ export function ChartDisplay({
diff --git a/apps/v4/components/code-tabs.tsx b/apps/v4/components/code-tabs.tsx index 98c48bf768..e6b9289589 100644 --- a/apps/v4/components/code-tabs.tsx +++ b/apps/v4/components/code-tabs.tsx @@ -18,7 +18,7 @@ export function CodeTabs({ children }: React.ComponentProps) { onValueChange={(value) => setConfig({ ...config, installationType: value as "cli" | "manual" }) } - className="relative mt-6 w-full" + className="relative mt-6 w-full *:data-[slot=tabs-list]:gap-6" > {children} diff --git a/apps/v4/components/command-menu.tsx b/apps/v4/components/command-menu.tsx index 7d7fbb60ce..cd6d65b123 100644 --- a/apps/v4/components/command-menu.tsx +++ b/apps/v4/components/command-menu.tsx @@ -1,15 +1,17 @@ "use client" import * as React from "react" -import { useRouter } from "next/navigation" +import { usePathname, useRouter } from "next/navigation" import { type DialogProps } from "@radix-ui/react-dialog" +import * as DialogPrimitive from "@radix-ui/react-dialog" import { IconArrowRight } from "@tabler/icons-react" import { useDocsSearch } from "fumadocs-core/search/client" -import { CornerDownLeftIcon, SquareDashedIcon } from "lucide-react" +import { CornerDownLeftIcon, SquareDashedIcon, XIcon } from "lucide-react" import { type Color, type ColorPalette } from "@/lib/colors" import { trackEvent } from "@/lib/events" import { showMcpDocs } from "@/lib/flags" +import { getCurrentBase, getPagesFromFolder } from "@/lib/page-tree" import { type source } from "@/lib/source" import { cn } from "@/lib/utils" import { useConfig } from "@/hooks/use-config" @@ -26,13 +28,13 @@ import { } from "@/registry/new-york-v4/ui/command" import { Dialog, - DialogContent, DialogDescription, DialogHeader, + DialogPortal, DialogTitle, DialogTrigger, } from "@/registry/new-york-v4/ui/dialog" -import { Kbd, KbdGroup } from "@/registry/new-york-v4/ui/kbd" +import { Kbd } from "@/registry/new-york-v4/ui/kbd" import { Separator } from "@/registry/new-york-v4/ui/separator" import { Spinner } from "@/registry/new-york-v4/ui/spinner" @@ -49,7 +51,9 @@ export function CommandMenu({ navItems?: { href: string; label: string }[] }) { const router = useRouter() + const pathname = usePathname() const [config] = useConfig() + const currentBase = getCurrentBase(pathname) const [open, setOpen] = React.useState(false) const [selectedType, setSelectedType] = React.useState< "color" | "page" | "component" | "block" | null @@ -138,10 +142,13 @@ export function CommandMenu({ [setSelectedType, setCopyPayload, packageManager] ) - const runCommand = React.useCallback((command: () => unknown) => { - setOpen(false) - command() - }, []) + const runCommand = React.useCallback( + (command: () => unknown) => { + setOpen(false) + command() + }, + [setOpen] + ) React.useEffect(() => { const down = (e: KeyboardEvent) => { @@ -207,10 +214,7 @@ export function CommandMenu({
- + Search documentation... Search for a command to run... @@ -269,40 +273,37 @@ export function CommandMenu({ className="!p-0 [&_[cmdk-group-heading]]:scroll-mt-16 [&_[cmdk-group-heading]]:!p-3 [&_[cmdk-group-heading]]:!pb-1" > {group.type === "folder" && - group.children.map((item) => { - if (item.type === "page") { - const isComponent = item.url.includes("/components/") + getPagesFromFolder(group, currentBase).map((item) => { + const isComponent = item.url.includes("/components/") - if (!showMcpDocs && item.url.includes("/mcp")) { - return null - } - - return ( - - handlePageHighlight(isComponent, item) - } - onSelect={() => { - runCommand(() => router.push(item.url)) - }} - > - {isComponent ? ( -
- ) : ( - - )} - {item.name} - - ) + if (!showMcpDocs && item.url.includes("/mcp")) { + return null } - return null + + return ( + + handlePageHighlight(isComponent, item) + } + onSelect={() => { + runCommand(() => router.push(item.url)) + }} + > + {isComponent ? ( +
+ ) : ( + + )} + {item.name} + + ) })} ))} @@ -523,3 +524,30 @@ function SearchResults({ ) } + +function DialogContent({ + className, + children, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean +}) { + return ( + + + + {children} + + + ) +} diff --git a/apps/v4/components/component-preview-tabs.tsx b/apps/v4/components/component-preview-tabs.tsx index 50394234b2..ab53af6f78 100644 --- a/apps/v4/components/component-preview-tabs.tsx +++ b/apps/v4/components/component-preview-tabs.tsx @@ -3,9 +3,11 @@ import * as React from "react" import { cn } from "@/lib/utils" +import { Button } from "@/registry/new-york-v4/ui/button" export function ComponentPreviewTabs({ className, + previewClassName, align = "center", hideCode = false, chromeLessOnMobile = false, @@ -13,16 +15,19 @@ export function ComponentPreviewTabs({ source, ...props }: React.ComponentProps<"div"> & { + previewClassName?: string align?: "center" | "start" | "end" hideCode?: boolean chromeLessOnMobile?: boolean component: React.ReactNode source: React.ReactNode }) { + const [isMobileCodeVisible, setIsMobileCodeVisible] = React.useState(false) + return (
{component} @@ -40,9 +46,32 @@ export function ComponentPreviewTabs({ {!hideCode && (
{source} + {!isMobileCodeVisible && ( +
+
+ +
+ )}
)}
diff --git a/apps/v4/components/component-preview.tsx b/apps/v4/components/component-preview.tsx index a207dcb80f..b09cd68974 100644 --- a/apps/v4/components/component-preview.tsx +++ b/apps/v4/components/component-preview.tsx @@ -1,45 +1,33 @@ +import * as React from "react" import Image from "next/image" +import { getRegistryComponent } from "@/lib/registry" import { ComponentPreviewTabs } from "@/components/component-preview-tabs" import { ComponentSource } from "@/components/component-source" -import { Index } from "@/registry/__index__" -import { type Style } from "@/registry/_legacy-styles" export function ComponentPreview({ name, - styleName = "new-york-v4", type, className, + previewClassName, align = "center", hideCode = false, chromeLessOnMobile = false, + styleName = "new-york-v4", ...props }: React.ComponentProps<"div"> & { name: string - styleName?: Style["name"] + styleName?: string align?: "center" | "start" | "end" description?: string hideCode?: boolean type?: "block" | "component" | "example" chromeLessOnMobile?: boolean + previewClassName?: string }) { - const Component = Index[styleName]?.[name]?.component - - if (!Component) { - return ( -

- Component{" "} - - {name} - {" "} - not found in registry. -

- ) - } - if (type === "block") { return ( -
+
{name} + Component{" "} + + {name} + {" "} + not found in registry. +

+ ) + } + return ( } + component={} source={ ) } + +function DynamicComponent({ + name, + styleName, +}: { + name: string + styleName: string +}) { + const Component = React.useMemo( + () => getRegistryComponent(name, styleName), + [name, styleName] + ) + + if (!Component) { + return null + } + + return React.createElement(Component) +} diff --git a/apps/v4/components/component-source.tsx b/apps/v4/components/component-source.tsx index 55bf3acca3..a905557247 100644 --- a/apps/v4/components/component-source.tsx +++ b/apps/v4/components/component-source.tsx @@ -3,12 +3,12 @@ import path from "node:path" import * as React from "react" import { highlightCode } from "@/lib/highlight-code" -import { getRegistryItem } from "@/lib/registry" +import { getDemoItem, getRegistryItem } from "@/lib/registry" +import { formatCode } from "@/lib/rehype" import { cn } from "@/lib/utils" import { CodeCollapsibleWrapper } from "@/components/code-collapsible-wrapper" import { CopyButton } from "@/components/copy-button" import { getIconForLanguageExtension } from "@/components/icons" -import { type Style } from "@/registry/_legacy-styles" export async function ComponentSource({ name, @@ -24,7 +24,7 @@ export async function ComponentSource({ title?: string language?: string collapsible?: boolean - styleName?: Style["name"] + styleName?: string }) { if (!name && !src) { return null @@ -33,7 +33,9 @@ export async function ComponentSource({ let code: string | undefined if (name) { - const item = await getRegistryItem(name, styleName) + const item = + (await getDemoItem(name, styleName)) ?? + (await getRegistryItem(name, styleName)) code = item?.files?.[0]?.content } @@ -46,12 +48,7 @@ export async function ComponentSource({ return null } - // Fix imports. - // Replace @/registry/${style}/ with @/components/. - code = code.replaceAll(`@/registry/${styleName}/`, "@/components/") - - // Replace export default with export. - code = code.replaceAll("export default", "export") + code = await formatCode(code, styleName) code = code.replaceAll("/* eslint-disable react/no-children-prop */\n", "") const lang = language ?? title?.split(".").pop() ?? "tsx" diff --git a/apps/v4/components/components-list.tsx b/apps/v4/components/components-list.tsx index 6b3447f083..fb0e7ecd60 100644 --- a/apps/v4/components/components-list.tsx +++ b/apps/v4/components/components-list.tsx @@ -1,20 +1,16 @@ import Link from "next/link" import { PAGES_NEW } from "@/lib/docs" -import { source } from "@/lib/source" +import { getPagesFromFolder, type PageTreeFolder } from "@/lib/page-tree" -export function ComponentsList() { - const components = source.pageTree.children.find( - (page) => page.$id === "components" - ) - - if (components?.type !== "folder") { - return - } - - const list = components.children.filter( - (component) => component.type === "page" - ) +export function ComponentsList({ + componentsFolder, + currentBase, +}: { + componentsFolder: PageTreeFolder + currentBase: string +}) { + const list = getPagesFromFolder(componentsFolder, currentBase) return (
diff --git a/apps/v4/components/docs-base-switcher.tsx b/apps/v4/components/docs-base-switcher.tsx new file mode 100644 index 0000000000..e8c3487341 --- /dev/null +++ b/apps/v4/components/docs-base-switcher.tsx @@ -0,0 +1,39 @@ +import Link from "next/link" + +import { cn } from "@/lib/utils" +import { BASES } from "@/registry/bases" + +export function DocsBaseSwitcher({ + base, + component, + className, +}: { + base: string + component: string + className?: string +}) { + const activeBase = BASES.find((baseItem) => base === baseItem.name) + + return ( +
+ {BASES.map((baseItem) => ( + + {baseItem.title} + + ))} + {activeBase?.meta?.logo && ( +
+ )} +
+ ) +} diff --git a/apps/v4/components/docs-copy-page.tsx b/apps/v4/components/docs-copy-page.tsx index 0e53870297..4f8840e8d4 100644 --- a/apps/v4/components/docs-copy-page.tsx +++ b/apps/v4/components/docs-copy-page.tsx @@ -183,7 +183,10 @@ export function DocsCopyPage({ page, url }: { page: string; url: string }) { {trigger} - + {Object.entries(menuItems).map(([key, value]) => ( {value(url)} @@ -193,13 +196,13 @@ export function DocsCopyPage({ page, url }: { page: string; url: string }) { {trigger} {Object.entries(menuItems).map(([key, value]) => ( diff --git a/apps/v4/components/docs-page-links.tsx b/apps/v4/components/docs-page-links.tsx new file mode 100644 index 0000000000..5eb332938e --- /dev/null +++ b/apps/v4/components/docs-page-links.tsx @@ -0,0 +1,179 @@ +"use client" + +import { IconCheck, IconCopy } from "@tabler/icons-react" + +import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard" + +function getPromptUrl(baseURL: string, url: string) { + return `${baseURL}?q=${encodeURIComponent( + `I'm looking at this shadcn/ui documentation: ${url}. +Help me understand how to use it. Be ready to explain concepts, give examples, or help debug based on it. + ` + )}` +} + +export function DocsPageLinks({ page, url }: { page: string; url: string }) { + const { copyToClipboard, isCopied } = useCopyToClipboard() + + return ( +
+ +
+ ) +} diff --git a/apps/v4/components/docs-sidebar.tsx b/apps/v4/components/docs-sidebar.tsx index 79dce7005d..e944be29ee 100644 --- a/apps/v4/components/docs-sidebar.tsx +++ b/apps/v4/components/docs-sidebar.tsx @@ -5,6 +5,7 @@ import { usePathname } from "next/navigation" import { PAGES_NEW } from "@/lib/docs" import { showMcpDocs } from "@/lib/flags" +import { getCurrentBase, getPagesFromFolder } from "@/lib/page-tree" import type { source } from "@/lib/source" import { Sidebar, @@ -18,11 +19,15 @@ import { } from "@/registry/new-york-v4/ui/sidebar" const TOP_LEVEL_SECTIONS = [ - { name: "Get Started", href: "/docs" }, + { name: "Introduction", href: "/docs" }, { name: "Components", href: "/docs/components", }, + { + name: "Installation", + href: "/docs/installation", + }, { name: "Directory", href: "/docs/directory", @@ -31,6 +36,10 @@ const TOP_LEVEL_SECTIONS = [ name: "MCP Server", href: "/docs/mcp", }, + { + name: "Registry", + href: "/docs/registry", + }, { name: "Forms", href: "/docs/forms", @@ -48,10 +57,11 @@ export function DocsSidebar({ ...props }: React.ComponentProps & { tree: typeof source.pageTree }) { const pathname = usePathname() + const currentBase = getCurrentBase(pathname) return ( @@ -102,37 +112,34 @@ export function DocsSidebar({ {item.type === "folder" && ( - {item.children.map((item) => { - if ( - !showMcpDocs && - item.type === "page" && - item.url?.includes("/mcp") - ) { + {getPagesFromFolder(item, currentBase).map((page) => { + if (!showMcpDocs && page.url.includes("/mcp")) { + return null + } + + if (EXCLUDED_PAGES.includes(page.url)) { return null } return ( - item.type === "page" && - !EXCLUDED_PAGES.includes(item.url) && ( - - - - - {item.name} - {PAGES_NEW.includes(item.url) && ( - - )} - - - - ) + + + + + {page.name} + {PAGES_NEW.includes(page.url) && ( + + )} + + + ) })} diff --git a/apps/v4/components/docs-toc.tsx b/apps/v4/components/docs-toc.tsx index ff0803035a..555d049b58 100644 --- a/apps/v4/components/docs-toc.tsx +++ b/apps/v4/components/docs-toc.tsx @@ -107,7 +107,7 @@ export function DocsTableOfContents({ return (
-

+

On This Page

{toc.map((item) => ( diff --git a/apps/v4/components/mobile-nav.tsx b/apps/v4/components/mobile-nav.tsx index c9f425d057..87237b324f 100644 --- a/apps/v4/components/mobile-nav.tsx +++ b/apps/v4/components/mobile-nav.tsx @@ -2,10 +2,11 @@ import * as React from "react" import Link, { type LinkProps } from "next/link" -import { useRouter } from "next/navigation" +import { usePathname, useRouter } from "next/navigation" import { PAGES_NEW } from "@/lib/docs" import { showMcpDocs } from "@/lib/flags" +import { getCurrentBase, getPagesFromFolder } from "@/lib/page-tree" import { type source } from "@/lib/source" import { cn } from "@/lib/utils" import { Button } from "@/registry/new-york-v4/ui/button" @@ -16,11 +17,15 @@ import { } from "@/registry/new-york-v4/ui/popover" const TOP_LEVEL_SECTIONS = [ - { name: "Get Started", href: "/docs" }, + { name: "Introduction", href: "/docs" }, { name: "Components", href: "/docs/components", }, + { + name: "Installation", + href: "/docs/installation", + }, { name: "Directory", href: "/docs/directory", @@ -29,6 +34,10 @@ const TOP_LEVEL_SECTIONS = [ name: "MCP Server", href: "/docs/mcp", }, + { + name: "Registry", + href: "/docs/registry", + }, { name: "Forms", href: "/docs/forms", @@ -49,6 +58,8 @@ export function MobileNav({ className?: string }) { const [open, setOpen] = React.useState(false) + const pathname = usePathname() + const currentBase = getCurrentBase(pathname) return ( @@ -125,31 +136,30 @@ export function MobileNav({
{tree?.children?.map((group, index) => { if (group.type === "folder") { + const pages = getPagesFromFolder(group, currentBase) return (
{group.name}
- {group.children.map((item) => { - if (item.type === "page") { - if (!showMcpDocs && item.url.includes("/mcp")) { - return null - } - return ( - - {item.name}{" "} - {PAGES_NEW.includes(item.url) && ( - - )} - - ) + {pages.map((item) => { + if (!showMcpDocs && item.url.includes("/mcp")) { + return null } + return ( + + {item.name}{" "} + {PAGES_NEW.includes(item.url) && ( + + )} + + ) })}
diff --git a/apps/v4/components/site-footer.tsx b/apps/v4/components/site-footer.tsx index b4d2e01e95..0db63d25a6 100644 --- a/apps/v4/components/site-footer.tsx +++ b/apps/v4/components/site-footer.tsx @@ -2,7 +2,7 @@ import { siteConfig } from "@/lib/config" export function SiteFooter() { return ( -