magicui
102 строки · 3.6 Кб
1"use client";
2import ComponentWrapper from "@/components/component-wrapper";
3import { Icons } from "@/components/icons";
4import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
5import { cn } from "@/lib/utils";
6import { registry } from "@/registry/index";
7import { RotateCcw } from "lucide-react";
8import * as React from "react";
9import { Button } from "./ui/button";
10
11interface ComponentPreviewProps extends React.HTMLAttributes<HTMLDivElement> {
12name: string;
13align?: "center" | "start" | "end";
14}
15
16export function ComponentPreview({
17name,
18children,
19className,
20align = "center",
21...props
22}: ComponentPreviewProps) {
23const [key, setKey] = React.useState(0); // State to trigger re-render of preview
24const Codes = React.Children.toArray(children) as React.ReactElement[];
25const Code = Codes[0]; // first child
26
27const Preview = React.useMemo(() => {
28const Component = registry[name]?.component;
29
30if (!Component) {
31console.error(`Component with name "${name}" not found in registry.`);
32return (
33<p className="text-sm text-muted-foreground">
34Component{" "}
35<code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm">
36{name}
37</code>{" "}
38not found in registry.
39</p>
40);
41}
42
43return <Component />;
44}, [name, key]);
45
46return (
47<div
48className={cn(
49"relative my-4 flex flex-col space-y-2 lg:max-w-[120ch]",
50className,
51)}
52{...props}
53>
54<Tabs defaultValue="preview" className="relative mr-auto w-full">
55<div className="flex items-center justify-between pb-3">
56<TabsList className="w-full justify-start rounded-none border-b bg-transparent p-0">
57<TabsTrigger
58value="preview"
59className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
60>
61Preview
62</TabsTrigger>
63<TabsTrigger
64value="code"
65className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
66>
67Code
68</TabsTrigger>
69</TabsList>
70</div>
71<TabsContent value="preview" className="relative rounded-md" key={key}>
72<ComponentWrapper>
73<Button
74onClick={() => setKey((prev) => prev + 1)}
75className="absolute right-0 top-0 z-50 ml-4 flex items-center rounded-lg px-3 py-1"
76variant="ghost"
77>
78<RotateCcw size={16} />
79</Button>
80<React.Suspense
81fallback={
82<div className="flex items-center text-sm text-muted-foreground">
83<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
84Loading...
85</div>
86}
87>
88{Preview}
89</React.Suspense>
90</ComponentWrapper>
91</TabsContent>
92<TabsContent value="code">
93<div className="flex flex-col space-y-4">
94<div className="w-full rounded-md [&_pre]:my-0 [&_pre]:max-h-[350px] [&_pre]:overflow-auto">
95{Code}
96</div>
97</div>
98</TabsContent>
99</Tabs>
100</div>
101);
102}
103