@j3m-quantum/ui 1.12.1 → 2.1.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 +78 -8
- package/cursor-rules-for-consumers.md +208 -122
- package/dist/cli/index.js +842 -0
- package/dist/cli/postinstall.js +45 -0
- package/dist/index.cjs +1041 -450
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +112 -11
- package/dist/index.d.ts +112 -11
- package/dist/index.js +968 -380
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
|
@@ -0,0 +1,842 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as fs2 from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
|
|
5
|
+
var CURSOR_RULES_CONTENT = `# J3M Design System Rules
|
|
6
|
+
|
|
7
|
+
## Package Usage
|
|
8
|
+
- This project uses @j3m-quantum/ui - a complete React component library with J3M styling
|
|
9
|
+
- Import components directly: \`import { Button, Card, Input } from '@j3m-quantum/ui'\`
|
|
10
|
+
- Do NOT use shadcn CLI to add components - everything is already bundled
|
|
11
|
+
- Do NOT create local component copies - use the package exports
|
|
12
|
+
|
|
13
|
+
## CRITICAL: Pre-built Blocks - USE THESE FIRST!
|
|
14
|
+
|
|
15
|
+
Before implementing ANY sidebar, navigation, header, or dashboard layout, ALWAYS import these pre-built blocks:
|
|
16
|
+
|
|
17
|
+
\`\`\`tsx
|
|
18
|
+
// Pre-built blocks - USE THESE, don't build from scratch!
|
|
19
|
+
import {
|
|
20
|
+
SiteHeader, // Header with breadcrumbs + search + sidebar trigger
|
|
21
|
+
NavMain, // Main navigation with icons + collapsible sub-items
|
|
22
|
+
NavSecondary, // Secondary nav (Support, Feedback links)
|
|
23
|
+
NavUser, // User profile with dropdown menu
|
|
24
|
+
NavProjects, // Project list navigation
|
|
25
|
+
SearchForm, // Search input for sidebar
|
|
26
|
+
} from '@j3m-quantum/ui'
|
|
27
|
+
\`\`\`
|
|
28
|
+
|
|
29
|
+
## \u26D4 NEVER Create These Manually
|
|
30
|
+
|
|
31
|
+
| Instead of building... | Use this block |
|
|
32
|
+
|------------------------|----------------|
|
|
33
|
+
| \u274C Custom sidebar navigation | \u2705 \`NavMain\` |
|
|
34
|
+
| \u274C Custom user menu/profile | \u2705 \`NavUser\` |
|
|
35
|
+
| \u274C Custom page header | \u2705 \`SiteHeader\` |
|
|
36
|
+
| \u274C Custom project list | \u2705 \`NavProjects\` |
|
|
37
|
+
| \u274C Custom secondary links | \u2705 \`NavSecondary\` |
|
|
38
|
+
| \u274C Custom search in sidebar | \u2705 \`SearchForm\` |
|
|
39
|
+
| \u274C Custom CSS tokens | \u2705 Package provides all tokens |
|
|
40
|
+
|
|
41
|
+
## Block Props Reference
|
|
42
|
+
|
|
43
|
+
### NavMain
|
|
44
|
+
\`\`\`tsx
|
|
45
|
+
import { NavMain, type NavItem } from '@j3m-quantum/ui'
|
|
46
|
+
import { Home, Settings, Users } from 'lucide-react'
|
|
47
|
+
|
|
48
|
+
const navItems: NavItem[] = [
|
|
49
|
+
{ title: "Home", url: "/", icon: Home, isActive: true },
|
|
50
|
+
{ title: "Settings", url: "/settings", icon: Settings, items: [
|
|
51
|
+
{ title: "General", url: "/settings/general" },
|
|
52
|
+
{ title: "Team", url: "/settings/team" },
|
|
53
|
+
]},
|
|
54
|
+
{ title: "Users", url: "/users", icon: Users },
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
<NavMain items={navItems} label="Navigation" />
|
|
58
|
+
\`\`\`
|
|
59
|
+
|
|
60
|
+
### NavUser
|
|
61
|
+
\`\`\`tsx
|
|
62
|
+
import { NavUser } from '@j3m-quantum/ui'
|
|
63
|
+
|
|
64
|
+
<NavUser
|
|
65
|
+
user={{
|
|
66
|
+
name: "John Doe",
|
|
67
|
+
email: "john@example.com",
|
|
68
|
+
avatar: "/avatar.jpg" // or "" for initials fallback
|
|
69
|
+
}}
|
|
70
|
+
/>
|
|
71
|
+
\`\`\`
|
|
72
|
+
|
|
73
|
+
### SiteHeader
|
|
74
|
+
\`\`\`tsx
|
|
75
|
+
import { SiteHeader, SidebarTrigger } from '@j3m-quantum/ui'
|
|
76
|
+
|
|
77
|
+
<SiteHeader
|
|
78
|
+
trigger={<SidebarTrigger />}
|
|
79
|
+
breadcrumbs={[
|
|
80
|
+
{ label: "Dashboard", href: "/" },
|
|
81
|
+
{ label: "Settings" } // No href = current page
|
|
82
|
+
]}
|
|
83
|
+
showSearch={true}
|
|
84
|
+
/>
|
|
85
|
+
\`\`\`
|
|
86
|
+
|
|
87
|
+
### NavSecondary
|
|
88
|
+
\`\`\`tsx
|
|
89
|
+
import { NavSecondary } from '@j3m-quantum/ui'
|
|
90
|
+
import { LifeBuoy, Send } from 'lucide-react'
|
|
91
|
+
|
|
92
|
+
<NavSecondary items={[
|
|
93
|
+
{ title: "Support", url: "/support", icon: LifeBuoy },
|
|
94
|
+
{ title: "Feedback", url: "/feedback", icon: Send },
|
|
95
|
+
]} />
|
|
96
|
+
\`\`\`
|
|
97
|
+
|
|
98
|
+
## Sidebar Features Checklist
|
|
99
|
+
|
|
100
|
+
When using Sidebar, remember these features:
|
|
101
|
+
|
|
102
|
+
| Feature | Usage |
|
|
103
|
+
|---------|-------|
|
|
104
|
+
| \`collapsible="icon"\` | Collapses sidebar to icons only |
|
|
105
|
+
| \`collapsible="offcanvas"\` | Slides sidebar off screen |
|
|
106
|
+
| \`<SidebarRail />\` | Edge rail for drag-to-toggle |
|
|
107
|
+
| \`tooltip\` prop on SidebarMenuButton | Shows tooltips when collapsed |
|
|
108
|
+
| \`<SidebarMenuBadge>\` | Notification counts on menu items |
|
|
109
|
+
| \`<SidebarGroup>\` + \`<SidebarGroupLabel>\` | Organize sections |
|
|
110
|
+
|
|
111
|
+
\`\`\`tsx
|
|
112
|
+
<Sidebar collapsible="icon">
|
|
113
|
+
<SidebarContent>
|
|
114
|
+
<SidebarGroup>
|
|
115
|
+
<SidebarGroupLabel>Platform</SidebarGroupLabel>
|
|
116
|
+
<NavMain items={navItems} />
|
|
117
|
+
</SidebarGroup>
|
|
118
|
+
</SidebarContent>
|
|
119
|
+
<SidebarRail />
|
|
120
|
+
</Sidebar>
|
|
121
|
+
\`\`\`
|
|
122
|
+
|
|
123
|
+
## CSS Import Order (Critical)
|
|
124
|
+
\`\`\`css
|
|
125
|
+
@import "tailwindcss";
|
|
126
|
+
@import "tw-animate-css"; /* Required for animations */
|
|
127
|
+
@import "@j3m-quantum/ui/styles"; /* J3M theme and tokens */
|
|
128
|
+
|
|
129
|
+
/* REQUIRED: Tell Tailwind to scan the package for utility classes */
|
|
130
|
+
@source "../node_modules/@j3m-quantum/ui/dist/**/*.js";
|
|
131
|
+
\`\`\`
|
|
132
|
+
|
|
133
|
+
The @source directive is CRITICAL - without it, Tailwind v4 won't generate CSS for component classes.
|
|
134
|
+
|
|
135
|
+
## Theme Modes (4 Modes)
|
|
136
|
+
| Mode | Classes | Description |
|
|
137
|
+
|------|---------|-------------|
|
|
138
|
+
| Light Solid | (default) | Opaque surfaces, gray backgrounds |
|
|
139
|
+
| Dark Solid | \`dark\` | Dark opaque surfaces |
|
|
140
|
+
| Light Glass | \`theme-glass\` | Frosted glass on image/gradient |
|
|
141
|
+
| Dark Glass | \`dark theme-glass\` | Dark frosted glass on image |
|
|
142
|
+
|
|
143
|
+
### Setting Up Theme
|
|
144
|
+
\`\`\`tsx
|
|
145
|
+
<div className="j3m-app-bg"> {/* Light solid */}
|
|
146
|
+
<div className="dark j3m-app-bg"> {/* Dark solid */}
|
|
147
|
+
<div className="theme-glass j3m-app-bg"> {/* Light glass */}
|
|
148
|
+
<div className="dark theme-glass j3m-app-bg"> {/* Dark glass */}
|
|
149
|
+
\`\`\`
|
|
150
|
+
|
|
151
|
+
## Glass Context (Important!)
|
|
152
|
+
In glass mode, cards containing interactive components need the \`glass-context\` class:
|
|
153
|
+
\`\`\`tsx
|
|
154
|
+
<Card className="glass-context">
|
|
155
|
+
<CardContent>
|
|
156
|
+
<Input placeholder="Name" />
|
|
157
|
+
<Button>Submit</Button>
|
|
158
|
+
</CardContent>
|
|
159
|
+
</Card>
|
|
160
|
+
\`\`\`
|
|
161
|
+
|
|
162
|
+
## Figma Layer \u2192 Component Mapping
|
|
163
|
+
|
|
164
|
+
When you see these Figma layer names, use these components:
|
|
165
|
+
|
|
166
|
+
| Figma Layer Name | Import |
|
|
167
|
+
|------------------|--------|
|
|
168
|
+
| "Button", "CTA", "Primary Button" | \`Button\` |
|
|
169
|
+
| "Card", "Container", "Panel" | \`Card, CardHeader, CardContent\` |
|
|
170
|
+
| "Input", "Text Field" | \`Input\` |
|
|
171
|
+
| "Dialog", "Modal", "Popup" | \`Dialog, DialogContent, DialogHeader\` |
|
|
172
|
+
| "Sheet", "Side Panel", "Drawer" | \`Sheet, SheetContent\` |
|
|
173
|
+
| "Sidebar", "Navigation", "Nav" | \`SidebarProvider, Sidebar, NavMain\` |
|
|
174
|
+
| "Header", "Page Header", "Toolbar" | \`SiteHeader\` |
|
|
175
|
+
| "User Menu", "Profile", "Avatar Menu" | \`NavUser\` |
|
|
176
|
+
| "Table", "Data Grid" | \`Table\` |
|
|
177
|
+
| "Planning Grid", "Week Table" | \`PlanningTable\` |
|
|
178
|
+
| "Calibration Table" | \`CalibrationTable\` |
|
|
179
|
+
|
|
180
|
+
## Available Components (60+)
|
|
181
|
+
|
|
182
|
+
### Inputs
|
|
183
|
+
Button, ButtonGroup, Input, InputGroup, Textarea, Checkbox, RadioGroup, Switch, Slider, Select, NativeSelect, Toggle, ToggleGroup, ThemeSwitch, Form, Field, Label
|
|
184
|
+
|
|
185
|
+
### Display
|
|
186
|
+
Card, Table, Badge, Avatar, UserAvatarsDropdown, Separator, Skeleton, Accordion, Tabs, Calendar, EventCalendar (BigCalendar), Carousel, Chart, AspectRatio, Empty, Item, Kbd
|
|
187
|
+
|
|
188
|
+
### Feedback
|
|
189
|
+
Alert, AlertDialog, Progress, CircularProgress, Tooltip, Sonner (Toast), Spinner
|
|
190
|
+
|
|
191
|
+
### Navigation
|
|
192
|
+
Breadcrumb, Pagination, Command, SearchTrigger, DropdownMenu, Menubar, NavigationMenu, ContextMenu
|
|
193
|
+
|
|
194
|
+
### Overlay
|
|
195
|
+
Dialog, Drawer, Sheet, Popover, HoverCard
|
|
196
|
+
|
|
197
|
+
### Layout
|
|
198
|
+
ScrollArea, Collapsible, Resizable, Sidebar, SidebarProvider, SidebarInset, Section
|
|
199
|
+
|
|
200
|
+
### Blocks (Pre-built compositions)
|
|
201
|
+
SiteHeader, NavMain, NavProjects, NavSecondary, NavUser, SearchForm, PlanningTable, CalibrationTable, SupplierWeeklyLoading, Gantt, Kanban
|
|
202
|
+
|
|
203
|
+
### Map
|
|
204
|
+
Map, MapTileLayer, MapMarker, MapPopup, MapTooltip, MapZoomControl
|
|
205
|
+
|
|
206
|
+
## DO
|
|
207
|
+
- Import all components from @j3m-quantum/ui
|
|
208
|
+
- Use pre-built blocks (NavMain, NavUser, SiteHeader) instead of building custom
|
|
209
|
+
- Use Tailwind semantic classes: bg-primary, text-muted-foreground, bg-accent
|
|
210
|
+
- Use \`glass-context\` class on Cards with interactive components in glass mode
|
|
211
|
+
- Check the component/block list above BEFORE building anything custom
|
|
212
|
+
|
|
213
|
+
## DON'T
|
|
214
|
+
- Don't create new component files for UI that exists in @j3m-quantum/ui
|
|
215
|
+
- Don't build custom sidebar/navigation - use NavMain, NavUser, etc.
|
|
216
|
+
- Don't use shadcn CLI - components are already bundled
|
|
217
|
+
- Don't add custom CSS tokens - the package provides everything
|
|
218
|
+
- Don't use arbitrary color values like bg-[#F58446] - use bg-primary
|
|
219
|
+
|
|
220
|
+
## Complete Dashboard Example
|
|
221
|
+
|
|
222
|
+
\`\`\`tsx
|
|
223
|
+
import {
|
|
224
|
+
SidebarProvider, Sidebar, SidebarContent, SidebarFooter, SidebarInset, SidebarRail,
|
|
225
|
+
SiteHeader, SidebarTrigger, NavMain, NavUser, NavSecondary, type NavItem
|
|
226
|
+
} from '@j3m-quantum/ui'
|
|
227
|
+
import { Home, Settings, LifeBuoy, Send } from 'lucide-react'
|
|
228
|
+
|
|
229
|
+
const navItems: NavItem[] = [
|
|
230
|
+
{ title: "Home", url: "/", icon: Home, isActive: true },
|
|
231
|
+
{ title: "Settings", url: "/settings", icon: Settings },
|
|
232
|
+
]
|
|
233
|
+
|
|
234
|
+
function App() {
|
|
235
|
+
return (
|
|
236
|
+
<div className="j3m-app-bg min-h-screen">
|
|
237
|
+
<SidebarProvider>
|
|
238
|
+
<Sidebar collapsible="icon">
|
|
239
|
+
<SidebarContent>
|
|
240
|
+
<NavMain items={navItems} />
|
|
241
|
+
</SidebarContent>
|
|
242
|
+
<SidebarFooter>
|
|
243
|
+
<NavSecondary items={[
|
|
244
|
+
{ title: "Support", url: "#", icon: LifeBuoy },
|
|
245
|
+
{ title: "Feedback", url: "#", icon: Send },
|
|
246
|
+
]} />
|
|
247
|
+
<NavUser user={{ name: "John Doe", email: "john@example.com", avatar: "" }} />
|
|
248
|
+
</SidebarFooter>
|
|
249
|
+
<SidebarRail />
|
|
250
|
+
</Sidebar>
|
|
251
|
+
<SidebarInset>
|
|
252
|
+
<SiteHeader
|
|
253
|
+
trigger={<SidebarTrigger />}
|
|
254
|
+
breadcrumbs={[{ label: "Dashboard" }]}
|
|
255
|
+
/>
|
|
256
|
+
<main className="p-4">
|
|
257
|
+
{/* Your content here */}
|
|
258
|
+
</main>
|
|
259
|
+
</SidebarInset>
|
|
260
|
+
</SidebarProvider>
|
|
261
|
+
</div>
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
\`\`\`
|
|
265
|
+
|
|
266
|
+
## Recommended Prompts for AI
|
|
267
|
+
|
|
268
|
+
**Good prompts:**
|
|
269
|
+
- "Create a dashboard using @j3m-quantum/ui blocks: NavMain, NavUser, SiteHeader"
|
|
270
|
+
- "Use only pre-built blocks from @j3m-quantum/ui, don't create custom components"
|
|
271
|
+
- "Import SiteHeader for the header and NavMain for navigation from @j3m-quantum/ui"
|
|
272
|
+
- "Check the j3m-quantum cursor rules before implementing"
|
|
273
|
+
|
|
274
|
+
**Bad prompts (avoid these):**
|
|
275
|
+
- "Create a sidebar" \u2192 AI might build from scratch
|
|
276
|
+
- "Add navigation" \u2192 Too vague, specify NavMain
|
|
277
|
+
- "Make a header" \u2192 Specify SiteHeader instead
|
|
278
|
+
|
|
279
|
+
## CLI Commands
|
|
280
|
+
|
|
281
|
+
\`\`\`bash
|
|
282
|
+
npx @j3m-quantum/ui init # Set up these rules (already done!)
|
|
283
|
+
npx @j3m-quantum/ui list # List all available components
|
|
284
|
+
npx @j3m-quantum/ui doctor # Check if setup is correct
|
|
285
|
+
\`\`\`
|
|
286
|
+
`;
|
|
287
|
+
var SOURCE_DIRECTIVE = '@source "../node_modules/@j3m-quantum/ui/dist/**/*.js";';
|
|
288
|
+
function findCssFile(cwd) {
|
|
289
|
+
const possiblePaths = [
|
|
290
|
+
path.join(cwd, "src", "index.css"),
|
|
291
|
+
path.join(cwd, "src", "styles", "globals.css"),
|
|
292
|
+
path.join(cwd, "src", "styles", "index.css"),
|
|
293
|
+
path.join(cwd, "src", "app", "globals.css"),
|
|
294
|
+
path.join(cwd, "app", "globals.css"),
|
|
295
|
+
path.join(cwd, "styles", "globals.css"),
|
|
296
|
+
path.join(cwd, "styles", "index.css")
|
|
297
|
+
];
|
|
298
|
+
for (const cssPath of possiblePaths) {
|
|
299
|
+
if (fs2.existsSync(cssPath)) {
|
|
300
|
+
return cssPath;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
function updateCssFile(cssPath) {
|
|
306
|
+
const content = fs2.readFileSync(cssPath, "utf-8");
|
|
307
|
+
if (content.includes("@j3m-quantum/ui/dist")) {
|
|
308
|
+
return { updated: false, message: "already configured" };
|
|
309
|
+
}
|
|
310
|
+
if (!content.includes("@j3m-quantum/ui/styles")) {
|
|
311
|
+
return { updated: false, message: "missing @j3m-quantum/ui/styles import" };
|
|
312
|
+
}
|
|
313
|
+
const lines = content.split("\n");
|
|
314
|
+
let insertIndex = -1;
|
|
315
|
+
for (let i = 0; i < lines.length; i++) {
|
|
316
|
+
if (lines[i].includes("@j3m-quantum/ui/styles")) {
|
|
317
|
+
insertIndex = i + 1;
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (insertIndex === -1) {
|
|
322
|
+
return { updated: false, message: "could not find insertion point" };
|
|
323
|
+
}
|
|
324
|
+
lines.splice(insertIndex, 0, "", "/* Required: Tell Tailwind v4 to scan package for utility classes */", SOURCE_DIRECTIVE);
|
|
325
|
+
fs2.writeFileSync(cssPath, lines.join("\n"), "utf-8");
|
|
326
|
+
return { updated: true, message: "added @source directive" };
|
|
327
|
+
}
|
|
328
|
+
async function init() {
|
|
329
|
+
const cwd = process.cwd();
|
|
330
|
+
const cursorDir = path.join(cwd, ".cursor");
|
|
331
|
+
const rulesDir = path.join(cursorDir, "rules");
|
|
332
|
+
const rulesFile = path.join(rulesDir, "j3m-quantum.md");
|
|
333
|
+
const cursorRulesFile = path.join(cwd, ".cursorrules");
|
|
334
|
+
console.log("");
|
|
335
|
+
console.log("\u{1F3A8} Setting up @j3m-quantum/ui...");
|
|
336
|
+
console.log("");
|
|
337
|
+
try {
|
|
338
|
+
if (!fs2.existsSync(rulesDir)) {
|
|
339
|
+
fs2.mkdirSync(rulesDir, { recursive: true });
|
|
340
|
+
console.log(" \u2713 Created .cursor/rules/ directory");
|
|
341
|
+
}
|
|
342
|
+
fs2.writeFileSync(rulesFile, CURSOR_RULES_CONTENT, "utf-8");
|
|
343
|
+
console.log(" \u2713 Created .cursor/rules/j3m-quantum.md");
|
|
344
|
+
if (fs2.existsSync(cursorRulesFile)) {
|
|
345
|
+
const existingContent = fs2.readFileSync(cursorRulesFile, "utf-8");
|
|
346
|
+
if (!existingContent.includes("@j3m-quantum/ui")) {
|
|
347
|
+
console.log(" \u2139 Found existing .cursorrules file");
|
|
348
|
+
console.log(" Consider adding: 'See .cursor/rules/j3m-quantum.md for J3M Design System rules'");
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
console.log("");
|
|
352
|
+
console.log("Configuring Tailwind v4...");
|
|
353
|
+
const cssFile = findCssFile(cwd);
|
|
354
|
+
if (cssFile) {
|
|
355
|
+
const relativePath = cssFile.replace(cwd, "").replace(/^\//, "");
|
|
356
|
+
const result = updateCssFile(cssFile);
|
|
357
|
+
if (result.updated) {
|
|
358
|
+
console.log(` \u2713 Updated ${relativePath} - ${result.message}`);
|
|
359
|
+
} else if (result.message === "already configured") {
|
|
360
|
+
console.log(` \u2713 ${relativePath} - already configured`);
|
|
361
|
+
} else {
|
|
362
|
+
console.log(` \u26A0 ${relativePath} - ${result.message}`);
|
|
363
|
+
console.log(" You may need to manually add:");
|
|
364
|
+
console.log(` ${SOURCE_DIRECTIVE}`);
|
|
365
|
+
}
|
|
366
|
+
} else {
|
|
367
|
+
console.log(" \u26A0 Could not find CSS entry file");
|
|
368
|
+
console.log(" Add this to your main CSS file after the @j3m-quantum/ui/styles import:");
|
|
369
|
+
console.log("");
|
|
370
|
+
console.log(` ${SOURCE_DIRECTIVE}`);
|
|
371
|
+
}
|
|
372
|
+
console.log("");
|
|
373
|
+
console.log("\u2705 Setup complete!");
|
|
374
|
+
console.log("");
|
|
375
|
+
console.log("What was configured:");
|
|
376
|
+
console.log(" \u2022 AI cursor rules for correct component usage");
|
|
377
|
+
console.log(" \u2022 Tailwind v4 @source directive to scan package classes");
|
|
378
|
+
console.log("");
|
|
379
|
+
console.log("AI assistants will now:");
|
|
380
|
+
console.log(" \u2022 Use components from @j3m-quantum/ui");
|
|
381
|
+
console.log(" \u2022 Know about all 60+ available components");
|
|
382
|
+
console.log(" \u2022 Map Figma layers to correct components");
|
|
383
|
+
console.log(" \u2022 Follow J3M styling guidelines");
|
|
384
|
+
console.log("");
|
|
385
|
+
console.log("Required CSS imports (if not already present):");
|
|
386
|
+
console.log(' @import "tailwindcss";');
|
|
387
|
+
console.log(' @import "tw-animate-css";');
|
|
388
|
+
console.log(' @import "@j3m-quantum/ui/styles";');
|
|
389
|
+
console.log(` ${SOURCE_DIRECTIVE}`);
|
|
390
|
+
console.log("");
|
|
391
|
+
console.log("Run 'npx @j3m-quantum/ui doctor' to verify setup");
|
|
392
|
+
console.log("");
|
|
393
|
+
} catch (error) {
|
|
394
|
+
console.error("\u274C Failed to set up:", error.message);
|
|
395
|
+
process.exit(1);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/cli/commands/list.ts
|
|
400
|
+
var REGISTRY = {
|
|
401
|
+
inputs: {
|
|
402
|
+
label: "Inputs",
|
|
403
|
+
components: [
|
|
404
|
+
{ name: "Button", description: "Primary action button with variants", import: "Button", figmaNames: ["Button", "CTA", "Primary Button"] },
|
|
405
|
+
{ name: "ButtonGroup", description: "Group of related buttons", import: "ButtonGroup" },
|
|
406
|
+
{ name: "Input", description: "Text input field", import: "Input", figmaNames: ["Input", "Text Field"] },
|
|
407
|
+
{ name: "InputGroup", description: "Input with addons", import: "InputGroup" },
|
|
408
|
+
{ name: "Textarea", description: "Multi-line text input", import: "Textarea" },
|
|
409
|
+
{ name: "Checkbox", description: "Checkbox input", import: "Checkbox", figmaNames: ["Checkbox", "Check"] },
|
|
410
|
+
{ name: "RadioGroup", description: "Radio button group", import: "RadioGroup, RadioGroupItem" },
|
|
411
|
+
{ name: "Switch", description: "Toggle switch", import: "Switch", figmaNames: ["Switch", "Toggle"] },
|
|
412
|
+
{ name: "Slider", description: "Range slider", import: "Slider" },
|
|
413
|
+
{ name: "Select", description: "Dropdown select", import: "Select, SelectTrigger, SelectContent, SelectItem, SelectValue", figmaNames: ["Select", "Dropdown", "Picker"] },
|
|
414
|
+
{ name: "NativeSelect", description: "Native HTML select", import: "NativeSelect" },
|
|
415
|
+
{ name: "Toggle", description: "Toggle button", import: "Toggle" },
|
|
416
|
+
{ name: "ToggleGroup", description: "Group of toggle buttons", import: "ToggleGroup, ToggleGroupItem" },
|
|
417
|
+
{ name: "ThemeSwitch", description: "Light/dark mode toggle", import: "ThemeSwitch" },
|
|
418
|
+
{ name: "Form", description: "Form with validation", import: "Form, FormField, FormItem, FormLabel, FormControl, FormMessage" },
|
|
419
|
+
{ name: "Field", description: "Form field wrapper", import: "Field" },
|
|
420
|
+
{ name: "Label", description: "Form label", import: "Label" }
|
|
421
|
+
]
|
|
422
|
+
},
|
|
423
|
+
display: {
|
|
424
|
+
label: "Display",
|
|
425
|
+
components: [
|
|
426
|
+
{ name: "Card", description: "Content container", import: "Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter", figmaNames: ["Card", "Container", "Panel"] },
|
|
427
|
+
{ name: "Table", description: "Data table", import: "Table, TableHeader, TableBody, TableRow, TableHead, TableCell", figmaNames: ["Table", "Data Grid"] },
|
|
428
|
+
{ name: "Badge", description: "Status badge/tag", import: "Badge", figmaNames: ["Badge", "Tag", "Label"] },
|
|
429
|
+
{ name: "Avatar", description: "User avatar", import: "Avatar, AvatarImage, AvatarFallback", figmaNames: ["Avatar", "Profile Image"] },
|
|
430
|
+
{ name: "UserAvatarsDropdown", description: "Avatar with dropdown", import: "UserAvatarsDropdown" },
|
|
431
|
+
{ name: "Separator", description: "Visual divider", import: "Separator" },
|
|
432
|
+
{ name: "Skeleton", description: "Loading placeholder", import: "Skeleton" },
|
|
433
|
+
{ name: "Accordion", description: "Collapsible sections", import: "Accordion, AccordionItem, AccordionTrigger, AccordionContent", figmaNames: ["Accordion", "Expandable"] },
|
|
434
|
+
{ name: "Tabs", description: "Tabbed content", import: "Tabs, TabsList, TabsTrigger, TabsContent", figmaNames: ["Tabs", "Tab Bar"] },
|
|
435
|
+
{ name: "Calendar", description: "Date picker calendar", import: "Calendar", figmaNames: ["Calendar", "Date Picker"] },
|
|
436
|
+
{ name: "EventCalendar", description: "Big calendar for events", import: "BigCalendar, type IEvent, type IUser" },
|
|
437
|
+
{ name: "Carousel", description: "Image/content carousel", import: "Carousel, CarouselContent, CarouselItem" },
|
|
438
|
+
{ name: "Chart", description: "Data visualization", import: "ChartContainer, ChartTooltip, ChartLegend", figmaNames: ["Chart", "Graph"] },
|
|
439
|
+
{ name: "AspectRatio", description: "Maintain aspect ratio", import: "AspectRatio" },
|
|
440
|
+
{ name: "Empty", description: "Empty state placeholder", import: "Empty" },
|
|
441
|
+
{ name: "Item", description: "List item", import: "Item" },
|
|
442
|
+
{ name: "Kbd", description: "Keyboard shortcut display", import: "Kbd" }
|
|
443
|
+
]
|
|
444
|
+
},
|
|
445
|
+
feedback: {
|
|
446
|
+
label: "Feedback",
|
|
447
|
+
components: [
|
|
448
|
+
{ name: "Alert", description: "Alert message", import: "Alert, AlertTitle, AlertDescription" },
|
|
449
|
+
{ name: "AlertDialog", description: "Confirmation dialog", import: "AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogAction, AlertDialogCancel" },
|
|
450
|
+
{ name: "Progress", description: "Progress bar", import: "Progress", figmaNames: ["Progress", "Progress Bar"] },
|
|
451
|
+
{ name: "CircularProgress", description: "Circular progress indicator", import: "CircularProgress" },
|
|
452
|
+
{ name: "Tooltip", description: "Hover tooltip", import: "Tooltip, TooltipTrigger, TooltipContent, TooltipProvider", figmaNames: ["Tooltip", "Hint"] },
|
|
453
|
+
{ name: "Sonner", description: "Toast notifications", import: "Toaster, toast" },
|
|
454
|
+
{ name: "Spinner", description: "Loading spinner", import: "Spinner" }
|
|
455
|
+
]
|
|
456
|
+
},
|
|
457
|
+
navigation: {
|
|
458
|
+
label: "Navigation",
|
|
459
|
+
components: [
|
|
460
|
+
{ name: "Breadcrumb", description: "Breadcrumb navigation", import: "Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator" },
|
|
461
|
+
{ name: "Pagination", description: "Page navigation", import: "Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious" },
|
|
462
|
+
{ name: "Command", description: "Command palette", import: "Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandDialog" },
|
|
463
|
+
{ name: "SearchTrigger", description: "Search button trigger", import: "SearchTrigger, useSearchShortcut" },
|
|
464
|
+
{ name: "DropdownMenu", description: "Dropdown menu", import: "DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator", figmaNames: ["Dropdown", "Menu"] },
|
|
465
|
+
{ name: "Menubar", description: "Horizontal menu bar", import: "Menubar, MenubarMenu, MenubarTrigger, MenubarContent, MenubarItem" },
|
|
466
|
+
{ name: "NavigationMenu", description: "Navigation menu", import: "NavigationMenu, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink" },
|
|
467
|
+
{ name: "ContextMenu", description: "Right-click menu", import: "ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem" }
|
|
468
|
+
]
|
|
469
|
+
},
|
|
470
|
+
overlay: {
|
|
471
|
+
label: "Overlay",
|
|
472
|
+
components: [
|
|
473
|
+
{ name: "Dialog", description: "Modal dialog", import: "Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter", figmaNames: ["Dialog", "Modal", "Popup"] },
|
|
474
|
+
{ name: "Drawer", description: "Bottom drawer", import: "Drawer, DrawerTrigger, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, DrawerFooter" },
|
|
475
|
+
{ name: "Sheet", description: "Side panel", import: "Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription", figmaNames: ["Sheet", "Side Panel", "Drawer"] },
|
|
476
|
+
{ name: "Popover", description: "Popover panel", import: "Popover, PopoverTrigger, PopoverContent" },
|
|
477
|
+
{ name: "HoverCard", description: "Hover preview card", import: "HoverCard, HoverCardTrigger, HoverCardContent" }
|
|
478
|
+
]
|
|
479
|
+
},
|
|
480
|
+
layout: {
|
|
481
|
+
label: "Layout",
|
|
482
|
+
components: [
|
|
483
|
+
{ name: "ScrollArea", description: "Custom scrollable area", import: "ScrollArea, ScrollBar" },
|
|
484
|
+
{ name: "Collapsible", description: "Collapsible section", import: "Collapsible, CollapsibleTrigger, CollapsibleContent" },
|
|
485
|
+
{ name: "Resizable", description: "Resizable panels", import: "ResizablePanelGroup, ResizablePanel, ResizableHandle" },
|
|
486
|
+
{ name: "Sidebar", description: "Application sidebar", import: "Sidebar, SidebarProvider, SidebarContent, SidebarHeader, SidebarFooter, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarTrigger, SidebarInset", figmaNames: ["Sidebar", "Navigation"] },
|
|
487
|
+
{ name: "Section", description: "Page section", import: "Section" }
|
|
488
|
+
]
|
|
489
|
+
},
|
|
490
|
+
blocks: {
|
|
491
|
+
label: "Blocks (Pre-built Compositions)",
|
|
492
|
+
components: [
|
|
493
|
+
{ name: "SiteHeader", description: "Sticky header with breadcrumbs", import: "SiteHeader" },
|
|
494
|
+
{ name: "NavMain", description: "Main navigation with collapsible items", import: "NavMain" },
|
|
495
|
+
{ name: "NavProjects", description: "Projects navigation section", import: "NavProjects" },
|
|
496
|
+
{ name: "NavSecondary", description: "Secondary navigation links", import: "NavSecondary" },
|
|
497
|
+
{ name: "NavUser", description: "User profile with dropdown", import: "NavUser" },
|
|
498
|
+
{ name: "SearchForm", description: "Search input form", import: "SearchForm" },
|
|
499
|
+
{ name: "PlanningTable", description: "Weekly supplier planning matrix", import: "PlanningTable, type Supplier, type PlanningTableConfig", figmaNames: ["Planning Grid", "Week Table", "Supplier Matrix"] },
|
|
500
|
+
{ name: "CalibrationTable", description: "Production calibration table", import: "CalibrationTable, type CalibrationPrefix", figmaNames: ["Calibration Table", "Production Grid"] },
|
|
501
|
+
{ name: "SupplierWeeklyLoading", description: "Weekly loading view", import: "SupplierWeeklyLoading, type LoadingDelivery", figmaNames: ["Loading View", "Delivery Grid"] },
|
|
502
|
+
{ name: "Gantt", description: "Gantt chart component", import: "Gantt" },
|
|
503
|
+
{ name: "Kanban", description: "Kanban board component", import: "Kanban" }
|
|
504
|
+
]
|
|
505
|
+
},
|
|
506
|
+
map: {
|
|
507
|
+
label: "Map (requires leaflet)",
|
|
508
|
+
components: [
|
|
509
|
+
{ name: "Map", description: "Map container", import: "Map" },
|
|
510
|
+
{ name: "MapTileLayer", description: "Map tile layer", import: "MapTileLayer" },
|
|
511
|
+
{ name: "MapMarker", description: "Map marker", import: "MapMarker" },
|
|
512
|
+
{ name: "MapPopup", description: "Marker popup", import: "MapPopup" },
|
|
513
|
+
{ name: "MapTooltip", description: "Marker tooltip", import: "MapTooltip" },
|
|
514
|
+
{ name: "MapZoomControl", description: "Zoom controls", import: "MapZoomControl" }
|
|
515
|
+
]
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
function list(category) {
|
|
519
|
+
console.log("");
|
|
520
|
+
console.log("\u{1F4E6} @j3m-quantum/ui Components");
|
|
521
|
+
console.log("\u2550".repeat(50));
|
|
522
|
+
const categories = category ? { [category]: REGISTRY[category] } : REGISTRY;
|
|
523
|
+
if (category && !REGISTRY[category]) {
|
|
524
|
+
console.log("");
|
|
525
|
+
console.log(`\u274C Unknown category: ${category}`);
|
|
526
|
+
console.log("");
|
|
527
|
+
console.log("Available categories:");
|
|
528
|
+
Object.keys(REGISTRY).forEach((cat) => {
|
|
529
|
+
console.log(` \u2022 ${cat}`);
|
|
530
|
+
});
|
|
531
|
+
console.log("");
|
|
532
|
+
console.log("Usage: npx @j3m-quantum/ui list --category <category>");
|
|
533
|
+
console.log("");
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
let totalCount = 0;
|
|
537
|
+
for (const [key, cat] of Object.entries(categories)) {
|
|
538
|
+
if (!cat) continue;
|
|
539
|
+
console.log("");
|
|
540
|
+
console.log(`\u25B8 ${cat.label}`);
|
|
541
|
+
console.log("\u2500".repeat(40));
|
|
542
|
+
for (const component of cat.components) {
|
|
543
|
+
totalCount++;
|
|
544
|
+
const figmaInfo = component.figmaNames ? ` (Figma: ${component.figmaNames.join(", ")})` : "";
|
|
545
|
+
console.log(` ${component.name}`);
|
|
546
|
+
console.log(` ${component.description}${figmaInfo}`);
|
|
547
|
+
console.log(` import { ${component.import} } from '@j3m-quantum/ui'`);
|
|
548
|
+
console.log("");
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
console.log("\u2550".repeat(50));
|
|
552
|
+
console.log(`Total: ${totalCount} components`);
|
|
553
|
+
console.log("");
|
|
554
|
+
console.log("Usage:");
|
|
555
|
+
console.log(" import { ComponentName } from '@j3m-quantum/ui'");
|
|
556
|
+
console.log("");
|
|
557
|
+
console.log("Filter by category:");
|
|
558
|
+
console.log(" npx @j3m-quantum/ui list --category blocks");
|
|
559
|
+
console.log("");
|
|
560
|
+
}
|
|
561
|
+
async function doctor() {
|
|
562
|
+
const cwd = process.cwd();
|
|
563
|
+
const results = [];
|
|
564
|
+
console.log("");
|
|
565
|
+
console.log("\u{1FA7A} @j3m-quantum/ui Doctor");
|
|
566
|
+
console.log("\u2550".repeat(50));
|
|
567
|
+
console.log("");
|
|
568
|
+
console.log("Checking your project setup...");
|
|
569
|
+
console.log("");
|
|
570
|
+
const packageJsonPath = path.join(cwd, "package.json");
|
|
571
|
+
if (fs2.existsSync(packageJsonPath)) {
|
|
572
|
+
const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
|
|
573
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
574
|
+
if (deps["@j3m-quantum/ui"]) {
|
|
575
|
+
const version = deps["@j3m-quantum/ui"];
|
|
576
|
+
results.push({
|
|
577
|
+
name: "@j3m-quantum/ui installed",
|
|
578
|
+
status: "pass",
|
|
579
|
+
message: `Version: ${version}`
|
|
580
|
+
});
|
|
581
|
+
} else {
|
|
582
|
+
results.push({
|
|
583
|
+
name: "@j3m-quantum/ui installed",
|
|
584
|
+
status: "fail",
|
|
585
|
+
message: "Package not found in dependencies",
|
|
586
|
+
fix: "npm install @j3m-quantum/ui"
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
if (deps["tw-animate-css"]) {
|
|
590
|
+
results.push({
|
|
591
|
+
name: "tw-animate-css installed",
|
|
592
|
+
status: "pass",
|
|
593
|
+
message: `Version: ${deps["tw-animate-css"]}`
|
|
594
|
+
});
|
|
595
|
+
} else {
|
|
596
|
+
results.push({
|
|
597
|
+
name: "tw-animate-css installed",
|
|
598
|
+
status: "warn",
|
|
599
|
+
message: "Not found - animations may not work",
|
|
600
|
+
fix: "npm install tw-animate-css"
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
if (deps["tailwindcss"]) {
|
|
604
|
+
const version = deps["tailwindcss"];
|
|
605
|
+
const majorVersion = parseInt(version.replace(/[^0-9]/g, "").charAt(0));
|
|
606
|
+
if (majorVersion >= 4) {
|
|
607
|
+
results.push({
|
|
608
|
+
name: "Tailwind CSS v4+",
|
|
609
|
+
status: "pass",
|
|
610
|
+
message: `Version: ${version}`
|
|
611
|
+
});
|
|
612
|
+
} else {
|
|
613
|
+
results.push({
|
|
614
|
+
name: "Tailwind CSS v4+",
|
|
615
|
+
status: "fail",
|
|
616
|
+
message: `Version ${version} - requires v4+`,
|
|
617
|
+
fix: "npm install tailwindcss@latest"
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
} else {
|
|
621
|
+
results.push({
|
|
622
|
+
name: "Tailwind CSS v4+",
|
|
623
|
+
status: "fail",
|
|
624
|
+
message: "Not found",
|
|
625
|
+
fix: "npm install -D tailwindcss @tailwindcss/vite"
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
} else {
|
|
629
|
+
results.push({
|
|
630
|
+
name: "package.json",
|
|
631
|
+
status: "fail",
|
|
632
|
+
message: "Not found - run from project root"
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
const cursorRulesPath = path.join(cwd, ".cursor", "rules", "j3m-quantum.md");
|
|
636
|
+
const altCursorRulesPath = path.join(cwd, ".cursorrules");
|
|
637
|
+
if (fs2.existsSync(cursorRulesPath)) {
|
|
638
|
+
results.push({
|
|
639
|
+
name: "Cursor rules configured",
|
|
640
|
+
status: "pass",
|
|
641
|
+
message: ".cursor/rules/j3m-quantum.md found"
|
|
642
|
+
});
|
|
643
|
+
} else if (fs2.existsSync(altCursorRulesPath)) {
|
|
644
|
+
const content = fs2.readFileSync(altCursorRulesPath, "utf-8");
|
|
645
|
+
if (content.includes("@j3m-quantum/ui")) {
|
|
646
|
+
results.push({
|
|
647
|
+
name: "Cursor rules configured",
|
|
648
|
+
status: "pass",
|
|
649
|
+
message: ".cursorrules contains J3M references"
|
|
650
|
+
});
|
|
651
|
+
} else {
|
|
652
|
+
results.push({
|
|
653
|
+
name: "Cursor rules configured",
|
|
654
|
+
status: "warn",
|
|
655
|
+
message: ".cursorrules exists but missing J3M rules",
|
|
656
|
+
fix: "npx @j3m-quantum/ui init"
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
} else {
|
|
660
|
+
results.push({
|
|
661
|
+
name: "Cursor rules configured",
|
|
662
|
+
status: "warn",
|
|
663
|
+
message: "No cursor rules found - AI may not use components correctly",
|
|
664
|
+
fix: "npx @j3m-quantum/ui init"
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
const possibleCssPaths = [
|
|
668
|
+
path.join(cwd, "src", "index.css"),
|
|
669
|
+
path.join(cwd, "src", "styles", "globals.css"),
|
|
670
|
+
path.join(cwd, "src", "app", "globals.css"),
|
|
671
|
+
path.join(cwd, "app", "globals.css"),
|
|
672
|
+
path.join(cwd, "styles", "globals.css")
|
|
673
|
+
];
|
|
674
|
+
let cssFound = false;
|
|
675
|
+
let cssContent = "";
|
|
676
|
+
let foundCssPath = "";
|
|
677
|
+
for (const cssPath of possibleCssPaths) {
|
|
678
|
+
if (fs2.existsSync(cssPath)) {
|
|
679
|
+
cssFound = true;
|
|
680
|
+
cssContent = fs2.readFileSync(cssPath, "utf-8");
|
|
681
|
+
foundCssPath = cssPath.replace(cwd, "");
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (cssFound) {
|
|
686
|
+
const hasJ3mStyles = cssContent.includes("@j3m-quantum/ui/styles");
|
|
687
|
+
const hasTailwind = cssContent.includes("tailwindcss");
|
|
688
|
+
cssContent.includes("tw-animate-css");
|
|
689
|
+
const hasSourceDirective = cssContent.includes("@j3m-quantum/ui/dist");
|
|
690
|
+
if (hasJ3mStyles && hasTailwind) {
|
|
691
|
+
const tailwindIndex = cssContent.indexOf("tailwindcss");
|
|
692
|
+
const twAnimateIndex = cssContent.indexOf("tw-animate-css");
|
|
693
|
+
const j3mIndex = cssContent.indexOf("@j3m-quantum/ui/styles");
|
|
694
|
+
const orderCorrect = tailwindIndex < j3mIndex && (twAnimateIndex === -1 || twAnimateIndex > tailwindIndex && twAnimateIndex < j3mIndex);
|
|
695
|
+
if (orderCorrect) {
|
|
696
|
+
results.push({
|
|
697
|
+
name: "CSS imports configured",
|
|
698
|
+
status: "pass",
|
|
699
|
+
message: `${foundCssPath} - imports in correct order`
|
|
700
|
+
});
|
|
701
|
+
} else {
|
|
702
|
+
results.push({
|
|
703
|
+
name: "CSS imports configured",
|
|
704
|
+
status: "warn",
|
|
705
|
+
message: `${foundCssPath} - import order may be incorrect`,
|
|
706
|
+
fix: "Order should be: tailwindcss \u2192 tw-animate-css \u2192 @j3m-quantum/ui/styles"
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
} else if (!hasJ3mStyles) {
|
|
710
|
+
results.push({
|
|
711
|
+
name: "CSS imports configured",
|
|
712
|
+
status: "fail",
|
|
713
|
+
message: `${foundCssPath} - missing @j3m-quantum/ui/styles`,
|
|
714
|
+
fix: 'Add: @import "@j3m-quantum/ui/styles";'
|
|
715
|
+
});
|
|
716
|
+
} else if (!hasTailwind) {
|
|
717
|
+
results.push({
|
|
718
|
+
name: "CSS imports configured",
|
|
719
|
+
status: "fail",
|
|
720
|
+
message: `${foundCssPath} - missing tailwindcss import`,
|
|
721
|
+
fix: 'Add: @import "tailwindcss";'
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
if (hasSourceDirective) {
|
|
725
|
+
results.push({
|
|
726
|
+
name: "Tailwind @source directive",
|
|
727
|
+
status: "pass",
|
|
728
|
+
message: `${foundCssPath} - @source configured for package scanning`
|
|
729
|
+
});
|
|
730
|
+
} else {
|
|
731
|
+
results.push({
|
|
732
|
+
name: "Tailwind @source directive",
|
|
733
|
+
status: "fail",
|
|
734
|
+
message: `${foundCssPath} - missing @source directive (components will be unstyled!)`,
|
|
735
|
+
fix: 'Add: @source "../node_modules/@j3m-quantum/ui/dist/**/*.js";'
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
} else {
|
|
739
|
+
results.push({
|
|
740
|
+
name: "CSS imports configured",
|
|
741
|
+
status: "warn",
|
|
742
|
+
message: "Could not find CSS entry file",
|
|
743
|
+
fix: "Create src/index.css with required imports"
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
const viteConfigPath = path.join(cwd, "vite.config.ts");
|
|
747
|
+
const viteConfigJsPath = path.join(cwd, "vite.config.js");
|
|
748
|
+
if (fs2.existsSync(viteConfigPath) || fs2.existsSync(viteConfigJsPath)) {
|
|
749
|
+
const configPath = fs2.existsSync(viteConfigPath) ? viteConfigPath : viteConfigJsPath;
|
|
750
|
+
const configContent = fs2.readFileSync(configPath, "utf-8");
|
|
751
|
+
if (configContent.includes("@tailwindcss/vite")) {
|
|
752
|
+
results.push({
|
|
753
|
+
name: "Vite + Tailwind plugin",
|
|
754
|
+
status: "pass",
|
|
755
|
+
message: "@tailwindcss/vite configured"
|
|
756
|
+
});
|
|
757
|
+
} else {
|
|
758
|
+
results.push({
|
|
759
|
+
name: "Vite + Tailwind plugin",
|
|
760
|
+
status: "warn",
|
|
761
|
+
message: "Consider using @tailwindcss/vite for better performance"
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
console.log("Results:");
|
|
766
|
+
console.log("\u2500".repeat(50));
|
|
767
|
+
for (const result of results) {
|
|
768
|
+
const icon = result.status === "pass" ? "\u2713" : result.status === "warn" ? "\u26A0" : "\u2717";
|
|
769
|
+
result.status === "pass" ? "" : result.status === "warn" ? "" : "";
|
|
770
|
+
console.log(` ${icon} ${result.name}`);
|
|
771
|
+
console.log(` ${result.message}`);
|
|
772
|
+
if (result.fix) {
|
|
773
|
+
console.log(` Fix: ${result.fix}`);
|
|
774
|
+
}
|
|
775
|
+
console.log("");
|
|
776
|
+
}
|
|
777
|
+
console.log("\u2500".repeat(50));
|
|
778
|
+
const passCount = results.filter((r) => r.status === "pass").length;
|
|
779
|
+
const warnCount = results.filter((r) => r.status === "warn").length;
|
|
780
|
+
const failCount = results.filter((r) => r.status === "fail").length;
|
|
781
|
+
console.log(`Summary: ${passCount} passed, ${warnCount} warnings, ${failCount} failed`);
|
|
782
|
+
console.log("");
|
|
783
|
+
if (failCount > 0) {
|
|
784
|
+
console.log("\u274C Some checks failed. Please fix the issues above.");
|
|
785
|
+
} else if (warnCount > 0) {
|
|
786
|
+
console.log("\u26A0\uFE0F Setup looks good with some warnings.");
|
|
787
|
+
} else {
|
|
788
|
+
console.log("\u2705 All checks passed! Your setup is ready.");
|
|
789
|
+
}
|
|
790
|
+
console.log("");
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// src/cli/index.ts
|
|
794
|
+
var args = process.argv.slice(2);
|
|
795
|
+
var command = args[0];
|
|
796
|
+
var HELP = `
|
|
797
|
+
@j3m-quantum/ui CLI
|
|
798
|
+
|
|
799
|
+
Usage:
|
|
800
|
+
npx @j3m-quantum/ui <command>
|
|
801
|
+
|
|
802
|
+
Commands:
|
|
803
|
+
init Set up cursor rules for AI assistance
|
|
804
|
+
list List all available components
|
|
805
|
+
doctor Check if your setup is correct
|
|
806
|
+
help Show this help message
|
|
807
|
+
|
|
808
|
+
Examples:
|
|
809
|
+
npx @j3m-quantum/ui init
|
|
810
|
+
npx @j3m-quantum/ui list
|
|
811
|
+
npx @j3m-quantum/ui list --category blocks
|
|
812
|
+
npx @j3m-quantum/ui doctor
|
|
813
|
+
`;
|
|
814
|
+
async function main() {
|
|
815
|
+
switch (command) {
|
|
816
|
+
case "init":
|
|
817
|
+
await init();
|
|
818
|
+
break;
|
|
819
|
+
case "list":
|
|
820
|
+
const categoryFlag = args.indexOf("--category");
|
|
821
|
+
const category = categoryFlag !== -1 ? args[categoryFlag + 1] : void 0;
|
|
822
|
+
list(category);
|
|
823
|
+
break;
|
|
824
|
+
case "doctor":
|
|
825
|
+
await doctor();
|
|
826
|
+
break;
|
|
827
|
+
case "help":
|
|
828
|
+
case "--help":
|
|
829
|
+
case "-h":
|
|
830
|
+
case void 0:
|
|
831
|
+
console.log(HELP);
|
|
832
|
+
break;
|
|
833
|
+
default:
|
|
834
|
+
console.error(`Unknown command: ${command}`);
|
|
835
|
+
console.log(HELP);
|
|
836
|
+
process.exit(1);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
main().catch((error) => {
|
|
840
|
+
console.error("Error:", error.message);
|
|
841
|
+
process.exit(1);
|
|
842
|
+
});
|