@getcoherent/core 0.5.12 → 0.5.14

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Sergei Kovtun
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.d.ts CHANGED
@@ -903,10 +903,7 @@ declare const LayoutBlockDefinitionSchema: z.ZodObject<{
903
903
  generatedCode?: string | undefined;
904
904
  }>;
905
905
  type LayoutBlockDefinition = z.infer<typeof LayoutBlockDefinitionSchema>;
906
- /**
907
- * Page layout type
908
- */
909
- declare const PageLayoutSchema: z.ZodEnum<["centered", "sidebar-left", "sidebar-right", "full-width", "grid"]>;
906
+ declare const PageLayoutSchema: z.ZodEffects<z.ZodEnum<["centered", "sidebar-left", "sidebar-right", "full-width", "grid"]>, "centered" | "sidebar-left" | "sidebar-right" | "full-width" | "grid", unknown>;
910
907
  type PageLayout = z.infer<typeof PageLayoutSchema>;
911
908
  /**
912
909
  * Page definition
@@ -956,7 +953,7 @@ declare const PageDefinitionSchema: z.ZodObject<{
956
953
  id: z.ZodPipeline<z.ZodEffects<z.ZodString, string, string>, z.ZodString>;
957
954
  name: z.ZodString;
958
955
  route: z.ZodPipeline<z.ZodEffects<z.ZodString, string, string>, z.ZodString>;
959
- layout: z.ZodEnum<["centered", "sidebar-left", "sidebar-right", "full-width", "grid"]>;
956
+ layout: z.ZodEffects<z.ZodEnum<["centered", "sidebar-left", "sidebar-right", "full-width", "grid"]>, "centered" | "sidebar-left" | "sidebar-right" | "full-width" | "grid", unknown>;
960
957
  sections: z.ZodDefault<z.ZodArray<z.ZodObject<{
961
958
  id: z.ZodString;
962
959
  name: z.ZodString;
@@ -1062,11 +1059,11 @@ declare const PageDefinitionSchema: z.ZodObject<{
1062
1059
  name: string;
1063
1060
  description: string;
1064
1061
  id: string;
1065
- layout: "centered" | "sidebar-left" | "sidebar-right" | "full-width" | "grid";
1066
1062
  createdAt: string;
1067
1063
  updatedAt: string;
1068
1064
  route: string;
1069
1065
  title: string;
1066
+ layout?: unknown;
1070
1067
  sections?: {
1071
1068
  name: string;
1072
1069
  id: string;
@@ -1882,7 +1879,7 @@ declare const DesignSystemConfigSchema: z.ZodObject<{
1882
1879
  id: z.ZodPipeline<z.ZodEffects<z.ZodString, string, string>, z.ZodString>;
1883
1880
  name: z.ZodString;
1884
1881
  route: z.ZodPipeline<z.ZodEffects<z.ZodString, string, string>, z.ZodString>;
1885
- layout: z.ZodEnum<["centered", "sidebar-left", "sidebar-right", "full-width", "grid"]>;
1882
+ layout: z.ZodEffects<z.ZodEnum<["centered", "sidebar-left", "sidebar-right", "full-width", "grid"]>, "centered" | "sidebar-left" | "sidebar-right" | "full-width" | "grid", unknown>;
1886
1883
  sections: z.ZodDefault<z.ZodArray<z.ZodObject<{
1887
1884
  id: z.ZodString;
1888
1885
  name: z.ZodString;
@@ -1988,11 +1985,11 @@ declare const DesignSystemConfigSchema: z.ZodObject<{
1988
1985
  name: string;
1989
1986
  description: string;
1990
1987
  id: string;
1991
- layout: "centered" | "sidebar-left" | "sidebar-right" | "full-width" | "grid";
1992
1988
  createdAt: string;
1993
1989
  updatedAt: string;
1994
1990
  route: string;
1995
1991
  title: string;
1992
+ layout?: unknown;
1996
1993
  sections?: {
1997
1994
  name: string;
1998
1995
  id: string;
@@ -2497,11 +2494,11 @@ declare const DesignSystemConfigSchema: z.ZodObject<{
2497
2494
  name: string;
2498
2495
  description: string;
2499
2496
  id: string;
2500
- layout: "centered" | "sidebar-left" | "sidebar-right" | "full-width" | "grid";
2501
2497
  createdAt: string;
2502
2498
  updatedAt: string;
2503
2499
  route: string;
2504
2500
  title: string;
2501
+ layout?: unknown;
2505
2502
  sections?: {
2506
2503
  name: string;
2507
2504
  id: string;
@@ -2718,7 +2715,9 @@ interface ComponentProvider {
2718
2715
  id: string;
2719
2716
  init(projectRoot: string): Promise<void>;
2720
2717
  install(name: string, projectRoot: string): Promise<void>;
2718
+ has(name: string): boolean;
2721
2719
  list(): ComponentMeta[];
2720
+ listNames(): string[];
2722
2721
  getComponentAPI(name: string): ComponentAPI | null;
2723
2722
  getCssVariables(tokens: DesignTokens): string;
2724
2723
  getThemeBlock(tokens: DesignTokens): string;
@@ -2747,6 +2746,8 @@ declare const SharedComponentEntrySchema: z.ZodObject<{
2747
2746
  createdAt: z.ZodOptional<z.ZodString>;
2748
2747
  /** Human-readable description */
2749
2748
  description: z.ZodOptional<z.ZodString>;
2749
+ /** TypeScript props interface body, e.g. "{ icon: React.ReactNode; title: string }" */
2750
+ propsInterface: z.ZodOptional<z.ZodString>;
2750
2751
  }, "strip", z.ZodTypeAny, {
2751
2752
  type: "layout" | "section" | "widget";
2752
2753
  name: string;
@@ -2755,6 +2756,7 @@ declare const SharedComponentEntrySchema: z.ZodObject<{
2755
2756
  usedIn: string[];
2756
2757
  description?: string | undefined;
2757
2758
  createdAt?: string | undefined;
2759
+ propsInterface?: string | undefined;
2758
2760
  }, {
2759
2761
  type: "layout" | "section" | "widget";
2760
2762
  name: string;
@@ -2763,6 +2765,7 @@ declare const SharedComponentEntrySchema: z.ZodObject<{
2763
2765
  description?: string | undefined;
2764
2766
  createdAt?: string | undefined;
2765
2767
  usedIn?: string[] | undefined;
2768
+ propsInterface?: string | undefined;
2766
2769
  }>;
2767
2770
  type SharedComponentEntry = z.infer<typeof SharedComponentEntrySchema>;
2768
2771
  /** Root schema for coherent.components.json */
@@ -2781,6 +2784,8 @@ declare const SharedComponentsManifestSchema: z.ZodObject<{
2781
2784
  createdAt: z.ZodOptional<z.ZodString>;
2782
2785
  /** Human-readable description */
2783
2786
  description: z.ZodOptional<z.ZodString>;
2787
+ /** TypeScript props interface body, e.g. "{ icon: React.ReactNode; title: string }" */
2788
+ propsInterface: z.ZodOptional<z.ZodString>;
2784
2789
  }, "strip", z.ZodTypeAny, {
2785
2790
  type: "layout" | "section" | "widget";
2786
2791
  name: string;
@@ -2789,6 +2794,7 @@ declare const SharedComponentsManifestSchema: z.ZodObject<{
2789
2794
  usedIn: string[];
2790
2795
  description?: string | undefined;
2791
2796
  createdAt?: string | undefined;
2797
+ propsInterface?: string | undefined;
2792
2798
  }, {
2793
2799
  type: "layout" | "section" | "widget";
2794
2800
  name: string;
@@ -2797,6 +2803,7 @@ declare const SharedComponentsManifestSchema: z.ZodObject<{
2797
2803
  description?: string | undefined;
2798
2804
  createdAt?: string | undefined;
2799
2805
  usedIn?: string[] | undefined;
2806
+ propsInterface?: string | undefined;
2800
2807
  }>, "many">>;
2801
2808
  /** Next numeric id for new entries (CID-XXX → nextId = 4 for CID-004) */
2802
2809
  nextId: z.ZodDefault<z.ZodNumber>;
@@ -2809,6 +2816,7 @@ declare const SharedComponentsManifestSchema: z.ZodObject<{
2809
2816
  usedIn: string[];
2810
2817
  description?: string | undefined;
2811
2818
  createdAt?: string | undefined;
2819
+ propsInterface?: string | undefined;
2812
2820
  }[];
2813
2821
  nextId: number;
2814
2822
  }, {
@@ -2820,6 +2828,7 @@ declare const SharedComponentsManifestSchema: z.ZodObject<{
2820
2828
  description?: string | undefined;
2821
2829
  createdAt?: string | undefined;
2822
2830
  usedIn?: string[] | undefined;
2831
+ propsInterface?: string | undefined;
2823
2832
  }[] | undefined;
2824
2833
  nextId?: number | undefined;
2825
2834
  }>;
@@ -3131,6 +3140,7 @@ interface CreateSharedComponentInput {
3131
3140
  file: string;
3132
3141
  usedIn?: string[];
3133
3142
  description?: string;
3143
+ propsInterface?: string;
3134
3144
  }
3135
3145
  /**
3136
3146
  * Add a new shared component: allocate CID, set createdAt, append to shared, increment nextId.
@@ -3445,7 +3455,7 @@ declare class PageGenerator {
3445
3455
  */
3446
3456
  generateSharedFooterCode(): string;
3447
3457
  /**
3448
- * Generate shared Sidebar component code for components/shared/sidebar.tsx.
3458
+ * Generate shared Sidebar component code using shadcn/ui Sidebar.
3449
3459
  * Used when navigation.type is 'sidebar' or 'both'.
3450
3460
  */
3451
3461
  generateSharedSidebarCode(): string;
@@ -3540,6 +3550,8 @@ interface GenerateSharedComponentInput {
3540
3550
  usedIn?: string[];
3541
3551
  /** If true, overwrite an existing component with the same name instead of creating a uniquely-named copy. */
3542
3552
  overwrite?: boolean;
3553
+ /** TypeScript props interface body, e.g. "{ title: string; icon: React.ReactNode }". */
3554
+ propsInterface?: string;
3543
3555
  }
3544
3556
  interface GenerateSharedComponentResult {
3545
3557
  id: string;
package/dist/index.js CHANGED
@@ -146,7 +146,7 @@ var LayoutBlockDefinitionSchema = z.object({
146
146
  createdAt: z.string().datetime().optional(),
147
147
  updatedAt: z.string().datetime().optional()
148
148
  });
149
- var PageLayoutSchema = z.enum([
149
+ var PAGE_LAYOUT_ENUM = z.enum([
150
150
  "centered",
151
151
  // Single centered column
152
152
  "sidebar-left",
@@ -158,6 +158,10 @@ var PageLayoutSchema = z.enum([
158
158
  "grid"
159
159
  // CSS Grid layout
160
160
  ]);
161
+ var PageLayoutSchema = z.preprocess((val) => {
162
+ if (val === "sidebar") return "sidebar-left";
163
+ return val;
164
+ }, PAGE_LAYOUT_ENUM);
161
165
  var PageAnalysisSchema = z.object({
162
166
  sections: z.array(
163
167
  z.object({
@@ -460,7 +464,9 @@ var SharedComponentEntrySchema = z2.object({
460
464
  usedIn: z2.array(z2.string()).default([]),
461
465
  createdAt: z2.string().datetime().optional(),
462
466
  /** Human-readable description */
463
- description: z2.string().optional()
467
+ description: z2.string().optional(),
468
+ /** TypeScript props interface body, e.g. "{ icon: React.ReactNode; title: string }" */
469
+ propsInterface: z2.string().optional()
464
470
  });
465
471
  var SharedComponentsManifestSchema = z2.object({
466
472
  shared: z2.array(SharedComponentEntrySchema).default([]),
@@ -1237,6 +1243,43 @@ function blendColors(hex1, hex2, ratio) {
1237
1243
  const toHex = (n) => n.toString(16).padStart(2, "0");
1238
1244
  return `#${toHex(blend(r1, r2))}${toHex(blend(g1, g2))}${toHex(blend(b1, b2))}`;
1239
1245
  }
1246
+ function hexToHsl(hex) {
1247
+ const c = hex.replace("#", "");
1248
+ const r = parseInt(c.slice(0, 2), 16) / 255;
1249
+ const g = parseInt(c.slice(2, 4), 16) / 255;
1250
+ const b = parseInt(c.slice(4, 6), 16) / 255;
1251
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
1252
+ const l = (max + min) / 2;
1253
+ if (max === min) return [0, 0, l];
1254
+ const d = max - min;
1255
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1256
+ let h = 0;
1257
+ if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
1258
+ else if (max === g) h = ((b - r) / d + 2) / 6;
1259
+ else h = ((r - g) / d + 4) / 6;
1260
+ return [h * 360, s, l];
1261
+ }
1262
+ function hslToHex(h, s, l) {
1263
+ h = (h % 360 + 360) % 360;
1264
+ const a = s * Math.min(l, 1 - l);
1265
+ const f = (n) => {
1266
+ const k = (n + h / 30) % 12;
1267
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
1268
+ return Math.round(255 * Math.max(0, Math.min(1, color))).toString(16).padStart(2, "0");
1269
+ };
1270
+ return `#${f(0)}${f(8)}${f(4)}`;
1271
+ }
1272
+ function generateChartColors(primary, secondary) {
1273
+ const [h1, s1, l1] = hexToHsl(primary);
1274
+ const [h2, s2, l2] = hexToHsl(secondary);
1275
+ return [
1276
+ primary,
1277
+ secondary,
1278
+ hslToHex(h1 + 60, s1 * 0.8, l1),
1279
+ hslToHex(h2 + 90, s2 * 0.7, l2),
1280
+ hslToHex(h1 + 180, s1 * 0.6, l1)
1281
+ ];
1282
+ }
1240
1283
  function buildCssVariables(config) {
1241
1284
  const light = config.tokens.colors.light;
1242
1285
  const dark = config.tokens.colors.dark;
@@ -1246,7 +1289,31 @@ function buildCssVariables(config) {
1246
1289
  const accentDarkVars = ` --accent: ${dark.muted};
1247
1290
  --accent-foreground: ${dark.foreground};
1248
1291
  `;
1292
+ const sidebarLightVars = ` --sidebar-background: ${light.background};
1293
+ --sidebar-foreground: ${light.foreground};
1294
+ --sidebar-primary: ${light.primary};
1295
+ --sidebar-primary-foreground: ${contrastFg(light.primary)};
1296
+ --sidebar-accent: ${light.muted};
1297
+ --sidebar-accent-foreground: ${light.foreground};
1298
+ --sidebar-border: ${light.border};
1299
+ --sidebar-ring: ${light.primary};
1300
+ `;
1301
+ const chartLight = generateChartColors(light.primary, light.secondary);
1302
+ const chartDark = generateChartColors(dark.primary, dark.secondary);
1303
+ const chartLightVars = chartLight.map((c, i) => ` --chart-${i + 1}: ${c};`).join("\n") + "\n";
1304
+ const chartDarkVars = chartDark.map((c, i) => ` --chart-${i + 1}: ${c};`).join("\n") + "\n";
1305
+ const sidebarDarkVars = ` --sidebar-background: ${dark.background};
1306
+ --sidebar-foreground: ${dark.foreground};
1307
+ --sidebar-primary: ${dark.primary};
1308
+ --sidebar-primary-foreground: ${contrastFg(dark.primary)};
1309
+ --sidebar-accent: ${dark.muted};
1310
+ --sidebar-accent-foreground: ${dark.foreground};
1311
+ --sidebar-border: ${dark.border};
1312
+ --sidebar-ring: ${dark.primary};
1313
+ `;
1314
+ const radius = config.tokens.radius?.md ?? "0.5rem";
1249
1315
  return `:root {
1316
+ --radius: ${radius};
1250
1317
  --background: ${light.background};
1251
1318
  --foreground: ${light.foreground};
1252
1319
  --primary: ${light.primary};
@@ -1268,7 +1335,7 @@ function buildCssVariables(config) {
1268
1335
  --warning: ${light.warning};
1269
1336
  --error: ${light.error};
1270
1337
  --info: ${light.info || light.primary};
1271
- ${accentVars}}
1338
+ ${accentVars}${sidebarLightVars}${chartLightVars}}
1272
1339
  .dark {
1273
1340
  --background: ${dark.background};
1274
1341
  --foreground: ${dark.foreground};
@@ -1291,7 +1358,7 @@ ${accentVars}}
1291
1358
  --warning: ${dark.warning};
1292
1359
  --error: ${dark.error};
1293
1360
  --info: ${dark.info || dark.primary};
1294
- ${accentDarkVars}}
1361
+ ${accentDarkVars}${sidebarDarkVars}${chartDarkVars}}
1295
1362
  `;
1296
1363
  }
1297
1364
 
@@ -1905,6 +1972,7 @@ function createEntry(manifest, input) {
1905
1972
  file: input.file,
1906
1973
  usedIn: input.usedIn ?? [],
1907
1974
  description: input.description,
1975
+ propsInterface: input.propsInterface,
1908
1976
  createdAt: now
1909
1977
  };
1910
1978
  const nextManifest = {
@@ -6070,6 +6138,8 @@ ${menuItems}
6070
6138
  <Link href="${signUpItem.route}" className="inline-flex items-center justify-center text-sm font-medium h-9 px-4 rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors">${signUpItem.label}</Link>` : ""}` : "";
6071
6139
  const dropdownImport = hasDropdowns ? `
6072
6140
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'` : "";
6141
+ const sheetImport = `
6142
+ import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'`;
6073
6143
  const appName = this.escapeString(this.config.name);
6074
6144
  const mobileNavItems = [...ungrouped];
6075
6145
  for (const [, items] of grouped) {
@@ -6089,7 +6159,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
6089
6159
 
6090
6160
  import Link from 'next/link'
6091
6161
  import { usePathname } from 'next/navigation'
6092
- import { useEffect, useState } from 'react'${dropdownImport}
6162
+ import { useEffect, useState } from 'react'${dropdownImport}${sheetImport}
6093
6163
 
6094
6164
  function ThemeToggle() {
6095
6165
  const [dark, setDark] = useState(false)
@@ -6138,26 +6208,23 @@ export function Header() {
6138
6208
  </div>
6139
6209
  <div className="flex items-center gap-1">${authButtonsBlock}
6140
6210
  <ThemeToggle />
6141
- <button
6142
- onClick={() => setMobileOpen(!mobileOpen)}
6143
- className="flex md:hidden items-center justify-center w-9 h-9 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
6144
- aria-label="Toggle menu"
6145
- >
6146
- {mobileOpen ? (
6147
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
6148
- ) : (
6149
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/></svg>
6150
- )}
6151
- </button>
6211
+ <Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
6212
+ <SheetTrigger asChild>
6213
+ <button
6214
+ className="flex md:hidden items-center justify-center w-9 h-9 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
6215
+ aria-label="Toggle menu"
6216
+ >
6217
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/></svg>
6218
+ </button>
6219
+ </SheetTrigger>
6220
+ <SheetContent side="right" className="w-72 p-4">
6221
+ <nav className="flex flex-col gap-1 pt-8">
6222
+ ${mobileLinks}${mobileAuthBlock}
6223
+ </nav>
6224
+ </SheetContent>
6225
+ </Sheet>
6152
6226
  </div>
6153
6227
  </div>
6154
- {mobileOpen && (
6155
- <div className="md:hidden border-t bg-background">
6156
- <div className="mx-auto max-w-7xl px-4 py-3 space-y-1">
6157
- ${mobileLinks}${mobileAuthBlock}
6158
- </div>
6159
- </div>
6160
- )}
6161
6228
  </nav>
6162
6229
  <Link
6163
6230
  href="/design-system"
@@ -6248,7 +6315,7 @@ ${companyColumn}
6248
6315
  `;
6249
6316
  }
6250
6317
  /**
6251
- * Generate shared Sidebar component code for components/shared/sidebar.tsx.
6318
+ * Generate shared Sidebar component code using shadcn/ui Sidebar.
6252
6319
  * Used when navigation.type is 'sidebar' or 'both'.
6253
6320
  */
6254
6321
  generateSharedSidebarCode() {
@@ -6279,71 +6346,71 @@ ${companyColumn}
6279
6346
  ungrouped.push(item);
6280
6347
  }
6281
6348
  }
6282
- const linkItems = ungrouped.map(
6283
- (item) => ` <Link
6284
- href="${item.route}"
6285
- className={\`flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors \${pathname === "${item.route}" ? 'bg-muted text-foreground' : 'text-muted-foreground hover:text-foreground hover:bg-muted/50'}\`}
6286
- >
6287
- ${item.label}
6288
- </Link>`
6289
- ).join("\n");
6290
- const groupBlocks = [];
6291
- for (const [groupName, items] of grouped) {
6292
- const groupLinks = items.map(
6293
- (item) => ` <Link
6294
- href="${item.route}"
6295
- className={\`flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors \${pathname === "${item.route}" ? 'bg-muted text-foreground font-medium' : 'text-muted-foreground hover:text-foreground hover:bg-muted/50'}\`}
6296
- >
6297
- ${item.label}
6298
- </Link>`
6299
- ).join("\n");
6300
- groupBlocks.push(` <div className="space-y-1">
6301
- <p className="px-3 py-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground/70">${groupName}</p>
6302
- ${groupLinks}
6303
- </div>`);
6304
- }
6305
- const allSections = [linkItems, ...groupBlocks].filter(Boolean).join("\n");
6349
+ const menuItem = (item) => ` <SidebarMenuItem>
6350
+ <SidebarMenuButton asChild isActive={pathname === "${item.route}"}>
6351
+ <Link href="${item.route}">${item.label}</Link>
6352
+ </SidebarMenuButton>
6353
+ </SidebarMenuItem>`;
6354
+ const ungroupedItems = ungrouped.map(menuItem).join("\n");
6355
+ const groupBlocks = Array.from(grouped.entries()).map(([groupName, items]) => {
6356
+ const groupItems = items.map(menuItem).join("\n");
6357
+ return ` <SidebarGroup>
6358
+ <SidebarGroupLabel>${groupName}</SidebarGroupLabel>
6359
+ <SidebarGroupContent>
6360
+ <SidebarMenu>
6361
+ ${groupItems}
6362
+ </SidebarMenu>
6363
+ </SidebarGroupContent>
6364
+ </SidebarGroup>`;
6365
+ }).join("\n");
6366
+ const mainGroup = ungroupedItems ? ` <SidebarGroup>
6367
+ <SidebarGroupContent>
6368
+ <SidebarMenu>
6369
+ ${ungroupedItems}
6370
+ </SidebarMenu>
6371
+ </SidebarGroupContent>
6372
+ </SidebarGroup>` : "";
6373
+ const allGroups = [mainGroup, groupBlocks].filter(Boolean).join("\n");
6306
6374
  const appName = this.escapeString(this.config.name);
6307
6375
  return `'use client'
6308
6376
 
6309
6377
  import Link from 'next/link'
6310
6378
  import { usePathname } from 'next/navigation'
6311
- import { useState } from 'react'
6312
-
6313
- export function Sidebar() {
6379
+ import {
6380
+ Sidebar,
6381
+ SidebarContent,
6382
+ SidebarGroup,
6383
+ SidebarGroupContent,
6384
+ SidebarGroupLabel,
6385
+ SidebarHeader,
6386
+ SidebarMenu,
6387
+ SidebarMenuButton,
6388
+ SidebarMenuItem,
6389
+ SidebarProvider,
6390
+ SidebarTrigger,
6391
+ } from '@/components/ui/sidebar'
6392
+
6393
+ export function AppSidebar() {
6314
6394
  const pathname = usePathname()
6315
- const [collapsed, setCollapsed] = useState(false)
6316
6395
 
6317
6396
  if (pathname?.startsWith('/design-system')) return null
6318
6397
 
6319
6398
  return (
6320
- <aside className={\`shrink-0 border-r bg-muted/30 transition-all duration-200 \${collapsed ? 'w-16' : 'w-64'}\`}>
6321
- <div className="flex h-14 items-center justify-between border-b px-4">
6322
- {!collapsed && (
6323
- <Link href="/" className="text-sm font-semibold text-foreground truncate">
6324
- ${appName}
6325
- </Link>
6326
- )}
6327
- <button
6328
- onClick={() => setCollapsed(!collapsed)}
6329
- className="flex items-center justify-center w-8 h-8 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
6330
- aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}
6331
- >
6332
- <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">
6333
- {collapsed ? (
6334
- <><path d="m9 18 6-6-6-6"/></>
6335
- ) : (
6336
- <><path d="m15 18-6-6 6-6"/></>
6337
- )}
6338
- </svg>
6339
- </button>
6340
- </div>
6341
- {!collapsed && (
6342
- <nav className="flex flex-col gap-1 p-3">
6343
- ${allSections}
6344
- </nav>
6345
- )}
6346
- </aside>
6399
+ <SidebarProvider>
6400
+ <Sidebar>
6401
+ <SidebarHeader>
6402
+ <div className="flex items-center justify-between px-2 py-1">
6403
+ <Link href="/" className="text-sm font-semibold text-foreground truncate">
6404
+ ${appName}
6405
+ </Link>
6406
+ <SidebarTrigger />
6407
+ </div>
6408
+ </SidebarHeader>
6409
+ <SidebarContent>
6410
+ ${allGroups}
6411
+ </SidebarContent>
6412
+ </Sidebar>
6413
+ </SidebarProvider>
6347
6414
  )
6348
6415
  }
6349
6416
  `;
@@ -6754,7 +6821,8 @@ async function generateSharedComponent(projectRoot, input) {
6754
6821
  type: input.type,
6755
6822
  file: filePath,
6756
6823
  usedIn: input.usedIn ?? [],
6757
- description: input.description
6824
+ description: input.description,
6825
+ propsInterface: input.propsInterface
6758
6826
  });
6759
6827
  await saveManifest(projectRoot, nextManifest);
6760
6828
  return { id: entry.id, name: entry.name, file: entry.file };
@@ -7082,6 +7150,19 @@ export default config
7082
7150
  --warning: ${light.warning};
7083
7151
  --error: ${light.error};
7084
7152
  --info: ${light.info || light.primary};
7153
+ --sidebar-background: ${light.background};
7154
+ --sidebar-foreground: ${light.foreground};
7155
+ --sidebar-primary: ${light.primary};
7156
+ --sidebar-primary-foreground: ${_ProjectScaffolder.contrastingForeground(light.primary)};
7157
+ --sidebar-accent: ${light.muted};
7158
+ --sidebar-accent-foreground: ${light.foreground};
7159
+ --sidebar-border: ${light.border};
7160
+ --sidebar-ring: ${light.primary};
7161
+ --chart-1: ${light.primary};
7162
+ --chart-2: ${light.secondary};
7163
+ --chart-3: ${light.success};
7164
+ --chart-4: ${light.warning};
7165
+ --chart-5: ${light.error};
7085
7166
  }
7086
7167
 
7087
7168
  .dark {
@@ -7108,6 +7189,19 @@ export default config
7108
7189
  --warning: ${dark.warning};
7109
7190
  --error: ${dark.error};
7110
7191
  --info: ${dark.info || dark.primary};
7192
+ --sidebar-background: ${dark.background};
7193
+ --sidebar-foreground: ${dark.foreground};
7194
+ --sidebar-primary: ${dark.primary};
7195
+ --sidebar-primary-foreground: ${_ProjectScaffolder.contrastingForeground(dark.primary)};
7196
+ --sidebar-accent: ${dark.muted};
7197
+ --sidebar-accent-foreground: ${dark.foreground};
7198
+ --sidebar-border: ${dark.border};
7199
+ --sidebar-ring: ${dark.primary};
7200
+ --chart-1: ${dark.primary};
7201
+ --chart-2: ${dark.secondary};
7202
+ --chart-3: ${dark.success};
7203
+ --chart-4: ${dark.warning};
7204
+ --chart-5: ${dark.error};
7111
7205
  }
7112
7206
 
7113
7207
  * {
@@ -7215,10 +7309,10 @@ export function cn(...inputs: ClassValue[]) {
7215
7309
  if (navType === "sidebar" || navType === "both") {
7216
7310
  const sidebarCode = this.pageGenerator.generateSharedSidebarCode();
7217
7311
  await generateSharedComponent(this.projectRoot, {
7218
- name: "Sidebar",
7312
+ name: "AppSidebar",
7219
7313
  type: "layout",
7220
7314
  code: sidebarCode,
7221
- description: "Vertical sidebar navigation with collapsible sections",
7315
+ description: "Application sidebar using shadcn/ui Sidebar components",
7222
7316
  usedIn: ["app/(app)/layout.tsx"]
7223
7317
  });
7224
7318
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.5.12",
6
+ "version": "0.5.14",
7
7
  "description": "Core design system engine for Coherent",
8
8
  "type": "module",
9
9
  "main": "./dist/index.js",
@@ -32,12 +32,6 @@
32
32
  ],
33
33
  "author": "Coherent Design Method",
34
34
  "license": "MIT",
35
- "scripts": {
36
- "dev": "tsup --watch",
37
- "build": "tsup",
38
- "typecheck": "tsc --noEmit",
39
- "test": "vitest"
40
- },
41
35
  "dependencies": {
42
36
  "handlebars": "^4.7.8",
43
37
  "zod": "^3.22.4"
@@ -47,5 +41,11 @@
47
41
  "tsup": "^8.0.1",
48
42
  "typescript": "^5.3.3",
49
43
  "vitest": "^1.2.1"
44
+ },
45
+ "scripts": {
46
+ "dev": "tsup --watch",
47
+ "build": "tsup",
48
+ "typecheck": "tsc --noEmit",
49
+ "test": "vitest"
50
50
  }
51
- }
51
+ }