"use client" import * as React from "react" import Image from "next/image" import Link from "next/link" import { Check, ChevronRight, Clipboard, File, Folder, Fullscreen, Monitor, RotateCw, Smartphone, Tablet, Terminal, } from "lucide-react" import { ImperativePanelHandle } from "react-resizable-panels" import { registryItemFileSchema, registryItemSchema } from "shadcn/schema" import { z } from "zod" import { trackEvent } from "@/lib/events" import { createFileTreeForRegistryItemFiles, FileTree } from "@/lib/registry" import { cn } from "@/lib/utils" import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard" import { getIconForLanguageExtension } from "@/components/icons" import { OpenInV0Button } from "@/components/open-in-v0-button" import { Button } from "@/registry/new-york-v4/ui/button" import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/registry/new-york-v4/ui/collapsible" import { ResizableHandle, ResizablePanel, ResizablePanelGroup, } from "@/registry/new-york-v4/ui/resizable" import { Separator } from "@/registry/new-york-v4/ui/separator" import { Sidebar, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarProvider, } from "@/registry/new-york-v4/ui/sidebar" import { Tabs, TabsList, TabsTrigger } from "@/registry/new-york-v4/ui/tabs" import { ToggleGroup, ToggleGroupItem, } from "@/registry/new-york-v4/ui/toggle-group" import { type Style } from "@/registry/styles" type BlockViewerContext = { item: z.infer view: "code" | "preview" setView: (view: "code" | "preview") => void activeFile: string | null setActiveFile: (file: string) => void resizablePanelRef: React.RefObject | null tree: ReturnType | null highlightedFiles: | (z.infer & { highlightedContent: string })[] | null iframeKey?: number setIframeKey?: React.Dispatch> } const BlockViewerContext = React.createContext(null) function useBlockViewer() { const context = React.useContext(BlockViewerContext) if (!context) { throw new Error("useBlockViewer must be used within a BlockViewerProvider.") } return context } function BlockViewerProvider({ item, tree, highlightedFiles, children, }: Pick & { children: React.ReactNode }) { const [view, setView] = React.useState("preview") const [activeFile, setActiveFile] = React.useState< BlockViewerContext["activeFile"] >(highlightedFiles?.[0].target ?? null) const resizablePanelRef = React.useRef(null) const [iframeKey, setIframeKey] = React.useState(0) return (
{children}
) } type BlockViewerProps = Pick< BlockViewerContext, "item" | "tree" | "highlightedFiles" > & { children: React.ReactNode styleName: Style["name"] } function BlockViewerToolbar({ styleName }: { styleName: Style["name"] }) { const { setView, view, item, resizablePanelRef, setIframeKey } = useBlockViewer() const { copyToClipboard, isCopied } = useCopyToClipboard() return (
setView(value as "preview" | "code")} > Preview Code {item.description?.replace(/\.$/, "")}
{ setView("preview") if (resizablePanelRef?.current) { resizablePanelRef.current.resize(parseInt(value)) } }} className="gap-1 *:data-[slot=toggle-group-item]:!size-6 *:data-[slot=toggle-group-item]:!rounded-sm" >
) } function BlockViewerIframe({ className, styleName, }: { className?: string styleName: Style["name"] }) { const { item, iframeKey } = useBlockViewer() return (