@cyberbloxai/ui-kit 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +19 -1
  2. package/package.json +6 -2
  3. package/src/App.css +42 -0
  4. package/src/App.tsx +31 -0
  5. package/src/cli.js +93 -0
  6. package/src/components/CodeBlock.tsx +50 -0
  7. package/src/components/ComponentLivePreview.tsx +310 -0
  8. package/src/components/NavLink.tsx +28 -0
  9. package/src/components/PropTable.tsx +54 -0
  10. package/src/components/showcase/AuthShowcase.tsx +164 -0
  11. package/src/components/showcase/ComponentsShowcase.tsx +133 -0
  12. package/src/components/showcase/DashboardShowcase.tsx +153 -0
  13. package/src/components/showcase/ErrorShowcase.tsx +55 -0
  14. package/src/components/showcase/NotificationShowcase.tsx +102 -0
  15. package/src/components/ui/accordion.tsx +52 -0
  16. package/src/components/ui/alert-dialog.tsx +104 -0
  17. package/src/components/ui/alert.tsx +43 -0
  18. package/src/components/ui/aspect-ratio.tsx +5 -0
  19. package/src/components/ui/avatar.tsx +38 -0
  20. package/src/components/ui/badge.tsx +29 -0
  21. package/src/components/ui/breadcrumb.tsx +90 -0
  22. package/src/components/ui/button.tsx +47 -0
  23. package/src/components/ui/calendar.tsx +54 -0
  24. package/src/components/ui/card.tsx +43 -0
  25. package/src/components/ui/carousel.tsx +224 -0
  26. package/src/components/ui/chart.tsx +303 -0
  27. package/src/components/ui/checkbox.tsx +26 -0
  28. package/src/components/ui/collapsible.tsx +9 -0
  29. package/src/components/ui/command.tsx +132 -0
  30. package/src/components/ui/context-menu.tsx +178 -0
  31. package/src/components/ui/dialog.tsx +95 -0
  32. package/src/components/ui/drawer.tsx +87 -0
  33. package/src/components/ui/dropdown-menu.tsx +179 -0
  34. package/src/components/ui/form.tsx +129 -0
  35. package/src/components/ui/hover-card.tsx +27 -0
  36. package/src/components/ui/input-otp.tsx +61 -0
  37. package/src/components/ui/input.tsx +22 -0
  38. package/src/components/ui/label.tsx +17 -0
  39. package/src/components/ui/menubar.tsx +207 -0
  40. package/src/components/ui/navigation-menu.tsx +120 -0
  41. package/src/components/ui/pagination.tsx +81 -0
  42. package/src/components/ui/popover.tsx +29 -0
  43. package/src/components/ui/progress.tsx +23 -0
  44. package/src/components/ui/radio-group.tsx +36 -0
  45. package/src/components/ui/resizable.tsx +37 -0
  46. package/src/components/ui/scroll-area.tsx +38 -0
  47. package/src/components/ui/select.tsx +143 -0
  48. package/src/components/ui/separator.tsx +20 -0
  49. package/src/components/ui/sheet.tsx +107 -0
  50. package/src/components/ui/sidebar.tsx +637 -0
  51. package/src/components/ui/skeleton.tsx +7 -0
  52. package/src/components/ui/slider.tsx +23 -0
  53. package/src/components/ui/sonner.tsx +27 -0
  54. package/src/components/ui/switch.tsx +27 -0
  55. package/src/components/ui/table.tsx +72 -0
  56. package/src/components/ui/tabs.tsx +53 -0
  57. package/src/components/ui/textarea.tsx +21 -0
  58. package/src/components/ui/toast.tsx +111 -0
  59. package/src/components/ui/toaster.tsx +24 -0
  60. package/src/components/ui/toggle-group.tsx +49 -0
  61. package/src/components/ui/toggle.tsx +37 -0
  62. package/src/components/ui/tooltip.tsx +28 -0
  63. package/src/components/ui/use-toast.ts +3 -0
  64. package/src/data/componentRegistry.ts +501 -0
  65. package/src/hooks/use-mobile.tsx +19 -0
  66. package/src/hooks/use-toast.ts +186 -0
  67. package/src/index.css +105 -0
  68. package/src/lib/index.ts +58 -0
  69. package/src/lib/utils.ts +6 -0
  70. package/src/main.tsx +5 -0
  71. package/src/pages/ComponentDetail.tsx +167 -0
  72. package/src/pages/ComponentsList.tsx +126 -0
  73. package/src/pages/Index.tsx +223 -0
  74. package/src/pages/NotFound.tsx +24 -0
  75. package/src/test/example.test.ts +7 -0
  76. package/src/test/setup.ts +15 -0
  77. package/src/vite-env.d.ts +1 -0
package/README.md CHANGED
@@ -18,6 +18,23 @@ CyberBlox UI Kit is a modular, themeable component library designed for building
18
18
 
19
19
  ## Installation
20
20
 
21
+ There are two ways to use CyberBlox UI:
22
+
23
+ ### 1. shadcn-style (Recommended)
24
+ This copies the component source code directly into your project, allowing you to customize everything.
25
+
26
+ ```bash
27
+ # 1. Initialize the project (sets up utils)
28
+ npx @cyberbloxai/ui-kit init
29
+
30
+ # 2. Add components as needed
31
+ npx @cyberbloxai/ui-kit add button
32
+ npx @cyberbloxai/ui-kit add dialog
33
+ ```
34
+
35
+ ### 2. Standard Library Style
36
+ Install it as a traditional npm package.
37
+
21
38
  ```bash
22
39
  npm install @cyberbloxai/ui-kit
23
40
  ```
@@ -25,7 +42,7 @@ npm install @cyberbloxai/ui-kit
25
42
  > **Note**: If you are using **Tailwind CSS v4** and encounter a dependency conflict (`ERESOLVE`), you can install using:
26
43
  > `npm install @cyberbloxai/ui-kit --legacy-peer-deps`
27
44
 
28
- ## Quick Start
45
+ ## Quick Start (Library Style)
29
46
 
30
47
  1. **Import Styles**: Add the CSS to your main entry file (e.g., `main.tsx` or `App.tsx`) **before** your other imports:
31
48
 
@@ -76,6 +93,7 @@ function App() {
76
93
 
77
94
  ## Troubleshooting
78
95
 
96
+ - **CLI Not Working**: If `npx @cyberbloxai/ui-kit` fails, try `npx @cyberbloxai/ui-kit@latest`.
79
97
  - **Blank Page / White Screen**: This usually indicates a JavaScript error. Check your browser console (`F12` -> Console).
80
98
  - Ensure you have `react` and `react-dom` installed.
81
99
  - If using Vite, try clearing your cache: `rm -rf node_modules/.vite` and restart with `npm run dev`.
package/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "@cyberbloxai/ui-kit",
3
- "version": "0.1.2",
4
- "description": "Production-ready UI component library built on Radix UI + Tailwind CSS.",
3
+ "version": "0.2.0",
4
+ "description": "Production-ready UI component library built on Radix UI + Tailwind CSS. Supports shadcn-style component installation.",
5
+ "bin": {
6
+ "cyberblox": "./src/cli.js"
7
+ },
5
8
  "repository": {
6
9
  "type": "git",
7
10
  "url": "git+https://github.com/abhishekjohn1507/uni-kit-forge.git"
@@ -23,6 +26,7 @@
23
26
  },
24
27
  "files": [
25
28
  "dist",
29
+ "src",
26
30
  "README.md"
27
31
  ],
28
32
  "sideEffects": [
package/src/App.css ADDED
@@ -0,0 +1,42 @@
1
+ #root {
2
+ max-width: 1280px;
3
+ margin: 0 auto;
4
+ padding: 2rem;
5
+ text-align: center;
6
+ }
7
+
8
+ .logo {
9
+ height: 6em;
10
+ padding: 1.5em;
11
+ will-change: filter;
12
+ transition: filter 300ms;
13
+ }
14
+ .logo:hover {
15
+ filter: drop-shadow(0 0 2em #646cffaa);
16
+ }
17
+ .logo.react:hover {
18
+ filter: drop-shadow(0 0 2em #61dafbaa);
19
+ }
20
+
21
+ @keyframes logo-spin {
22
+ from {
23
+ transform: rotate(0deg);
24
+ }
25
+ to {
26
+ transform: rotate(360deg);
27
+ }
28
+ }
29
+
30
+ @media (prefers-reduced-motion: no-preference) {
31
+ a:nth-of-type(2) .logo {
32
+ animation: logo-spin infinite 20s linear;
33
+ }
34
+ }
35
+
36
+ .card {
37
+ padding: 2em;
38
+ }
39
+
40
+ .read-the-docs {
41
+ color: #888;
42
+ }
package/src/App.tsx ADDED
@@ -0,0 +1,31 @@
1
+ import { Toaster } from "@/components/ui/toaster";
2
+ import { Toaster as Sonner } from "@/components/ui/sonner";
3
+ import { TooltipProvider } from "@/components/ui/tooltip";
4
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
5
+ import { BrowserRouter, Routes, Route } from "react-router-dom";
6
+ import Index from "./pages/Index";
7
+ import ComponentsList from "./pages/ComponentsList";
8
+ import ComponentDetail from "./pages/ComponentDetail";
9
+ import NotFound from "./pages/NotFound";
10
+
11
+ const queryClient = new QueryClient();
12
+
13
+ const App = () => (
14
+ <QueryClientProvider client={queryClient}>
15
+ <TooltipProvider>
16
+ <Toaster />
17
+ <Sonner />
18
+ <BrowserRouter>
19
+ <Routes>
20
+ <Route path="/" element={<Index />} />
21
+ <Route path="/components" element={<ComponentsList />} />
22
+ <Route path="/components/:id" element={<ComponentDetail />} />
23
+ {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
24
+ <Route path="*" element={<NotFound />} />
25
+ </Routes>
26
+ </BrowserRouter>
27
+ </TooltipProvider>
28
+ </QueryClientProvider>
29
+ );
30
+
31
+ export default App;
package/src/cli.js ADDED
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ // This script will be located in node_modules/@cyberbloxai/ui-kit/src/cli.js
11
+ // We need to find the source components directory relative to this script.
12
+ const packageRoot = path.join(__dirname, '..');
13
+ const componentsSrc = path.join(packageRoot, 'src', 'components', 'ui');
14
+ const utilsSrc = path.join(packageRoot, 'src', 'lib', 'utils.ts');
15
+
16
+ const args = process.argv.slice(2);
17
+ const command = args[0];
18
+
19
+ function getTargetDir() {
20
+ const isSrcExists = fs.existsSync(path.join(process.cwd(), 'src'));
21
+ return isSrcExists ? path.join(process.cwd(), 'src') : process.cwd();
22
+ }
23
+
24
+ function copyFile(src, dest) {
25
+ const destDir = path.dirname(dest);
26
+ if (!fs.existsSync(destDir)) {
27
+ fs.mkdirSync(destDir, { recursive: true });
28
+ }
29
+ fs.copyFileSync(src, dest);
30
+ console.log(` Created ${path.relative(process.cwd(), dest)}`);
31
+ }
32
+
33
+ function init() {
34
+ console.log('Initializing CyberBlox UI components...');
35
+ const targetBase = getTargetDir();
36
+
37
+ // Copy utils
38
+ const utilsDest = path.join(targetBase, 'lib', 'utils.ts');
39
+ copyFile(utilsSrc, utilsDest);
40
+
41
+ console.log('\nSuccess! Now you can add components using:');
42
+ console.log('npx cyberblox add [component-name]');
43
+ }
44
+
45
+ function addComponent(name) {
46
+ if (!name) {
47
+ console.error('Please specify a component name, e.g., npx cyberblox add button');
48
+ process.exit(1);
49
+ }
50
+
51
+ const fileName = name.endsWith('.tsx') ? name : `${name}.tsx`;
52
+ const srcPath = path.join(componentsSrc, fileName);
53
+
54
+ if (!fs.existsSync(srcPath)) {
55
+ console.error(`Component "${name}" not found in library.`);
56
+ process.exit(1);
57
+ }
58
+
59
+ const targetBase = getTargetDir();
60
+ const destPath = path.join(targetBase, 'components', 'ui', fileName);
61
+
62
+ copyFile(srcPath, destPath);
63
+ console.log(`\nComponent "${name}" added successfully!`);
64
+ }
65
+
66
+ function listComponents() {
67
+ console.log('Available components:');
68
+ const files = fs.readdirSync(componentsSrc);
69
+ files.forEach(file => {
70
+ if (file.endsWith('.tsx')) {
71
+ console.log(`- ${file.replace('.tsx', '')}`);
72
+ }
73
+ });
74
+ }
75
+
76
+ switch (command) {
77
+ case 'init':
78
+ init();
79
+ break;
80
+ case 'add':
81
+ addComponent(args[1]);
82
+ break;
83
+ case 'list':
84
+ listComponents();
85
+ break;
86
+ default:
87
+ console.log('CyberBlox UI CLI');
88
+ console.log('\nUsage:');
89
+ console.log(' npx cyberblox init - Setup lib/utils.ts');
90
+ console.log(' npx cyberblox add [name] - Add a component to your project');
91
+ console.log(' npx cyberblox list - List all available components');
92
+ break;
93
+ }
@@ -0,0 +1,50 @@
1
+ import { useState } from "react";
2
+ import { Check, Copy } from "lucide-react";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ interface CodeBlockProps {
6
+ code: string;
7
+ language?: string;
8
+ className?: string;
9
+ }
10
+
11
+ const CodeBlock = ({ code, language = "tsx", className }: CodeBlockProps) => {
12
+ const [copied, setCopied] = useState(false);
13
+
14
+ const handleCopy = () => {
15
+ navigator.clipboard.writeText(code);
16
+ setCopied(true);
17
+ setTimeout(() => setCopied(false), 2000);
18
+ };
19
+
20
+ return (
21
+ <div className={cn("relative group", className)}>
22
+ <div className="flex items-center justify-between px-4 py-2 bg-muted/80 border border-border/40 rounded-t-lg">
23
+ <span className="text-xs font-mono text-muted-foreground">{language}</span>
24
+ <button
25
+ onClick={handleCopy}
26
+ className="flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors"
27
+ >
28
+ {copied ? (
29
+ <>
30
+ <Check className="h-3.5 w-3.5 text-success" />
31
+ <span>Copied</span>
32
+ </>
33
+ ) : (
34
+ <>
35
+ <Copy className="h-3.5 w-3.5" />
36
+ <span>Copy</span>
37
+ </>
38
+ )}
39
+ </button>
40
+ </div>
41
+ <pre className="overflow-x-auto p-4 bg-background/80 border border-t-0 border-border/40 rounded-b-lg">
42
+ <code className="text-sm font-mono text-foreground/90 leading-relaxed whitespace-pre">
43
+ {code}
44
+ </code>
45
+ </pre>
46
+ </div>
47
+ );
48
+ };
49
+
50
+ export default CodeBlock;
@@ -0,0 +1,310 @@
1
+ import { useState } from "react";
2
+ import { Button } from "@/components/ui/button";
3
+ import { Input } from "@/components/ui/input";
4
+ import { Badge } from "@/components/ui/badge";
5
+ import { Switch } from "@/components/ui/switch";
6
+ import { Slider } from "@/components/ui/slider";
7
+ import { Checkbox } from "@/components/ui/checkbox";
8
+ import { Progress } from "@/components/ui/progress";
9
+ import { Avatar, AvatarFallback } from "@/components/ui/avatar";
10
+ import { Textarea } from "@/components/ui/textarea";
11
+ import { Skeleton } from "@/components/ui/skeleton";
12
+ import { Label } from "@/components/ui/label";
13
+ import {
14
+ Dialog, DialogTrigger, DialogContent,
15
+ DialogHeader, DialogTitle, DialogDescription,
16
+ DialogFooter, DialogClose,
17
+ } from "@/components/ui/dialog";
18
+ import {
19
+ Drawer, DrawerTrigger, DrawerContent,
20
+ DrawerHeader, DrawerTitle, DrawerDescription,
21
+ DrawerFooter, DrawerClose,
22
+ } from "@/components/ui/drawer";
23
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
24
+ import {
25
+ Select, SelectTrigger, SelectValue, SelectContent,
26
+ SelectItem, SelectGroup, SelectLabel,
27
+ } from "@/components/ui/select";
28
+ import {
29
+ Accordion, AccordionItem, AccordionTrigger, AccordionContent,
30
+ } from "@/components/ui/accordion";
31
+ import {
32
+ Tooltip, TooltipTrigger, TooltipContent, TooltipProvider,
33
+ } from "@/components/ui/tooltip";
34
+ import { Loader2, ArrowRight, Plus, Settings, Info } from "lucide-react";
35
+
36
+ interface Props {
37
+ componentId: string;
38
+ }
39
+
40
+ const ComponentLivePreview = ({ componentId }: Props) => {
41
+ const [sliderVal, setSliderVal] = useState([50]);
42
+
43
+ switch (componentId) {
44
+ case "button":
45
+ return (
46
+ <div className="flex flex-wrap gap-3">
47
+ <Button>Primary</Button>
48
+ <Button variant="secondary">Secondary</Button>
49
+ <Button variant="outline">Outline</Button>
50
+ <Button variant="destructive">Destructive</Button>
51
+ <Button variant="ghost">Ghost</Button>
52
+ <Button variant="link">Link</Button>
53
+ <Button disabled><Loader2 className="mr-2 h-4 w-4 animate-spin" />Loading</Button>
54
+ <Button size="icon"><ArrowRight /></Button>
55
+ </div>
56
+ );
57
+
58
+ case "input":
59
+ return (
60
+ <div className="space-y-3 max-w-sm">
61
+ <Input placeholder="Default input" />
62
+ <Input type="email" placeholder="Email input" />
63
+ <Input placeholder="Disabled" disabled />
64
+ </div>
65
+ );
66
+
67
+ case "badge":
68
+ return (
69
+ <div className="flex flex-wrap gap-2">
70
+ <Badge>Default</Badge>
71
+ <Badge variant="secondary">Secondary</Badge>
72
+ <Badge variant="destructive">Destructive</Badge>
73
+ <Badge variant="outline">Outline</Badge>
74
+ </div>
75
+ );
76
+
77
+ case "switch":
78
+ return (
79
+ <div className="space-y-3">
80
+ <div className="flex items-center gap-3">
81
+ <Switch id="s1" />
82
+ <Label htmlFor="s1">Off by default</Label>
83
+ </div>
84
+ <div className="flex items-center gap-3">
85
+ <Switch id="s2" defaultChecked />
86
+ <Label htmlFor="s2">On by default</Label>
87
+ </div>
88
+ </div>
89
+ );
90
+
91
+ case "slider":
92
+ return (
93
+ <div className="space-y-4 max-w-sm">
94
+ <div className="space-y-2">
95
+ <div className="flex justify-between text-xs text-muted-foreground">
96
+ <span>Volume</span>
97
+ <span>{sliderVal[0]}%</span>
98
+ </div>
99
+ <Slider value={sliderVal} onValueChange={setSliderVal} max={100} step={1} />
100
+ </div>
101
+ </div>
102
+ );
103
+
104
+ case "checkbox":
105
+ return (
106
+ <div className="space-y-3">
107
+ {["Design system", "Components", "Documentation"].map((label) => (
108
+ <div key={label} className="flex items-center gap-2">
109
+ <Checkbox id={label} />
110
+ <Label htmlFor={label}>{label}</Label>
111
+ </div>
112
+ ))}
113
+ </div>
114
+ );
115
+
116
+ case "progress":
117
+ return (
118
+ <div className="space-y-4 max-w-sm">
119
+ <Progress value={30} />
120
+ <Progress value={60} />
121
+ <Progress value={90} />
122
+ </div>
123
+ );
124
+
125
+ case "avatar":
126
+ return (
127
+ <div className="flex items-center gap-4">
128
+ <div className="flex -space-x-2">
129
+ {["AK", "BR", "CS", "DW"].map((i) => (
130
+ <Avatar key={i} className="h-10 w-10 border-2 border-background">
131
+ <AvatarFallback className="bg-primary/20 text-primary text-xs">{i}</AvatarFallback>
132
+ </Avatar>
133
+ ))}
134
+ </div>
135
+ <Avatar className="h-14 w-14">
136
+ <AvatarFallback className="bg-accent/20 text-accent text-lg">JD</AvatarFallback>
137
+ </Avatar>
138
+ </div>
139
+ );
140
+
141
+ case "textarea":
142
+ return (
143
+ <div className="space-y-2 max-w-sm">
144
+ <Label htmlFor="bio">Bio</Label>
145
+ <Textarea id="bio" placeholder="Tell us about yourself..." rows={4} />
146
+ </div>
147
+ );
148
+
149
+ case "skeleton":
150
+ return (
151
+ <div className="flex items-center gap-4">
152
+ <Skeleton className="h-12 w-12 rounded-full" />
153
+ <div className="space-y-2">
154
+ <Skeleton className="h-4 w-[200px]" />
155
+ <Skeleton className="h-4 w-[150px]" />
156
+ </div>
157
+ </div>
158
+ );
159
+
160
+ case "label":
161
+ return (
162
+ <div className="space-y-2 max-w-sm">
163
+ <Label htmlFor="demo">Full Name</Label>
164
+ <Input id="demo" placeholder="John Doe" />
165
+ </div>
166
+ );
167
+
168
+ case "dialog":
169
+ return (
170
+ <Dialog>
171
+ <DialogTrigger asChild>
172
+ <Button variant="outline">Open Dialog</Button>
173
+ </DialogTrigger>
174
+ <DialogContent>
175
+ <DialogHeader>
176
+ <DialogTitle>Are you sure?</DialogTitle>
177
+ <DialogDescription>This action cannot be undone.</DialogDescription>
178
+ </DialogHeader>
179
+ <DialogFooter>
180
+ <DialogClose asChild>
181
+ <Button variant="outline">Cancel</Button>
182
+ </DialogClose>
183
+ <Button>Confirm</Button>
184
+ </DialogFooter>
185
+ </DialogContent>
186
+ </Dialog>
187
+ );
188
+
189
+ case "drawer":
190
+ return (
191
+ <Drawer>
192
+ <DrawerTrigger asChild>
193
+ <Button variant="outline">Open Drawer</Button>
194
+ </DrawerTrigger>
195
+ <DrawerContent>
196
+ <DrawerHeader>
197
+ <DrawerTitle>Settings</DrawerTitle>
198
+ <DrawerDescription>Adjust your preferences below.</DrawerDescription>
199
+ </DrawerHeader>
200
+ <div className="p-4 space-y-3">
201
+ <div className="flex items-center justify-between">
202
+ <Label>Notifications</Label>
203
+ <Switch />
204
+ </div>
205
+ <div className="flex items-center justify-between">
206
+ <Label>Dark Mode</Label>
207
+ <Switch defaultChecked />
208
+ </div>
209
+ </div>
210
+ <DrawerFooter>
211
+ <Button>Save Changes</Button>
212
+ <DrawerClose asChild>
213
+ <Button variant="outline">Cancel</Button>
214
+ </DrawerClose>
215
+ </DrawerFooter>
216
+ </DrawerContent>
217
+ </Drawer>
218
+ );
219
+
220
+ case "tabs":
221
+ return (
222
+ <Tabs defaultValue="overview" className="w-full max-w-md">
223
+ <TabsList className="grid w-full grid-cols-3">
224
+ <TabsTrigger value="overview">Overview</TabsTrigger>
225
+ <TabsTrigger value="analytics">Analytics</TabsTrigger>
226
+ <TabsTrigger value="settings">Settings</TabsTrigger>
227
+ </TabsList>
228
+ <TabsContent value="overview" className="mt-3 text-sm text-muted-foreground">
229
+ <p>Here's a quick summary of your project status and recent activity.</p>
230
+ </TabsContent>
231
+ <TabsContent value="analytics" className="mt-3 text-sm text-muted-foreground">
232
+ <p>View charts and metrics about your usage and performance.</p>
233
+ </TabsContent>
234
+ <TabsContent value="settings" className="mt-3 text-sm text-muted-foreground">
235
+ <p>Configure notifications, integrations, and account preferences.</p>
236
+ </TabsContent>
237
+ </Tabs>
238
+ );
239
+
240
+ case "select":
241
+ return (
242
+ <div className="space-y-3 max-w-[220px]">
243
+ <Label>Favorite fruit</Label>
244
+ <Select>
245
+ <SelectTrigger>
246
+ <SelectValue placeholder="Select a fruit" />
247
+ </SelectTrigger>
248
+ <SelectContent>
249
+ <SelectGroup>
250
+ <SelectLabel>Fruits</SelectLabel>
251
+ <SelectItem value="apple">Apple</SelectItem>
252
+ <SelectItem value="banana">Banana</SelectItem>
253
+ <SelectItem value="orange">Orange</SelectItem>
254
+ <SelectItem value="grape">Grape</SelectItem>
255
+ </SelectGroup>
256
+ </SelectContent>
257
+ </Select>
258
+ </div>
259
+ );
260
+
261
+ case "accordion":
262
+ return (
263
+ <Accordion type="single" collapsible className="w-full max-w-md">
264
+ <AccordionItem value="item-1">
265
+ <AccordionTrigger>Is it accessible?</AccordionTrigger>
266
+ <AccordionContent>Yes. It adheres to the WAI-ARIA design pattern.</AccordionContent>
267
+ </AccordionItem>
268
+ <AccordionItem value="item-2">
269
+ <AccordionTrigger>Is it styled?</AccordionTrigger>
270
+ <AccordionContent>Yes. It comes with default styles that match the design system.</AccordionContent>
271
+ </AccordionItem>
272
+ <AccordionItem value="item-3">
273
+ <AccordionTrigger>Is it animated?</AccordionTrigger>
274
+ <AccordionContent>Yes. It uses CSS animations for smooth open and close transitions.</AccordionContent>
275
+ </AccordionItem>
276
+ </Accordion>
277
+ );
278
+
279
+ case "tooltip":
280
+ return (
281
+ <TooltipProvider>
282
+ <div className="flex flex-wrap gap-3">
283
+ <Tooltip>
284
+ <TooltipTrigger asChild>
285
+ <Button variant="outline" size="icon"><Plus className="h-4 w-4" /></Button>
286
+ </TooltipTrigger>
287
+ <TooltipContent><p>Add item</p></TooltipContent>
288
+ </Tooltip>
289
+ <Tooltip>
290
+ <TooltipTrigger asChild>
291
+ <Button variant="outline" size="icon"><Settings className="h-4 w-4" /></Button>
292
+ </TooltipTrigger>
293
+ <TooltipContent side="bottom"><p>Settings</p></TooltipContent>
294
+ </Tooltip>
295
+ <Tooltip>
296
+ <TooltipTrigger asChild>
297
+ <Button variant="outline" size="icon"><Info className="h-4 w-4" /></Button>
298
+ </TooltipTrigger>
299
+ <TooltipContent side="right"><p>More info</p></TooltipContent>
300
+ </Tooltip>
301
+ </div>
302
+ </TooltipProvider>
303
+ );
304
+
305
+ default:
306
+ return <p className="text-muted-foreground text-sm">No preview available.</p>;
307
+ }
308
+ };
309
+
310
+ export default ComponentLivePreview;
@@ -0,0 +1,28 @@
1
+ import { NavLink as RouterNavLink, NavLinkProps } from "react-router-dom";
2
+ import { forwardRef } from "react";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ interface NavLinkCompatProps extends Omit<NavLinkProps, "className"> {
6
+ className?: string;
7
+ activeClassName?: string;
8
+ pendingClassName?: string;
9
+ }
10
+
11
+ const NavLink = forwardRef<HTMLAnchorElement, NavLinkCompatProps>(
12
+ ({ className, activeClassName, pendingClassName, to, ...props }, ref) => {
13
+ return (
14
+ <RouterNavLink
15
+ ref={ref}
16
+ to={to}
17
+ className={({ isActive, isPending }) =>
18
+ cn(className, isActive && activeClassName, isPending && pendingClassName)
19
+ }
20
+ {...props}
21
+ />
22
+ );
23
+ },
24
+ );
25
+
26
+ NavLink.displayName = "NavLink";
27
+
28
+ export { NavLink };
@@ -0,0 +1,54 @@
1
+ import type { PropDoc } from "@/data/componentRegistry";
2
+ import { Badge } from "@/components/ui/badge";
3
+
4
+ interface PropTableProps {
5
+ props: PropDoc[];
6
+ }
7
+
8
+ const PropTable = ({ props }: PropTableProps) => {
9
+ return (
10
+ <div className="overflow-x-auto rounded-lg border border-border/40">
11
+ <table className="w-full text-sm">
12
+ <thead>
13
+ <tr className="bg-muted/60 border-b border-border/40">
14
+ <th className="text-left px-4 py-3 font-medium text-muted-foreground">Prop</th>
15
+ <th className="text-left px-4 py-3 font-medium text-muted-foreground">Type</th>
16
+ <th className="text-left px-4 py-3 font-medium text-muted-foreground hidden sm:table-cell">Default</th>
17
+ <th className="text-left px-4 py-3 font-medium text-muted-foreground hidden md:table-cell">Description</th>
18
+ </tr>
19
+ </thead>
20
+ <tbody>
21
+ {props.map((prop) => (
22
+ <tr key={prop.name} className="border-b border-border/20 hover:bg-muted/20 transition-colors">
23
+ <td className="px-4 py-3">
24
+ <code className="text-xs font-mono text-primary bg-primary/10 px-1.5 py-0.5 rounded">
25
+ {prop.name}
26
+ </code>
27
+ {prop.required && (
28
+ <Badge variant="destructive" className="ml-2 text-[10px] px-1.5 py-0">
29
+ required
30
+ </Badge>
31
+ )}
32
+ </td>
33
+ <td className="px-4 py-3">
34
+ <code className="text-xs font-mono text-muted-foreground break-all">{prop.type}</code>
35
+ </td>
36
+ <td className="px-4 py-3 hidden sm:table-cell">
37
+ {prop.default ? (
38
+ <code className="text-xs font-mono text-foreground/70">{prop.default}</code>
39
+ ) : (
40
+ <span className="text-xs text-muted-foreground">—</span>
41
+ )}
42
+ </td>
43
+ <td className="px-4 py-3 text-xs text-muted-foreground hidden md:table-cell">
44
+ {prop.description}
45
+ </td>
46
+ </tr>
47
+ ))}
48
+ </tbody>
49
+ </table>
50
+ </div>
51
+ );
52
+ };
53
+
54
+ export default PropTable;