@cyberbloxai/ui-kit 0.1.2 → 0.2.1

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 +30 -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 +393 -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,34 @@ 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. It also handles dependencies and installs necessary npm packages automatically.
25
+
26
+ ```bash
27
+ # 1. Initialize the project (creates components.json and lib/utils.ts)
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
+ npx @cyberbloxai/ui-kit add alert-dialog # This will also add 'button' automatically!
34
+ ```
35
+
36
+ **What happens during `init`?**
37
+ - A `components.json` file is created in your root directory.
38
+ - `lib/utils.ts` is created with the `cn` helper.
39
+
40
+ **What happens during `add`?**
41
+ - The component's `.tsx` file is copied to your `components/ui` folder.
42
+ - Any internal dependencies (like `button` for `alert-dialog`) are also added.
43
+ - Any required npm packages (like `@radix-ui/react-dialog`) are installed automatically.
44
+
45
+
46
+ ### 2. Standard Library Style
47
+ Install it as a traditional npm package.
48
+
21
49
  ```bash
22
50
  npm install @cyberbloxai/ui-kit
23
51
  ```
@@ -25,7 +53,7 @@ npm install @cyberbloxai/ui-kit
25
53
  > **Note**: If you are using **Tailwind CSS v4** and encounter a dependency conflict (`ERESOLVE`), you can install using:
26
54
  > `npm install @cyberbloxai/ui-kit --legacy-peer-deps`
27
55
 
28
- ## Quick Start
56
+ ## Quick Start (Library Style)
29
57
 
30
58
  1. **Import Styles**: Add the CSS to your main entry file (e.g., `main.tsx` or `App.tsx`) **before** your other imports:
31
59
 
@@ -76,6 +104,7 @@ function App() {
76
104
 
77
105
  ## Troubleshooting
78
106
 
107
+ - **CLI Not Working**: If `npx @cyberbloxai/ui-kit` fails, try `npx @cyberbloxai/ui-kit@latest`.
79
108
  - **Blank Page / White Screen**: This usually indicates a JavaScript error. Check your browser console (`F12` -> Console).
80
109
  - Ensure you have `react` and `react-dom` installed.
81
110
  - 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.1",
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,393 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { execSync } from 'child_process';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ const packageRoot = path.join(__dirname, '..');
12
+ const componentsSrc = path.join(packageRoot, 'src', 'components', 'ui');
13
+ const utilsSrc = path.join(packageRoot, 'src', 'lib', 'utils.ts');
14
+
15
+ const args = process.argv.slice(2);
16
+ const command = args[0];
17
+
18
+ const DEFAULT_CONFIG = {
19
+ "$schema": "https://ui.shadcn.com/schema.json",
20
+ "style": "default",
21
+ "rsc": false,
22
+ "tsx": true,
23
+ "tailwind": {
24
+ "config": "tailwind.config.js",
25
+ "css": "src/index.css",
26
+ "baseColor": "slate",
27
+ "cssVariables": true,
28
+ "prefix": ""
29
+ },
30
+ "aliases": {
31
+ "components": "@/components",
32
+ "utils": "@/lib/utils",
33
+ "ui": "@/components/ui",
34
+ "lib": "@/lib",
35
+ "hooks": "@/hooks"
36
+ }
37
+ };
38
+
39
+ // Component dependencies map
40
+ const COMPONENT_REGISTRY = {
41
+ "accordion": {
42
+ "dependencies": ["@radix-ui/react-accordion"],
43
+ "registryDependencies": ["lucide-react"]
44
+ },
45
+ "alert-dialog": {
46
+ "dependencies": ["@radix-ui/react-alert-dialog", "button"],
47
+ "registryDependencies": ["lucide-react"]
48
+ },
49
+ "alert": {
50
+ "dependencies": [],
51
+ "registryDependencies": ["lucide-react", "class-variance-authority"]
52
+ },
53
+ "aspect-ratio": {
54
+ "dependencies": ["@radix-ui/react-aspect-ratio"],
55
+ "registryDependencies": []
56
+ },
57
+ "avatar": {
58
+ "dependencies": ["@radix-ui/react-avatar"],
59
+ "registryDependencies": []
60
+ },
61
+ "badge": {
62
+ "dependencies": [],
63
+ "registryDependencies": ["class-variance-authority"]
64
+ },
65
+ "breadcrumb": {
66
+ "dependencies": ["@radix-ui/react-slot"],
67
+ "registryDependencies": ["lucide-react"]
68
+ },
69
+ "button": {
70
+ "dependencies": ["@radix-ui/react-slot"],
71
+ "registryDependencies": ["class-variance-authority", "lucide-react"]
72
+ },
73
+ "calendar": {
74
+ "dependencies": ["react-day-picker", "date-fns", "button"],
75
+ "registryDependencies": ["lucide-react"]
76
+ },
77
+ "card": {
78
+ "dependencies": [],
79
+ "registryDependencies": []
80
+ },
81
+ "carousel": {
82
+ "dependencies": ["embla-carousel-react", "button"],
83
+ "registryDependencies": ["lucide-react"]
84
+ },
85
+ "checkbox": {
86
+ "dependencies": ["@radix-ui/react-checkbox"],
87
+ "registryDependencies": ["lucide-react"]
88
+ },
89
+ "collapsible": {
90
+ "dependencies": ["@radix-ui/react-collapsible"],
91
+ "registryDependencies": []
92
+ },
93
+ "command": {
94
+ "dependencies": ["cmdk", "dialog"],
95
+ "registryDependencies": ["lucide-react"]
96
+ },
97
+ "context-menu": {
98
+ "dependencies": ["@radix-ui/react-context-menu"],
99
+ "registryDependencies": ["lucide-react"]
100
+ },
101
+ "dialog": {
102
+ "dependencies": ["@radix-ui/react-dialog"],
103
+ "registryDependencies": ["lucide-react"]
104
+ },
105
+ "drawer": {
106
+ "dependencies": ["vaul"],
107
+ "registryDependencies": ["lucide-react"]
108
+ },
109
+ "dropdown-menu": {
110
+ "dependencies": ["@radix-ui/react-dropdown-menu"],
111
+ "registryDependencies": ["lucide-react"]
112
+ },
113
+ "form": {
114
+ "dependencies": ["@radix-ui/react-label", "@radix-ui/react-slot", "react-hook-form", "@hookform/resolvers", "zod", "label"],
115
+ "registryDependencies": ["lucide-react"]
116
+ },
117
+ "hover-card": {
118
+ "dependencies": ["@radix-ui/react-hover-card"],
119
+ "registryDependencies": []
120
+ },
121
+ "input-otp": {
122
+ "dependencies": ["input-otp"],
123
+ "registryDependencies": ["lucide-react"]
124
+ },
125
+ "input": {
126
+ "dependencies": [],
127
+ "registryDependencies": []
128
+ },
129
+ "label": {
130
+ "dependencies": ["@radix-ui/react-label"],
131
+ "registryDependencies": ["class-variance-authority"]
132
+ },
133
+ "menubar": {
134
+ "dependencies": ["@radix-ui/react-menubar"],
135
+ "registryDependencies": ["lucide-react"]
136
+ },
137
+ "navigation-menu": {
138
+ "dependencies": ["@radix-ui/react-navigation-menu"],
139
+ "registryDependencies": ["lucide-react", "class-variance-authority"]
140
+ },
141
+ "pagination": {
142
+ "dependencies": ["button"],
143
+ "registryDependencies": ["lucide-react"]
144
+ },
145
+ "popover": {
146
+ "dependencies": ["@radix-ui/react-popover"],
147
+ "registryDependencies": []
148
+ },
149
+ "progress": {
150
+ "dependencies": ["@radix-ui/react-progress"],
151
+ "registryDependencies": []
152
+ },
153
+ "radio-group": {
154
+ "dependencies": ["@radix-ui/react-radio-group"],
155
+ "registryDependencies": ["lucide-react"]
156
+ },
157
+ "resizable": {
158
+ "dependencies": ["react-resizable-panels"],
159
+ "registryDependencies": ["lucide-react"]
160
+ },
161
+ "scroll-area": {
162
+ "dependencies": ["@radix-ui/react-scroll-area"],
163
+ "registryDependencies": []
164
+ },
165
+ "select": {
166
+ "dependencies": ["@radix-ui/react-select"],
167
+ "registryDependencies": ["lucide-react"]
168
+ },
169
+ "separator": {
170
+ "dependencies": ["@radix-ui/react-separator"],
171
+ "registryDependencies": []
172
+ },
173
+ "sheet": {
174
+ "dependencies": ["@radix-ui/react-dialog"],
175
+ "registryDependencies": ["lucide-react", "class-variance-authority"]
176
+ },
177
+ "sidebar": {
178
+ "dependencies": ["@radix-ui/react-slot", "button", "input", "separator", "sheet", "skeleton", "tooltip"],
179
+ "registryDependencies": ["lucide-react", "class-variance-authority"]
180
+ },
181
+ "skeleton": {
182
+ "dependencies": [],
183
+ "registryDependencies": []
184
+ },
185
+ "slider": {
186
+ "dependencies": ["@radix-ui/react-slider"],
187
+ "registryDependencies": []
188
+ },
189
+ "sonner": {
190
+ "dependencies": ["sonner", "next-themes"],
191
+ "registryDependencies": []
192
+ },
193
+ "switch": {
194
+ "dependencies": ["@radix-ui/react-switch"],
195
+ "registryDependencies": []
196
+ },
197
+ "table": {
198
+ "dependencies": [],
199
+ "registryDependencies": []
200
+ },
201
+ "tabs": {
202
+ "dependencies": ["@radix-ui/react-tabs"],
203
+ "registryDependencies": []
204
+ },
205
+ "textarea": {
206
+ "dependencies": [],
207
+ "registryDependencies": []
208
+ },
209
+ "use-toast": {
210
+ "dependencies": [],
211
+ "registryDependencies": []
212
+ },
213
+ "toast": {
214
+ "dependencies": ["@radix-ui/react-toast"],
215
+ "registryDependencies": ["lucide-react", "class-variance-authority"]
216
+ },
217
+ "toaster": {
218
+ "dependencies": ["toast", "use-toast"],
219
+ "registryDependencies": []
220
+ },
221
+ "toggle-group": {
222
+ "dependencies": ["@radix-ui/react-toggle-group", "toggle"],
223
+ "registryDependencies": []
224
+ },
225
+ "toggle": {
226
+ "dependencies": ["@radix-ui/react-toggle"],
227
+ "registryDependencies": ["class-variance-authority"]
228
+ },
229
+ "tooltip": {
230
+ "dependencies": ["@radix-ui/react-tooltip"],
231
+ "registryDependencies": []
232
+ }
233
+ };
234
+
235
+ function getProjectConfig() {
236
+ const configPath = path.join(process.cwd(), 'components.json');
237
+ if (fs.existsSync(configPath)) {
238
+ return JSON.parse(fs.readFileSync(configPath, 'utf8'));
239
+ }
240
+ return null;
241
+ }
242
+
243
+ function resolveAlias(alias, config) {
244
+ const aliases = config.aliases || {};
245
+ if (alias.startsWith('@/')) {
246
+ // Basic @/ support - assuming it maps to src/ or project root
247
+ const isSrcExists = fs.existsSync(path.join(process.cwd(), 'src'));
248
+ const base = isSrcExists ? 'src' : '';
249
+ return path.join(process.cwd(), base, alias.replace('@/', ''));
250
+ }
251
+ return path.join(process.cwd(), alias);
252
+ }
253
+
254
+ function copyFile(src, dest) {
255
+ const destDir = path.dirname(dest);
256
+ if (!fs.existsSync(destDir)) {
257
+ fs.mkdirSync(destDir, { recursive: true });
258
+ }
259
+
260
+ let content = fs.readFileSync(src, 'utf8');
261
+
262
+ // Basic path replacement: replace @/ with project root relative paths if needed
263
+ // In a real shadcn CLI, this is more complex (respecting aliases)
264
+
265
+ fs.writeFileSync(dest, content);
266
+ console.log(` Created ${path.relative(process.cwd(), dest)}`);
267
+ }
268
+
269
+ function installDependencies(deps) {
270
+ if (!deps || deps.length === 0) return;
271
+
272
+ console.log(` Installing dependencies: ${deps.join(', ')}...`);
273
+ try {
274
+ const command = fs.existsSync(path.join(process.cwd(), 'yarn.lock'))
275
+ ? `yarn add ${deps.join(' ')}`
276
+ : `npm install ${deps.join(' ')}`;
277
+ execSync(command, { stdio: 'inherit' });
278
+ } catch (error) {
279
+ console.warn(' Failed to install dependencies automatically. Please install them manually.');
280
+ }
281
+ }
282
+
283
+ async function init() {
284
+ console.log('Initializing CyberBlox UI...');
285
+
286
+ const configPath = path.join(process.cwd(), 'components.json');
287
+ if (fs.existsSync(configPath)) {
288
+ console.log(' components.json already exists.');
289
+ } else {
290
+ fs.writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2));
291
+ console.log(' Created components.json');
292
+ }
293
+
294
+ const config = getProjectConfig() || DEFAULT_CONFIG;
295
+ const utilsDest = resolveAlias(config.aliases.utils + '.ts', config);
296
+
297
+ copyFile(utilsSrc, utilsDest);
298
+
299
+ console.log('\nSuccess! Project initialized.');
300
+ console.log('Now you can add components using:');
301
+ console.log('npx @cyberbloxai/ui-kit add [component-name]');
302
+ }
303
+
304
+ function addComponent(name) {
305
+ if (!name) {
306
+ console.error('Please specify a component name.');
307
+ process.exit(1);
308
+ }
309
+
310
+ const config = getProjectConfig();
311
+ if (!config) {
312
+ console.error('Project not initialized. Run "npx @cyberbloxai/ui-kit init" first.');
313
+ process.exit(1);
314
+ }
315
+
316
+ const registryItem = COMPONENT_REGISTRY[name];
317
+
318
+ // Recursive add for internal dependencies
319
+ if (registryItem && registryItem.dependencies) {
320
+ registryItem.dependencies.forEach(dep => {
321
+ if (!dep.startsWith('@')) { // It's an internal component
322
+ addComponent(dep);
323
+ }
324
+ });
325
+ }
326
+
327
+ const fileName = name.endsWith('.tsx') || name.endsWith('.ts') ? name : `${name}.tsx`;
328
+ const srcPath = path.join(componentsSrc, fileName);
329
+
330
+ // Also check in hooks if not found in components
331
+ let finalSrcPath = srcPath;
332
+ let targetDir = resolveAlias(config.aliases.ui, config);
333
+
334
+ if (!fs.existsSync(srcPath)) {
335
+ const hookPath = path.join(packageRoot, 'src', 'hooks', fileName);
336
+ const libPath = path.join(packageRoot, 'src', 'lib', fileName);
337
+
338
+ if (fs.existsSync(hookPath)) {
339
+ finalSrcPath = hookPath;
340
+ targetDir = resolveAlias(config.aliases.hooks || '@/hooks', config);
341
+ } else if (fs.existsSync(libPath)) {
342
+ finalSrcPath = libPath;
343
+ targetDir = resolveAlias(config.aliases.lib || '@/lib', config);
344
+ } else {
345
+ console.error(`Component or file "${name}" not found.`);
346
+ return;
347
+ }
348
+ }
349
+
350
+ const destPath = path.join(targetDir, path.basename(finalSrcPath));
351
+
352
+ if (fs.existsSync(destPath)) {
353
+ console.log(` File ${path.basename(finalSrcPath)} already exists. Skipping.`);
354
+ } else {
355
+ copyFile(finalSrcPath, destPath);
356
+
357
+ // Install npm dependencies
358
+ if (registryItem && registryItem.dependencies) {
359
+ const npmDeps = registryItem.dependencies.filter(d => d.startsWith('@') || !COMPONENT_REGISTRY[d]);
360
+ const regDeps = registryItem.registryDependencies || [];
361
+ installDependencies([...new Set([...npmDeps, ...regDeps])]);
362
+ }
363
+ }
364
+ }
365
+
366
+ function listComponents() {
367
+ console.log('Available components:');
368
+ const files = fs.readdirSync(componentsSrc);
369
+ files.forEach(file => {
370
+ if (file.endsWith('.tsx')) {
371
+ console.log(`- ${file.replace('.tsx', '')}`);
372
+ }
373
+ });
374
+ }
375
+
376
+ switch (command) {
377
+ case 'init':
378
+ init();
379
+ break;
380
+ case 'add':
381
+ addComponent(args[1]);
382
+ break;
383
+ case 'list':
384
+ listComponents();
385
+ break;
386
+ default:
387
+ console.log('CyberBlox UI CLI');
388
+ console.log('\nUsage:');
389
+ console.log(' npx @cyberbloxai/ui-kit init - Setup components.json and utils');
390
+ console.log(' npx @cyberbloxai/ui-kit add [name] - Add a component');
391
+ console.log(' npx @cyberbloxai/ui-kit list - List components');
392
+ break;
393
+ }
@@ -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;