@nqlib/nqui 0.4.3 → 0.4.4

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 (153) hide show
  1. package/INSTALLATION.md +215 -0
  2. package/README.md +104 -151
  3. package/dist/button-CJHdCq9I.js +155 -0
  4. package/dist/button-R304rhsj.cjs +1 -0
  5. package/dist/calendar.cjs.js +1 -1
  6. package/dist/calendar.es.js +1 -1
  7. package/dist/carousel-D1FMVglR.cjs +1 -0
  8. package/dist/carousel-U7RZhYZj.js +179 -0
  9. package/dist/carousel.cjs.js +1 -1
  10. package/dist/carousel.es.js +1 -1
  11. package/dist/command-palette-DCtLpM3Q.js +694 -0
  12. package/dist/command-palette-MHc03bBf.cjs +5 -0
  13. package/dist/command.cjs.js +1 -1
  14. package/dist/command.es.js +1 -1
  15. package/dist/components/custom/color-picker.d.ts +1 -1
  16. package/dist/components/custom/color-picker.d.ts.map +1 -1
  17. package/dist/components/custom/color-slider.d.ts +4 -10
  18. package/dist/components/custom/color-slider.d.ts.map +1 -1
  19. package/dist/components/custom/enhanced-radio-group.d.ts +13 -4
  20. package/dist/components/custom/enhanced-radio-group.d.ts.map +1 -1
  21. package/dist/components/custom/enhanced-tabs.d.ts.map +1 -1
  22. package/dist/components/debug/debug-features.d.ts +29 -0
  23. package/dist/components/debug/debug-features.d.ts.map +1 -0
  24. package/dist/components/debug/debug-panel.d.ts.map +1 -1
  25. package/dist/components/error-boundary.d.ts +20 -0
  26. package/dist/components/error-boundary.d.ts.map +1 -0
  27. package/dist/components/index.d.ts +103 -0
  28. package/dist/components/index.d.ts.map +1 -0
  29. package/dist/components/ui/badge.d.ts +16 -5
  30. package/dist/components/ui/badge.d.ts.map +1 -1
  31. package/dist/components/ui/button.d.ts +38 -4
  32. package/dist/components/ui/button.d.ts.map +1 -1
  33. package/dist/components/ui/checkbox.d.ts +16 -2
  34. package/dist/components/ui/checkbox.d.ts.map +1 -1
  35. package/dist/components/ui/combobox.d.ts +2 -1
  36. package/dist/components/ui/combobox.d.ts.map +1 -1
  37. package/dist/components/ui/input-group.d.ts +1 -1
  38. package/dist/components/ui/input-group.d.ts.map +1 -1
  39. package/dist/components/ui/pagination.d.ts +3 -2
  40. package/dist/components/ui/pagination.d.ts.map +1 -1
  41. package/dist/components/ui/radio-group.d.ts +3 -1
  42. package/dist/components/ui/radio-group.d.ts.map +1 -1
  43. package/dist/components/ui/select.d.ts +6 -1
  44. package/dist/components/ui/select.d.ts.map +1 -1
  45. package/dist/components/ui/sidebar.d.ts +1 -1
  46. package/dist/components/ui/sidebar.d.ts.map +1 -1
  47. package/dist/components/ui/slider.d.ts +10 -2
  48. package/dist/components/ui/slider.d.ts.map +1 -1
  49. package/dist/components/ui/sonner.d.ts +18 -2
  50. package/dist/components/ui/sonner.d.ts.map +1 -1
  51. package/dist/components/ui/spinner.d.ts +2 -1
  52. package/dist/components/ui/spinner.d.ts.map +1 -1
  53. package/dist/components/ui/switch.d.ts +15 -2
  54. package/dist/components/ui/switch.d.ts.map +1 -1
  55. package/dist/components/ui/tabs.d.ts +1 -1
  56. package/dist/components/ui/tabs.d.ts.map +1 -1
  57. package/dist/components/ui/toggle.d.ts +1 -1
  58. package/dist/components/ui/toggle.d.ts.map +1 -1
  59. package/dist/debug-panel-CG-vAN0L.js +9016 -0
  60. package/dist/debug-panel-DHBfAc1V.cjs +75 -0
  61. package/dist/debug.cjs.js +1 -0
  62. package/dist/debug.es.js +7 -0
  63. package/dist/{drawer-CU4lkcz7.js → drawer-DO26uhym.js} +31 -31
  64. package/dist/drawer-DVarEy65.cjs +1 -0
  65. package/dist/drawer.cjs.js +1 -1
  66. package/dist/drawer.es.js +1 -1
  67. package/dist/{enhanced-calendar-BENbxw7_.js → enhanced-calendar-BGlsSYJd.js} +1 -1
  68. package/dist/{enhanced-calendar-5PA8CeF7.cjs → enhanced-calendar-C7EQIr6i.cjs} +1 -1
  69. package/dist/entries/debug.d.ts +14 -0
  70. package/dist/entries/debug.d.ts.map +1 -0
  71. package/dist/entries/sonner.d.ts +1 -2
  72. package/dist/entries/sonner.d.ts.map +1 -1
  73. package/dist/hooks/use-mobile.d.ts.map +1 -1
  74. package/dist/hooks/use-scroll-spy.d.ts.map +1 -1
  75. package/dist/index-CI756mSv.cjs +41 -0
  76. package/dist/index-CgfzsUO6.js +1069 -0
  77. package/dist/index.d.ts +2 -98
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/lib/index.d.ts +9 -0
  80. package/dist/lib/index.d.ts.map +1 -0
  81. package/dist/lib/wrap-inline-label-text.d.ts +7 -0
  82. package/dist/lib/wrap-inline-label-text.d.ts.map +1 -0
  83. package/dist/nqui.cjs.js +49 -245
  84. package/dist/nqui.es.js +7399 -16735
  85. package/dist/sonner-CpmECDBk.js +179 -0
  86. package/dist/sonner-nE9hIalJ.cjs +48 -0
  87. package/dist/sonner.cjs.js +1 -1
  88. package/dist/sonner.es.js +3 -2
  89. package/dist/styles.css +186 -1
  90. package/docs/components/README.md +107 -8
  91. package/docs/components/nqui-badge.md +1 -0
  92. package/docs/components/nqui-button.md +3 -1
  93. package/docs/components/nqui-card.md +8 -0
  94. package/docs/components/nqui-carousel.md +6 -0
  95. package/docs/components/nqui-checkbox.md +38 -1
  96. package/docs/components/nqui-color-slider.md +5 -3
  97. package/docs/components/nqui-combobox.md +58 -37
  98. package/docs/components/nqui-drawer.md +1 -1
  99. package/docs/components/nqui-radio-group.md +45 -2
  100. package/docs/components/nqui-scroll-area.md +1 -1
  101. package/docs/components/nqui-select.md +2 -2
  102. package/docs/components/nqui-sheet.md +1 -1
  103. package/docs/components/nqui-slider.md +13 -0
  104. package/docs/components/nqui-spinner.md +6 -1
  105. package/docs/components/nqui-switch.md +23 -1
  106. package/docs/components/nqui-tabs.md +11 -1
  107. package/docs/components/nqui-toaster.md +5 -1
  108. package/docs/internal-notes/PUBLISHING.md +46 -4
  109. package/docs/nqui-skills/SKILL.md +102 -0
  110. package/docs/nqui-skills/design-system.md +143 -0
  111. package/docs/nqui-skills/rules/composition.md +183 -0
  112. package/docs/nqui-skills/rules/forms.md +190 -0
  113. package/docs/nqui-skills/rules/icons.md +158 -0
  114. package/docs/nqui-skills/rules/styling.md +192 -0
  115. package/package.json +23 -12
  116. package/scripts/build-styles.js +16 -0
  117. package/scripts/cli.js +1 -0
  118. package/scripts/download-skills.js +91 -0
  119. package/scripts/examples/nextjs-layout-sidebar.tsx +100 -0
  120. package/scripts/examples/nextjs-page-sidebar.tsx +81 -0
  121. package/scripts/examples/vite-app.tsx +135 -0
  122. package/scripts/examples/vite-main.tsx +17 -0
  123. package/scripts/examples.js +92 -6
  124. package/scripts/generate-docs.js +169 -0
  125. package/scripts/init-css.js +34 -14
  126. package/scripts/init-cursor.js +8 -0
  127. package/scripts/init-debug-css.js +4 -2
  128. package/scripts/post-install.js +41 -9
  129. package/scripts/publish-npmjs.js +17 -3
  130. package/scripts/resolve-target-dir.js +20 -1
  131. package/scripts/verify-build.js +1 -1
  132. package/scripts/wizard.js +12 -7
  133. package/dist/button-CYFTFDKe.cjs +0 -1
  134. package/dist/button-nJvDl3w8.js +0 -44
  135. package/dist/carousel-DEyyJi49.js +0 -179
  136. package/dist/carousel-Dhhz8m5V.cjs +0 -1
  137. package/dist/command-palette-UHk8zZOg.cjs +0 -45
  138. package/dist/command-palette-d-TrdBsM.js +0 -1778
  139. package/dist/components/custom/enhanced-badge.d.ts +0 -33
  140. package/dist/components/custom/enhanced-badge.d.ts.map +0 -1
  141. package/dist/components/custom/enhanced-button.d.ts +0 -34
  142. package/dist/components/custom/enhanced-button.d.ts.map +0 -1
  143. package/dist/components/custom/enhanced-checkbox.d.ts +0 -28
  144. package/dist/components/custom/enhanced-checkbox.d.ts.map +0 -1
  145. package/dist/components/custom/enhanced-combobox.d.ts +0 -35
  146. package/dist/components/custom/enhanced-combobox.d.ts.map +0 -1
  147. package/dist/components/custom/enhanced-select.d.ts +0 -30
  148. package/dist/components/custom/enhanced-select.d.ts.map +0 -1
  149. package/dist/components/custom/enhanced-sonner.d.ts +0 -16
  150. package/dist/components/custom/enhanced-sonner.d.ts.map +0 -1
  151. package/dist/drawer-BcIxWRN8.cjs +0 -1
  152. package/dist/sonner-Co6YpYVs.js +0 -546
  153. package/dist/sonner-DbQhVp8m.cjs +0 -330
@@ -0,0 +1,192 @@
1
+ # Styling & Customization
2
+
3
+ nqui uses Tailwind CSS v4 with semantic CSS variables. See customization docs for theming and CSS variables.
4
+
5
+ ## Contents
6
+
7
+ - Semantic colors
8
+ - Built-in variants first
9
+ - className for layout only
10
+ - No space-x-* / space-y-*
11
+ - Prefer size-* over w-* h-* when equal
12
+ - Prefer truncate shorthand
13
+ - No manual dark: color overrides
14
+ - Use cn() for conditional classes
15
+ - No manual z-index on overlay components (use elevation.css)
16
+
17
+ ---
18
+
19
+ ## Semantic colors
20
+
21
+ **Incorrect:**
22
+
23
+ ```tsx
24
+ <div className="bg-blue-500 text-white">
25
+ <p className="text-gray-600">Secondary text</p>
26
+ </div>
27
+ ```
28
+
29
+ **Correct:**
30
+
31
+ ```tsx
32
+ <div className="bg-primary text-primary-foreground">
33
+ <p className="text-muted-foreground">Secondary text</p>
34
+ </div>
35
+ ```
36
+
37
+ ---
38
+
39
+ ## No raw color values for status/state indicators
40
+
41
+ For positive, negative, or status indicators, use Badge variants, semantic tokens like `text-destructive`, or define custom CSS variables — don't reach for raw Tailwind colors.
42
+
43
+ **Incorrect:**
44
+
45
+ ```tsx
46
+ <span className="text-emerald-600">+20.1%</span>
47
+ <span className="text-green-500">Active</span>
48
+ <span className="text-red-600">-3.2%</span>
49
+ ```
50
+
51
+ **Correct:**
52
+
53
+ ```tsx
54
+ <Badge variant="secondary">+20.1%</Badge>
55
+ <Badge>Active</Badge>
56
+ <span className="text-destructive">-3.2%</span>
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Built-in variants first
62
+
63
+ **Incorrect:**
64
+
65
+ ```tsx
66
+ <Button className="border border-input bg-transparent hover:bg-accent">
67
+ Click me
68
+ </Button>
69
+ ```
70
+
71
+ **Correct:**
72
+
73
+ ```tsx
74
+ <Button variant="outline">Click me</Button>
75
+ ```
76
+
77
+ ---
78
+
79
+ ## className for layout only
80
+
81
+ Use `className` for layout (e.g. `max-w-md`, `mx-auto`, `mt-4`), **not** for overriding component colors or typography. To change colors, use semantic tokens, built-in variants, or CSS variables.
82
+
83
+ **Incorrect:**
84
+
85
+ ```tsx
86
+ <Card className="bg-blue-100 text-blue-900 font-bold">
87
+ <CardContent>Dashboard</CardContent>
88
+ </Card>
89
+ ```
90
+
91
+ **Correct:**
92
+
93
+ ```tsx
94
+ <Card className="max-w-md mx-auto">
95
+ <CardContent>Dashboard</CardContent>
96
+ </Card>
97
+ ```
98
+
99
+ To customize a component's appearance, prefer these approaches in order:
100
+ 1. **Built-in variants** — `variant="outline"`, `variant="destructive"`, etc.
101
+ 2. **Semantic color tokens** — `bg-primary`, `text-muted-foreground`.
102
+ 3. **CSS variables** — define custom colors in the global CSS file.
103
+
104
+ ---
105
+
106
+ ## No space-x-* / space-y-*
107
+
108
+ Use `gap-*` instead. `space-y-4` → `flex flex-col gap-4`. `space-x-2` → `flex gap-2`.
109
+
110
+ ```tsx
111
+ <div className="flex flex-col gap-4">
112
+ <Input />
113
+ <Input />
114
+ <Button>Submit</Button>
115
+ </div>
116
+ ```
117
+
118
+ ---
119
+
120
+ ## Prefer size-* over w-* h-* when equal
121
+
122
+ `size-10` not `w-10 h-10`. Applies to icons, avatars, skeletons, etc.
123
+
124
+ ---
125
+
126
+ ## Prefer truncate shorthand
127
+
128
+ `truncate` not `overflow-hidden text-ellipsis whitespace-nowrap`.
129
+
130
+ ---
131
+
132
+ ## No manual dark: color overrides
133
+
134
+ Use semantic tokens — they handle light/dark via CSS variables. `bg-background text-foreground` not `bg-white dark:bg-gray-950`.
135
+
136
+ ---
137
+
138
+ ## Use cn() for conditional classes
139
+
140
+ Use the `cn()` utility from nqui for conditional or merged class names. Don't write manual ternaries in className strings.
141
+
142
+ **Incorrect:**
143
+
144
+ ```tsx
145
+ <div className={`flex items-center ${isActive ? "bg-primary text-primary-foreground" : "bg-muted"}`}>
146
+ ```
147
+
148
+ **Correct:**
149
+
150
+ ```tsx
151
+ import { cn } from "@/lib/utils"
152
+
153
+ <div className={cn("flex items-center", isActive ? "bg-primary text-primary-foreground" : "bg-muted")}>
154
+ ```
155
+
156
+ ---
157
+
158
+ ## No manual z-index on overlay components (use elevation.css)
159
+
160
+ `Dialog`, `Sheet`, `Drawer`, `AlertDialog`, `DropdownMenu`, `Popover`, `Tooltip`, `HoverCard` handle their own stacking. Use the centralized z-index system from `elevation.css`.
161
+
162
+ **Incorrect:**
163
+
164
+ ```tsx
165
+ <div className="z-50">
166
+ <Dialog>...</Dialog>
167
+ </div>
168
+ ```
169
+
170
+ **Correct:**
171
+
172
+ ```tsx
173
+ import { cn } from "@/lib/utils"
174
+
175
+ <div className={cn("z-[var(--z-modal)]")}>
176
+ <Dialog>...</Dialog>
177
+ </div>
178
+ ```
179
+
180
+ Reference: [elevation.css](../src/styles/elevation.css)
181
+
182
+ | Variable | Value | Use Case |
183
+ |----------|-------|----------|
184
+ | `--z-base` | 0 | Base layer |
185
+ | `--z-content` | 10 | Standard content |
186
+ | `--z-sticky-content` | 15 | Sticky content within containers |
187
+ | `--z-sticky-page` | 20 | Page-level sticky elements |
188
+ | `--z-floating` | 30 | Floating panels, sidebars |
189
+ | `--z-modal-backdrop` | 40 | Modal backdrops |
190
+ | `--z-modal` | 50 | Modal content |
191
+ | `--z-popover` | 60 | Dropdowns, select menus |
192
+ | `--z-tooltip` | 70 | Tooltips |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nqlib/nqui",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "A React component library with enhanced UI components and developer tools",
5
5
  "type": "module",
6
6
  "main": "./dist/nqui.cjs.js",
@@ -47,6 +47,11 @@
47
47
  "require": "./dist/styles.css",
48
48
  "default": "./dist/styles.css"
49
49
  },
50
+ "./debug": {
51
+ "types": "./dist/entries/debug.d.ts",
52
+ "import": "./dist/debug.es.js",
53
+ "require": "./dist/debug.cjs.js"
54
+ },
50
55
  "./debug.css": "./dist/nqui.css"
51
56
  },
52
57
  "files": [
@@ -65,7 +70,7 @@
65
70
  },
66
71
  "repository": {
67
72
  "type": "git",
68
- "url": "https://github.com/nqlib/nqui.git"
73
+ "url": "git+https://github.com/nqlib/nqui.git"
69
74
  },
70
75
  "keywords": [
71
76
  "ui",
@@ -103,18 +108,21 @@
103
108
  "build-storybook": "storybook build",
104
109
  "test-storybook": "test-storybook",
105
110
  "test-storybook:ci": "test-storybook --ci",
106
- "test-storybook:coverage": "test-storybook --coverage"
111
+ "test-storybook:coverage": "test-storybook --coverage",
112
+ "test": "vitest run",
113
+ "test:watch": "vitest",
114
+ "nqui:init": "npx @nqlib/nqui install-peers && npx @nqlib/nqui init-cursor && npx @nqlib/nqui init-skills && npx @nqlib/nqui init-css --sidebar --force"
107
115
  },
108
116
  "bin": {
109
- "nqui": "./scripts/cli.js",
110
- "nqui-init-css": "./scripts/init-css.js",
111
- "nqui-init-cursor": "./scripts/init-cursor.js",
112
- "nqui-install-peers": "./scripts/install-peers.js",
113
- "nqui-init-debug": "./scripts/init-debug-css.js",
114
- "nqui-setup": "./scripts/post-install.js"
117
+ "nqui": "scripts/cli.js",
118
+ "nqui-init-css": "scripts/init-css.js",
119
+ "nqui-init-cursor": "scripts/init-cursor.js",
120
+ "nqui-init-skills": "scripts/download-skills.js",
121
+ "nqui-install-peers": "scripts/install-peers.js",
122
+ "nqui-init-debug": "scripts/init-debug-css.js",
123
+ "nqui-setup": "scripts/post-install.js"
115
124
  },
116
125
  "dependencies": {
117
- "@nqlib/nqcode": "workspace:*",
118
126
  "@codesandbox/sandpack-react": "^2.20.0",
119
127
  "@dnd-kit/core": "^6.3.1",
120
128
  "@dnd-kit/modifiers": "^9.0.0",
@@ -123,7 +131,6 @@
123
131
  "@fontsource-variable/inter": "^5.2.8",
124
132
  "@hugeicons/core-free-icons": "^3.1.1",
125
133
  "@hugeicons/react": "^1.1.4",
126
- "@nqlib/nqappbuilder": "workspace:*",
127
134
  "@radix-ui/react-avatar": "^1.1.11",
128
135
  "@radix-ui/react-checkbox": "^1.3.3",
129
136
  "@radix-ui/react-collapsible": "^1.1.12",
@@ -240,6 +247,8 @@
240
247
  "@storybook/react-vite": "^10.1.11",
241
248
  "@storybook/test-runner": "^0.24.2",
242
249
  "@storybook/testing-library": "^0.2.2",
250
+ "@testing-library/jest-dom": "^6.6.3",
251
+ "@testing-library/react": "^16.1.0",
243
252
  "@types/lodash.throttle": "^4.1.9",
244
253
  "@types/node": "^24.10.1",
245
254
  "@types/react": "^19.0.0",
@@ -255,6 +264,8 @@
255
264
  "storybook": "^10.1.11",
256
265
  "typescript": "~5.9.3",
257
266
  "typescript-eslint": "^8.46.4",
258
- "vite": "^7.2.4"
267
+ "vite": "^7.2.4",
268
+ "vitest": "^3.1.4",
269
+ "jsdom": "^26.1.0"
259
270
  }
260
271
  }
@@ -19,6 +19,7 @@ const projectRoot = resolve(__dirname, '..');
19
19
  const indexCssPath = join(projectRoot, 'src', 'index.css');
20
20
  const colorsCssPath = join(projectRoot, 'src', 'styles', 'colors.css');
21
21
  const elevationCssPath = join(projectRoot, 'src', 'styles', 'elevation.css');
22
+ const hitAreaCssPath = join(projectRoot, 'src', 'styles', 'hit-area.css');
22
23
  const outputPath = join(projectRoot, 'dist', 'styles.css');
23
24
 
24
25
  function extractStandaloneCSS() {
@@ -30,6 +31,11 @@ function extractStandaloneCSS() {
30
31
  throw new Error(`Colors CSS file not found: ${colorsCssPath}`);
31
32
  }
32
33
 
34
+ let hitAreaCss = '';
35
+ if (existsSync(hitAreaCssPath)) {
36
+ hitAreaCss = readFileSync(hitAreaCssPath, 'utf-8').trimEnd();
37
+ }
38
+
33
39
  let indexCss = readFileSync(indexCssPath, 'utf-8');
34
40
  let colorsCss = readFileSync(colorsCssPath, 'utf-8');
35
41
  let elevationCss = '';
@@ -110,14 +116,23 @@ function extractStandaloneCSS() {
110
116
  .replace(/@import\s+["']@fontsource-variable\/inter["'];?\s*\n/g, '')
111
117
  .replace(/@import\s+["']\.\/styles\/colors\.css["'];?\s*\n/g, '')
112
118
  .replace(/@import\s+["']\.\/styles\/elevation\.css["'];?\s*\n/g, '')
119
+ .replace(/@import\s+["']\.\/styles\/hit-area\.css["'];?\s*\n/g, '')
113
120
  .replace(/\/\*\s*Import enhanced color system\s*\*\//g, '')
114
121
  .replace(/\/\*\s*Import elevation system\s*\*\//g, '')
122
+ .replace(/\/\*\s*Hit-area utilities \(expanded pointer targets\)\s*\*\/\s*\n/g, '')
115
123
  // Remove @source inline() directives (already extracted above) - must match multiline
116
124
  .replace(/\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/\s*@source\s+inline\([\s\S]*?\)\s*;/g, '')
117
125
  // Remove other @source directives (non-inline ones)
118
126
  .replace(/@source\s+(?!inline\()[^;]+;?\s*\n/g, '')
119
127
  .replace(/@custom-variant\s+[^;]+;?\s*\n/g, '');
120
128
 
129
+ if (hitAreaCss) {
130
+ indexCss = indexCss.replace(
131
+ /@theme inline\s*\{/,
132
+ `/* Hit-area — https://bazza.dev/craft/2026/hit-area */\n${hitAreaCss}\n\n@theme inline {`
133
+ );
134
+ }
135
+
121
136
  // Extract :root and .dark blocks from index.css
122
137
  const indexRootMatch = indexCss.match(/:root\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/s);
123
138
  const indexDarkMatch = indexCss.match(/\.dark\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/s);
@@ -232,6 +247,7 @@ function extractStandaloneCSS() {
232
247
  * - Light and dark mode support
233
248
  * - Base layer styles
234
249
  * - Utility animations
250
+ * - Hit-area @utility blocks (inlined from src/styles/hit-area.css)
235
251
  * - @source inline() directives for zero-config Tailwind utility generation
236
252
  *
237
253
  * Generated by: npm run build:lib
package/scripts/cli.js CHANGED
@@ -20,6 +20,7 @@ const subcommand = process.argv[2];
20
20
 
21
21
  const routes = {
22
22
  'init-cursor': './init-cursor.js',
23
+ 'init-skills': './download-skills.js',
23
24
  'install-peers': './install-peers.js',
24
25
  'init-debug': './init-debug-css.js',
25
26
  'init-debug-css': './init-debug-css.js',
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Download nqui-skills to user's project
4
+ *
5
+ * Usage: npx @nqlib/nqui init-skills
6
+ *
7
+ * Copies docs/nqui-skills to user's .cursor/nqui-skills
8
+ * Creates AGENTS.md pointing to the skills
9
+ */
10
+
11
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, cpSync } from 'fs';
12
+ import { join, resolve } from 'path';
13
+ import { getPackageRoot } from './getPackageRoot.js';
14
+ import { resolveTargetDir } from './resolve-target-dir.js';
15
+
16
+ const root = getPackageRoot();
17
+ const skillsSource = join(root, 'docs', 'nqui-skills');
18
+
19
+ function ensureDir(dir) {
20
+ if (!existsSync(dir)) {
21
+ mkdirSync(dir, { recursive: true });
22
+ }
23
+ }
24
+
25
+ export async function downloadSkills({ force = true }) {
26
+ const targetDir = resolveTargetDir(process.cwd());
27
+ const cursorDir = join(targetDir, '.cursor');
28
+ const skillsDest = join(cursorDir, 'nqui-skills');
29
+ const agentsFile = join(targetDir, 'AGENTS.md');
30
+
31
+ // Create .cursor directory if needed
32
+ ensureDir(cursorDir);
33
+
34
+ // Copy skills folder
35
+ if (existsSync(skillsSource)) {
36
+ if (existsSync(skillsDest) && !force) {
37
+ console.log('⏭️ nqui-skills already exists. Use --force to overwrite.');
38
+ } else {
39
+ cpSync(skillsSource, skillsDest, { recursive: true });
40
+ console.log('✅ Copied nqui-skills to:', skillsDest);
41
+ }
42
+ } else {
43
+ console.warn('⚠️ Source skills not found:', skillsSource);
44
+ return;
45
+ }
46
+
47
+ // Create or update AGENTS.md
48
+ const agentsContent = `# AGENTS.md
49
+
50
+ This file points to nqui skills for AI assistants.
51
+
52
+ ## nqui Skills
53
+
54
+ For component implementation and UI design with @nqlib/nqui, load skills from:
55
+
56
+ \`\`\`
57
+ .cursor/nqui-skills/SKILL.md
58
+ \`\`\`
59
+
60
+ The skills include:
61
+ - Component implementation guide
62
+ - Design system conventions (sizing, z-index)
63
+ - ToggleGroup usage rules
64
+ - App design patterns
65
+
66
+ ## How to Use
67
+
68
+ When working with nqui components, AI assistants should load:
69
+ - \`.cursor/nqui-skills/SKILL.md\` - main guide
70
+
71
+ ---
72
+
73
+ Generated by nqui. Run \`npx @nqlib/nqui init-skills\` to update.
74
+ `;
75
+
76
+ if (existsSync(agentsFile) && !force) {
77
+ console.log('⏭️ AGENTS.md already exists. Use --force to overwrite.');
78
+ } else {
79
+ writeFileSync(agentsFile, agentsContent);
80
+ console.log('✅ Created AGENTS.md at:', agentsFile);
81
+ }
82
+
83
+ console.log('\n📚 nqui-skills installed!');
84
+ console.log(' Restart Cursor to load the skills.');
85
+ }
86
+
87
+ // CLI execution
88
+ const args = process.argv.slice(2);
89
+ const force = args.includes('--force') || args.length === 0;
90
+
91
+ downloadSkills({ force }).catch(console.error);
@@ -0,0 +1,100 @@
1
+ import type { Metadata } from "next";
2
+ import { ThemeProvider } from "next-themes";
3
+ import "./globals.css";
4
+ import {
5
+ SidebarProvider,
6
+ Sidebar,
7
+ SidebarContent,
8
+ SidebarHeader,
9
+ SidebarMenu,
10
+ SidebarMenuItem,
11
+ SidebarMenuButton,
12
+ SidebarInset,
13
+ SidebarTrigger,
14
+ Separator,
15
+ } from "@nqlib/nqui";
16
+ import { NquiLogo } from "@nqlib/nqui";
17
+ import { HomeIcon, SettingsIcon, MailIcon, FileIcon } from "@hugeicons/core-free-icons";
18
+ import { HugeiconsIcon } from "@hugeicons/react";
19
+ import Link from "next/link";
20
+
21
+ export const metadata: Metadata = {
22
+ title: "nqui App",
23
+ description: "3-column app with sidebar, header, and content area (showcase-style)",
24
+ };
25
+
26
+ export default function RootLayout({
27
+ children,
28
+ }: Readonly<{
29
+ children: React.ReactNode;
30
+ }>) {
31
+ return (
32
+ <html lang="en" suppressHydrationWarning>
33
+ <body>
34
+ <ThemeProvider
35
+ attribute="class"
36
+ defaultTheme="system"
37
+ enableSystem
38
+ disableTransitionOnChange
39
+ >
40
+ <SidebarProvider defaultOpen>
41
+ <Sidebar>
42
+ <SidebarHeader>
43
+ <div className="flex items-center gap-2 px-2 py-4">
44
+ <NquiLogo className="w-8 h-8" />
45
+ <span className="font-semibold">My App</span>
46
+ </div>
47
+ </SidebarHeader>
48
+ <SidebarContent>
49
+ <SidebarMenu>
50
+ <SidebarMenuItem>
51
+ <SidebarMenuButton asChild>
52
+ <Link href="/">
53
+ <HugeiconsIcon icon={HomeIcon} className="w-4 h-4" />
54
+ <span>Home</span>
55
+ </Link>
56
+ </SidebarMenuButton>
57
+ </SidebarMenuItem>
58
+ <SidebarMenuItem>
59
+ <SidebarMenuButton asChild>
60
+ <Link href="/inbox">
61
+ <HugeiconsIcon icon={MailIcon} className="w-4 h-4" />
62
+ <span>Inbox</span>
63
+ </Link>
64
+ </SidebarMenuButton>
65
+ </SidebarMenuItem>
66
+ <SidebarMenuItem>
67
+ <SidebarMenuButton asChild>
68
+ <Link href="/files">
69
+ <HugeiconsIcon icon={FileIcon} className="w-4 h-4" />
70
+ <span>Files</span>
71
+ </Link>
72
+ </SidebarMenuButton>
73
+ </SidebarMenuItem>
74
+ <SidebarMenuItem>
75
+ <SidebarMenuButton asChild>
76
+ <Link href="/settings">
77
+ <HugeiconsIcon icon={SettingsIcon} className="w-4 h-4" />
78
+ <span>Settings</span>
79
+ </Link>
80
+ </SidebarMenuButton>
81
+ </SidebarMenuItem>
82
+ </SidebarMenu>
83
+ </SidebarContent>
84
+ </Sidebar>
85
+ <SidebarInset className="flex flex-col min-h-screen">
86
+ <header className="flex h-12 items-center gap-2 border-b px-4 shrink-0 bg-background/95">
87
+ <SidebarTrigger className="-ml-1" />
88
+ <Separator orientation="vertical" className="h-4" />
89
+ <span className="text-sm font-medium">My App</span>
90
+ </header>
91
+ <main className="flex-1 min-h-0 flex">
92
+ {children}
93
+ </main>
94
+ </SidebarInset>
95
+ </SidebarProvider>
96
+ </ThemeProvider>
97
+ </body>
98
+ </html>
99
+ );
100
+ }
@@ -0,0 +1,81 @@
1
+ "use client";
2
+
3
+ import { Button } from "@nqlib/nqui";
4
+ import {
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ TableOfContents,
11
+ Input,
12
+ Label,
13
+ Checkbox,
14
+ Separator,
15
+ } from "@nqlib/nqui";
16
+
17
+ export default function Home() {
18
+ return (
19
+ <div className="flex flex-1 min-h-0">
20
+ <div className="flex-1 min-w-0 overflow-y-auto p-6">
21
+ <div className="max-w-3xl space-y-8">
22
+ <div className="space-y-2">
23
+ <h1 className="text-3xl font-bold">Welcome to My App</h1>
24
+ <p className="text-muted-foreground">
25
+ Sample 3-column layout: sidebar, main content, and table of contents (showcase-style).
26
+ </p>
27
+ </div>
28
+
29
+ <section className="space-y-4">
30
+ <h2 id="getting-started" className="text-xl font-semibold scroll-mt-6">
31
+ Getting Started
32
+ </h2>
33
+ <Card>
34
+ <CardHeader>
35
+ <CardTitle>Quick start</CardTitle>
36
+ <CardDescription>
37
+ Edit this page to start building your app
38
+ </CardDescription>
39
+ </CardHeader>
40
+ <CardContent className="space-y-4">
41
+ <div className="grid gap-2">
42
+ <Label htmlFor="name">Name</Label>
43
+ <Input id="name" placeholder="Enter your name" />
44
+ </div>
45
+ <div className="grid gap-2">
46
+ <Label htmlFor="email">Email</Label>
47
+ <Input id="email" type="email" placeholder="Enter your email" />
48
+ </div>
49
+ <Checkbox id="terms">Accept terms and conditions</Checkbox>
50
+ <Separator />
51
+ <div className="flex gap-2">
52
+ <Button variant="default">Submit</Button>
53
+ <Button variant="outline">Cancel</Button>
54
+ </div>
55
+ </CardContent>
56
+ </Card>
57
+ </section>
58
+
59
+ <section className="space-y-4">
60
+ <h2 id="next-steps" className="text-xl font-semibold scroll-mt-6">
61
+ Next steps
62
+ </h2>
63
+ <p className="text-muted-foreground text-sm">
64
+ Edit <code className="rounded bg-muted px-1 py-0.5">app/page.tsx</code> to get started.
65
+ </p>
66
+ </section>
67
+ </div>
68
+ </div>
69
+ <aside className="w-56 shrink-0 border-l bg-muted/30 p-4 hidden lg:block overflow-y-auto">
70
+ <TableOfContents
71
+ autoDetect
72
+ headingSelector="h2"
73
+ variant="clerk"
74
+ enableScrollSpy
75
+ title="Contents"
76
+ scrollOffset={80}
77
+ />
78
+ </aside>
79
+ </div>
80
+ );
81
+ }