@getcoherent/core 0.2.4 → 0.3.0
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/dist/index.d.ts +15 -3
- package/dist/index.js +131 -10
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3469,7 +3469,9 @@ declare class PageGenerator {
|
|
|
3469
3469
|
/**
|
|
3470
3470
|
* Generate layout code (for root layout)
|
|
3471
3471
|
*/
|
|
3472
|
-
generateLayout(layout: PageLayout, appType?: 'multi-page' | 'spa'
|
|
3472
|
+
generateLayout(layout: PageLayout, appType?: 'multi-page' | 'spa', options?: {
|
|
3473
|
+
skipNav?: boolean;
|
|
3474
|
+
}): Promise<string>;
|
|
3473
3475
|
/**
|
|
3474
3476
|
* Generate Next.js App Router root layout
|
|
3475
3477
|
*/
|
|
@@ -3479,6 +3481,15 @@ declare class PageGenerator {
|
|
|
3479
3481
|
* Documentation is part of Design System; also hide on legacy /docs for consistency.
|
|
3480
3482
|
*/
|
|
3481
3483
|
generateAppNav(): string;
|
|
3484
|
+
/**
|
|
3485
|
+
* Generate shared Header component code for components/shared/header.tsx.
|
|
3486
|
+
* Contains navigation items, theme toggle, and Design System FAB.
|
|
3487
|
+
*/
|
|
3488
|
+
generateSharedHeaderCode(): string;
|
|
3489
|
+
/**
|
|
3490
|
+
* Generate shared Footer component code for components/shared/footer.tsx.
|
|
3491
|
+
*/
|
|
3492
|
+
generateSharedFooterCode(): string;
|
|
3482
3493
|
/**
|
|
3483
3494
|
* Generate React SPA root layout
|
|
3484
3495
|
*/
|
|
@@ -3680,8 +3691,9 @@ declare class ProjectScaffolder {
|
|
|
3680
3691
|
*/
|
|
3681
3692
|
private generatePages;
|
|
3682
3693
|
/**
|
|
3683
|
-
* Generate root layout
|
|
3684
|
-
*
|
|
3694
|
+
* Generate root layout with shared Header/Footer components.
|
|
3695
|
+
* Creates layout.tsx (without inline nav), then registers shared Header and Footer
|
|
3696
|
+
* in the manifest and wires them into layout.tsx via integrateSharedLayoutIntoRootLayout.
|
|
3685
3697
|
*/
|
|
3686
3698
|
generateRootLayout(): Promise<void>;
|
|
3687
3699
|
private generateDefaultPages;
|
package/dist/index.js
CHANGED
|
@@ -5552,9 +5552,9 @@ ${sections}
|
|
|
5552
5552
|
/**
|
|
5553
5553
|
* Generate layout code (for root layout)
|
|
5554
5554
|
*/
|
|
5555
|
-
async generateLayout(layout, appType = "multi-page") {
|
|
5555
|
+
async generateLayout(layout, appType = "multi-page", options) {
|
|
5556
5556
|
if (appType === "multi-page") {
|
|
5557
|
-
return this.generateNextJSLayout(layout);
|
|
5557
|
+
return this.generateNextJSLayout(layout, options);
|
|
5558
5558
|
} else {
|
|
5559
5559
|
return this.generateReactSPALayout(layout);
|
|
5560
5560
|
}
|
|
@@ -5562,9 +5562,9 @@ ${sections}
|
|
|
5562
5562
|
/**
|
|
5563
5563
|
* Generate Next.js App Router root layout
|
|
5564
5564
|
*/
|
|
5565
|
-
generateNextJSLayout(_layout) {
|
|
5565
|
+
generateNextJSLayout(_layout, options) {
|
|
5566
5566
|
const cssVars = buildCssVariables(this.config);
|
|
5567
|
-
const navEnabled = this.config.navigation?.enabled;
|
|
5567
|
+
const navEnabled = this.config.navigation?.enabled && !options?.skipNav;
|
|
5568
5568
|
const navRendered = navEnabled ? "<AppNav />" : "";
|
|
5569
5569
|
const isDark = this.config.theme?.defaultMode === "dark";
|
|
5570
5570
|
const htmlClass = isDark ? ' className="dark"' : "";
|
|
@@ -5610,7 +5610,7 @@ export default function RootLayout({
|
|
|
5610
5610
|
</head>
|
|
5611
5611
|
<body className="min-h-screen flex flex-col bg-background text-foreground antialiased">
|
|
5612
5612
|
${navEnabled ? ` ${navRendered}
|
|
5613
|
-
` : ""}<div className="flex-1 flex flex-col">{children}</div>
|
|
5613
|
+
` : ""} <div className="flex-1 flex flex-col">{children}</div>
|
|
5614
5614
|
</body>
|
|
5615
5615
|
</html>
|
|
5616
5616
|
)
|
|
@@ -5737,6 +5737,111 @@ export function AppNav() {
|
|
|
5737
5737
|
</Fragment>
|
|
5738
5738
|
)
|
|
5739
5739
|
}
|
|
5740
|
+
`;
|
|
5741
|
+
}
|
|
5742
|
+
/**
|
|
5743
|
+
* Generate shared Header component code for components/shared/header.tsx.
|
|
5744
|
+
* Contains navigation items, theme toggle, and Design System FAB.
|
|
5745
|
+
*/
|
|
5746
|
+
generateSharedHeaderCode() {
|
|
5747
|
+
const navItems = this.config.navigation?.items || [];
|
|
5748
|
+
const authRoutes = /* @__PURE__ */ new Set([
|
|
5749
|
+
"/login",
|
|
5750
|
+
"/signin",
|
|
5751
|
+
"/sign-in",
|
|
5752
|
+
"/signup",
|
|
5753
|
+
"/sign-up",
|
|
5754
|
+
"/register",
|
|
5755
|
+
"/forgot-password",
|
|
5756
|
+
"/reset-password"
|
|
5757
|
+
]);
|
|
5758
|
+
const visibleItems = navItems.filter((item) => !authRoutes.has(item.route) && !item.route.includes("["));
|
|
5759
|
+
const hasMultipleItems = visibleItems.length > 1;
|
|
5760
|
+
const items = visibleItems.map(
|
|
5761
|
+
(item) => `<Link href="${item.route}" className={\`text-sm font-medium px-3 py-2 rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring \${pathname === "${item.route}" ? 'bg-muted text-foreground' : 'text-muted-foreground hover:text-foreground hover:bg-muted/50'}\`}>${item.label}</Link>`
|
|
5762
|
+
).join("\n ");
|
|
5763
|
+
const navItemsBlock = hasMultipleItems ? `
|
|
5764
|
+
${items}
|
|
5765
|
+
` : "";
|
|
5766
|
+
const appName = this.escapeString(this.config.name);
|
|
5767
|
+
return `'use client'
|
|
5768
|
+
|
|
5769
|
+
import Link from 'next/link'
|
|
5770
|
+
import { usePathname } from 'next/navigation'
|
|
5771
|
+
import { useEffect, useState } from 'react'
|
|
5772
|
+
|
|
5773
|
+
function ThemeToggle() {
|
|
5774
|
+
const [dark, setDark] = useState(false)
|
|
5775
|
+
useEffect(() => {
|
|
5776
|
+
setDark(document.documentElement.classList.contains('dark'))
|
|
5777
|
+
}, [])
|
|
5778
|
+
const toggle = () => {
|
|
5779
|
+
const next = !dark
|
|
5780
|
+
setDark(next)
|
|
5781
|
+
document.documentElement.classList.toggle('dark', next)
|
|
5782
|
+
}
|
|
5783
|
+
return (
|
|
5784
|
+
<button
|
|
5785
|
+
onClick={toggle}
|
|
5786
|
+
className="flex items-center justify-center w-9 h-9 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
|
|
5787
|
+
title={dark ? 'Switch to light theme' : 'Switch to dark theme'}
|
|
5788
|
+
aria-label="Toggle theme"
|
|
5789
|
+
>
|
|
5790
|
+
{dark ? (
|
|
5791
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>
|
|
5792
|
+
) : (
|
|
5793
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></svg>
|
|
5794
|
+
)}
|
|
5795
|
+
</button>
|
|
5796
|
+
)
|
|
5797
|
+
}
|
|
5798
|
+
|
|
5799
|
+
export function Header() {
|
|
5800
|
+
const pathname = usePathname()
|
|
5801
|
+
return (
|
|
5802
|
+
<>
|
|
5803
|
+
<nav className="sticky top-0 z-50 shrink-0 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
5804
|
+
<div className="mx-auto flex h-14 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8">
|
|
5805
|
+
<div className="flex items-center gap-6">
|
|
5806
|
+
<Link href="/" className="flex items-center gap-2 text-sm font-semibold text-foreground hover:text-foreground/90 transition-colors shrink-0">
|
|
5807
|
+
${appName}
|
|
5808
|
+
</Link>
|
|
5809
|
+
<div className="flex items-center gap-1">${navItemsBlock}</div>
|
|
5810
|
+
</div>
|
|
5811
|
+
<div className="flex items-center gap-1">
|
|
5812
|
+
<ThemeToggle />
|
|
5813
|
+
</div>
|
|
5814
|
+
</div>
|
|
5815
|
+
</nav>
|
|
5816
|
+
<Link
|
|
5817
|
+
href="/design-system"
|
|
5818
|
+
className="fixed bottom-4 right-4 z-50 flex items-center gap-2 rounded-full border border-white/20 bg-black/60 backdrop-blur-md text-white px-4 py-2 text-xs shadow-sm hover:bg-black/80 transition-all"
|
|
5819
|
+
title="Design System"
|
|
5820
|
+
>
|
|
5821
|
+
Design System
|
|
5822
|
+
</Link>
|
|
5823
|
+
</>
|
|
5824
|
+
)
|
|
5825
|
+
}
|
|
5826
|
+
`;
|
|
5827
|
+
}
|
|
5828
|
+
/**
|
|
5829
|
+
* Generate shared Footer component code for components/shared/footer.tsx.
|
|
5830
|
+
*/
|
|
5831
|
+
generateSharedFooterCode() {
|
|
5832
|
+
const appName = this.escapeString(this.config.name);
|
|
5833
|
+
return `'use client'
|
|
5834
|
+
|
|
5835
|
+
export function Footer() {
|
|
5836
|
+
return (
|
|
5837
|
+
<footer className="border-t">
|
|
5838
|
+
<div className="mx-auto flex h-14 max-w-7xl items-center justify-between px-4 text-sm text-muted-foreground sm:px-6 lg:px-8">
|
|
5839
|
+
<p>\\u00A9 {new Date().getFullYear()} ${appName}</p>
|
|
5840
|
+
<p className="hidden sm:block">Built with Coherent Design Method</p>
|
|
5841
|
+
</div>
|
|
5842
|
+
</footer>
|
|
5843
|
+
)
|
|
5844
|
+
}
|
|
5740
5845
|
`;
|
|
5741
5846
|
}
|
|
5742
5847
|
/**
|
|
@@ -6552,17 +6657,33 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
6552
6657
|
}
|
|
6553
6658
|
}
|
|
6554
6659
|
/**
|
|
6555
|
-
* Generate root layout
|
|
6556
|
-
*
|
|
6660
|
+
* Generate root layout with shared Header/Footer components.
|
|
6661
|
+
* Creates layout.tsx (without inline nav), then registers shared Header and Footer
|
|
6662
|
+
* in the manifest and wires them into layout.tsx via integrateSharedLayoutIntoRootLayout.
|
|
6557
6663
|
*/
|
|
6558
6664
|
async generateRootLayout() {
|
|
6559
6665
|
const appType = this.config.settings.appType || "multi-page";
|
|
6560
6666
|
const layout = this.config.pages[0]?.layout || "centered";
|
|
6561
|
-
const code = await this.pageGenerator.generateLayout(layout, appType);
|
|
6667
|
+
const code = await this.pageGenerator.generateLayout(layout, appType, { skipNav: true });
|
|
6562
6668
|
await this.writeFile("app/layout.tsx", code);
|
|
6563
6669
|
if (this.config.navigation?.enabled && appType === "multi-page") {
|
|
6564
|
-
const
|
|
6565
|
-
await this.
|
|
6670
|
+
const headerCode = this.pageGenerator.generateSharedHeaderCode();
|
|
6671
|
+
await generateSharedComponent(this.projectRoot, {
|
|
6672
|
+
name: "Header",
|
|
6673
|
+
type: "layout",
|
|
6674
|
+
code: headerCode,
|
|
6675
|
+
description: "Main site header with navigation and theme toggle",
|
|
6676
|
+
usedIn: ["app/layout.tsx"]
|
|
6677
|
+
});
|
|
6678
|
+
const footerCode = this.pageGenerator.generateSharedFooterCode();
|
|
6679
|
+
await generateSharedComponent(this.projectRoot, {
|
|
6680
|
+
name: "Footer",
|
|
6681
|
+
type: "layout",
|
|
6682
|
+
code: footerCode,
|
|
6683
|
+
description: "Site footer",
|
|
6684
|
+
usedIn: ["app/layout.tsx"]
|
|
6685
|
+
});
|
|
6686
|
+
await integrateSharedLayoutIntoRootLayout(this.projectRoot);
|
|
6566
6687
|
}
|
|
6567
6688
|
}
|
|
6568
6689
|
async generateDefaultPages() {
|