@nqlib/nqui 0.4.1 → 0.4.2
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/INSTALLATION.md +215 -0
- package/README.md +2 -1
- package/dist/command-palette-BuYcxPCc.cjs +5 -0
- package/dist/command-palette-dEJ9aEk4.js +694 -0
- package/dist/command.cjs.js +1 -1
- package/dist/command.es.js +1 -1
- package/dist/components/custom/enhanced-badge.d.ts +1 -1
- package/dist/components/custom/enhanced-button.d.ts +6 -1
- package/dist/components/custom/enhanced-button.d.ts.map +1 -1
- package/dist/components/custom/enhanced-checkbox.d.ts +11 -0
- package/dist/components/custom/enhanced-checkbox.d.ts.map +1 -1
- package/dist/components/custom/enhanced-radio-group.d.ts +13 -4
- package/dist/components/custom/enhanced-radio-group.d.ts.map +1 -1
- package/dist/components/custom/enhanced-sonner.d.ts +5 -6
- package/dist/components/custom/enhanced-sonner.d.ts.map +1 -1
- package/dist/components/custom/enhanced-tabs.d.ts.map +1 -1
- package/dist/components/error-boundary.d.ts +20 -0
- package/dist/components/error-boundary.d.ts.map +1 -0
- package/dist/components/index.d.ts +102 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/ui/badge.d.ts +1 -1
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/checkbox.d.ts +4 -1
- package/dist/components/ui/checkbox.d.ts.map +1 -1
- package/dist/components/ui/input-group.d.ts +1 -1
- package/dist/components/ui/input-group.d.ts.map +1 -1
- package/dist/components/ui/radio-group.d.ts +3 -1
- package/dist/components/ui/radio-group.d.ts.map +1 -1
- package/dist/components/ui/sidebar.d.ts.map +1 -1
- package/dist/debug-panel-AjzBdMMz.js +9198 -0
- package/dist/debug-panel-NaOmD68t.cjs +171 -0
- package/dist/debug.cjs.js +1 -0
- package/dist/debug.es.js +7 -0
- package/dist/drawer-Cqq0Ozb2.cjs +1 -0
- package/dist/{drawer-CU4lkcz7.js → drawer-pUXPg3lF.js} +2 -2
- package/dist/drawer.cjs.js +1 -1
- package/dist/drawer.es.js +1 -1
- package/dist/entries/debug.d.ts +14 -0
- package/dist/entries/debug.d.ts.map +1 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -1
- package/dist/hooks/use-scroll-spy.d.ts.map +1 -1
- package/dist/index-CI756mSv.cjs +41 -0
- package/dist/index-CgfzsUO6.js +1069 -0
- package/dist/index.d.ts +2 -98
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/index.d.ts +9 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/nqui.cjs.js +42 -212
- package/dist/nqui.es.js +8589 -17780
- package/dist/sonner-BtzU00r3.js +248 -0
- package/dist/sonner-Dfk26eds.cjs +54 -0
- package/dist/sonner.cjs.js +1 -1
- package/dist/sonner.es.js +1 -1
- package/dist/styles.css +3 -0
- package/docs/components/README.md +99 -1
- package/docs/components/nqui-card.md +7 -0
- package/docs/components/nqui-checkbox.md +23 -1
- package/docs/components/nqui-radio-group.md +45 -2
- package/docs/components/nqui-tabs.md +11 -1
- package/docs/nqui-skills/SKILL.md +95 -0
- package/docs/nqui-skills/design-system.md +130 -0
- package/docs/nqui-skills/rules/composition.md +183 -0
- package/docs/nqui-skills/rules/forms.md +190 -0
- package/docs/nqui-skills/rules/icons.md +158 -0
- package/docs/nqui-skills/rules/styling.md +192 -0
- package/package.json +23 -10
- package/scripts/cli.js +1 -0
- package/scripts/download-skills.js +91 -0
- package/scripts/examples/nextjs-layout-sidebar.tsx +100 -0
- package/scripts/examples/nextjs-page-sidebar.tsx +81 -0
- package/scripts/examples/vite-app.tsx +135 -0
- package/scripts/examples/vite-main.tsx +17 -0
- package/scripts/examples.js +92 -6
- package/scripts/generate-docs.js +169 -0
- package/scripts/init-css.js +34 -14
- package/scripts/init-cursor.js +8 -0
- package/scripts/post-install.js +41 -9
- package/scripts/wizard.js +12 -7
- package/dist/command-palette-UHk8zZOg.cjs +0 -45
- package/dist/command-palette-d-TrdBsM.js +0 -1778
- package/dist/drawer-BcIxWRN8.cjs +0 -1
- package/dist/sonner-Co6YpYVs.js +0 -546
- 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
|
+
"version": "0.4.2",
|
|
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,15 +108,19 @@
|
|
|
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": "
|
|
110
|
-
"nqui-init-css": "
|
|
111
|
-
"nqui-init-cursor": "
|
|
112
|
-
"nqui-
|
|
113
|
-
"nqui-
|
|
114
|
-
"nqui-
|
|
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
126
|
"@codesandbox/sandpack-react": "^2.20.0",
|
|
@@ -238,6 +247,8 @@
|
|
|
238
247
|
"@storybook/react-vite": "^10.1.11",
|
|
239
248
|
"@storybook/test-runner": "^0.24.2",
|
|
240
249
|
"@storybook/testing-library": "^0.2.2",
|
|
250
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
251
|
+
"@testing-library/react": "^16.1.0",
|
|
241
252
|
"@types/lodash.throttle": "^4.1.9",
|
|
242
253
|
"@types/node": "^24.10.1",
|
|
243
254
|
"@types/react": "^19.0.0",
|
|
@@ -253,6 +264,8 @@
|
|
|
253
264
|
"storybook": "^10.1.11",
|
|
254
265
|
"typescript": "~5.9.3",
|
|
255
266
|
"typescript-eslint": "^8.46.4",
|
|
256
|
-
"vite": "^7.2.4"
|
|
267
|
+
"vite": "^7.2.4",
|
|
268
|
+
"vitest": "^3.1.4",
|
|
269
|
+
"jsdom": "^26.1.0"
|
|
257
270
|
}
|
|
258
271
|
}
|
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
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { Routes, Route } from "react-router-dom";
|
|
2
|
+
import {
|
|
3
|
+
SidebarProvider,
|
|
4
|
+
Sidebar,
|
|
5
|
+
SidebarContent,
|
|
6
|
+
SidebarHeader,
|
|
7
|
+
SidebarMenu,
|
|
8
|
+
SidebarMenuItem,
|
|
9
|
+
SidebarMenuButton,
|
|
10
|
+
SidebarInset,
|
|
11
|
+
SidebarTrigger,
|
|
12
|
+
Separator,
|
|
13
|
+
TableOfContents,
|
|
14
|
+
NquiLogo,
|
|
15
|
+
} from "@nqlib/nqui";
|
|
16
|
+
import { HomeIcon, SettingsIcon, MailIcon, FileIcon } from "@hugeicons/core-free-icons";
|
|
17
|
+
import { HugeiconsIcon } from "@hugeicons/react";
|
|
18
|
+
import { Link } from "react-router-dom";
|
|
19
|
+
|
|
20
|
+
function Layout({ children }: { children: React.ReactNode }) {
|
|
21
|
+
return (
|
|
22
|
+
<SidebarProvider defaultOpen>
|
|
23
|
+
<Sidebar>
|
|
24
|
+
<SidebarHeader>
|
|
25
|
+
<div className="flex items-center gap-2 px-2 py-4">
|
|
26
|
+
<NquiLogo className="w-8 h-8" />
|
|
27
|
+
<span className="font-semibold">My App</span>
|
|
28
|
+
</div>
|
|
29
|
+
</SidebarHeader>
|
|
30
|
+
<SidebarContent>
|
|
31
|
+
<SidebarMenu>
|
|
32
|
+
<SidebarMenuItem>
|
|
33
|
+
<SidebarMenuButton asChild>
|
|
34
|
+
<Link to="/">
|
|
35
|
+
<HugeiconsIcon icon={HomeIcon} className="w-4 h-4" />
|
|
36
|
+
<span>Home</span>
|
|
37
|
+
</Link>
|
|
38
|
+
</SidebarMenuButton>
|
|
39
|
+
</SidebarMenuItem>
|
|
40
|
+
<SidebarMenuItem>
|
|
41
|
+
<SidebarMenuButton asChild>
|
|
42
|
+
<Link to="/inbox">
|
|
43
|
+
<HugeiconsIcon icon={MailIcon} className="w-4 h-4" />
|
|
44
|
+
<span>Inbox</span>
|
|
45
|
+
</Link>
|
|
46
|
+
</SidebarMenuButton>
|
|
47
|
+
</SidebarMenuItem>
|
|
48
|
+
<SidebarMenuItem>
|
|
49
|
+
<SidebarMenuButton asChild>
|
|
50
|
+
<Link to="/files">
|
|
51
|
+
<HugeiconsIcon icon={FileIcon} className="w-4 h-4" />
|
|
52
|
+
<span>Files</span>
|
|
53
|
+
</Link>
|
|
54
|
+
</SidebarMenuButton>
|
|
55
|
+
</SidebarMenuItem>
|
|
56
|
+
<SidebarMenuItem>
|
|
57
|
+
<SidebarMenuButton asChild>
|
|
58
|
+
<Link to="/settings">
|
|
59
|
+
<HugeiconsIcon icon={SettingsIcon} className="w-4 h-4" />
|
|
60
|
+
<span>Settings</span>
|
|
61
|
+
</Link>
|
|
62
|
+
</SidebarMenuButton>
|
|
63
|
+
</SidebarMenuItem>
|
|
64
|
+
</SidebarMenu>
|
|
65
|
+
</SidebarContent>
|
|
66
|
+
</Sidebar>
|
|
67
|
+
<SidebarInset className="flex flex-col min-h-screen">
|
|
68
|
+
<header className="flex h-12 items-center gap-2 border-b px-4 shrink-0 bg-background/95">
|
|
69
|
+
<SidebarTrigger className="-ml-1" />
|
|
70
|
+
<Separator orientation="vertical" className="h-4" />
|
|
71
|
+
<span className="text-sm font-medium">My App</span>
|
|
72
|
+
</header>
|
|
73
|
+
<main className="flex-1 min-h-0 flex">
|
|
74
|
+
{children}
|
|
75
|
+
</main>
|
|
76
|
+
</SidebarInset>
|
|
77
|
+
</SidebarProvider>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function HomePage() {
|
|
82
|
+
return (
|
|
83
|
+
<div className="flex flex-1 min-h-0">
|
|
84
|
+
<div className="flex-1 min-w-0 overflow-y-auto p-6">
|
|
85
|
+
<div className="max-w-3xl space-y-8">
|
|
86
|
+
<div className="space-y-2">
|
|
87
|
+
<h1 className="text-3xl font-bold">Welcome to My App</h1>
|
|
88
|
+
<p className="text-muted-foreground">
|
|
89
|
+
Sample 3-column layout: sidebar, main content, and table of contents (showcase-style).
|
|
90
|
+
</p>
|
|
91
|
+
</div>
|
|
92
|
+
<section className="space-y-4">
|
|
93
|
+
<h2 id="getting-started" className="text-xl font-semibold scroll-mt-6">
|
|
94
|
+
Getting Started
|
|
95
|
+
</h2>
|
|
96
|
+
<p className="text-muted-foreground text-sm">
|
|
97
|
+
Edit <code className="rounded bg-muted px-1 py-0.5">App.tsx</code> to get started.
|
|
98
|
+
</p>
|
|
99
|
+
</section>
|
|
100
|
+
<section className="space-y-4">
|
|
101
|
+
<h2 id="next-steps" className="text-xl font-semibold scroll-mt-6">
|
|
102
|
+
Next steps
|
|
103
|
+
</h2>
|
|
104
|
+
<p className="text-muted-foreground text-sm">
|
|
105
|
+
Add routes and pages. The right column shows a table of contents from headings on this page.
|
|
106
|
+
</p>
|
|
107
|
+
</section>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
<aside className="w-56 shrink-0 border-l bg-muted/30 p-4 hidden lg:block overflow-y-auto">
|
|
111
|
+
<TableOfContents
|
|
112
|
+
autoDetect
|
|
113
|
+
headingSelector="h2"
|
|
114
|
+
variant="clerk"
|
|
115
|
+
enableScrollSpy
|
|
116
|
+
title="Contents"
|
|
117
|
+
scrollOffset={80}
|
|
118
|
+
/>
|
|
119
|
+
</aside>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export default function App() {
|
|
125
|
+
return (
|
|
126
|
+
<Layout>
|
|
127
|
+
<Routes>
|
|
128
|
+
<Route path="/" element={<HomePage />} />
|
|
129
|
+
<Route path="/inbox" element={<div className="p-6">Inbox – Coming soon</div>} />
|
|
130
|
+
<Route path="/files" element={<div className="p-6">Files – Coming soon</div>} />
|
|
131
|
+
<Route path="/settings" element={<div className="p-6">Settings – Coming soon</div>} />
|
|
132
|
+
</Routes>
|
|
133
|
+
</Layout>
|
|
134
|
+
);
|
|
135
|
+
}
|