@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.
- package/README.md +30 -1
- package/package.json +6 -2
- package/src/App.css +42 -0
- package/src/App.tsx +31 -0
- package/src/cli.js +393 -0
- package/src/components/CodeBlock.tsx +50 -0
- package/src/components/ComponentLivePreview.tsx +310 -0
- package/src/components/NavLink.tsx +28 -0
- package/src/components/PropTable.tsx +54 -0
- package/src/components/showcase/AuthShowcase.tsx +164 -0
- package/src/components/showcase/ComponentsShowcase.tsx +133 -0
- package/src/components/showcase/DashboardShowcase.tsx +153 -0
- package/src/components/showcase/ErrorShowcase.tsx +55 -0
- package/src/components/showcase/NotificationShowcase.tsx +102 -0
- package/src/components/ui/accordion.tsx +52 -0
- package/src/components/ui/alert-dialog.tsx +104 -0
- package/src/components/ui/alert.tsx +43 -0
- package/src/components/ui/aspect-ratio.tsx +5 -0
- package/src/components/ui/avatar.tsx +38 -0
- package/src/components/ui/badge.tsx +29 -0
- package/src/components/ui/breadcrumb.tsx +90 -0
- package/src/components/ui/button.tsx +47 -0
- package/src/components/ui/calendar.tsx +54 -0
- package/src/components/ui/card.tsx +43 -0
- package/src/components/ui/carousel.tsx +224 -0
- package/src/components/ui/chart.tsx +303 -0
- package/src/components/ui/checkbox.tsx +26 -0
- package/src/components/ui/collapsible.tsx +9 -0
- package/src/components/ui/command.tsx +132 -0
- package/src/components/ui/context-menu.tsx +178 -0
- package/src/components/ui/dialog.tsx +95 -0
- package/src/components/ui/drawer.tsx +87 -0
- package/src/components/ui/dropdown-menu.tsx +179 -0
- package/src/components/ui/form.tsx +129 -0
- package/src/components/ui/hover-card.tsx +27 -0
- package/src/components/ui/input-otp.tsx +61 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/label.tsx +17 -0
- package/src/components/ui/menubar.tsx +207 -0
- package/src/components/ui/navigation-menu.tsx +120 -0
- package/src/components/ui/pagination.tsx +81 -0
- package/src/components/ui/popover.tsx +29 -0
- package/src/components/ui/progress.tsx +23 -0
- package/src/components/ui/radio-group.tsx +36 -0
- package/src/components/ui/resizable.tsx +37 -0
- package/src/components/ui/scroll-area.tsx +38 -0
- package/src/components/ui/select.tsx +143 -0
- package/src/components/ui/separator.tsx +20 -0
- package/src/components/ui/sheet.tsx +107 -0
- package/src/components/ui/sidebar.tsx +637 -0
- package/src/components/ui/skeleton.tsx +7 -0
- package/src/components/ui/slider.tsx +23 -0
- package/src/components/ui/sonner.tsx +27 -0
- package/src/components/ui/switch.tsx +27 -0
- package/src/components/ui/table.tsx +72 -0
- package/src/components/ui/tabs.tsx +53 -0
- package/src/components/ui/textarea.tsx +21 -0
- package/src/components/ui/toast.tsx +111 -0
- package/src/components/ui/toaster.tsx +24 -0
- package/src/components/ui/toggle-group.tsx +49 -0
- package/src/components/ui/toggle.tsx +37 -0
- package/src/components/ui/tooltip.tsx +28 -0
- package/src/components/ui/use-toast.ts +3 -0
- package/src/data/componentRegistry.ts +501 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/hooks/use-toast.ts +186 -0
- package/src/index.css +105 -0
- package/src/lib/index.ts +58 -0
- package/src/lib/utils.ts +6 -0
- package/src/main.tsx +5 -0
- package/src/pages/ComponentDetail.tsx +167 -0
- package/src/pages/ComponentsList.tsx +126 -0
- package/src/pages/Index.tsx +223 -0
- package/src/pages/NotFound.tsx +24 -0
- package/src/test/example.test.ts +7 -0
- package/src/test/setup.ts +15 -0
- 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
|
|
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;
|