@nqlib/nqui 0.4.3 → 0.4.5
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 +234 -0
- package/README.md +109 -151
- package/dist/button-CJHdCq9I.js +155 -0
- package/dist/button-R304rhsj.cjs +1 -0
- package/dist/calendar.cjs.js +1 -1
- package/dist/calendar.es.js +1 -1
- package/dist/carousel-D1FMVglR.cjs +1 -0
- package/dist/carousel-U7RZhYZj.js +179 -0
- package/dist/carousel.cjs.js +1 -1
- package/dist/carousel.es.js +1 -1
- package/dist/command-palette-DCtLpM3Q.js +694 -0
- package/dist/command-palette-MHc03bBf.cjs +5 -0
- package/dist/command.cjs.js +1 -1
- package/dist/command.es.js +1 -1
- package/dist/components/custom/color-picker.d.ts +1 -1
- package/dist/components/custom/color-picker.d.ts.map +1 -1
- package/dist/components/custom/color-slider.d.ts +4 -10
- package/dist/components/custom/color-slider.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-tabs.d.ts.map +1 -1
- package/dist/components/debug/debug-features.d.ts +29 -0
- package/dist/components/debug/debug-features.d.ts.map +1 -0
- package/dist/components/debug/debug-panel.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 +103 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/ui/badge.d.ts +16 -5
- package/dist/components/ui/badge.d.ts.map +1 -1
- package/dist/components/ui/button.d.ts +38 -4
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/checkbox.d.ts +16 -2
- package/dist/components/ui/checkbox.d.ts.map +1 -1
- package/dist/components/ui/combobox.d.ts +2 -1
- package/dist/components/ui/combobox.d.ts.map +1 -1
- package/dist/components/ui/frosted-glass.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/pagination.d.ts +3 -2
- package/dist/components/ui/pagination.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/select.d.ts +6 -1
- package/dist/components/ui/select.d.ts.map +1 -1
- package/dist/components/ui/sidebar.d.ts +1 -1
- package/dist/components/ui/sidebar.d.ts.map +1 -1
- package/dist/components/ui/slider.d.ts +10 -2
- package/dist/components/ui/slider.d.ts.map +1 -1
- package/dist/components/ui/sonner.d.ts +18 -2
- package/dist/components/ui/sonner.d.ts.map +1 -1
- package/dist/components/ui/spinner.d.ts +2 -1
- package/dist/components/ui/spinner.d.ts.map +1 -1
- package/dist/components/ui/switch.d.ts +15 -2
- package/dist/components/ui/switch.d.ts.map +1 -1
- package/dist/components/ui/tabs.d.ts +1 -1
- package/dist/components/ui/tabs.d.ts.map +1 -1
- package/dist/components/ui/toggle.d.ts +1 -1
- package/dist/components/ui/toggle.d.ts.map +1 -1
- package/dist/debug-panel-CNKk-No5.cjs +75 -0
- package/dist/debug-panel-pg39-6xw.js +9011 -0
- package/dist/debug.cjs.js +1 -0
- package/dist/debug.es.js +7 -0
- package/dist/{drawer-CU4lkcz7.js → drawer-DO26uhym.js} +31 -31
- package/dist/drawer-DVarEy65.cjs +1 -0
- package/dist/drawer.cjs.js +1 -1
- package/dist/drawer.es.js +1 -1
- package/dist/{enhanced-calendar-BENbxw7_.js → enhanced-calendar-BGlsSYJd.js} +1 -1
- package/dist/{enhanced-calendar-5PA8CeF7.cjs → enhanced-calendar-C7EQIr6i.cjs} +1 -1
- package/dist/entries/debug.d.ts +14 -0
- package/dist/entries/debug.d.ts.map +1 -0
- package/dist/entries/sonner.d.ts +1 -2
- package/dist/entries/sonner.d.ts.map +1 -1
- 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/lib/wrap-inline-label-text.d.ts +7 -0
- package/dist/lib/wrap-inline-label-text.d.ts.map +1 -0
- package/dist/nqui.cjs.js +49 -245
- package/dist/nqui.es.js +7402 -16735
- package/dist/sonner-CpmECDBk.js +179 -0
- package/dist/sonner-nE9hIalJ.cjs +48 -0
- package/dist/sonner.cjs.js +1 -1
- package/dist/sonner.es.js +3 -2
- package/dist/styles.css +237 -10
- package/docs/components/README.md +109 -10
- package/docs/components/nqui-badge.md +1 -0
- package/docs/components/nqui-button.md +3 -1
- package/docs/components/nqui-card.md +8 -0
- package/docs/components/nqui-carousel.md +6 -0
- package/docs/components/nqui-checkbox.md +38 -1
- package/docs/components/nqui-color-slider.md +5 -3
- package/docs/components/nqui-combobox.md +58 -37
- package/docs/components/nqui-drawer.md +1 -1
- package/docs/components/nqui-frosted-glass.md +83 -5
- package/docs/components/nqui-radio-group.md +47 -2
- package/docs/components/nqui-scroll-area.md +1 -1
- package/docs/components/nqui-select.md +2 -2
- package/docs/components/nqui-sheet.md +1 -1
- package/docs/components/nqui-slider.md +13 -0
- package/docs/components/nqui-spinner.md +6 -1
- package/docs/components/nqui-switch.md +23 -1
- package/docs/components/nqui-tabs.md +11 -1
- package/docs/components/nqui-toaster.md +5 -1
- package/docs/internal-notes/PUBLISHING.md +46 -4
- package/docs/nqui-skills/SKILL.md +106 -0
- package/docs/nqui-skills/design-system.md +143 -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 -12
- package/scripts/build-styles.js +16 -0
- 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/init-debug-css.js +4 -2
- package/scripts/post-install.js +41 -9
- package/scripts/publish-npmjs.js +17 -3
- package/scripts/resolve-target-dir.js +20 -1
- package/scripts/setup-helper.js +13 -1
- package/scripts/verify-build.js +1 -1
- package/scripts/wizard.js +12 -7
- package/dist/button-CYFTFDKe.cjs +0 -1
- package/dist/button-nJvDl3w8.js +0 -44
- package/dist/carousel-DEyyJi49.js +0 -179
- package/dist/carousel-Dhhz8m5V.cjs +0 -1
- package/dist/command-palette-UHk8zZOg.cjs +0 -45
- package/dist/command-palette-d-TrdBsM.js +0 -1778
- package/dist/components/custom/enhanced-badge.d.ts +0 -33
- package/dist/components/custom/enhanced-badge.d.ts.map +0 -1
- package/dist/components/custom/enhanced-button.d.ts +0 -34
- package/dist/components/custom/enhanced-button.d.ts.map +0 -1
- package/dist/components/custom/enhanced-checkbox.d.ts +0 -28
- package/dist/components/custom/enhanced-checkbox.d.ts.map +0 -1
- package/dist/components/custom/enhanced-combobox.d.ts +0 -35
- package/dist/components/custom/enhanced-combobox.d.ts.map +0 -1
- package/dist/components/custom/enhanced-select.d.ts +0 -30
- package/dist/components/custom/enhanced-select.d.ts.map +0 -1
- package/dist/components/custom/enhanced-sonner.d.ts +0 -16
- package/dist/components/custom/enhanced-sonner.d.ts.map +0 -1
- package/dist/drawer-BcIxWRN8.cjs +0 -1
- package/dist/sonner-Co6YpYVs.js +0 -546
- package/dist/sonner-DbQhVp8m.cjs +0 -330
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { StrictMode } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import { ThemeProvider } from "next-themes";
|
|
4
|
+
import { BrowserRouter } from "react-router-dom";
|
|
5
|
+
import "./index.css";
|
|
6
|
+
import App from "./App";
|
|
7
|
+
// Required dependencies: npm install @nqlib/nqui tw-animate-css next-themes hugeicons-core-free-icons hugeicons-react react-router-dom
|
|
8
|
+
|
|
9
|
+
createRoot(document.getElementById("root")!).render(
|
|
10
|
+
<StrictMode>
|
|
11
|
+
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
|
|
12
|
+
<BrowserRouter>
|
|
13
|
+
<App />
|
|
14
|
+
</BrowserRouter>
|
|
15
|
+
</ThemeProvider>
|
|
16
|
+
</StrictMode>
|
|
17
|
+
);
|
package/scripts/examples.js
CHANGED
|
@@ -7,7 +7,7 @@ import { askQuestion } from './wizard.js';
|
|
|
7
7
|
/**
|
|
8
8
|
* Copy Next.js example files to user's project
|
|
9
9
|
*/
|
|
10
|
-
export async function copyNextJsExamples(framework, { force }) {
|
|
10
|
+
export async function copyNextJsExamples(framework, { force, sidebar }) {
|
|
11
11
|
if (framework !== 'nextjs') {
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
@@ -21,9 +21,95 @@ export async function copyNextJsExamples(framework, { force }) {
|
|
|
21
21
|
? join(cwd, 'src', 'app')
|
|
22
22
|
: join(cwd, 'app');
|
|
23
23
|
|
|
24
|
+
// Choose examples based on sidebar flag
|
|
25
|
+
const examples = sidebar
|
|
26
|
+
? [
|
|
27
|
+
{ src: 'nextjs-page-sidebar.tsx', dest: join(appDir, 'page.tsx'), name: 'page.tsx' },
|
|
28
|
+
{ src: 'nextjs-layout-sidebar.tsx', dest: join(appDir, 'layout.tsx'), name: 'layout.tsx' },
|
|
29
|
+
]
|
|
30
|
+
: [
|
|
31
|
+
{ src: 'nextjs-page.tsx', dest: join(appDir, 'page.tsx'), name: 'page.tsx' },
|
|
32
|
+
{ src: 'nextjs-layout.tsx', dest: join(appDir, 'layout.tsx'), name: 'layout.tsx' },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const copied = [];
|
|
36
|
+
const existing = [];
|
|
37
|
+
|
|
38
|
+
// Check which files exist
|
|
39
|
+
for (const { dest, name } of examples) {
|
|
40
|
+
if (existsSync(dest)) {
|
|
41
|
+
existing.push({ dest, name });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Ask about overwriting if files exist and force is not set
|
|
46
|
+
let shouldOverwrite = force;
|
|
47
|
+
if (existing.length > 0 && !force) {
|
|
48
|
+
const fileList = existing.map(e => e.name).join(' and ');
|
|
49
|
+
const answer = await askQuestion(
|
|
50
|
+
`\n⚠️ ${fileList} already exist(s). Overwrite? (y/n): `
|
|
51
|
+
);
|
|
52
|
+
shouldOverwrite = answer === 'y';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (const { src, dest, name } of examples) {
|
|
56
|
+
const srcPath = join(examplesDir, src);
|
|
57
|
+
|
|
58
|
+
if (!existsSync(srcPath)) {
|
|
59
|
+
console.warn(`⚠️ Example file not found: ${srcPath}`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (existsSync(dest) && !shouldOverwrite) {
|
|
64
|
+
console.log(`⏭️ Skipped: ${dest} (already exists)`);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const content = readFileSync(srcPath, 'utf8');
|
|
69
|
+
writeFileSync(dest, content, 'utf8');
|
|
70
|
+
copied.push(dest);
|
|
71
|
+
console.log(`✅ ${existsSync(dest) && shouldOverwrite ? 'Overwritten' : 'Created'}: ${dest}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (copied.length > 0) {
|
|
75
|
+
const deps = sidebar
|
|
76
|
+
? 'npm install @nqlib/nqui @hugeicons/react @hugeicons/core-free-icons tw-animate-css next-themes react-router-dom'
|
|
77
|
+
: 'npm install @nqlib/nqui tw-animate-css next-themes';
|
|
78
|
+
console.log(`\n📝 Required dependencies for example files:`);
|
|
79
|
+
console.log(` ${deps}\n`);
|
|
80
|
+
if (sidebar) {
|
|
81
|
+
console.log(` Note: 3-column layout uses Sidebar, TableOfContents; main.tsx includes ThemeProvider + BrowserRouter for Vite.\n`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return copied;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Copy Vite example files to user's project
|
|
90
|
+
*/
|
|
91
|
+
export async function copyViteExamples(framework, { force, sidebar }) {
|
|
92
|
+
if (framework !== 'vite') {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const root = getPackageRoot();
|
|
97
|
+
const examplesDir = join(root, 'scripts', 'examples');
|
|
98
|
+
const cwd = process.cwd();
|
|
99
|
+
|
|
100
|
+
// Determine src directory
|
|
101
|
+
const srcDir = existsSync(join(cwd, 'src')) ? join(cwd, 'src') : join(cwd, 'src');
|
|
102
|
+
|
|
103
|
+
// Ensure src directory exists
|
|
104
|
+
if (!existsSync(srcDir)) {
|
|
105
|
+
console.warn('⚠️ src directory not found');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Choose examples based on sidebar flag (3-column with TOC when sidebar; same files + main for ThemeProvider)
|
|
24
110
|
const examples = [
|
|
25
|
-
{ src: '
|
|
26
|
-
{ src: '
|
|
111
|
+
{ src: 'vite-app.tsx', dest: join(srcDir, 'App.tsx'), name: 'App.tsx' },
|
|
112
|
+
{ src: 'vite-main.tsx', dest: join(srcDir, 'main.tsx'), name: 'main.tsx' },
|
|
27
113
|
];
|
|
28
114
|
|
|
29
115
|
const copied = [];
|
|
@@ -66,11 +152,11 @@ export async function copyNextJsExamples(framework, { force }) {
|
|
|
66
152
|
}
|
|
67
153
|
|
|
68
154
|
if (copied.length > 0) {
|
|
155
|
+
const deps = 'npm install @nqlib/nqui tw-animate-css next-themes @hugeicons/react @hugeicons/core-free-icons react-router-dom';
|
|
69
156
|
console.log(`\n📝 Required dependencies for example files:`);
|
|
70
|
-
console.log(`
|
|
71
|
-
console.log(`
|
|
157
|
+
console.log(` ${deps}`);
|
|
158
|
+
console.log(` Note: For Vite, wrap your app with ThemeProvider and BrowserRouter in main.tsx\n`);
|
|
72
159
|
}
|
|
73
160
|
|
|
74
161
|
return copied;
|
|
75
162
|
}
|
|
76
|
-
|