From ea383ac7e4585fdce6fbef6744e8503e5d1970f0 Mon Sep 17 00:00:00 2001 From: winoffrg Date: Tue, 31 Mar 2026 17:09:46 +0530 Subject: [PATCH 1/6] feat: new blocks page --- apps/www/app/(home)/blocks/page.tsx | 20 -- apps/www/app/blocks/[[...slug]]/page.tsx | 134 +++++++++++ apps/www/app/blocks/blocks.css | 7 + apps/www/app/blocks/layout.tsx | 41 ++++ apps/www/app/docs/layout.tsx | 2 +- apps/www/app/global.css | 4 +- apps/www/app/limeplay.css | 2 - apps/www/app/shadcn.css | 3 - .../www/components/blocks/block-info-pane.tsx | 72 ++++++ .../components/blocks/block-preview-pane.tsx | 22 ++ apps/www/components/blocks/blocks-sidebar.tsx | 214 ++++++++++++++++++ apps/www/components/ui/breadcrumb.tsx | 118 ++++++++++ apps/www/components/ui/resizable.tsx | 65 +++--- apps/www/components/ui/sheet.tsx | 30 +-- apps/www/components/ui/sidebar.tsx | 31 ++- apps/www/components/ui/tooltip.tsx | 14 +- .../components/youtube-music-hover-player.tsx | 9 +- .../www/content/docs/blocks/linear-player.mdx | 79 +++++++ apps/www/content/docs/blocks/meta.json | 5 + .../www/content/docs/blocks/youtube-music.mdx | 50 ++++ apps/www/hooks/use-mobile.ts | 4 +- apps/www/lib/block-showcase.tsx | 70 ++++++ apps/www/lib/blocks-source.ts | 7 + apps/www/package.json | 13 +- apps/www/source.config.ts | 24 ++ bun.lock | 141 +++++++----- 26 files changed, 1011 insertions(+), 170 deletions(-) delete mode 100644 apps/www/app/(home)/blocks/page.tsx create mode 100644 apps/www/app/blocks/[[...slug]]/page.tsx create mode 100644 apps/www/app/blocks/blocks.css create mode 100644 apps/www/app/blocks/layout.tsx create mode 100644 apps/www/components/blocks/block-info-pane.tsx create mode 100644 apps/www/components/blocks/block-preview-pane.tsx create mode 100644 apps/www/components/blocks/blocks-sidebar.tsx create mode 100644 apps/www/components/ui/breadcrumb.tsx create mode 100644 apps/www/content/docs/blocks/linear-player.mdx create mode 100644 apps/www/content/docs/blocks/meta.json create mode 100644 apps/www/content/docs/blocks/youtube-music.mdx create mode 100644 apps/www/lib/block-showcase.tsx create mode 100644 apps/www/lib/blocks-source.ts diff --git a/apps/www/app/(home)/blocks/page.tsx b/apps/www/app/(home)/blocks/page.tsx deleted file mode 100644 index 1421017a..00000000 --- a/apps/www/app/(home)/blocks/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { BlockDisplay } from "@/components/block-display" - -export default function Blocks() { - return ( -
-
- - -
-
- ) -} diff --git a/apps/www/app/blocks/[[...slug]]/page.tsx b/apps/www/app/blocks/[[...slug]]/page.tsx new file mode 100644 index 00000000..da278513 --- /dev/null +++ b/apps/www/app/blocks/[[...slug]]/page.tsx @@ -0,0 +1,134 @@ +import type { Metadata } from "next" + +import { CodeBlock, Pre } from "fumadocs-ui/components/codeblock" +import { DocsLayout } from "fumadocs-ui/layouts/docs" +import { notFound } from "next/navigation" + +import { BlockInfoPane } from "@/components/blocks/block-info-pane" +import { BlockPreviewPane } from "@/components/blocks/block-preview-pane" +import { getMDXComponents } from "@/components/mdx-components" +import { + ResizableHandle, + ResizablePanel, + ResizablePanelGroup, +} from "@/components/ui/resizable" +import { getBlockShowcase } from "@/lib/block-showcase" +import { blocksSource } from "@/lib/blocks-source" + +export const revalidate = false +export const dynamic = "force-static" +export const dynamicParams = false + +type BlockPageProps = { + params: Promise<{ slug?: string[] }> +} + +export default async function BlockPage(props: BlockPageProps) { + const params = await props.params + const slug = params.slug ?? [] + const page = blocksSource.getPage(slug) + + if (!page) { + notFound() + } + + const showcase = getBlockShowcase(page.data.preview) + + const MDXContent = page.data.body + const PreviewComponent = showcase.component + const content = ( + ( + +
{props.children}
+
+ ), + })} + /> + ) + + return ( +
+ +
+
+
+ + + + +
+ + +
+
+
+
+ ) +} + +export async function generateMetadata( + props: BlockPageProps +): Promise { + const params = await props.params + + if (!params.slug?.length) { + return { + title: "Blocks", + } + } + + const page = blocksSource.getPage(params.slug) + + if (!page) notFound() + + return { + description: page.data.description, + title: `${page.data.title} Block`, + } +} + +export function generateStaticParams() { + return blocksSource.generateParams() +} diff --git a/apps/www/app/blocks/blocks.css b/apps/www/app/blocks/blocks.css new file mode 100644 index 00000000..5fc1030a --- /dev/null +++ b/apps/www/app/blocks/blocks.css @@ -0,0 +1,7 @@ +@import "tailwindcss"; +@import "fumadocs-ui/css/neutral.css"; +@import "fumadocs-ui/css/preset.css"; + +@theme { + --fd-layout-width: 0; +} \ No newline at end of file diff --git a/apps/www/app/blocks/layout.tsx b/apps/www/app/blocks/layout.tsx new file mode 100644 index 00000000..a92e7bfb --- /dev/null +++ b/apps/www/app/blocks/layout.tsx @@ -0,0 +1,41 @@ +import type { ReactNode } from "react" + +import { RootProvider } from "fumadocs-ui/provider/next" + +import { BlocksSidebar } from "@/components/blocks/blocks-sidebar" +import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar" +import { getBlockIcon } from "@/lib/block-showcase" +import { blocksSource } from "@/lib/blocks-source" + +import "./blocks.css" + +export default function BlocksLayout({ children }: { children: ReactNode }) { + const items = blocksSource.getPages().map((page) => ({ + description: page.data.description, + href: page.url, + icon: page.data.icon ? getBlockIcon(page.data.icon) : undefined, + status: page.data.status, + title: page.data.title, + })) + + return ( + + + + {children} + + + ) +} diff --git a/apps/www/app/docs/layout.tsx b/apps/www/app/docs/layout.tsx index dd10123a..c645dac2 100644 --- a/apps/www/app/docs/layout.tsx +++ b/apps/www/app/docs/layout.tsx @@ -1,6 +1,6 @@ import type { ReactNode } from "react" -import "@/app/docs/docs.css" +import "./docs.css" import { DocsLayout } from "fumadocs-ui/layouts/docs" import { RootProvider } from "fumadocs-ui/provider/next" diff --git a/apps/www/app/global.css b/apps/www/app/global.css index 58bfc2aa..5311dd0b 100644 --- a/apps/www/app/global.css +++ b/apps/www/app/global.css @@ -1,9 +1,11 @@ @import "tailwindcss"; @import "tw-animate-css"; -@import "./docs/docs.css"; + @import "./shadcn.css"; @import "./limeplay.css"; +@custom-variant dark (&:is(.dark *)); + :root { --page-padding-inline: 1rem; --page-padding: max(env(safe-area-inset-left), var(--page-padding-inline)) diff --git a/apps/www/app/limeplay.css b/apps/www/app/limeplay.css index 0bb239ca..61ec4526 100644 --- a/apps/www/app/limeplay.css +++ b/apps/www/app/limeplay.css @@ -1,5 +1,3 @@ -@import "tailwindcss"; - :root { --lp-timeline-track-height: 4px; --lp-timeline-track-height-active: 7px; diff --git a/apps/www/app/shadcn.css b/apps/www/app/shadcn.css index 27217bfa..43d585fe 100644 --- a/apps/www/app/shadcn.css +++ b/apps/www/app/shadcn.css @@ -1,6 +1,3 @@ -@import "tailwindcss"; -@import "tw-animate-css"; - @custom-variant dark (&:is(.dark *)); @theme inline { diff --git a/apps/www/components/blocks/block-info-pane.tsx b/apps/www/components/blocks/block-info-pane.tsx new file mode 100644 index 00000000..ce88f8e1 --- /dev/null +++ b/apps/www/components/blocks/block-info-pane.tsx @@ -0,0 +1,72 @@ +import type { ReactNode } from "react" + +import { + DocsBody, + DocsDescription, + DocsPage, + DocsTitle, +} from "fumadocs-ui/page" +import { DotIcon } from "lucide-react" +import Link from "next/link" + +export function BlockInfoPane({ + content, + description, + title, + url, +}: { + content: ReactNode + description?: string + title: string + url: string +}) { + return ( +
+
+
+
+ +
+
+ + {title} + {description} + +
+
+
+ {content} +
+
+
+
+
+
+ ) +} diff --git a/apps/www/components/blocks/block-preview-pane.tsx b/apps/www/components/blocks/block-preview-pane.tsx new file mode 100644 index 00000000..66a663cf --- /dev/null +++ b/apps/www/components/blocks/block-preview-pane.tsx @@ -0,0 +1,22 @@ +import type { ReactNode } from "react" + +import { LimeplayLogo } from "@/registry/default/ui/limeplay-logo" + +export function BlockPreviewPane({ children }: { children: ReactNode }) { + return ( +
+
+
+ + {children} +
+
+
+ ) +} diff --git a/apps/www/components/blocks/blocks-sidebar.tsx b/apps/www/components/blocks/blocks-sidebar.tsx new file mode 100644 index 00000000..28e168eb --- /dev/null +++ b/apps/www/components/blocks/blocks-sidebar.tsx @@ -0,0 +1,214 @@ +"use client" + +import type { ReactNode } from "react" + +import { motion } from "motion/react" +import Link from "next/link" +import { usePathname } from "next/navigation" + +import { + SidebarContent, + SidebarGroup, + SidebarGroupContent, + SidebarGroupLabel, + SidebarHeader, + SidebarMenu, + SidebarMenuBadge, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/components/ui/sidebar" +import { cn } from "@/lib/utils" + +const SIDEBAR_EASE = [0.23, 0.88, 0.26, 0.92] as const +const SIDEBAR_DURATION = 0.35 + +type BlocksSidebarItem = { + description?: string + href: string + icon?: ReactNode + status?: string + title: string +} + +export function BlocksSidebar({ items }: { items: BlocksSidebarItem[] }) { + const pathname = usePathname() + const { isMobile, open, openMobile } = useSidebar() + const isExpanded = isMobile ? openMobile : open + + return ( + <> + + + +
+ +
+

+ Blocks +

+ + {items.length} + +
+
+ + + + Browse + + + {items.map((item) => ( + + ))} + + + + +
+
+ + ) +} + +function FloatingSidebarToggle() { + const { isMobile, open, openMobile, toggleSidebar } = useSidebar() + const isExpanded = isMobile ? openMobile : open + + return ( + + + + ) +} + +function SidebarDismissLayer() { + const { isMobile, open, setOpen } = useSidebar() + + if (isMobile || !open) { + return null + } + + return ( + diff --git a/apps/www/content/docs/blocks/linear-player.mdx b/apps/www/content/docs/blocks/linear-player.mdx new file mode 100644 index 00000000..dd6da48a --- /dev/null +++ b/apps/www/content/docs/blocks/linear-player.mdx @@ -0,0 +1,79 @@ +--- +title: Linear Player +description: A modern seamless flat media player inspired by Linear's clean interface design, with full video playback, timeline, volume, captions, and playlist controls. +component: linear-player +icon: linear-player +preview: linear-player +registry: default +status: free +--- + +```npm +npx shadcn add @limeplay/linear-player +``` + +## Interaction Type + +- Hover over the player to reveal the transport controls overlay. +- Drag or click the timeline slider to scrub through the video. +- Use the volume group control to adjust level or toggle mute. +- Toggle captions, playback rate, and picture-in-picture from the bottom controls. +- Open the playlist panel to browse and switch between queued items. + +## How to Use + +```tsx +import { LinearMediaPlayer } from "@/components/linear-player/media-player" + +export function DemoLinearPlayer() { + return ( +
+ +
+ ) +} +``` + +The exported surface is intentionally small. `LinearMediaPlayer` mounts its own `MediaProvider`, media element, player hooks, timeline, and controls so the block can be dropped into a product shell without extra wrapper code. + +## Architecture + +The block is composed around a layered overlay design: + +1. A `MediaProvider` container that owns playback, timeline, volume, captions, and playlist state. +2. A timeline slider control with time labels for precise scrubbing. +3. A bottom controls bar with playback, volume group, captions, playback rate, and picture-in-picture controls. + +This produces a clean, flat player surface that stays out of the way until interaction, matching the minimal aesthetic of modern product interfaces. + +## Props + +| Prop | Description | +| --- | --- | +| `LinearMediaPlayer` | Public entry component for the block. Accepts an `as` prop to specify the media element type (`"video"` or `"audio"`). | +| `MediaProvider` | Mounted internally so playback state is isolated to this player instance. | +| `BottomControls` | Internal composition layer for playback, volume, captions, rate, and picture-in-picture controls. | + +## Attribution + +Inspired by the clean, flat player treatment used by Linear, then adapted into a registry-ready block with Limeplay primitives and a queue-aware internal architecture. + +## Source Code + +Use the top-right **Source Code** action to inspect the implementation. This showcase page is intentionally designed as a live documentation shell, while the actual source stays in the default registry collection. + +## Keep in Mind + +Most showcase blocks here are recreations or reinterpretations of strong interaction patterns from production products. The goal is not one-to-one cloning, but understanding the behavior, rebuilding the structure cleanly, and packaging it into a reusable registry block. + +Because this player ships as a full-viewport video surface, it works best when given the entire available space. Treat it as a primary content area, not a compact embedded widget. + +## Contact + +If you find a bug, broken dependency path, or missing attribution note, reach out through the project channels and include the block name so the issue can be traced quickly. + +## License & Usage + +- Free blocks can be adapted in personal and commercial work with attribution where required. +- Pro blocks do not require attribution once you have the appropriate access tier. +- You can modify structure, styling, and behavior after pulling the registry code into your own app. diff --git a/apps/www/content/docs/blocks/meta.json b/apps/www/content/docs/blocks/meta.json new file mode 100644 index 00000000..4be6b723 --- /dev/null +++ b/apps/www/content/docs/blocks/meta.json @@ -0,0 +1,5 @@ +{ + "title": "Blocks", + "description": "Headless showcase pages for registry blocks.", + "defaultOpen": true +} diff --git a/apps/www/content/docs/blocks/youtube-music.mdx b/apps/www/content/docs/blocks/youtube-music.mdx new file mode 100644 index 00000000..935cbf44 --- /dev/null +++ b/apps/www/content/docs/blocks/youtube-music.mdx @@ -0,0 +1,50 @@ +--- +title: Youtube Music +description: A pro registry block that recreates the compact YouTube Music playback rail with playlist, timeline, and transport controls. +component: youtube-music +icon: youtube-music +preview: youtube-music +registry: pro +status: pro +--- + +```npm +npx shadcn add @limeplay/pro/youtube-music +``` + +## Interaction Type + +- Try hovering transport actions and playback mode controls. +- Open the playlist panel to inspect the queue-driven layout. +- Drag or click the fixed timeline to scrub the active track. +- Use the volume control group to test mute and level state. + +## How to Use + +```tsx +import { YouTubeMusicPlayer } from "@/components/youtube-music/media-player" + +export function DemoYouTubeMusic() { + return ( +
+ +
+ ) +} +``` + +The exported surface is intentionally small. `YouTubeMusicPlayer` mounts its own `MediaProvider`, media element, player hooks, fixed timeline, and controls so the block can be dropped into a product shell without extra wrapper code. + +## Architecture + +The block is composed around three dense layers: + +1. A `MediaProvider` container that owns playback, timeline, volume, and playlist state. + +## Props + +| Prop | Description | +| --- | --- | +| `YouTubeMusicPlayer` | Public entry component for the block. It does not require props in the current registry version. | +| `MediaProvider` | Mounted internally so playback state is isolated to this player instance. | +| `PlayerControls` | Internal composition layer for playback, track info, actions, playlist, and mode controls. | diff --git a/apps/www/hooks/use-mobile.ts b/apps/www/hooks/use-mobile.ts index f7583338..2b0fe1df 100644 --- a/apps/www/hooks/use-mobile.ts +++ b/apps/www/hooks/use-mobile.ts @@ -12,9 +12,7 @@ export function useIsMobile() { } mql.addEventListener("change", onChange) setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) - return () => { - mql.removeEventListener("change", onChange) - } + return () => mql.removeEventListener("change", onChange) }, []) return !!isMobile diff --git a/apps/www/lib/block-showcase.tsx b/apps/www/lib/block-showcase.tsx new file mode 100644 index 00000000..8cf4e20c --- /dev/null +++ b/apps/www/lib/block-showcase.tsx @@ -0,0 +1,70 @@ +import type { ReactNode } from "react" + +import { LinearMediaPlayer } from "@/registry/default/blocks/linear-player/components/media-player" +import { YouTubeMusicPlayer } from "@/registry/pro/blocks/youtube-music/components/media-player" + +type BlockShowcaseDefinition = { + component: () => ReactNode + icon: ReactNode +} + +function LinearIcon() { + return ( + + ) +} + +function YouTubeMusicIcon() { + return ( + + ) +} + +const blockShowcaseRegistry = { + "linear-player": { + component: () => ( +
+ +
+ ), + icon: , + }, + "youtube-music": { + component: () => , + icon: , + }, +} satisfies Record + +export function getBlockIcon(preview: string): ReactNode | undefined { + return blockShowcaseRegistry[preview as keyof typeof blockShowcaseRegistry] + .icon +} + +export function getBlockShowcase(preview: string) { + return blockShowcaseRegistry[preview as keyof typeof blockShowcaseRegistry] +} diff --git a/apps/www/lib/blocks-source.ts b/apps/www/lib/blocks-source.ts new file mode 100644 index 00000000..5a7547d3 --- /dev/null +++ b/apps/www/lib/blocks-source.ts @@ -0,0 +1,7 @@ +import { loader } from "fumadocs-core/source" +import { blocks } from "fumadocs-mdx:collections/server" + +export const blocksSource = loader({ + baseUrl: "/blocks", + source: blocks.toFumadocsSource(), +}) diff --git a/apps/www/package.json b/apps/www/package.json index 69a6e7cd..53bea399 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -39,23 +39,24 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", - "fumadocs-core": "16.4.0", - "fumadocs-mdx": "14.2.2", - "fumadocs-typescript": "^5.0.0", - "fumadocs-ui": "16.4.0", + "fumadocs-core": "16.7.7", + "fumadocs-mdx": "14.2.11", + "fumadocs-typescript": "^5.2.0", + "fumadocs-ui": "16.7.7", "hast-util-to-jsx-runtime": "^2.3.6", "jotai": "^2.12.5", "lodash": "^4.17.21", "lodash.clamp": "^4.0.3", "lodash.shuffle": "^4.2.0", "lodash.throttle": "^4.1.1", - "lucide-react": "^0.542.0", + "lucide-react": "^1.7.0", "motion": "^12.23.24", "next": "^16.1.6", "next-themes": "^0.4.6", + "radix-ui": "^1.4.3", "react": "^19.2.1", "react-dom": "^19.2.1", - "react-resizable-panels": "^3.0.4", + "react-resizable-panels": "^4", "react-use": "^17.6.0", "remark": "^15.0.1", "remark-code-import": "^1.2.0", diff --git a/apps/www/source.config.ts b/apps/www/source.config.ts index 21aca6ba..4438d461 100644 --- a/apps/www/source.config.ts +++ b/apps/www/source.config.ts @@ -2,6 +2,7 @@ import { defineConfig, defineDocs } from "fumadocs-mdx/config" import rehypeSlug from "rehype-slug" import { codeImport } from "remark-code-import" import remarkGfm from "remark-gfm" +import { z } from "zod" export const docs = defineDocs({ dir: "content/docs", @@ -13,6 +14,29 @@ export const docs = defineDocs({ }, }) +const blockFrontmatterSchema = z.object({ + _openapi: z.record(z.unknown()).optional(), + component: z.string(), + description: z.string().optional(), + full: z.boolean().optional(), + icon: z.string().optional(), + preview: z.string(), + registry: z.enum(["default", "pro"]).default("default"), + status: z.enum(["free", "pro"]).default("free"), + title: z.string(), +}) + +export const blocks = defineDocs({ + dir: "content/docs/blocks", + docs: { + postprocess: { + extractLinkReferences: true, + includeProcessedMarkdown: true, + }, + schema: blockFrontmatterSchema, + }, +}) + export default defineConfig({ mdxOptions: { rehypeCodeOptions: { diff --git a/bun.lock b/bun.lock index 3c771823..e94a1a62 100644 --- a/bun.lock +++ b/bun.lock @@ -53,23 +53,24 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", - "fumadocs-core": "16.4.0", - "fumadocs-mdx": "14.2.2", - "fumadocs-typescript": "^5.0.0", - "fumadocs-ui": "16.4.0", + "fumadocs-core": "16.7.7", + "fumadocs-mdx": "14.2.11", + "fumadocs-typescript": "^5.2.0", + "fumadocs-ui": "16.7.7", "hast-util-to-jsx-runtime": "^2.3.6", "jotai": "^2.12.5", "lodash": "^4.17.21", "lodash.clamp": "^4.0.3", "lodash.shuffle": "^4.2.0", "lodash.throttle": "^4.1.1", - "lucide-react": "^0.542.0", + "lucide-react": "^1.7.0", "motion": "^12.23.24", "next": "^16.1.6", "next-themes": "^0.4.6", + "radix-ui": "^1.4.3", "react": "^19.2.1", "react-dom": "^19.2.1", - "react-resizable-panels": "^3.0.4", + "react-resizable-panels": "^4", "react-use": "^17.6.0", "remark": "^15.0.1", "remark-code-import": "^1.2.0", @@ -274,14 +275,12 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], - "@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.0.3", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-CArYtQKGLAOruCMeq5/RxCg6vUXFx3OuKBdTm30Wn/+gCefehmZ8Y2xSMxMrO2iel7hRyE3HKfV56t3vAU6D4Q=="], + "@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.1", "", {}, "sha512-CbNbf+tlJn1baRnPkNePnBqTLxGliG6DDgNa/UtV66abwIjwsliPMOt0172tzxABYzSuxZBZfcp//qI8AvBWPg=="], - "@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.7.5", "", { "dependencies": { "@formatjs/fast-memoize": "3.0.3", "tslib": "^2.8.0" } }, "sha512-7/nd90cn5CT7SVF71/ybUKAcnvBlr9nZlJJp8O8xIZHXFgYOC4SXExZlSdgHv2l6utjw1byidL06QzChvQMHwA=="], + "@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.8.2", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.1" } }, "sha512-q05KMYGJLyqFNFtIb8NhWLF5X3aK/k0wYt7dnRFuy6aLQL+vUwQ1cg5cO4qawEiINybeCPXAWlprY2mSBjSXAQ=="], "@fumadocs/tailwind": ["@fumadocs/tailwind@0.0.3", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "tailwindcss": "^4.0.0" }, "optionalPeers": ["tailwindcss"] }, "sha512-/FWcggMz9BhoX+13xBoZLX+XX9mYvJ50dkTqy3IfocJqua65ExcsKfxwKH8hgTO3vA5KnWv4+4jU7LaW2AjAmQ=="], - "@fumadocs/ui": ["@fumadocs/ui@16.4.0", "", { "dependencies": { "fumadocs-core": "16.4.0", "lodash.merge": "^4.6.2", "next-themes": "^0.4.6", "postcss-selector-parser": "^7.1.1", "tailwind-merge": "^3.4.0" }, "peerDependencies": { "@types/react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "tailwindcss": "^4.0.0" }, "optionalPeers": ["@types/react", "next", "tailwindcss"] }, "sha512-ovk5PvghMNII+bVkuIoalXLJppCIUOUf+OEyz3e6JdnHYBNwzagWjVppCKLuXK0HIE8yRSqdtQvB66bnkvfP8A=="], - "@hono/node-server": ["@hono/node-server@1.19.10", "", { "peerDependencies": { "hono": "^4" } }, "sha512-hZ7nOssGqRgyV3FVVQdfi+U4q02uB23bpnYpdvNXkYTRRyWx84b7yf1ans+dnJ/7h41sGL3CeQTfO+ZGxuO+Iw=="], "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], @@ -430,10 +429,20 @@ "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], + "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="], + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], + "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="], + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], + "@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="], + + "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="], + + "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="], + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="], "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="], @@ -442,6 +451,8 @@ "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], + "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="], + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], @@ -454,12 +465,24 @@ "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], + "@radix-ui/react-form": ["@radix-ui/react-form@0.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="], + + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="], + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], + "@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="], + "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="], + "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="], + "@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="], + + "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="], + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], @@ -470,6 +493,10 @@ "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], + "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="], + + "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="], + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], @@ -478,14 +505,22 @@ "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g=="], + "@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="], + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="], + "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="], + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], + "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="], + "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="], "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="], + "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="], + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="], "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], @@ -496,6 +531,8 @@ "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], + "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="], + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], @@ -514,23 +551,23 @@ "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], - "@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="], + "@shikijs/core": ["@shikijs/core@4.0.2", "", { "dependencies": { "@shikijs/primitive": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw=="], - "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="], + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag=="], - "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="], + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg=="], - "@shikijs/langs": ["@shikijs/langs@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg=="], + "@shikijs/langs": ["@shikijs/langs@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg=="], - "@shikijs/primitive": ["@shikijs/primitive@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-ns0hHZc5eWZuvuIEJz2pTx3Qecz0aRVYumVQJ8JgWY2tq/dH8WxdcVM49Fc2NsHEILNIT6vfdW9MF26RANWiTA=="], + "@shikijs/primitive": ["@shikijs/primitive@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw=="], - "@shikijs/rehype": ["@shikijs/rehype@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@types/hast": "^3.0.4", "hast-util-to-string": "^3.0.1", "shiki": "3.23.0", "unified": "^11.0.5", "unist-util-visit": "^5.1.0" } }, "sha512-GepKJxXHbXFfAkiZZZ+4V7x71Lw3s0ALYmydUxJRdvpKjSx9FOMSaunv6WRLFBXR6qjYerUq1YZQno+2gLEPwA=="], + "@shikijs/rehype": ["@shikijs/rehype@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@types/hast": "^3.0.4", "hast-util-to-string": "^3.0.1", "shiki": "4.0.2", "unified": "^11.0.5", "unist-util-visit": "^5.1.0" } }, "sha512-cmPlKLD8JeojasNFoY64162ScpEdEdQUMuVodPCrv1nx1z3bjmGwoKWDruQWa/ejSznImlaeB0Ty6Q3zPaVQAA=="], - "@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="], + "@shikijs/themes": ["@shikijs/themes@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA=="], - "@shikijs/transformers": ["@shikijs/transformers@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/types": "3.23.0" } }, "sha512-F9msZVxdF+krQNSdQ4V+Ja5QemeAoTQ2jxt7nJCwhDsdF1JWS3KxIQXA3lQbyKwS3J61oHRUSv4jYWv3CkaKTQ=="], + "@shikijs/transformers": ["@shikijs/transformers@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/types": "4.0.2" } }, "sha512-1+L0gf9v+SdDXs08vjaLb3mBFa8U7u37cwcBQIv/HCocLwX69Tt6LpUCjtB+UUTvQxI7BnjZKhN/wMjhHBcJGg=="], - "@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="], + "@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="], "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], @@ -1068,13 +1105,13 @@ "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "fumadocs-core": ["fumadocs-core@16.4.0", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.7.2", "@orama/orama": "^3.1.18", "@shikijs/rehype": "^3.20.0", "@shikijs/transformers": "^3.20.0", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.3.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^3.20.0", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "@mixedbread/sdk": "^0.46.0", "@orama/core": "1.x.x", "@tanstack/react-router": "1.x.x", "@types/react": "*", "algoliasearch": "5.x.x", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0", "zod": "*" }, "optionalPeers": ["@mixedbread/sdk", "@orama/core", "@tanstack/react-router", "@types/react", "algoliasearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-MIszw14eb32Pk+R/a3T0D3ALeh6kd7pkG6fAUY7AfGptZi4qwyNApuKRYF/BnuAjVzYIFzNOgnWzWMA41YX9pQ=="], + "fumadocs-core": ["fumadocs-core@16.7.7", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.8.2", "@orama/orama": "^3.1.18", "@shikijs/rehype": "^4.0.2", "@shikijs/transformers": "^4.0.2", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "mdast-util-mdx": "^3.0.0", "mdast-util-to-markdown": "^2.1.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.3.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^4.0.2", "tinyglobby": "^0.2.15", "unified": "^11.0.5", "unist-util-visit": "^5.1.0", "vfile": "^6.0.3" }, "peerDependencies": { "@mdx-js/mdx": "*", "@mixedbread/sdk": "^0.46.0", "@orama/core": "1.x.x", "@oramacloud/client": "2.x.x", "@tanstack/react-router": "1.x.x", "@types/estree-jsx": "*", "@types/hast": "*", "@types/mdast": "*", "@types/react": "*", "algoliasearch": "5.x.x", "flexsearch": "*", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0 || ^1.0.0", "zod": "4.x.x" }, "optionalPeers": ["@mdx-js/mdx", "@mixedbread/sdk", "@orama/core", "@oramacloud/client", "@tanstack/react-router", "@types/estree-jsx", "@types/hast", "@types/mdast", "@types/react", "algoliasearch", "flexsearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-Eqh3AZ24loMnwNJZlereRwBp1q2nB/JOJ5xsIG4bF6tFZ2mTzc3rToKoRRAVNhNFwMVqlZBGVXWo+rjx1hOtjQ=="], - "fumadocs-mdx": ["fumadocs-mdx@14.2.2", "", { "dependencies": { "@mdx-js/mdx": "^3.1.1", "@standard-schema/spec": "^1.1.0", "chokidar": "^5.0.0", "esbuild": "^0.27.2", "estree-util-value-to-estree": "^3.5.0", "js-yaml": "^4.1.1", "mdast-util-to-markdown": "^2.1.2", "picocolors": "^1.1.1", "picomatch": "^4.0.3", "remark-mdx": "^3.1.1", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3", "zod": "^4.2.1" }, "peerDependencies": { "@fumadocs/mdx-remote": "^1.4.0", "@types/react": "*", "fumadocs-core": "^15.0.0 || ^16.0.0", "next": "^15.3.0 || ^16.0.0", "react": "*", "vite": "6.x.x || 7.x.x" }, "optionalPeers": ["@fumadocs/mdx-remote", "@types/react", "next", "react", "vite"], "bin": { "fumadocs-mdx": "dist/bin.js" } }, "sha512-ClRjZd5WloWhbNHcUgA0PvbiTFuVKjv+qmrfF4aAeHzae6jeZtm1dvSYZ6iKoEHjFz6bt3UqiCgLHAUuXS8ifg=="], + "fumadocs-mdx": ["fumadocs-mdx@14.2.11", "", { "dependencies": { "@mdx-js/mdx": "^3.1.1", "@standard-schema/spec": "^1.1.0", "chokidar": "^5.0.0", "esbuild": "^0.27.3", "estree-util-value-to-estree": "^3.5.0", "js-yaml": "^4.1.1", "mdast-util-mdx": "^3.0.0", "mdast-util-to-markdown": "^2.1.2", "picocolors": "^1.1.1", "picomatch": "^4.0.3", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.1.0", "vfile": "^6.0.3", "zod": "^4.3.6" }, "peerDependencies": { "@fumadocs/mdx-remote": "^1.4.0", "@types/mdast": "*", "@types/mdx": "*", "@types/react": "*", "fumadocs-core": "^15.0.0 || ^16.0.0", "mdast-util-directive": "*", "next": "^15.3.0 || ^16.0.0", "react": "*", "vite": "6.x.x || 7.x.x || 8.x.x" }, "optionalPeers": ["@fumadocs/mdx-remote", "@types/mdast", "@types/mdx", "@types/react", "mdast-util-directive", "next", "react", "vite"], "bin": { "fumadocs-mdx": "dist/bin.js" } }, "sha512-j0gHKs45c62ARteE8/yBM2Nu2I8AE2Cs37ktPEdc/8EX7TL66XP74un5OpHp6itLyWTu8Jur0imOiiIDq8+rDg=="], - "fumadocs-typescript": ["fumadocs-typescript@5.1.5", "", { "dependencies": { "estree-util-value-to-estree": "^3.5.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "remark": "^15.0.1", "remark-rehype": "^11.1.2", "ts-morph": "^27.0.2", "unified": "^11.0.5", "unist-util-visit": "^5.1.0" }, "peerDependencies": { "@types/estree": "*", "@types/hast": "*", "@types/mdast": "*", "@types/react": "*", "fumadocs-core": "^16.5.0", "fumadocs-ui": "^16.5.0", "react": "*", "typescript": "*" }, "optionalPeers": ["@types/estree", "@types/hast", "@types/mdast", "@types/react", "fumadocs-ui"] }, "sha512-uKXfsN2uEJKNX6A0jJbjj2Hg9uUnN9REvknwXgBdBjwK5Ap8cVQnWoKLQQqsD0bp8ypPS7pqmnXXU/6dfAfy0w=="], + "fumadocs-typescript": ["fumadocs-typescript@5.2.0", "", { "dependencies": { "estree-util-value-to-estree": "^3.5.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "remark": "^15.0.1", "remark-rehype": "^11.1.2", "ts-morph": "^27.0.2", "unified": "^11.0.5", "unist-util-visit": "^5.1.0" }, "peerDependencies": { "@types/estree": "*", "@types/hast": "*", "@types/mdast": "*", "@types/react": "*", "fumadocs-core": "^16.7.0", "fumadocs-ui": "^16.7.0", "react": "*", "shiki": "*", "typescript": "*" }, "optionalPeers": ["@types/estree", "@types/hast", "@types/mdast", "@types/react", "fumadocs-ui", "shiki"] }, "sha512-iyrRztDjNDIkUEOYJzP3O7mcqGo57nXNlNLgphwyrGfiuMHfsq7glkHAfn+eCUBVDLVOzkk1sNTytFcU2Khkaw=="], - "fumadocs-ui": ["fumadocs-ui@16.4.0", "", { "dependencies": { "@fumadocs/ui": "16.4.0", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-direction": "^1.1.1", "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-presence": "^1.1.5", "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", "class-variance-authority": "^0.7.1", "fumadocs-core": "16.4.0", "next-themes": "^0.4.6", "react-medium-image-zoom": "^5.4.0", "scroll-into-view-if-needed": "^3.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^19.2.0", "react-dom": "^19.2.0", "tailwindcss": "^4.0.0" }, "optionalPeers": ["@types/react", "tailwindcss"] }, "sha512-tZnmbX2g4aMPHLArrpfzS8BdJ5Xyw3I9IXlmkcZm3I0lvh6GcVfWnPe5A3nIzywzdQzPSR79Bm1tiuSfvxcfyw=="], + "fumadocs-ui": ["fumadocs-ui@16.7.7", "", { "dependencies": { "@fumadocs/tailwind": "0.0.3", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-direction": "^1.1.1", "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-presence": "^1.1.5", "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", "class-variance-authority": "^0.7.1", "lucide-react": "^1.6.0", "motion": "^12.38.0", "next-themes": "^0.4.6", "react-medium-image-zoom": "^5.4.1", "react-remove-scroll": "^2.7.2", "rehype-raw": "^7.0.0", "scroll-into-view-if-needed": "^3.1.0", "tailwind-merge": "^3.5.0", "unist-util-visit": "^5.1.0" }, "peerDependencies": { "@takumi-rs/image-response": "*", "@types/mdx": "*", "@types/react": "*", "fumadocs-core": "16.7.7", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "shiki": "*" }, "optionalPeers": ["@takumi-rs/image-response", "@types/mdx", "@types/react", "next", "shiki"] }, "sha512-yeDkVgROkTH+FP38CFcGGlkeNGiiDyNNQpmm0btt9rg653kTITuMAzXU5F8PZ+8upwPIgOdJwFcdxuQEobjO9w=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], @@ -1402,7 +1439,7 @@ "lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="], - "lucide-react": ["lucide-react@0.542.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw=="], + "lucide-react": ["lucide-react@1.7.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], @@ -1688,6 +1725,8 @@ "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + "radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="], + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], @@ -1704,7 +1743,7 @@ "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], - "react-resizable-panels": ["react-resizable-panels@3.0.6", "", { "peerDependencies": { "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew=="], + "react-resizable-panels": ["react-resizable-panels@4.8.0", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-2uEABkewb3ky/ZgIlAUxWa1W/LjsK494fdV1QsXxst7CDRHCzo7h22tWWu3NNaBjmiuriOCt3CvhipnaYcpoIw=="], "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], @@ -1830,7 +1869,7 @@ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - "shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="], + "shiki": ["shiki@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/engine-javascript": "4.0.2", "@shikijs/engine-oniguruma": "4.0.2", "@shikijs/langs": "4.0.2", "@shikijs/themes": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ=="], "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], @@ -1932,7 +1971,7 @@ "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], - "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "tinyexec": ["tinyexec@1.0.4", "", {}, "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], @@ -2104,6 +2143,8 @@ "@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + "@antfu/ni/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], @@ -2134,6 +2175,8 @@ "@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], + "@radix-ui/react-alert-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + "@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], "@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], @@ -2148,9 +2191,9 @@ "@radix-ui/react-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], - "@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + "@radix-ui/react-toolbar/@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], - "@shikijs/primitive/@shikijs/types": ["@shikijs/types@4.0.1", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-EaygPEn57+jJ76mw+nTLvIpJMAcMPokFbrF8lufsZP7Ukk+ToJYEcswN1G0e49nUZAq7aCQtoeW219A8HK1ZOw=="], + "@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], "@tailwindcss/node/tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="], @@ -2220,9 +2263,9 @@ "fumadocs-mdx/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], - "fumadocs-typescript/fumadocs-core": ["fumadocs-core@16.6.9", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.8.1", "@orama/orama": "^3.1.18", "@shikijs/rehype": "^4.0.0", "@shikijs/transformers": "^4.0.0", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "mdast-util-mdx": "^3.0.0", "mdast-util-to-markdown": "^2.1.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.3.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^4.0.0", "tinyglobby": "^0.2.15", "unified": "^11.0.5", "unist-util-visit": "^5.1.0", "vfile": "^6.0.3" }, "peerDependencies": { "@mdx-js/mdx": "*", "@mixedbread/sdk": "^0.46.0", "@orama/core": "1.x.x", "@oramacloud/client": "2.x.x", "@tanstack/react-router": "1.x.x", "@types/estree-jsx": "*", "@types/hast": "*", "@types/mdast": "*", "@types/react": "*", "algoliasearch": "5.x.x", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0 || ^1.0.0", "zod": "4.x.x" }, "optionalPeers": ["@mdx-js/mdx", "@mixedbread/sdk", "@orama/core", "@oramacloud/client", "@tanstack/react-router", "@types/estree-jsx", "@types/hast", "@types/mdast", "@types/react", "algoliasearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-zSDk9tAP7z3de1Zzc1weVOmXtO+zqgus9mSlkzkxbQQgA99liGZlPujImSbNMMVn47h6xJk2zfv/CV3cuDrQ0A=="], + "fumadocs-ui/motion": ["motion@12.38.0", "", { "dependencies": { "framer-motion": "^12.38.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w=="], - "fumadocs-typescript/fumadocs-ui": ["fumadocs-ui@16.6.9", "", { "dependencies": { "@fumadocs/tailwind": "0.0.3", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-direction": "^1.1.1", "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-presence": "^1.1.5", "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", "class-variance-authority": "^0.7.1", "lucide-react": "^0.575.0", "motion": "^12.34.3", "next-themes": "^0.4.6", "react-medium-image-zoom": "^5.4.1", "react-remove-scroll": "^2.7.2", "rehype-raw": "^7.0.0", "scroll-into-view-if-needed": "^3.1.0", "tailwind-merge": "^3.5.0", "unist-util-visit": "^5.1.0" }, "peerDependencies": { "@takumi-rs/image-response": "*", "@types/react": "*", "fumadocs-core": "16.6.9", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0" }, "optionalPeers": ["@takumi-rs/image-response", "@types/react", "next"] }, "sha512-VMANqhWf4fj70tDKre5qq7eqwprRn0QCEKuZeRO2sHeWDFlJFfrLmIUeqRDvqTmUjsntSywXRrWflWlzedYumw=="], + "fumadocs-ui/react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], "glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], @@ -2252,6 +2295,10 @@ "prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], + "radix-ui/@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], + + "radix-ui/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + "rehype-slug/unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="], "remark-code-import/unist-util-visit": ["unist-util-visit@4.1.2", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", "unist-util-visit-parents": "^5.1.1" } }, "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg=="], @@ -2308,17 +2355,7 @@ "eslint-plugin-import/tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], - "fumadocs-typescript/fumadocs-core/@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.8.1", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.0", "tslib": "^2.8.1" } }, "sha512-xwEuwQFdtSq1UKtQnyTZWC+eHdv7Uygoa+H2k/9uzBVQjDyp9r20LNDNKedWXll7FssT3GRHvqsdJGYSUWqYFA=="], - - "fumadocs-typescript/fumadocs-core/@shikijs/rehype": ["@shikijs/rehype@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1", "@types/hast": "^3.0.4", "hast-util-to-string": "^3.0.1", "shiki": "4.0.1", "unified": "^11.0.5", "unist-util-visit": "^5.1.0" } }, "sha512-bx7bYA0/p/pgeEICaPO0jT6TXrXHmr9tGRUDhOMy1cAUN2YA0iANfXX7seBnImy8DGu/rxm1ij9/ZofYrAaUjQ=="], - - "fumadocs-typescript/fumadocs-core/@shikijs/transformers": ["@shikijs/transformers@4.0.1", "", { "dependencies": { "@shikijs/core": "4.0.1", "@shikijs/types": "4.0.1" } }, "sha512-oE46W2eHpvD06+C0MBthd2YrDM6cktvJDFl764tOEXxfr3dAJhxMc0uNZ2tQXp+bkMgl4E7IL88Mj9RnSqiayw=="], - - "fumadocs-typescript/fumadocs-core/shiki": ["shiki@4.0.1", "", { "dependencies": { "@shikijs/core": "4.0.1", "@shikijs/engine-javascript": "4.0.1", "@shikijs/engine-oniguruma": "4.0.1", "@shikijs/langs": "4.0.1", "@shikijs/themes": "4.0.1", "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-EkAEhDTN5WhpoQFXFw79OHIrSAfHhlImeCdSyg4u4XvrpxKEmdo/9x/HWSowujAnUrFsGOwWiE58a6GVentMnQ=="], - - "fumadocs-typescript/fumadocs-ui/lucide-react": ["lucide-react@0.575.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-VuXgKZrk0uiDlWjGGXmKV6MSk9Yy4l10qgVvzGn2AWBx1Ylt0iBexKOAoA6I7JO3m+M9oeovJd3yYENfkUbOeg=="], - - "fumadocs-typescript/fumadocs-ui/react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], + "fumadocs-ui/motion/framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="], "glob/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], @@ -2348,25 +2385,9 @@ "@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - "fumadocs-typescript/fumadocs-core/@formatjs/intl-localematcher/@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.0", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg=="], - - "fumadocs-typescript/fumadocs-core/@shikijs/rehype/@shikijs/types": ["@shikijs/types@4.0.1", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-EaygPEn57+jJ76mw+nTLvIpJMAcMPokFbrF8lufsZP7Ukk+ToJYEcswN1G0e49nUZAq7aCQtoeW219A8HK1ZOw=="], - - "fumadocs-typescript/fumadocs-core/@shikijs/transformers/@shikijs/core": ["@shikijs/core@4.0.1", "", { "dependencies": { "@shikijs/primitive": "4.0.1", "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-vWvqi9JNgz1dRL9Nvog5wtx7RuNkf7MEPl2mU/cyUUxJeH1CAr3t+81h8zO8zs7DK6cKLMoU9TvukWIDjP4Lzg=="], - - "fumadocs-typescript/fumadocs-core/@shikijs/transformers/@shikijs/types": ["@shikijs/types@4.0.1", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-EaygPEn57+jJ76mw+nTLvIpJMAcMPokFbrF8lufsZP7Ukk+ToJYEcswN1G0e49nUZAq7aCQtoeW219A8HK1ZOw=="], - - "fumadocs-typescript/fumadocs-core/shiki/@shikijs/core": ["@shikijs/core@4.0.1", "", { "dependencies": { "@shikijs/primitive": "4.0.1", "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-vWvqi9JNgz1dRL9Nvog5wtx7RuNkf7MEPl2mU/cyUUxJeH1CAr3t+81h8zO8zs7DK6cKLMoU9TvukWIDjP4Lzg=="], - - "fumadocs-typescript/fumadocs-core/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-DJK9NiwtGYqMuKCRO4Ip0FKNDQpmaiS+K5bFjJ7DWFn4zHueDWgaUG8kAofkrnXF6zPPYYQY7J5FYVW9MbZyBg=="], - - "fumadocs-typescript/fumadocs-core/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-oCWdCTDch3J8Kc0OZJ98KuUPC02O1VqIE3W/e2uvrHqTxYRR21RGEJMtchrgrxhsoJJCzmIciKsqG+q/yD+Cxg=="], - - "fumadocs-typescript/fumadocs-core/shiki/@shikijs/langs": ["@shikijs/langs@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1" } }, "sha512-v/mluaybWdnGJR4GqAR6zh8qAZohW9k+cGYT28Y7M8+jLbC0l4yG085O1A+WkseHTn+awd+P3UBymb2+MXFc8w=="], - - "fumadocs-typescript/fumadocs-core/shiki/@shikijs/themes": ["@shikijs/themes@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1" } }, "sha512-FW41C/D6j/yKQkzVdjrRPiJCtgeDaYRJFEyCKFCINuRJRj9WcmubhP4KQHPZ4+9eT87jruSrYPyoblNRyDFzvA=="], + "fumadocs-ui/motion/framer-motion/motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="], - "fumadocs-typescript/fumadocs-core/shiki/@shikijs/types": ["@shikijs/types@4.0.1", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-EaygPEn57+jJ76mw+nTLvIpJMAcMPokFbrF8lufsZP7Ukk+ToJYEcswN1G0e49nUZAq7aCQtoeW219A8HK1ZOw=="], + "fumadocs-ui/motion/framer-motion/motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], From 690feed05288f47fc97bd12650650f1b2498cb14 Mon Sep 17 00:00:00 2001 From: winoffrg Date: Tue, 31 Mar 2026 17:24:34 +0530 Subject: [PATCH 2/6] fix: build error --- apps/www/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/www/package.json b/apps/www/package.json index 53bea399..bc67a1c5 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -56,7 +56,7 @@ "radix-ui": "^1.4.3", "react": "^19.2.1", "react-dom": "^19.2.1", - "react-resizable-panels": "^4", + "react-resizable-panels": "4.8.0", "react-use": "^17.6.0", "remark": "^15.0.1", "remark-code-import": "^1.2.0", From cbb899faa73c5682b1123eb288620b51f6584add Mon Sep 17 00:00:00 2001 From: winoffrg Date: Tue, 31 Mar 2026 17:24:44 +0530 Subject: [PATCH 3/6] fix: build error --- bun.lock | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/bun.lock b/bun.lock index e94a1a62..4514ce95 100644 --- a/bun.lock +++ b/bun.lock @@ -70,7 +70,7 @@ "radix-ui": "^1.4.3", "react": "^19.2.1", "react-dom": "^19.2.1", - "react-resizable-panels": "^4", + "react-resizable-panels": "4.8.0", "react-use": "^17.6.0", "remark": "^15.0.1", "remark-code-import": "^1.2.0", @@ -1097,7 +1097,7 @@ "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], - "framer-motion": ["framer-motion@12.34.5", "", { "dependencies": { "motion-dom": "^12.34.5", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-Z2dQ+o7BsfpJI3+u0SQUNCrN+ajCKJen1blC4rCHx1Ta2EOHs+xKJegLT2aaD9iSMbU3OoX+WabQXkloUbZmJQ=="], + "framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="], "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], @@ -1577,11 +1577,11 @@ "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "motion": ["motion@12.34.5", "", { "dependencies": { "framer-motion": "^12.34.5", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-N06NLJ9IeBHeielRqIvYvjPfXuRdyTxa+9++BgpGa+hY2D7TcMkI6QzV3jaRuv0aZRXgMa7cPy9YcBUBisPzAQ=="], + "motion": ["motion@12.38.0", "", { "dependencies": { "framer-motion": "^12.38.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w=="], - "motion-dom": ["motion-dom@12.34.5", "", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-k33CsnxO2K3gBRMUZT+vPmc4Utlb5menKdG0RyVNLtlqRaaJPRWlE9fXl8NTtfZ5z3G8TDvqSu0MENLqSTaHZA=="], + "motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="], - "motion-utils": ["motion-utils@12.29.2", "", {}, "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A=="], + "motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], @@ -2263,8 +2263,6 @@ "fumadocs-mdx/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], - "fumadocs-ui/motion": ["motion@12.38.0", "", { "dependencies": { "framer-motion": "^12.38.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w=="], - "fumadocs-ui/react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], "glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], @@ -2355,8 +2353,6 @@ "eslint-plugin-import/tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], - "fumadocs-ui/motion/framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="], - "glob/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], "remark-code-import/unist-util-visit/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], @@ -2385,10 +2381,6 @@ "@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - "fumadocs-ui/motion/framer-motion/motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="], - - "fumadocs-ui/motion/framer-motion/motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], - "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "shadcn/ts-morph/@ts-morph/common/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], From f3a2232e8c9dd99ce1869e4dc700c15bb47b115c Mon Sep 17 00:00:00 2001 From: winoffrg Date: Tue, 31 Mar 2026 23:58:12 +0530 Subject: [PATCH 4/6] feat: new build system, shadcn CLI --- apps/www/app/(view)/view/[name]/page.tsx | 59 -- apps/www/app/blocks/[[...slug]]/page.tsx | 9 +- apps/www/components/block-display.tsx | 5 +- apps/www/components/block-viewer.tsx | 18 +- apps/www/components/ui/resizable.tsx | 68 +- apps/www/lib/events.ts | 5 +- apps/www/lib/registry.ts | 11 +- apps/www/next-env.d.ts | 2 +- apps/www/package.json | 9 +- apps/www/registry/collection/index.ts | 17 +- apps/www/scripts/build-registry.ts | 780 ----------------------- apps/www/scripts/registry-dev.mts | 446 +++++++++++++ apps/www/scripts/validate-registries.ts | 314 +++++++++ apps/www/source.config.ts | 1 - apps/www/tsconfig.json | 3 +- apps/www/vercel.json | 5 + 16 files changed, 837 insertions(+), 915 deletions(-) delete mode 100644 apps/www/app/(view)/view/[name]/page.tsx delete mode 100644 apps/www/scripts/build-registry.ts create mode 100644 apps/www/scripts/registry-dev.mts create mode 100644 apps/www/scripts/validate-registries.ts diff --git a/apps/www/app/(view)/view/[name]/page.tsx b/apps/www/app/(view)/view/[name]/page.tsx deleted file mode 100644 index 49dba69a..00000000 --- a/apps/www/app/(view)/view/[name]/page.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { notFound } from "next/navigation" -import * as React from "react" -import { registryItemSchema } from "shadcn/schema" -import { z } from "zod" - -import { ThemeToggle } from "@/components/layouts/theme-toggle" -import { atomReader } from "@/hooks/use-config" -import { getRegistryComponent, getRegistryItem } from "@/lib/registry" - -export const revalidate = false -export const dynamic = "force-static" -export const dynamicParams = false - -const getCachedRegistryItem = React.cache(async (name: string) => { - return await getRegistryItem(name) -}) - -export default async function BlockPage({ - params, -}: { - params: Promise<{ - name: string - }> -}) { - const { name } = await params - const item = await getCachedRegistryItem(name) - const Component = getRegistryComponent(name) - - if (!item || !Component) { - return notFound() - } - - return ( -
- {process.env.NODE_ENV === "development" && ( - - )} - -
- ) -} - -export async function generateStaticParams() { - const { Index } = await import("@/registry/__index__") - const config = atomReader() - const index = z.record(registryItemSchema).parse(Index[config.style]) - - const result = Object.values(index) - .filter((block) => - ["registry:block", "registry:component", "registry:internal"].includes( - block.type - ) - ) - .map((block) => ({ - name: block.name, - })) - - return result -} diff --git a/apps/www/app/blocks/[[...slug]]/page.tsx b/apps/www/app/blocks/[[...slug]]/page.tsx index da278513..683d57a7 100644 --- a/apps/www/app/blocks/[[...slug]]/page.tsx +++ b/apps/www/app/blocks/[[...slug]]/page.tsx @@ -81,11 +81,8 @@ export default async function BlockPage(props: BlockPageProps) { lg:block `} > - - + + - + diff --git a/apps/www/components/block-display.tsx b/apps/www/components/block-display.tsx index 8b3f0255..7dc6dbb7 100644 --- a/apps/www/components/block-display.tsx +++ b/apps/www/components/block-display.tsx @@ -1,5 +1,4 @@ -import type { registryItemFileSchema } from "shadcn/schema" -import type { z } from "zod" +import type { RegistryItem } from "shadcn/schema" import { highlight } from "fumadocs-core/highlight" import * as React from "react" @@ -46,7 +45,7 @@ const getCachedFileTree = React.cache( ) const getCachedHighlightedFiles = React.cache( - async (files: z.infer[]) => { + async (files: NonNullable) => { return await Promise.all( files.map(async (file) => ({ ...file, diff --git a/apps/www/components/block-viewer.tsx b/apps/www/components/block-viewer.tsx index 2ac9fc3b..6987d79c 100644 --- a/apps/www/components/block-viewer.tsx +++ b/apps/www/components/block-viewer.tsx @@ -1,8 +1,7 @@ "use client" -import type { ImperativePanelHandle } from "react-resizable-panels" -import type { registryItemFileSchema, registryItemSchema } from "shadcn/schema" -import type { z } from "zod" +import type { PanelImperativeHandle } from "react-resizable-panels" +import type { RegistryItem } from "shadcn/schema" import { Check, @@ -59,13 +58,13 @@ import { cn } from "@/lib/utils" interface BlockViewerContext { activeFile: null | string highlightedFiles: - | (z.infer & { + | (NonNullable[number] & { highlightedContent: any })[] | null iframeKey?: number - item: z.infer - resizablePanelRef: null | React.RefObject + item: RegistryItem + resizablePanelRef: null | React.RefObject setActiveFile: (file: string) => void setIframeKey?: React.Dispatch> setView: (view: "code" | "preview") => void @@ -147,7 +146,7 @@ function BlockViewerCode() { md:h-(--height) `} > - + @@ -260,7 +259,7 @@ function BlockViewerProvider({ const [activeFile, setActiveFile] = React.useState< BlockViewerContext["activeFile"] >(highlightedFiles?.[0].target ?? null) - const resizablePanelRef = React.useRef(null) + const resizablePanelRef = React.useRef(null) const [iframeKey, setIframeKey] = React.useState(0) return ( @@ -455,7 +454,6 @@ function BlockViewerView() { relative z-10 after:absolute after:inset-0 after:right-3 after:z-0 after:rounded-xl after:bg-background/50 `} - direction="horizontal" > } + panelRef={resizablePanelRef as React.Ref} > diff --git a/apps/www/components/ui/resizable.tsx b/apps/www/components/ui/resizable.tsx index 8083b2d9..858ecf0c 100644 --- a/apps/www/components/ui/resizable.tsx +++ b/apps/www/components/ui/resizable.tsx @@ -1,49 +1,18 @@ "use client" -import { GripVerticalIcon } from "lucide-react" -import * as React from "react" import * as ResizablePrimitive from "react-resizable-panels" import { cn } from "@/lib/utils" -const ResizablePanelGroup = React.forwardRef< - React.ElementRef, - ResizablePrimitive.PanelGroupProps ->(({ className, ...props }, ref) => ( - -)) - -ResizablePanelGroup.displayName = "ResizablePanelGroup" - -const ResizablePanel = React.forwardRef< - React.ElementRef, - ResizablePrimitive.PanelProps ->((props, ref) => ( - -)) - -ResizablePanel.displayName = "ResizablePanel" - function ResizableHandle({ className, withHandle, ...props -}: ResizablePrimitive.PanelResizeHandleProps & { +}: ResizablePrimitive.SeparatorProps & { withHandle?: boolean }) { return ( - - {withHandle ? ( -
- -
- ) : null} -
+ {withHandle && ( +
+ )} + + ) +} + +function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) { + return +} + +function ResizablePanelGroup({ + className, + ...props +}: ResizablePrimitive.GroupProps) { + return ( + ) } diff --git a/apps/www/lib/events.ts b/apps/www/lib/events.ts index 6ceeeb8f..b2685330 100644 --- a/apps/www/lib/events.ts +++ b/apps/www/lib/events.ts @@ -18,7 +18,10 @@ const eventSchema = z.object({ ]), // declare type AllowedPropertyValues = string | number | boolean | null properties: z - .record(z.union([z.string(), z.number(), z.boolean(), z.null()])) + .record( + z.string(), + z.union([z.string(), z.number(), z.boolean(), z.literal(null)]) + ) .optional(), }) diff --git a/apps/www/lib/registry.ts b/apps/www/lib/registry.ts index e7b436eb..fd9f0257 100644 --- a/apps/www/lib/registry.ts +++ b/apps/www/lib/registry.ts @@ -1,5 +1,4 @@ -import type { registryItemFileSchema } from "shadcn/schema" -import type { z } from "zod" +import type { RegistryItem } from "shadcn/schema" import { promises as fs } from "fs" import { tmpdir } from "os" @@ -139,7 +138,7 @@ async function createTempSourceFile(filename: string) { return path.join(dir, filename) } -function fixFilePaths(files: z.infer["files"]) { +function fixFilePaths(files: NonNullable) { if (!files) { return [] } @@ -157,7 +156,9 @@ function fixFilePaths(files: z.infer["files"]) { }) } -async function getFileContent(file: z.infer) { +async function getFileContent( + file: NonNullable[number] +) { const raw = await fs.readFile(file.path, "utf-8") const project = new Project({ @@ -189,7 +190,7 @@ async function getFileContent(file: z.infer) { return code } -function getFileTarget(file: z.infer) { +function getFileTarget(file: NonNullable[number]) { let target = file.target if (!target || target === "") { diff --git a/apps/www/next-env.d.ts b/apps/www/next-env.d.ts index 9edff1c7..c4b7818f 100644 --- a/apps/www/next-env.d.ts +++ b/apps/www/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/www/package.json b/apps/www/package.json index bc67a1c5..133d2ea5 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -6,8 +6,9 @@ "build": "bun run registry:build && next build", "dev": "next dev --turbopack", "start": "next start", - "registry:build": "REGISTRY_HOST=https://limeplay.winoffrg.dev tsx --tsconfig ./tsconfig.scripts.json ./scripts/build-registry.ts", - "registry:dev": "REGISTRY_HOST=http://localhost:3000 tsx --watch --tsconfig ./tsconfig.scripts.json ./scripts/build-registry.ts --cache", + "registry:build": "REGISTRY_HOST=https://limeplay.winoffrg.dev exec tsx --tsconfig ./tsconfig.scripts.json ./scripts/registry-dev.mts", + "registry:dev": "REGISTRY_HOST=http://localhost:3000 exec tsx --tsconfig ./tsconfig.scripts.json ./scripts/registry-dev.mts --watch", + "validate:registries": "bun run ./scripts/validate-registries.ts", "format:write": "prettier --write \"**/*.{ts,tsx,mdx}\" --cache --config ../../prettier.config.cjs && next lint", "format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache --config ../../prettier.config.cjs", "install:vercel": "bash ./scripts/vercel-install.sh" @@ -68,7 +69,7 @@ "tsx": "^4.20.6", "tw-animate-css": "^1.3.6", "unist-util-visit": "^5.0.0", - "zod": "^3.24.2", + "zod": "^4.3.6", "zustand": "^5.0.8" }, "devDependencies": { @@ -88,7 +89,7 @@ "rehype-slug": "^6.0.0", "rimraf": "^6.0.1", "schema-dts": "^1.1.5", - "shadcn": "^3.6.2", + "shadcn": "^4.1.1", "tailwindcss": "^4.1.11", "typescript": "^5.8.3" } diff --git a/apps/www/registry/collection/index.ts b/apps/www/registry/collection/index.ts index 40e8ac3a..32e88ec5 100644 --- a/apps/www/registry/collection/index.ts +++ b/apps/www/registry/collection/index.ts @@ -1,5 +1,4 @@ -import { type Registry, registryItemSchema } from "shadcn/schema" -import { z } from "zod" +import { type Registry, registrySchema } from "shadcn/schema" import { blocks } from "@/registry/collection/registry-blocks" import { examples } from "@/registry/collection/registry-examples" @@ -7,9 +6,9 @@ import { hooks } from "@/registry/collection/registry-hooks" import { internal, lib } from "@/registry/collection/registry-lib" import { ui } from "@/registry/collection/registry-ui" -export const registry: Registry = { +const result = registrySchema.safeParse({ homepage: "https://limeplay.winoffrg.dev", - items: z.array(registryItemSchema).parse([ + items: [ { cssVars: {}, dependencies: ["class-variance-authority", "lucide-react"], @@ -25,6 +24,14 @@ export const registry: Registry = { ...hooks, ...internal, ...examples, - ]), + ], name: "limeplay/ui", +}) + +if (!result.success) { + console.error("โŒ Registry validation failed:") + console.error(JSON.stringify(result.error.format(), null, 2)) + throw new Error("Invalid registry schema") } + +export const registry: Registry = result.data diff --git a/apps/www/scripts/build-registry.ts b/apps/www/scripts/build-registry.ts deleted file mode 100644 index c72a634f..00000000 --- a/apps/www/scripts/build-registry.ts +++ /dev/null @@ -1,780 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions */ - -import { exec } from "child_process" -import { promises as fs, statSync } from "fs" -import path from "path" -import { rimraf } from "rimraf" -import { type Registry, registryItemSchema } from "shadcn/schema" -import { z } from "zod" - -import { registry } from "@/registry/collection/index" - -type LogLevel = "debug" | "error" | "info" | "warn" -const LOG_LEVEL: LogLevel = (process.env.LOG_LEVEL ?? "info") as LogLevel - -const logLevels: Record = { - debug: 3, - error: 0, - info: 2, - warn: 1, -} - -const shouldLog = (level: LogLevel): boolean => { - return logLevels[level] <= logLevels[LOG_LEVEL] -} - -const logger = { - debug: (message: string) => { - shouldLog("debug") && console.debug(message) - }, - error: (message: string) => { - console.error(message) - }, - info: (message: string) => { - shouldLog("info") && console.log(message) - }, - warn: (message: string) => { - shouldLog("warn") && console.warn(message) - }, -} - -const STYLE = "default" -const PRO_STYLE = "pro" -const DEPRECATED_ITEMS = ["test"] -const REGISTRY_HOST = process.env.REGISTRY_HOST ?? "http://localhost:3000" -const BASE_URL = `${REGISTRY_HOST}/r` -const PRO_BASE_URL = `${REGISTRY_HOST}/r/pro` - -logger.info(`๐ŸŒ Using registry host: ${REGISTRY_HOST}`) - -const PATH_MAPPINGS = [ - { - pattern: "blocks/", - targetFn: (path: string) => { - // Extract the part after "blocks/" - const match = /blocks\/([^/]+)\/(.+)/.exec(path) - if (match) { - const [, blockName, filePath] = match - return `components/${blockName}/${filePath}` - } - return null - }, - }, - // Add more mappings as needed: - // { pattern: "hooks/", targetFn: ... }, - // { pattern: "ui/", targetFn: ... }, -] - -// Create a map of all file paths to their corresponding items -function createFilePathToItemMap( - items: Registry["items"] -): Map { - const map = new Map() - items.forEach((item) => { - if (item.files) { - item.files.forEach((file) => { - const filePath = typeof file === "string" ? file : file.path - map.set(filePath, item.name) - }) - } - }) - return map -} - -// Create a map of all registry items for quick lookup -function createRegistryItemsMap( - items: Registry["items"] -): Map { - const map = new Map() - items.forEach((item) => { - if (item.name && !DEPRECATED_ITEMS.includes(item.name)) { - map.set(item.name, item) - } - }) - return map -} - -/** - * Dynamically load pro registry items if available. - */ -// Unified registry items from index -const registryItems = registry.items -const registryItemsMap = createRegistryItemsMap(registryItems) -const filePathToItemMap = createFilePathToItemMap(registryItems) - -// Helper to check if item is pro -const isProItem = (item: Registry["items"][number]) => { - return item.categories?.includes("pro") -} - -async function buildCombinedRegistryIndex( - registries: Array<{ registry: Registry; style: string }> -) { - logger.info( - `๐Ÿ—‚๏ธ Building registry/__index__.tsx with ${registries.length} tier(s)...` - ) - - let index = `/* eslint-disable @typescript-eslint/ban-ts-comment */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -// @ts-nocheck -// This file is autogenerated by scripts/build-registry.ts -// Do not edit this file directly. - -import * as React from "react" - -export const Index: Record = {` - - for (const { registry, style } of registries) { - index += ` - "${style}": {` - - for (const item of registry.items) { - const resolveFiles = item.files?.map( - (file) => `registry/${style}/${file.path}` - ) - if (!resolveFiles) { - continue - } - - const componentPath = item.files?.[0]?.path - ? `@/registry/${style}/${item.files[0].path}` - : "" - - index += ` - "${item.name}": { - name: "${item.name}", - description: "${item.description ?? ""}", - type: "${item.type}", - registryDependencies: ${JSON.stringify(item.registryDependencies)}, - files: [${item.files?.map((file) => { - const filePath = `registry/${style}/${ - typeof file === "string" ? file : file.path - }` - const resolvedFilePath = path.resolve(filePath) - return typeof file === "string" - ? `"${resolvedFilePath}"` - : `{ - path: "${filePath}", - type: "${file.type}", - target: "${file.target ?? ""}" - }` - })}], - component: ${ - componentPath - ? `React.lazy(async () => { - const mod = await import("${componentPath}") - const exportName = Object.keys(mod).find(key => typeof mod[key] === 'function' || typeof mod[key] === 'object') || "${item.name}" - return { default: mod.default || mod[exportName] } - })` - : "null" - }, - meta: ${JSON.stringify(item.meta)}, - },` - } - - index += ` - },` - } - - index += ` -}` - - // Create registry directory if it doesn't exist - const registryDir = path.join(process.cwd(), "registry") - await fs.mkdir(registryDir, { recursive: true }) - - // Write combined index - rimraf.sync(path.join(registryDir, "__index__.tsx")) - await fs.writeFile(path.join(registryDir, "__index__.tsx"), index) -} - -async function buildRegistryJsonFile( - registry: Registry, - style: string, - fileName = "registry.json" -) { - logger.info(`๐Ÿ’… Building ${fileName}...`) - // 1. Fix the path for registry items. - const fixedRegistry = { - ...registry, - items: registry.items.map((item) => { - const files = item.files?.map((file) => { - return { - ...file, - path: `registry/${style}/${file.path}`, - } - }) - - return { - ...item, - files, - } - }), - } - - // 2. Write the content of the registry - rimraf.sync(path.join(process.cwd(), fileName)) - await fs.writeFile( - path.join(process.cwd(), fileName), - JSON.stringify(fixedRegistry, null, 2) - ) -} - -// Build free registry -// Helper to create registry object -function createRegistry( - items: Registry["items"], - name = "winoffrg/limeplay" -): Registry { - return { - homepage: "https://limeplay.winoffrg.dev", - items: z.array(registryItemSchema).parse(processRegistryItems(items)), - name, - } -} - -// Fetch and parse shadcn registry into a map keyed by name (no top-level await) -async function getShadcnRegistryMap(): Promise> { - try { - const items = await fetch( - "https://github.com/shadcn-ui/ui/blob/main/apps/v4/public/r/index.json?raw=true" - ).then((res) => res.json()) - return parseShadcnRegistryItemsToMap(items as Array<{ name?: string }>) - } catch { - return new Map() - } -} - -async function main() { - try { - logger.info("๐Ÿง Validating dependencies...") - - const hasProRegistry = await proRegistryExists() - - // Split items based on category - // Free items: No 'pro' category - const freeItems = registryItems.filter((item) => !isProItem(item)) - - const proItems = registryItems.filter((item) => { - if (!isProItem(item)) return false - - const firstFile = item.files?.[0] - if (!firstFile) return false - - const filePath = - typeof firstFile === "string" ? firstFile : firstFile.path - const pathParts = filePath.split("/") - - // For blocks: blocks//... - // For ui: ui/.tsx - let itemDir: string - if (pathParts[0] === "blocks" && pathParts.length > 1) { - itemDir = path.join( - process.cwd(), - "registry/pro", - pathParts[0], - pathParts[1] - ) - } else { - itemDir = path.join(process.cwd(), "registry/pro", pathParts[0]) - } - - try { - const stat = statSync(itemDir) - if (!stat.isDirectory()) { - logger.debug( - `โญ๏ธ Skipping "${item.name}" - source directory not found: ${itemDir}` - ) - return false - } - return true - } catch { - logger.debug( - `โญ๏ธ Skipping "${item.name}" - source directory not found: ${itemDir}` - ) - return false - } - }) - - // Check if we have pro items defined but missing submodule - if (proItems.length > 0 && !hasProRegistry) { - logger.warn( - "โš ๏ธ Pro items found in registry but Pro submodule missing. Pro build will be skipped." - ) - } - - // Prepare Free Registry items (include index metadata) - const freeRegistryItemsWithIndex = [ - { - cssVars: {}, - dependencies: [ - "tw-animate-css", - "class-variance-authority", - "lucide-react", - ], - files: [], - name: "index", - registryDependencies: ["utils"], - type: "registry:style" as const, - }, - ...freeItems, - ] - - // Build free registry - const freeRegistry = createRegistry(freeRegistryItemsWithIndex) - - // Validate dependencies for free registry (only checking against free items and shadcn) - // We pass the global registryItemsMap but validateDependencies logic might need adjustment if it expects map to only contain valid items. - // Actually, validateDependencies checks undefined dependencies. - // If a free item depends on a pro item (which is in registryItemsMap), it is technically found. - // But we should ban free -> pro dependency. - // For now we'll rely on good faith or add a check later. - await validateDependencies( - freeRegistry, - registryItemsMap, - filePathToItemMap - ) - - // Build free registry JSON - await buildRegistryJsonFile(freeRegistry, STYLE) - - // Run shadcn build for free components - // Output to /public/r (root - backwards compat) AND /public/r/free - await runShadcnBuild("registry.json", "../www/public/r") - - // Copy to /r/free for explicit free path - const freeOutputDir = path.join(process.cwd(), "public/r/free") - await fs.mkdir(freeOutputDir, { recursive: true }) - const rootOutputDir = path.join(process.cwd(), "public/r") - const rootFiles = await fs.readdir(rootOutputDir) - for (const file of rootFiles) { - if (file.endsWith(".json") && file !== "registry.json") { - // Skip directories like 'free' and 'pro' - const srcPath = path.join(rootOutputDir, file) - const stat = await fs.stat(srcPath) - if (stat.isFile()) { - await fs.copyFile(srcPath, path.join(freeOutputDir, file)) - } - } - } - // Copy registry.json to free dir as well - await fs.copyFile( - path.join(rootOutputDir, "registry.json"), - path.join(freeOutputDir, "registry.json") - ) - logger.info("โœ… Copied free components to /r/free/") - - // Prepare for combined index - const registriesToIndex = [{ registry: freeRegistry, style: STYLE }] - - // Build pro registry if available and submodule exists - if (proItems.length > 0 && hasProRegistry) { - logger.info("๐Ÿ” Building pro registry...") - const proRegistry = createRegistry(proItems, "winoffrg/limeplay-pro") - - // Validate dependencies for pro registry - // It can depend on free items + pro items - // We use the same map. - await validateDependencies( - proRegistry, - registryItemsMap, - filePathToItemMap, - PRO_BASE_URL - ) - - // Add to index list - registriesToIndex.push({ registry: proRegistry, style: PRO_STYLE }) - - // Build pro registry JSON - await buildRegistryJsonFile(proRegistry, PRO_STYLE, "registry-pro.json") - - // Run shadcn build for pro components - await runShadcnBuild("registry-pro.json", "../www/public/r/pro") - logger.info("โœ… Pro registry built successfully") - } else { - if (proItems.length === 0) { - logger.info("โญ๏ธ No Pro items defined in registry.") - } else { - logger.info("โญ๏ธ Skipping pro registry build (missing submodule)") - } - } - - // Build combined index - await buildCombinedRegistryIndex(registriesToIndex) - - logger.info("๐ŸŽ‰ Registry build complete!") - } catch (error) { - logger.error(`${error}`) - process.exit(1) - } -} - -// Convert shadcn registry array into a map keyed by item name. -// We ignore duplicates and only keep the first occurrence. -function parseShadcnRegistryItemsToMap( - items: Array<{ name?: string }> -): Map { - const byName = new Map() - if (!Array.isArray(items)) return byName - for (const item of items) { - const name = typeof item.name === "string" ? item.name : undefined - if (!name) continue - if (!byName.has(name)) { - byName.set(name, item) - } - } - return byName -} - -function processRegistryItems(items: Registry["items"]): Registry["items"] { - return items - .filter((item) => !DEPRECATED_ITEMS.includes(item.name)) - .map((item) => { - if (item.registryDependencies?.length) { - item.registryDependencies = item.registryDependencies.map((dep) => - resolveRegistryDependency(dep) - ) - } - - if (item.files) { - item.files = item.files.map((file) => { - if (typeof file === "string") return file - - if (file.target) return file - - for (const mapping of PATH_MAPPINGS) { - if (file.path.includes(mapping.pattern)) { - const target = mapping.targetFn(file.path) - if (target) { - logger.debug(`โœ… Added target for "${file.path}" โ†’ "${target}"`) - return { ...file, target } - } - } - } - - return file - }) - } - - return item - }) -} - -/** - * Check if the pro registry has actual components. - */ -async function proRegistryExists(): Promise { - try { - const proPath = path.join(process.cwd(), "registry/pro") - const stat = await fs.stat(proPath) - if (!stat.isDirectory()) return false - - const files = await fs.readdir(proPath, { recursive: true }) - return files.some( - (f) => typeof f === "string" && (f.endsWith(".tsx") || f.endsWith(".ts")) - ) - } catch { - return false - } -} - -function resolveRegistryDependency(dependency: string): string { - if (typeof dependency !== "string" || dependency.startsWith("http")) { - return dependency - } - - if (registryItemsMap.has(dependency)) { - const item = registryItemsMap.get(dependency) - if (isProItem(item!)) { - return `${PRO_BASE_URL}/${dependency}.json` - } - return `${BASE_URL}/${dependency}.json` - } - - return dependency -} - -async function runShadcnBuild( - registryFile: string, - outputDir: string -): Promise { - logger.info(`๐Ÿ—๏ธ Building ${registryFile} to ${outputDir}...`) - return new Promise((resolve, reject) => { - const proc = exec( - `bun x shadcn build ${registryFile} --output ${outputDir}` - ) - - proc.stdout?.on("data", (data) => { - console.log(data) - }) - - proc.stderr?.on("data", (data) => { - console.error(data) - }) - - proc.on("exit", (code) => { - if (code === 0) { - resolve(undefined) - } else { - reject(new Error(`Process exited with code ${code}`)) - } - }) - }) -} - -// Check for missing and undefined dependencies -async function validateDependencies( - registry: Registry, - itemsMap: Map, - filePathMap: Map, - baseUrl: string = BASE_URL -) { - logger.info("๐Ÿ” Validating dependencies based on imports...") - const shadcnRegistryMap = await getShadcnRegistryMap() - - // Regex to find imports from our registry - const importRegex = /@\/registry\/(default|pro)\/([^"']+)/g - - // Additional regex to catch import * as Namespace patterns - const namespaceImportRegex = - /import\s+\*\s+as\s+\w+\s+from\s+["']@\/registry\/(default|pro)\/([^"']+)["']/g - - // Track missing registry entries - const missingRegistryItems = new Map>() - - // Debug registry items - logger.debug("๐Ÿ“‹ Registry items: " + Array.from(itemsMap.keys()).join(", ")) - - // Check for undefined dependencies first - for (const item of registry.items) { - if (!item.registryDependencies?.length) continue - - const undefinedDependencies = [] - - for (const dependency of item.registryDependencies) { - // Skip URL dependencies - if (typeof dependency !== "string" || dependency.startsWith("http")) { - continue - } - - if (dependency.startsWith("@") && dependency.includes("/")) { - continue - } - - // Check if dependency exists - if (!itemsMap.has(dependency) && !shadcnRegistryMap.has(dependency)) { - undefinedDependencies.push(dependency) - } - } - - if (undefinedDependencies.length > 0) { - logger.error( - `โŒ Component "${item.name}" has missing dependencies in registryDependencies:` - ) - undefinedDependencies.forEach((dep) => { - logger.error(` - ${dep} (not found in registry)`) - }) - logger.error(` These dependencies need to be defined or removed.`) - } - } - - // Check for missing dependencies based on imports - for (const item of registry.items) { - if (!item.files) continue - - const declaredDependencies = new Set( - (item.registryDependencies ?? []).map((dep) => { - // Extract component name from URL if needed - if (dep.startsWith("http")) { - return dep.split("/").pop()?.replace(".json", "") || dep - } - return dep - }) - ) - logger.debug( - `๐Ÿ“ฆ Checking ${item.name} with dependencies: ${ - declaredDependencies.size - ? Array.from(declaredDependencies).join(", ") - : "none" - }` - ) - - const missingDependencies = new Set() - - for (const file of item.files) { - if (typeof file === "string") continue - - try { - // Determine the correct style directory based on item category - const styleDir = isProItem(item) ? PRO_STYLE : STYLE - const filePath = path.join( - process.cwd(), - "registry", - styleDir, - file.path - ) - if ( - !(await fs - .stat(filePath) - .then(() => true) - .catch(() => false)) - ) { - logger.debug(`โš ๏ธ File not found: ${filePath}`) - continue - } - - logger.debug(`๐Ÿ”Ž Checking file: ${file.path}`) - const content = await fs.readFile(filePath, "utf8") - - // Process both regular imports and namespace imports - const regularImports = [...content.matchAll(importRegex)] - const namespaceImports = [...content.matchAll(namespaceImportRegex)] - - logger.debug( - ` - Found ${regularImports.length.toString()} regular imports, ${namespaceImports.length.toString()} namespace imports` - ) - - const allMatches = [...regularImports, ...namespaceImports] - - if (allMatches.length === 0) { - logger.debug(` - No registry imports found in file`) - } - - for (const match of allMatches) { - const importStyle = match[1] // "default" or "pro" - const importPath = match[2] - logger.debug( - ` - Found import: @/registry/${importStyle}/${importPath}` - ) - - const importParts = importPath.split("/") - - // Skip if it's importing from itself - if (file.path.startsWith(`${importParts[0]}/${importParts[1]}`)) { - logger.debug(` - Skipping self-import: ${importPath}`) - continue - } - - const importType = importParts[0] // ui, blocks, hooks, etc. - const importName = importParts[1] // player-hooks, media-provider, etc. - logger.debug(` - Import type: ${importType}, name: ${importName}`) - - // Try to find the component by name - if (itemsMap.has(importName)) { - logger.debug(` - Component exists: ${importName}`) - // Component exists by name - check if it's already a dependency - const dependencyUrl = `${baseUrl}/${importName}.json` - if ( - !declaredDependencies.has(importName) && - !declaredDependencies.has(dependencyUrl) - ) { - logger.debug(` - Adding missing dependency: ${importName}`) - missingDependencies.add(importName) - } else { - logger.debug(` - Dependency already declared: ${importName}`) - } - continue - } else { - logger.debug(` - No direct component match for: ${importName}`) - - // Track missing registry items - if (!missingRegistryItems.has(item.name)) { - missingRegistryItems.set(item.name, new Set()) - } - missingRegistryItems.get(item.name)?.add(importName) - } - - // Find the component that provides this file - const componentPath = `${importParts[0]}/${importParts[1]}` - const possibleFilePaths = Array.from(filePathMap.keys()).filter((p) => - p.startsWith(componentPath) - ) - - logger.debug( - ` - Looking for components with path: ${componentPath}` - ) - logger.debug( - ` - Found ${possibleFilePaths.length.toString()} possible matches` - ) - - if (possibleFilePaths.length > 0) { - for (const fp of possibleFilePaths) { - const componentName = filePathMap.get(fp) ?? "" - logger.debug( - ` - Matched file: ${fp} โ†’ component: ${componentName}` - ) - - // Check if this component is already in dependencies - const dependencyUrl = `${baseUrl}/${componentName}.json` - if ( - componentName && - componentName !== item.name && - !declaredDependencies.has(componentName) && - !declaredDependencies.has(dependencyUrl) - ) { - logger.debug( - ` - Adding missing dependency: ${componentName}` - ) - missingDependencies.add(componentName) - } else if (componentName) { - logger.debug( - ` - Dependency already declared or self-reference: ${componentName}` - ) - } - } - } else { - logger.debug(` - No file path matches found`) - } - } - } catch (error) { - logger.error(`Error reading file ${file.path}: ${error as string}`) - } - } - - if (missingDependencies.size > 0) { - logger.warn( - `โš ๏ธ Component "${item.name}" is missing dependencies in registryDependencies:` - ) - missingDependencies.forEach((dep) => { - logger.warn(` - ${dep}`) - }) - logger.warn( - ` Add them to the registryDependencies array in the registry definition.` - ) - - // Force log flush by adding a slight delay - await new Promise((resolve) => setTimeout(resolve, 10)) - } else { - logger.debug(`โœ… No missing dependencies for ${item.name}`) - } - } - - // Report missing registry items - if (missingRegistryItems.size > 0) { - logger.error( - "\n๐Ÿšซ Components are importing from registry items that don't exist:" - ) - - for (const [component, imports] of missingRegistryItems.entries()) { - logger.error( - ` - "${component}" imports: ${Array.from(imports).join(", ")}` - ) - } - - logger.error( - " These components should be registered in the appropriate registry file (registry-ui.ts, etc.)\n" - ) - - // Force log flush by adding a slight delay - await new Promise((resolve) => setTimeout(resolve, 100)) - } -} - -main() - .then(() => { - process.exit(0) - }) - .catch((error: unknown) => { - logger.error(`${error}`) - process.exit(1) - }) diff --git a/apps/www/scripts/registry-dev.mts b/apps/www/scripts/registry-dev.mts new file mode 100644 index 00000000..8bdf595c --- /dev/null +++ b/apps/www/scripts/registry-dev.mts @@ -0,0 +1,446 @@ +/** + * registry-dev.mts + * + * Single-file registry build pipeline: + * 1. Compile โ†’ registry.json, registry-pro.json, registry/__index__.tsx + * 2. shadcn build โ†’ public/r/ (free) and public/r/pro/ (pro) + * 3. Copy free โ†’ public/r/free/ + * 4. validate-registries.ts + * + * Flags: + * --watch Re-run on file changes in registry/collection/ and registry/default/ + * + * Usage: + * REGISTRY_HOST=http://localhost:3000 tsx --tsconfig ./tsconfig.scripts.json ./scripts/registry-dev.mts --watch + * REGISTRY_HOST=https://limeplay.winoffrg.dev tsx --tsconfig ./tsconfig.scripts.json ./scripts/registry-dev.mts + */ + +import { type ChildProcess, exec } from "child_process" +import { promises as fs, statSync, watch } from "fs" +import path from "path" +import { rimraf } from "rimraf" +import { type Registry } from "shadcn/schema" + +// Dynamic import to avoid ESM named-export resolution issues with .mts + tsx +const { registry } = await import("@/registry/collection/index") + +// --------------------------------------------------------------------------- +// Config +// --------------------------------------------------------------------------- + +const WATCH = process.argv.includes("--watch") +const CWD = process.cwd() + +const STYLE = "default" +const PRO_STYLE = "pro" +const REGISTRY_HOST = process.env.REGISTRY_HOST ?? "http://localhost:3000" +const BASE_URL = `${REGISTRY_HOST}/r` +const PRO_BASE_URL = `${REGISTRY_HOST}/r/pro` + +// --------------------------------------------------------------------------- +// Maps +// --------------------------------------------------------------------------- + +const registryItems = registry.items +const registryItemsMap = new Map() +for (const item of registryItems) { + registryItemsMap.set(item.name, item) +} + +const isProItem = (item: Registry["items"][number]) => + item.categories?.includes("pro") + +// --------------------------------------------------------------------------- +// Path mappings โ€“ auto-generate `target` for block files that lack one +// --------------------------------------------------------------------------- + +const PATH_MAPPINGS = [ + { + pattern: "blocks/", + targetFn: (filePath: string) => { + const match = /blocks\/([^/]+)\/(.+)/.exec(filePath) + if (match) { + const [, blockName, rest] = match + return `components/${blockName}/${rest}` + } + return null + }, + }, +] + +// --------------------------------------------------------------------------- +// Resolve registry dependencies to full URLs +// --------------------------------------------------------------------------- + +async function buildRegistryIndex( + registries: Array<{ registry: Registry; style: string }> +) { + console.log( + `Building registry/__index__.tsx with ${registries.length} tier(s)...` + ) + + let index = `/* eslint-disable @typescript-eslint/ban-ts-comment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +// @ts-nocheck +// This file is autogenerated by scripts/registry-dev.mts +// Do not edit this file directly. + +import * as React from "react" + +export const Index: Record = {` + + for (const { registry: reg, style } of registries) { + index += `\n "${style}": {` + + for (const item of reg.items) { + if (!item.files?.length) { + index += ` + "${item.name}": { + name: "${item.name}", + description: "${item.description ?? ""}", + type: "${item.type}", + registryDependencies: ${JSON.stringify(item.registryDependencies)}, + files: [], + component: null, + meta: ${JSON.stringify(item.meta)}, + },` + continue + } + + const componentPath = `@/registry/${style}/${ + typeof item.files[0] === "string" ? item.files[0] : item.files[0].path + }` + + const filesStr = item.files + .map((file) => { + if (typeof file === "string") { + const fp = `registry/${style}/${file}` + return `"${path.resolve(fp)}"` + } + const fp = `registry/${style}/${file.path}` + return `{ + path: "${fp}", + type: "${file.type}", + target: "${file.target ?? ""}" + }` + }) + .join(",") + + index += ` + "${item.name}": { + name: "${item.name}", + description: "${item.description ?? ""}", + type: "${item.type}", + registryDependencies: ${JSON.stringify(item.registryDependencies)}, + files: [${filesStr}], + component: React.lazy(async () => { + const mod = await import("${componentPath}") + const exportName = Object.keys(mod).find(key => typeof mod[key] === 'function' || typeof mod[key] === 'object') || "${item.name}" + return { default: mod.default || mod[exportName] } + }), + meta: ${JSON.stringify(item.meta)}, + },` + } + + index += `\n },` + } + + index += `\n}\n` + + const dest = path.join(CWD, "registry", "__index__.tsx") + await fs.mkdir(path.dirname(dest), { recursive: true }) + rimraf.sync(dest) + await fs.writeFile(dest, index) +} + +// --------------------------------------------------------------------------- +// Process items โ€“ resolve deps + auto-fill targets +// --------------------------------------------------------------------------- + +async function compile() { + console.log(`Using registry host: ${REGISTRY_HOST}`) + + const hasProRegistry = await proRegistryExists() + + // Split items by tier + const freeItems = registryItems.filter((item) => !isProItem(item)) + const proItems = registryItems.filter((item) => { + if (!isProItem(item)) return false + const firstFile = item.files?.[0] + if (!firstFile) return false + const filePath = typeof firstFile === "string" ? firstFile : firstFile.path + const pathParts = filePath.split("/") + let itemDir: string + if (pathParts[0] === "blocks" && pathParts.length > 1) { + itemDir = path.join(CWD, "registry/pro", pathParts[0], pathParts[1]) + } else { + itemDir = path.join(CWD, "registry/pro", pathParts[0]) + } + try { + return statSync(itemDir).isDirectory() + } catch { + return false + } + }) + + // Free registry (the "index" style entry is already in the collection) + const freeRegistry = createRegistry(freeItems) + await writeRegistryJson(freeRegistry, STYLE, "registry.json") + + const registriesToIndex = [{ registry: freeRegistry, style: STYLE }] + + // Pro registry + if (proItems.length > 0 && hasProRegistry) { + console.log("Building pro registry...") + const proRegistry = createRegistry(proItems, "winoffrg/limeplay-pro") + await writeRegistryJson(proRegistry, PRO_STYLE, "registry-pro.json") + registriesToIndex.push({ registry: proRegistry, style: PRO_STYLE }) + } else if (proItems.length > 0) { + console.log("Pro items defined but submodule missing โ€“ skipping pro build") + } else { + console.log("No pro items defined") + } + + await buildRegistryIndex(registriesToIndex) + console.log("Compile complete!") +} + +// --------------------------------------------------------------------------- +// Create a Registry object from processed items +// --------------------------------------------------------------------------- + +async function copyFreeToExplicitDir() { + const srcDir = path.join(CWD, "public/r") + const destDir = path.join(CWD, "public/r/free") + await fs.mkdir(destDir, { recursive: true }) + + const entries = await fs.readdir(srcDir) + for (const entry of entries) { + if (!entry.endsWith(".json")) continue + const srcPath = path.join(srcDir, entry) + const stat = await fs.stat(srcPath) + if (stat.isFile()) { + await fs.copyFile(srcPath, path.join(destDir, entry)) + } + } + console.log("Copied free components to /r/free/") +} + +// --------------------------------------------------------------------------- +// Write registry JSON (with style-prefixed paths for shadcn build) +// --------------------------------------------------------------------------- + +function createRegistry( + items: Registry["items"], + name = "winoffrg/limeplay" +): Registry { + return { + homepage: "https://limeplay.winoffrg.dev", + items: processItems(items), + name, + } +} + +// --------------------------------------------------------------------------- +// Build registry/__index__.tsx (React.lazy component lookup for docs site) +// --------------------------------------------------------------------------- + +async function pipeline() { + const start = Date.now() + console.log("\n--- Registry build started ---\n") + + // 1. Compile registry.json, registry-pro.json, __index__.tsx + await compile() + + // 2. shadcn build (free) + await run("bun x shadcn build registry.json --output public/r") + + // 3. Copy free โ†’ /r/free/ + await copyFreeToExplicitDir() + + // 4. shadcn build (pro) โ€“ only if registry-pro.json was generated + try { + await fs.stat(path.join(CWD, "registry-pro.json")) + await run("bun x shadcn build registry-pro.json --output public/r/pro") + } catch { + // No pro registry + } + + // 5. Validate + await run("bun run ./scripts/validate-registries.ts") + + const elapsed = ((Date.now() - start) / 1000).toFixed(1) + console.log(`\n--- Registry build complete (${elapsed}s) ---\n`) +} + +// --------------------------------------------------------------------------- +// Pro registry detection +// --------------------------------------------------------------------------- + +function processItems(items: Registry["items"]): Registry["items"] { + return items.map((item) => { + if (item.registryDependencies?.length) { + item.registryDependencies = item.registryDependencies.map( + resolveRegistryDependency + ) + } + + if (item.files) { + item.files = item.files.map((file) => { + if (typeof file === "string") return file + if (file.target) return file + + for (const mapping of PATH_MAPPINGS) { + if (file.path.includes(mapping.pattern)) { + const target = mapping.targetFn(file.path) + if (target) return { ...file, target } + } + } + return file + }) + } + + return item + }) +} + +// --------------------------------------------------------------------------- +// Shell helper +// --------------------------------------------------------------------------- + +async function proRegistryExists(): Promise { + try { + const proPath = path.join(CWD, "registry/pro") + const stat = await fs.stat(proPath) + if (!stat.isDirectory()) return false + const files = await fs.readdir(proPath, { recursive: true }) + return files.some( + (f) => typeof f === "string" && (f.endsWith(".tsx") || f.endsWith(".ts")) + ) + } catch { + return false + } +} + +// --------------------------------------------------------------------------- +// Copy free output to /r/free/ +// --------------------------------------------------------------------------- + +function resolveRegistryDependency(dependency: string): string { + if (typeof dependency !== "string" || dependency.startsWith("http")) { + return dependency + } + if (registryItemsMap.has(dependency)) { + const item = registryItemsMap.get(dependency)! + if (isProItem(item)) { + return `${PRO_BASE_URL}/${dependency}.json` + } + return `${BASE_URL}/${dependency}.json` + } + return dependency +} + +// --------------------------------------------------------------------------- +// Compile step +// --------------------------------------------------------------------------- + +function run(cmd: string): Promise { + return new Promise((resolve, reject) => { + const proc: ChildProcess = exec(cmd, { cwd: CWD }) + proc.stdout?.pipe(process.stdout) + proc.stderr?.pipe(process.stderr) + proc.on("exit", (code) => { + if (code === 0) resolve() + else reject(new Error(`Command failed (exit ${code}): ${cmd}`)) + }) + }) +} + +// --------------------------------------------------------------------------- +// Full pipeline +// --------------------------------------------------------------------------- + +function startWatcher() { + const dirs = [ + path.join(CWD, "registry/collection"), + path.join(CWD, "registry/default"), + path.join(CWD, "registry/pro"), + ] + + let debounce: null | ReturnType = null + let running = false + + const rebuild = () => { + if (running) return + running = true + pipeline() + .catch((err) => console.error("Build failed:", err.message)) + .finally(() => { + running = false + }) + } + + for (const dir of dirs) { + try { + watch(dir, { recursive: true }, (_event, filename) => { + if (!filename) return + if ( + !filename.endsWith(".ts") && + !filename.endsWith(".tsx") && + !filename.endsWith(".css") + ) + return + + if (debounce) clearTimeout(debounce) + debounce = setTimeout(rebuild, 300) + }) + console.log(`Watching: ${path.relative(CWD, dir)}/`) + } catch { + // Directory may not exist (e.g. registry/pro without submodule) + } + } +} + +// --------------------------------------------------------------------------- +// Watch mode +// --------------------------------------------------------------------------- + +async function writeRegistryJson( + reg: Registry, + style: string, + fileName: string +) { + console.log(`Writing ${fileName}...`) + + const output = { + ...reg, + items: reg.items.map((item) => ({ + ...item, + files: item.files?.map((file) => + typeof file === "string" + ? file + : { ...file, path: `registry/${style}/${file.path}` } + ), + })), + } + + const dest = path.join(CWD, fileName) + rimraf.sync(dest) + await fs.writeFile(dest, JSON.stringify(output, null, 2)) +} + +// --------------------------------------------------------------------------- +// Entry +// --------------------------------------------------------------------------- + +pipeline() + .then(() => { + if (WATCH) { + startWatcher() + console.log("Watching for changes... (Ctrl+C to stop)\n") + } + }) + .catch((err) => { + console.error(err) + process.exit(1) + }) diff --git a/apps/www/scripts/validate-registries.ts b/apps/www/scripts/validate-registries.ts new file mode 100644 index 00000000..6ae83dfa --- /dev/null +++ b/apps/www/scripts/validate-registries.ts @@ -0,0 +1,314 @@ +/** + * validate-registries.ts + * + * Validates the built registry output in public/r/ to catch errors + * in registry items during development. This runs independently of + * the build script and can be used in CI or as a pre-build check. + * + * Validates: + * 1. The registry collection (source of truth) against registrySchema. + * 2. The built registry.json in public/r/ against registrySchema. + * 3. Each individual built component JSON in public/r/*.json against + * registryItemSchema. + * 4. Cross-references: every item in registry.json has a corresponding + * individual JSON file and vice versa. + * 5. All registryDependencies resolve to existing items. + */ + +import { promises as fs } from "fs" +import path from "path" +import { registryItemSchema, registrySchema } from "shadcn/schema" + +import { registry as registryCollection } from "@/registry/collection/index" + +const REGISTRY_OUTPUT_DIR = path.join(process.cwd(), "public/r") +const TIERS = ["free", "pro"] as const + +let hasErrors = false +let warningCount = 0 + +/** + * 4. Cross-reference: every item in registry.json should have a + * corresponding individual JSON, and vice versa. + */ +async function crossReferenceItems( + registryData: null | { items: Array<{ name: string }> }, + individualItems: Map +) { + if (!registryData) { + warn("Skipping cross-reference check (no registry.json data)") + return + } + + console.log("\n๐Ÿ”— Cross-referencing registry items...") + + const registryNames = new Set(registryData.items.map((item) => item.name)) + const individualNames = new Set(individualItems.keys()) + + // Items in registry.json but missing individual JSON files + const missingJsonFiles = Array.from(registryNames).filter( + (name) => !individualNames.has(name) + ) + + if (missingJsonFiles.length > 0) { + warn( + `Items in registry.json missing individual JSON files: ${missingJsonFiles.join(", ")}` + ) + } + + // Individual JSON files not referenced in registry.json + const extraJsonFiles = Array.from(individualNames).filter( + (name) => !registryNames.has(name) + ) + + if (extraJsonFiles.length > 0) { + // This is informational, not necessarily an error + warn( + `Individual JSON files not in registry.json: ${extraJsonFiles.join(", ")}` + ) + } + + if (missingJsonFiles.length === 0 && extraJsonFiles.length === 0) { + pass("All registry items have matching JSON files") + } +} + +function error(msg: string) { + console.log(`โŒ ${msg}`) + hasErrors = true +} + +async function fileExists(filePath: string): Promise { + try { + await fs.access(filePath) + return true + } catch { + return false + } +} + +async function main() { + console.log("๐Ÿงช Validating registries...\n") + + await validateRegistryCollection() + const registryData = await validateBuiltRegistryJson() + const individualItems = await validateIndividualJsonFiles() + await crossReferenceItems(registryData, individualItems) + await validateDependencyResolution(registryData) + await validateTierRegistries() + + // Summary + console.log("\n" + "=".repeat(50)) + if (hasErrors) { + console.log("\nโŒ Validation failed with errors.") + process.exit(1) + } else if (warningCount > 0) { + console.log(`\nโš ๏ธ Validation passed with ${warningCount} warning(s).`) + } else { + console.log("\nโœ… All registries passed validation.") + } +} + +function pass(msg: string) { + console.log(`โœ… ${msg}`) +} + +async function readJsonFile(filePath: string): Promise { + const content = await fs.readFile(filePath, "utf-8") + return JSON.parse(content) +} + +/** + * 2. Validate the built registry.json file. + */ +async function validateBuiltRegistryJson() { + console.log("\n๐Ÿ“‹ Validating built registry.json...") + + const registryJsonPath = path.join(REGISTRY_OUTPUT_DIR, "registry.json") + if (!(await fileExists(registryJsonPath))) { + warn("public/r/registry.json not found. Run `registry:build` first.") + return null + } + + const data = await readJsonFile(registryJsonPath) + const result = registrySchema.safeParse(data) + + if (!result.success) { + error("public/r/registry.json validation failed:") + console.log(JSON.stringify(result.error.format(), null, 2)) + return null + } + + pass(`public/r/registry.json is valid (${result.data.items.length} items)`) + return result.data +} + +/** + * 5. Validate registryDependencies resolve to existing items. + */ +async function validateDependencyResolution( + registryData: null | { + items: Array<{ name: string; registryDependencies?: string[] }> + } +) { + if (!registryData) { + warn("Skipping dependency resolution check (no registry.json data)") + return + } + + console.log("\n๐Ÿ”— Validating dependency resolution...") + + const allNames = new Set(registryData.items.map((item) => item.name)) + let missingCount = 0 + + for (const item of registryData.items) { + if (!item.registryDependencies?.length) continue + + for (const dep of item.registryDependencies) { + // URL dependencies - extract the name and check the JSON exists + if (dep.startsWith("http")) { + const depName = dep.split("/").pop()?.replace(".json", "") + if (depName && !allNames.has(depName)) { + // Check if it's an external dependency (shadcn, etc.) + if (!dep.includes("limeplay")) { + // External dependency - skip validation + continue + } + warn( + `"${item.name}" depends on "${depName}" (${dep}) which is not in the registry` + ) + missingCount++ + } + continue + } + + // Non-URL dependencies + if (!dep.startsWith("@") && !allNames.has(dep)) { + warn(`"${item.name}" depends on "${dep}" which is not in the registry`) + missingCount++ + } + } + } + + if (missingCount === 0) { + pass("All registryDependencies resolve correctly") + } +} + +/** + * 3. Validate each individual component JSON file in public/r/. + */ +async function validateIndividualJsonFiles() { + console.log("\n๐Ÿ” Validating individual component JSON files...") + + if (!(await fileExists(REGISTRY_OUTPUT_DIR))) { + warn("public/r/ directory not found. Run `registry:build` first.") + return new Map() + } + + const files = await fs.readdir(REGISTRY_OUTPUT_DIR) + const jsonFiles = files.filter( + (f) => f.endsWith(".json") && f !== "registry.json" // Skip the main registry file + ) + + const validatedItems = new Map() + let validCount = 0 + let invalidCount = 0 + + for (const file of jsonFiles) { + const filePath = path.join(REGISTRY_OUTPUT_DIR, file) + const stat = await fs.stat(filePath) + if (!stat.isFile()) continue + + try { + const data = await readJsonFile(filePath) + const result = registryItemSchema.safeParse(data) + + if (!result.success) { + error(`${file} validation failed:`) + // Print a concise summary of issues + const issues = result.error.issues + for (const issue of issues) { + console.log(` - ${issue.path.join(".")}: ${issue.message}`) + } + invalidCount++ + } else { + validatedItems.set(result.data.name, result.data) + validCount++ + } + } catch (e) { + error(`Failed to read/parse ${file}: ${e}`) + invalidCount++ + } + } + + if (invalidCount === 0) { + pass(`All ${validCount} individual JSON files are valid`) + } else { + error( + `${invalidCount}/${validCount + invalidCount} individual JSON files have validation errors` + ) + } + + return validatedItems +} + +/** + * 1. Validate the registry collection (source of truth). + */ +async function validateRegistryCollection() { + console.log("\n๐Ÿ“ฆ Validating registry collection...") + + try { + const result = registrySchema.safeParse(registryCollection) + if (!result.success) { + error("Registry collection validation failed:") + console.log(JSON.stringify(result.error.format(), null, 2)) + } else { + pass(`Registry collection is valid (${result.data.items.length} items)`) + } + } catch (e) { + error(`Failed to validate registry collection: ${e}`) + } +} + +/** + * 6. Validate tier-specific registries (free/pro). + */ +async function validateTierRegistries() { + for (const tier of TIERS) { + const tierDir = path.join(REGISTRY_OUTPUT_DIR, tier) + if (!(await fileExists(tierDir))) continue + + console.log(`\n๐Ÿ“‚ Validating ${tier}/ registry...`) + + const registryJsonPath = path.join(tierDir, "registry.json") + if (await fileExists(registryJsonPath)) { + const data = await readJsonFile(registryJsonPath) + const result = registrySchema.safeParse(data) + + if (!result.success) { + error(`${tier}/registry.json validation failed:`) + console.log(JSON.stringify(result.error.format(), null, 2)) + } else { + pass( + `${tier}/registry.json is valid (${result.data.items.length} items)` + ) + } + } + } +} + +function warn(msg: string) { + console.log(`โš ๏ธ ${msg}`) + warningCount++ +} + +main() + .then(() => { + process.exit(0) + }) + .catch((err) => { + console.log("โŒ Error:", err instanceof Error ? err.message : err) + process.exit(1) + }) diff --git a/apps/www/source.config.ts b/apps/www/source.config.ts index 4438d461..8c6dd578 100644 --- a/apps/www/source.config.ts +++ b/apps/www/source.config.ts @@ -15,7 +15,6 @@ export const docs = defineDocs({ }) const blockFrontmatterSchema = z.object({ - _openapi: z.record(z.unknown()).optional(), component: z.string(), description: z.string().optional(), full: z.boolean().optional(), diff --git a/apps/www/tsconfig.json b/apps/www/tsconfig.json index 1cdab215..b420575d 100644 --- a/apps/www/tsconfig.json +++ b/apps/www/tsconfig.json @@ -38,7 +38,8 @@ "postcss.config.mjs", "eslint.config.mjs", ".next/dev/types/**/*.ts", - "next.config.mjs" + "next.config.mjs", + "scripts/*" ], "exclude": ["node_modules", ".next", "registry/__index__.tsx"] } diff --git a/apps/www/vercel.json b/apps/www/vercel.json index 49628f28..aa12dff2 100644 --- a/apps/www/vercel.json +++ b/apps/www/vercel.json @@ -5,6 +5,11 @@ "source": "/docs", "destination": "/docs/quick-start", "permanent": true + }, + { + "source": "/r/pro/:path*", + "destination": "/403", + "permanent": false } ], "rewrites": [ From cb89da7a6c7336ad28a0a7b17c2dfbbe33556cba Mon Sep 17 00:00:00 2001 From: winoffrg Date: Tue, 31 Mar 2026 23:58:19 +0530 Subject: [PATCH 5/6] feat: new build system, shadcn CLI --- bun.lock | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/bun.lock b/bun.lock index 4514ce95..49051846 100644 --- a/bun.lock +++ b/bun.lock @@ -82,7 +82,7 @@ "tsx": "^4.20.6", "tw-animate-css": "^1.3.6", "unist-util-visit": "^5.0.0", - "zod": "^3.24.2", + "zod": "^4.3.6", "zustand": "^5.0.8", }, "devDependencies": { @@ -102,7 +102,7 @@ "rehype-slug": "^6.0.0", "rimraf": "^6.0.1", "schema-dts": "^1.1.5", - "shadcn": "^3.6.2", + "shadcn": "^4.1.1", "tailwindcss": "^4.1.11", "typescript": "^5.8.3", }, @@ -2133,7 +2133,7 @@ "yoctocolors-cjs": ["yoctocolors-cjs@2.1.3", "", {}, "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw=="], - "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "zod-to-json-schema": ["zod-to-json-schema@3.25.0", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ=="], @@ -2261,8 +2261,6 @@ "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "fumadocs-mdx/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], - "fumadocs-ui/react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], "glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], @@ -2313,6 +2311,8 @@ "shadcn/ts-morph": ["ts-morph@26.0.0", "", { "dependencies": { "@ts-morph/common": "~0.27.0", "code-block-writer": "^13.0.3" } }, "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug=="], + "shadcn/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "stacktrace-gps/source-map": ["source-map@0.5.6", "", {}, "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA=="], "string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], @@ -2325,6 +2325,8 @@ "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "www/shadcn": ["shadcn@4.1.1", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/plugin-transform-typescript": "^7.28.0", "@babel/preset-typescript": "^7.27.1", "@dotenvx/dotenvx": "^1.48.4", "@modelcontextprotocol/sdk": "^1.26.0", "@types/validate-npm-package-name": "^4.0.2", "browserslist": "^4.26.2", "commander": "^14.0.0", "cosmiconfig": "^9.0.0", "dedent": "^1.6.0", "deepmerge": "^4.3.1", "diff": "^8.0.2", "execa": "^9.6.0", "fast-glob": "^3.3.3", "fs-extra": "^11.3.1", "fuzzysort": "^3.1.0", "https-proxy-agent": "^7.0.6", "kleur": "^4.1.5", "msw": "^2.10.4", "node-fetch": "^3.3.2", "open": "^11.0.0", "ora": "^8.2.0", "postcss": "^8.5.6", "postcss-selector-parser": "^7.1.0", "prompts": "^2.4.2", "recast": "^0.23.11", "stringify-object": "^5.0.0", "tailwind-merge": "^3.0.1", "ts-morph": "^26.0.0", "tsconfig-paths": "^4.2.0", "validate-npm-package-name": "^7.0.1", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.6" }, "bin": { "shadcn": "dist/index.js" } }, "sha512-nBj+7LYC9kzV9v9QmRPpoOhfW4KctJVQejywdAt/K+K+z4RYlJOcO2a4AaF7elrRWkfCbgXeGK02liV0KB9HvQ=="], + "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "@dotenvx/dotenvx/execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], @@ -2375,6 +2377,14 @@ "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "www/shadcn/fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "www/shadcn/ts-morph": ["ts-morph@26.0.0", "", { "dependencies": { "@ts-morph/common": "~0.27.0", "code-block-writer": "^13.0.3" } }, "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug=="], + + "www/shadcn/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "www/shadcn/zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], + "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -2385,6 +2395,12 @@ "shadcn/ts-morph/@ts-morph/common/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + "www/shadcn/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "www/shadcn/ts-morph/@ts-morph/common": ["@ts-morph/common@0.27.0", "", { "dependencies": { "fast-glob": "^3.3.3", "minimatch": "^10.0.1", "path-browserify": "^1.0.1" } }, "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ=="], + "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "www/shadcn/ts-morph/@ts-morph/common/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], } } From 52582ef66636a1d364cf7e173fb84302d3f1efa3 Mon Sep 17 00:00:00 2001 From: winoffrg Date: Wed, 1 Apr 2026 17:12:47 +0530 Subject: [PATCH 6/6] chore: remove branding and rename --- apps/www/app/blocks/layout.tsx | 2 - .../www/components/blocks/block-info-pane.tsx | 14 +-- apps/www/components/blocks/blocks-sidebar.tsx | 119 ++++++++---------- apps/www/components/header.tsx | 23 ---- apps/www/components/hero-buttons.tsx | 2 +- apps/www/components/ui/kbd.tsx | 34 +++++ apps/www/components/ui/resizable.tsx | 2 +- .../components/youtube-music-hover-player.tsx | 3 +- .../www/content/docs/blocks/linear-player.mdx | 47 +------ .../www/content/docs/blocks/youtube-music.mdx | 19 +-- apps/www/lib/block-showcase.tsx | 45 ------- apps/www/source.config.ts | 1 - 12 files changed, 98 insertions(+), 213 deletions(-) create mode 100644 apps/www/components/ui/kbd.tsx diff --git a/apps/www/app/blocks/layout.tsx b/apps/www/app/blocks/layout.tsx index a92e7bfb..211a2aa9 100644 --- a/apps/www/app/blocks/layout.tsx +++ b/apps/www/app/blocks/layout.tsx @@ -4,7 +4,6 @@ import { RootProvider } from "fumadocs-ui/provider/next" import { BlocksSidebar } from "@/components/blocks/blocks-sidebar" import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar" -import { getBlockIcon } from "@/lib/block-showcase" import { blocksSource } from "@/lib/blocks-source" import "./blocks.css" @@ -13,7 +12,6 @@ export default function BlocksLayout({ children }: { children: ReactNode }) { const items = blocksSource.getPages().map((page) => ({ description: page.data.description, href: page.url, - icon: page.data.icon ? getBlockIcon(page.data.icon) : undefined, status: page.data.status, title: page.data.title, })) diff --git a/apps/www/components/blocks/block-info-pane.tsx b/apps/www/components/blocks/block-info-pane.tsx index ce88f8e1..71c2d261 100644 --- a/apps/www/components/blocks/block-info-pane.tsx +++ b/apps/www/components/blocks/block-info-pane.tsx @@ -55,17 +55,9 @@ export function BlockInfoPane({
- {title} - {description} - -
-
-
- {content} -
-
-
-
+ {title} + {description} + {content}
) diff --git a/apps/www/components/blocks/blocks-sidebar.tsx b/apps/www/components/blocks/blocks-sidebar.tsx index 28e168eb..52b2b31a 100644 --- a/apps/www/components/blocks/blocks-sidebar.tsx +++ b/apps/www/components/blocks/blocks-sidebar.tsx @@ -11,15 +11,15 @@ import { SidebarGroup, SidebarGroupContent, SidebarGroupLabel, - SidebarHeader, SidebarMenu, - SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, useSidebar, } from "@/components/ui/sidebar" import { cn } from "@/lib/utils" +import { Tooltip, TooltipTrigger } from "../ui/tooltip" + const SIDEBAR_EASE = [0.23, 0.88, 0.26, 0.92] as const const SIDEBAR_DURATION = 0.35 @@ -39,7 +39,16 @@ export function BlocksSidebar({ items }: { items: BlocksSidebarItem[] }) { return ( <> - + + + {/* + Toggle{" "} + + Cmd + B + + */} +
- + {/*

Blocks @@ -67,7 +76,7 @@ export function BlocksSidebar({ items }: { items: BlocksSidebarItem[] }) { {items.length}

-
+
*/} @@ -78,10 +87,8 @@ export function BlocksSidebar({ items }: { items: BlocksSidebarItem[] }) { ))} @@ -103,10 +110,10 @@ function FloatingSidebarToggle() { animate={{ height: isExpanded && !isMobile ? "42px" : "32px", width: isExpanded && !isMobile ? "42px" : "32px", - x: isExpanded && !isMobile ? "-10px" : "0px", - y: isExpanded && !isMobile ? "-10px" : "0px", + x: isExpanded && !isMobile ? "-20px" : "-14px", + y: isExpanded && !isMobile ? "-3px" : "2px", }} - className="fixed top-0 left-10 z-[21] mt-[35.5px] flex items-center justify-center rounded-xl bg-background" + className="fixed top-0 left-10 z-21 mt-[35.5px] flex items-center justify-center" initial={false} onClick={toggleSidebar} transition={{ @@ -114,43 +121,43 @@ function FloatingSidebarToggle() { ease: SIDEBAR_EASE, }} > - +
+ Toggle Sidebar + + ) } @@ -178,37 +185,19 @@ function SidebarDismissLayer() { function SidebarItem({ active, href, - icon, label, - status, }: { active: boolean href: string - icon?: ReactNode label: string - status?: string }) { return ( - {icon} {label} - {status ? ( - - {status} - - ) : null} ) } diff --git a/apps/www/components/header.tsx b/apps/www/components/header.tsx index c845ca19..9c73f26a 100644 --- a/apps/www/components/header.tsx +++ b/apps/www/components/header.tsx @@ -49,17 +49,6 @@ export function Header() {
- -
diff --git a/apps/www/components/hero-buttons.tsx b/apps/www/components/hero-buttons.tsx index fd966a5f..4b76df82 100644 --- a/apps/www/components/hero-buttons.tsx +++ b/apps/www/components/hero-buttons.tsx @@ -84,7 +84,7 @@ export default function HeroButtons() { hover:bg-primary/90 md:flex `} - href="/docs/quick-start" + href="/blocks/linear-player" initial={{ padding: "0px 20px" }} transition={{ bounce: 0.6, diff --git a/apps/www/components/ui/kbd.tsx b/apps/www/components/ui/kbd.tsx new file mode 100644 index 00000000..59423a4a --- /dev/null +++ b/apps/www/components/ui/kbd.tsx @@ -0,0 +1,34 @@ +import { cn } from "@/lib/utils" + +function Kbd({ className, ...props }: React.ComponentProps<"kbd">) { + return ( + + ) +} + +function KbdGroup({ className, ...props }: React.ComponentProps<"div">) { + return ( + + ) +} + +export { Kbd, KbdGroup } diff --git a/apps/www/components/ui/resizable.tsx b/apps/www/components/ui/resizable.tsx index 858ecf0c..9c32ceb0 100644 --- a/apps/www/components/ui/resizable.tsx +++ b/apps/www/components/ui/resizable.tsx @@ -28,7 +28,7 @@ function ResizableHandle({ {...props} > {withHandle && ( -
+
)} ) diff --git a/apps/www/components/youtube-music-hover-player.tsx b/apps/www/components/youtube-music-hover-player.tsx index 24812f51..e051ce88 100644 --- a/apps/www/components/youtube-music-hover-player.tsx +++ b/apps/www/components/youtube-music-hover-player.tsx @@ -4,10 +4,9 @@ import { SquareArrowOutUpRightIcon } from "lucide-react" import { motion } from "motion/react" import Link from "next/link" +import { Button } from "@/components/ui/button" import { YouTubeMusicPlayer } from "@/registry/pro/blocks/youtube-music/components/media-player" -import { Button } from "./ui/button" - export function YouTubeMusicHoverPlayer() { return ( ReactNode - icon: ReactNode -} - -function LinearIcon() { - return ( - - ) -} - -function YouTubeMusicIcon() { - return ( - - ) } const blockShowcaseRegistry = { @@ -52,19 +14,12 @@ const blockShowcaseRegistry = { ), - icon: , }, "youtube-music": { component: () => , - icon: , }, } satisfies Record -export function getBlockIcon(preview: string): ReactNode | undefined { - return blockShowcaseRegistry[preview as keyof typeof blockShowcaseRegistry] - .icon -} - export function getBlockShowcase(preview: string) { return blockShowcaseRegistry[preview as keyof typeof blockShowcaseRegistry] } diff --git a/apps/www/source.config.ts b/apps/www/source.config.ts index 8c6dd578..31ae2332 100644 --- a/apps/www/source.config.ts +++ b/apps/www/source.config.ts @@ -18,7 +18,6 @@ const blockFrontmatterSchema = z.object({ component: z.string(), description: z.string().optional(), full: z.boolean().optional(), - icon: z.string().optional(), preview: z.string(), registry: z.enum(["default", "pro"]).default("default"), status: z.enum(["free", "pro"]).default("free"),