create-kofi-stack 1.0.2 → 1.1.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.
Files changed (2) hide show
  1. package/dist/index.js +1797 -57
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -713,7 +713,7 @@ ${extras.length > 0 ? `${pc.bold("Extras:")} ${extras.join(", ")}` : ""}`,
713
713
  }
714
714
 
715
715
  // src/generators/index.ts
716
- import path18 from "path";
716
+ import path19 from "path";
717
717
  import * as p6 from "@clack/prompts";
718
718
  import pc2 from "picocolors";
719
719
  import ora from "ora";
@@ -3254,7 +3254,7 @@ async function generatePayloadPackageJson(marketingDir) {
3254
3254
  "db:seed": "tsx src/seed.ts"
3255
3255
  },
3256
3256
  dependencies: {
3257
- next: "^15.0.0",
3257
+ next: "^16.0.0",
3258
3258
  react: "^19.0.0",
3259
3259
  "react-dom": "^19.0.0",
3260
3260
  payload: "^3.0.0",
@@ -3421,9 +3421,17 @@ export const Media: CollectionConfig = {
3421
3421
  mediaContent
3422
3422
  );
3423
3423
  const pagesContent = `import type { CollectionConfig } from 'payload'
3424
- import { HeroBlock } from '../blocks/Hero'
3425
- import { ContentBlock } from '../blocks/Content'
3426
- import { CTABlock } from '../blocks/CTA'
3424
+ import {
3425
+ HeroBlock,
3426
+ LogoBannerBlock,
3427
+ FeaturesBlock,
3428
+ BenefitsBlock,
3429
+ PricingBlock,
3430
+ TestimonialsBlock,
3431
+ FAQBlock,
3432
+ ContentBlock,
3433
+ CTABlock,
3434
+ } from '../blocks'
3427
3435
 
3428
3436
  export const Pages: CollectionConfig = {
3429
3437
  slug: 'pages',
@@ -3464,7 +3472,17 @@ export const Pages: CollectionConfig = {
3464
3472
  {
3465
3473
  name: 'layout',
3466
3474
  type: 'blocks',
3467
- blocks: [HeroBlock, ContentBlock, CTABlock],
3475
+ blocks: [
3476
+ HeroBlock,
3477
+ LogoBannerBlock,
3478
+ FeaturesBlock,
3479
+ BenefitsBlock,
3480
+ PricingBlock,
3481
+ TestimonialsBlock,
3482
+ FAQBlock,
3483
+ ContentBlock,
3484
+ CTABlock,
3485
+ ],
3468
3486
  },
3469
3487
  ],
3470
3488
  }
@@ -3677,6 +3695,7 @@ async function generatePayloadBlocks(marketingDir) {
3677
3695
 
3678
3696
  export const HeroBlock: Block = {
3679
3697
  slug: 'hero',
3698
+ labels: { singular: 'Hero', plural: 'Heroes' },
3680
3699
  fields: [
3681
3700
  {
3682
3701
  name: 'heading',
@@ -3692,74 +3711,242 @@ export const HeroBlock: Block = {
3692
3711
  type: 'upload',
3693
3712
  relationTo: 'media',
3694
3713
  },
3714
+ {
3715
+ name: 'buttons',
3716
+ type: 'array',
3717
+ maxRows: 2,
3718
+ fields: [
3719
+ { name: 'label', type: 'text', required: true },
3720
+ { name: 'url', type: 'text', required: true },
3721
+ {
3722
+ name: 'variant',
3723
+ type: 'select',
3724
+ options: [
3725
+ { label: 'Primary', value: 'primary' },
3726
+ { label: 'Secondary', value: 'secondary' },
3727
+ ],
3728
+ defaultValue: 'primary',
3729
+ },
3730
+ ],
3731
+ },
3732
+ ],
3733
+ }
3734
+ `;
3735
+ await writeFile(path15.join(marketingDir, "src/blocks/Hero.ts"), heroContent);
3736
+ const logoBannerContent = `import type { Block } from 'payload'
3737
+
3738
+ export const LogoBannerBlock: Block = {
3739
+ slug: 'logoBanner',
3740
+ labels: { singular: 'Logo Banner', plural: 'Logo Banners' },
3741
+ fields: [
3742
+ { name: 'heading', type: 'text' },
3743
+ {
3744
+ name: 'logos',
3745
+ type: 'array',
3746
+ fields: [
3747
+ { name: 'name', type: 'text', required: true },
3748
+ { name: 'logo', type: 'upload', relationTo: 'media' },
3749
+ ],
3750
+ },
3751
+ ],
3752
+ }
3753
+ `;
3754
+ await writeFile(path15.join(marketingDir, "src/blocks/LogoBanner.ts"), logoBannerContent);
3755
+ const featuresContent = `import type { Block } from 'payload'
3756
+
3757
+ export const FeaturesBlock: Block = {
3758
+ slug: 'features',
3759
+ labels: { singular: 'Features', plural: 'Features' },
3760
+ fields: [
3761
+ { name: 'heading', type: 'text' },
3762
+ { name: 'subheading', type: 'textarea' },
3763
+ {
3764
+ name: 'features',
3765
+ type: 'array',
3766
+ fields: [
3767
+ {
3768
+ name: 'icon',
3769
+ type: 'select',
3770
+ options: [
3771
+ { label: 'Zap', value: 'zap' },
3772
+ { label: 'Shield', value: 'shield' },
3773
+ { label: 'Globe', value: 'globe' },
3774
+ { label: 'Layers', value: 'layers' },
3775
+ { label: 'Settings', value: 'settings' },
3776
+ { label: 'Users', value: 'users' },
3777
+ { label: 'Lock', value: 'lock' },
3778
+ { label: 'Star', value: 'star' },
3779
+ ],
3780
+ },
3781
+ { name: 'title', type: 'text', required: true },
3782
+ { name: 'description', type: 'textarea' },
3783
+ ],
3784
+ },
3785
+ ],
3786
+ }
3787
+ `;
3788
+ await writeFile(path15.join(marketingDir, "src/blocks/Features.ts"), featuresContent);
3789
+ const benefitsContent = `import type { Block } from 'payload'
3790
+
3791
+ export const BenefitsBlock: Block = {
3792
+ slug: 'benefits',
3793
+ labels: { singular: 'Benefits', plural: 'Benefits' },
3794
+ fields: [
3795
+ { name: 'label', type: 'text' },
3796
+ { name: 'heading', type: 'text', required: true },
3797
+ { name: 'description', type: 'textarea' },
3798
+ { name: 'image', type: 'upload', relationTo: 'media' },
3799
+ {
3800
+ name: 'imagePosition',
3801
+ type: 'select',
3802
+ options: [
3803
+ { label: 'Left', value: 'left' },
3804
+ { label: 'Right', value: 'right' },
3805
+ ],
3806
+ defaultValue: 'right',
3807
+ },
3808
+ {
3809
+ name: 'benefits',
3810
+ type: 'array',
3811
+ fields: [{ name: 'text', type: 'text', required: true }],
3812
+ },
3695
3813
  {
3696
3814
  name: 'cta',
3697
3815
  type: 'group',
3698
3816
  fields: [
3817
+ { name: 'label', type: 'text' },
3818
+ { name: 'url', type: 'text' },
3819
+ ],
3820
+ },
3821
+ ],
3822
+ }
3823
+ `;
3824
+ await writeFile(path15.join(marketingDir, "src/blocks/Benefits.ts"), benefitsContent);
3825
+ const pricingContent = `import type { Block } from 'payload'
3826
+
3827
+ export const PricingBlock: Block = {
3828
+ slug: 'pricing',
3829
+ labels: { singular: 'Pricing', plural: 'Pricing' },
3830
+ fields: [
3831
+ { name: 'heading', type: 'text' },
3832
+ { name: 'subheading', type: 'textarea' },
3833
+ {
3834
+ name: 'plans',
3835
+ type: 'array',
3836
+ fields: [
3837
+ { name: 'name', type: 'text', required: true },
3838
+ { name: 'price', type: 'text', required: true },
3839
+ { name: 'period', type: 'text', defaultValue: '/month' },
3840
+ { name: 'description', type: 'textarea' },
3841
+ { name: 'featured', type: 'checkbox', defaultValue: false },
3699
3842
  {
3700
- name: 'label',
3701
- type: 'text',
3843
+ name: 'features',
3844
+ type: 'array',
3845
+ fields: [
3846
+ { name: 'feature', type: 'text', required: true },
3847
+ { name: 'included', type: 'checkbox', defaultValue: true },
3848
+ ],
3702
3849
  },
3703
3850
  {
3704
- name: 'url',
3705
- type: 'text',
3851
+ name: 'cta',
3852
+ type: 'group',
3853
+ fields: [
3854
+ { name: 'label', type: 'text' },
3855
+ { name: 'url', type: 'text' },
3856
+ ],
3706
3857
  },
3707
3858
  ],
3708
3859
  },
3709
3860
  ],
3710
3861
  }
3711
3862
  `;
3712
- await writeFile(path15.join(marketingDir, "src/blocks/Hero.ts"), heroContent);
3863
+ await writeFile(path15.join(marketingDir, "src/blocks/Pricing.ts"), pricingContent);
3864
+ const testimonialsContent = `import type { Block } from 'payload'
3865
+
3866
+ export const TestimonialsBlock: Block = {
3867
+ slug: 'testimonials',
3868
+ labels: { singular: 'Testimonials', plural: 'Testimonials' },
3869
+ fields: [
3870
+ { name: 'heading', type: 'text' },
3871
+ { name: 'subheading', type: 'textarea' },
3872
+ {
3873
+ name: 'testimonials',
3874
+ type: 'array',
3875
+ fields: [
3876
+ { name: 'quote', type: 'textarea', required: true },
3877
+ { name: 'author', type: 'text', required: true },
3878
+ { name: 'role', type: 'text' },
3879
+ { name: 'company', type: 'text' },
3880
+ { name: 'image', type: 'upload', relationTo: 'media' },
3881
+ ],
3882
+ },
3883
+ ],
3884
+ }
3885
+ `;
3886
+ await writeFile(path15.join(marketingDir, "src/blocks/Testimonials.ts"), testimonialsContent);
3887
+ const faqContent = `import type { Block } from 'payload'
3888
+
3889
+ export const FAQBlock: Block = {
3890
+ slug: 'faq',
3891
+ labels: { singular: 'FAQ', plural: 'FAQs' },
3892
+ fields: [
3893
+ { name: 'heading', type: 'text' },
3894
+ { name: 'subheading', type: 'textarea' },
3895
+ {
3896
+ name: 'items',
3897
+ type: 'array',
3898
+ fields: [
3899
+ { name: 'question', type: 'text', required: true },
3900
+ { name: 'answer', type: 'textarea', required: true },
3901
+ ],
3902
+ },
3903
+ ],
3904
+ }
3905
+ `;
3906
+ await writeFile(path15.join(marketingDir, "src/blocks/FAQ.ts"), faqContent);
3713
3907
  const contentContent = `import type { Block } from 'payload'
3714
3908
 
3715
3909
  export const ContentBlock: Block = {
3716
3910
  slug: 'content',
3911
+ labels: { singular: 'Content', plural: 'Content' },
3717
3912
  fields: [
3718
- {
3719
- name: 'content',
3720
- type: 'richText',
3721
- },
3913
+ { name: 'content', type: 'richText' },
3722
3914
  ],
3723
3915
  }
3724
3916
  `;
3725
- await writeFile(
3726
- path15.join(marketingDir, "src/blocks/Content.ts"),
3727
- contentContent
3728
- );
3917
+ await writeFile(path15.join(marketingDir, "src/blocks/Content.ts"), contentContent);
3729
3918
  const ctaContent = `import type { Block } from 'payload'
3730
3919
 
3731
3920
  export const CTABlock: Block = {
3732
3921
  slug: 'cta',
3922
+ labels: { singular: 'CTA', plural: 'CTAs' },
3733
3923
  fields: [
3924
+ { name: 'heading', type: 'text' },
3925
+ { name: 'description', type: 'textarea' },
3734
3926
  {
3735
- name: 'heading',
3736
- type: 'text',
3737
- },
3738
- {
3739
- name: 'description',
3740
- type: 'textarea',
3927
+ name: 'style',
3928
+ type: 'select',
3929
+ options: [
3930
+ { label: 'Light', value: 'light' },
3931
+ { label: 'Dark', value: 'dark' },
3932
+ { label: 'Primary', value: 'primary' },
3933
+ ],
3934
+ defaultValue: 'dark',
3741
3935
  },
3742
3936
  {
3743
3937
  name: 'buttons',
3744
3938
  type: 'array',
3745
3939
  maxRows: 2,
3746
3940
  fields: [
3747
- {
3748
- name: 'label',
3749
- type: 'text',
3750
- required: true,
3751
- },
3752
- {
3753
- name: 'url',
3754
- type: 'text',
3755
- required: true,
3756
- },
3941
+ { name: 'label', type: 'text', required: true },
3942
+ { name: 'url', type: 'text', required: true },
3757
3943
  {
3758
3944
  name: 'variant',
3759
3945
  type: 'select',
3760
3946
  options: [
3761
3947
  { label: 'Primary', value: 'primary' },
3762
3948
  { label: 'Secondary', value: 'secondary' },
3949
+ { label: 'Outline', value: 'outline' },
3763
3950
  ],
3764
3951
  defaultValue: 'primary',
3765
3952
  },
@@ -3770,6 +3957,12 @@ export const CTABlock: Block = {
3770
3957
  `;
3771
3958
  await writeFile(path15.join(marketingDir, "src/blocks/CTA.ts"), ctaContent);
3772
3959
  const indexContent = `export { HeroBlock } from './Hero'
3960
+ export { LogoBannerBlock } from './LogoBanner'
3961
+ export { FeaturesBlock } from './Features'
3962
+ export { BenefitsBlock } from './Benefits'
3963
+ export { PricingBlock } from './Pricing'
3964
+ export { TestimonialsBlock } from './Testimonials'
3965
+ export { FAQBlock } from './FAQ'
3773
3966
  export { ContentBlock } from './Content'
3774
3967
  export { CTABlock } from './CTA'
3775
3968
  `;
@@ -5009,6 +5202,1549 @@ Follow our blog for updates on new features and best practices.
5009
5202
  );
5010
5203
  }
5011
5204
 
5205
+ // src/generators/design-system.ts
5206
+ import path18 from "path";
5207
+ var fontImports = {
5208
+ inter: {
5209
+ import: "import { Inter } from 'next/font/google'",
5210
+ variable: "--font-inter",
5211
+ config: `const inter = Inter({
5212
+ variable: '--font-inter',
5213
+ subsets: ['latin'],
5214
+ })`
5215
+ },
5216
+ "dm-sans": {
5217
+ import: "import { DM_Sans } from 'next/font/google'",
5218
+ variable: "--font-dm-sans",
5219
+ config: `const dmSans = DM_Sans({
5220
+ variable: '--font-dm-sans',
5221
+ subsets: ['latin'],
5222
+ weight: ['400', '500', '600', '700'],
5223
+ })`
5224
+ },
5225
+ geist: {
5226
+ import: "import { Geist } from 'next/font/google'",
5227
+ variable: "--font-geist",
5228
+ config: `const geist = Geist({
5229
+ variable: '--font-geist',
5230
+ subsets: ['latin'],
5231
+ })`
5232
+ },
5233
+ "plus-jakarta": {
5234
+ import: "import { Plus_Jakarta_Sans } from 'next/font/google'",
5235
+ variable: "--font-plus-jakarta",
5236
+ config: `const plusJakarta = Plus_Jakarta_Sans({
5237
+ variable: '--font-plus-jakarta',
5238
+ subsets: ['latin'],
5239
+ weight: ['400', '500', '600', '700'],
5240
+ })`
5241
+ },
5242
+ outfit: {
5243
+ import: "import { Outfit } from 'next/font/google'",
5244
+ variable: "--font-outfit",
5245
+ config: `const outfit = Outfit({
5246
+ variable: '--font-outfit',
5247
+ subsets: ['latin'],
5248
+ })`
5249
+ },
5250
+ "space-grotesk": {
5251
+ import: "import { Space_Grotesk } from 'next/font/google'",
5252
+ variable: "--font-space-grotesk",
5253
+ config: `const spaceGrotesk = Space_Grotesk({
5254
+ variable: '--font-space-grotesk',
5255
+ subsets: ['latin'],
5256
+ weight: ['400', '500', '600', '700'],
5257
+ })`
5258
+ }
5259
+ };
5260
+ var radiusValues = {
5261
+ none: "0px",
5262
+ sm: "4px",
5263
+ md: "8px",
5264
+ lg: "12px",
5265
+ xl: "16px",
5266
+ full: "9999px"
5267
+ };
5268
+ var spacingMultipliers = {
5269
+ compact: 0.875,
5270
+ default: 1,
5271
+ relaxed: 1.125
5272
+ };
5273
+ async function generateDesignSystemApp(config, targetDir) {
5274
+ const appDir = path18.join(targetDir, "apps/design-system");
5275
+ await ensureDir(path18.join(appDir, "src/app"));
5276
+ await ensureDir(path18.join(appDir, "src/app/colors"));
5277
+ await ensureDir(path18.join(appDir, "src/app/typography"));
5278
+ await ensureDir(path18.join(appDir, "src/app/spacing"));
5279
+ await ensureDir(path18.join(appDir, "src/app/brand"));
5280
+ await ensureDir(path18.join(appDir, "src/app/blocks"));
5281
+ await ensureDir(path18.join(appDir, "src/app/components"));
5282
+ await ensureDir(path18.join(appDir, "src/lib"));
5283
+ await ensureDir(path18.join(appDir, "public/brand"));
5284
+ await generatePackageJson2(config, appDir);
5285
+ await generateTsConfig2(appDir);
5286
+ await generateNextConfig2(appDir);
5287
+ await generatePostCssConfig2(appDir);
5288
+ await generateGlobalsCss2(config, appDir);
5289
+ await generateLayoutTsx(config, appDir);
5290
+ await generateHomePage(config, appDir);
5291
+ await generateColorsPage(config, appDir);
5292
+ await generateTypographyPage(config, appDir);
5293
+ await generateSpacingPage(config, appDir);
5294
+ await generateBrandPage(config, appDir);
5295
+ await generateBlocksPage(appDir);
5296
+ await generateComponentsPage(appDir);
5297
+ await generateUtils(appDir);
5298
+ }
5299
+ async function generatePackageJson2(config, appDir) {
5300
+ const packageJson = {
5301
+ name: "@repo/design-system",
5302
+ version: "0.1.0",
5303
+ private: true,
5304
+ scripts: {
5305
+ dev: "next dev --port 3003",
5306
+ build: "next build",
5307
+ start: "next start",
5308
+ lint: "biome check .",
5309
+ "lint:fix": "biome check --write .",
5310
+ typecheck: "tsc --noEmit"
5311
+ },
5312
+ dependencies: {
5313
+ "@repo/ui": "workspace:*",
5314
+ "class-variance-authority": "^0.7.1",
5315
+ clsx: "^2.1.1",
5316
+ next: "^16.0.0",
5317
+ "next-themes": "^0.4.6",
5318
+ react: "^19.0.0",
5319
+ "react-dom": "^19.0.0",
5320
+ recharts: "^2.15.0",
5321
+ sonner: "^2.0.0",
5322
+ "tailwind-merge": "^3.0.0",
5323
+ "tw-animate-css": "^1.3.0"
5324
+ },
5325
+ devDependencies: {
5326
+ "@repo/config-typescript": "workspace:*",
5327
+ "@tailwindcss/postcss": "^4.0.0",
5328
+ "@types/node": "^20.0.0",
5329
+ "@types/react": "^19.0.0",
5330
+ "@types/react-dom": "^19.0.0",
5331
+ tailwindcss: "^4.0.0",
5332
+ typescript: "^5.0.0"
5333
+ }
5334
+ };
5335
+ await writeJSON(path18.join(appDir, "package.json"), packageJson);
5336
+ }
5337
+ async function generateTsConfig2(appDir) {
5338
+ const tsConfig = {
5339
+ extends: "@repo/config-typescript/nextjs.json",
5340
+ compilerOptions: {
5341
+ jsx: "preserve",
5342
+ paths: {
5343
+ "@/*": ["./src/*"],
5344
+ "@repo/ui": ["../../packages/ui/src"],
5345
+ "@repo/ui/*": ["../../packages/ui/src/*"]
5346
+ }
5347
+ },
5348
+ include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
5349
+ exclude: ["node_modules"]
5350
+ };
5351
+ await writeJSON(path18.join(appDir, "tsconfig.json"), tsConfig);
5352
+ }
5353
+ async function generateNextConfig2(appDir) {
5354
+ const content = `import type { NextConfig } from 'next'
5355
+
5356
+ const nextConfig: NextConfig = {
5357
+ transpilePackages: ['@repo/ui'],
5358
+ }
5359
+
5360
+ export default nextConfig
5361
+ `;
5362
+ await writeFile(path18.join(appDir, "next.config.ts"), content);
5363
+ }
5364
+ async function generatePostCssConfig2(appDir) {
5365
+ const content = `export default {
5366
+ plugins: {
5367
+ '@tailwindcss/postcss': {},
5368
+ },
5369
+ }
5370
+ `;
5371
+ await writeFile(path18.join(appDir, "postcss.config.mjs"), content);
5372
+ }
5373
+ async function generateGlobalsCss2(config, appDir) {
5374
+ const { designSystem } = config;
5375
+ const radiusValue = radiusValues[designSystem.borderRadius];
5376
+ const spacingMult = spacingMultipliers[designSystem.spacingScale];
5377
+ const content = `@import "tailwindcss";
5378
+ @import "tw-animate-css";
5379
+
5380
+ @custom-variant dark (&:is(.dark *));
5381
+
5382
+ /* Design System - CSS Variables */
5383
+
5384
+ :root {
5385
+ /* Border Radius */
5386
+ --radius: ${radiusValue};
5387
+ --radius-xs: calc(${radiusValue} * 0.5);
5388
+ --radius-sm: calc(${radiusValue} * 0.75);
5389
+ --radius-md: ${radiusValue};
5390
+ --radius-lg: calc(${radiusValue} * 1.5);
5391
+ --radius-pill: 9999px;
5392
+
5393
+ /* Spacing Scale Multiplier: ${designSystem.spacingScale} (${spacingMult}x) */
5394
+
5395
+ /* Color Tokens - Light Mode */
5396
+ --background: #ffffff;
5397
+ --card: #ffffff;
5398
+ --popover: #ffffff;
5399
+ --muted: #f5f7fa;
5400
+
5401
+ /* Foreground tokens */
5402
+ --foreground: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "10%" : v).join(" ")});
5403
+ --card-foreground: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "10%" : v).join(" ")});
5404
+ --popover-foreground: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "10%" : v).join(" ")});
5405
+ --muted-foreground: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "40%" : i === 1 ? "20%" : v).join(" ")});
5406
+
5407
+ /* Brand colors */
5408
+ --primary: hsl(${designSystem.primaryColor});
5409
+ --primary-foreground: #ffffff;
5410
+ --secondary: hsl(${designSystem.secondaryColor});
5411
+ --secondary-foreground: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "10%" : v).join(" ")});
5412
+ --accent: hsl(${designSystem.accentColor});
5413
+ --accent-foreground: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "10%" : v).join(" ")});
5414
+
5415
+ /* Semantic colors */
5416
+ --success: #22c55e;
5417
+ --warning: #f59e0b;
5418
+ --destructive: #ef4444;
5419
+ --destructive-foreground: #ffffff;
5420
+
5421
+ /* Border and input */
5422
+ --border: #e2e8f0;
5423
+ --input: #e2e8f0;
5424
+ --ring: hsl(${designSystem.primaryColor});
5425
+
5426
+ /* Chart colors */
5427
+ --chart-1: hsl(${designSystem.primaryColor});
5428
+ --chart-2: #22c55e;
5429
+ --chart-3: hsl(${designSystem.accentColor});
5430
+ --chart-4: #ef4444;
5431
+ --chart-5: #6b7280;
5432
+
5433
+ /* Sidebar tokens */
5434
+ --sidebar: #ffffff;
5435
+ --sidebar-foreground: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "10%" : v).join(" ")});
5436
+ --sidebar-primary: hsl(${designSystem.primaryColor});
5437
+ --sidebar-primary-foreground: #ffffff;
5438
+ --sidebar-accent: hsla(${designSystem.primaryColor}, 0.1);
5439
+ --sidebar-accent-foreground: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "10%" : v).join(" ")});
5440
+ --sidebar-border: #e2e8f0;
5441
+ --sidebar-ring: hsl(${designSystem.primaryColor});
5442
+ }
5443
+
5444
+ .dark {
5445
+ /* Color Tokens - Dark Mode */
5446
+ --background: #0b0d11;
5447
+ --card: #111418;
5448
+ --popover: #111418;
5449
+ --muted: #161a20;
5450
+
5451
+ --foreground: #f5f7fa;
5452
+ --card-foreground: #f5f7fa;
5453
+ --popover-foreground: #f5f7fa;
5454
+ --muted-foreground: #9ba3b0;
5455
+
5456
+ --primary: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "60%" : v).join(" ")});
5457
+ --primary-foreground: #ffffff;
5458
+ --secondary: #1e293b;
5459
+ --secondary-foreground: #f8fafc;
5460
+ --accent: #1e293b;
5461
+ --accent-foreground: #f8fafc;
5462
+
5463
+ --success: #4ade80;
5464
+ --warning: #fbbf24;
5465
+ --destructive: #fca5a5;
5466
+ --destructive-foreground: #0f172a;
5467
+
5468
+ --border: rgba(255, 255, 255, 0.1);
5469
+ --input: rgba(255, 255, 255, 0.1);
5470
+ --ring: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "60%" : v).join(" ")});
5471
+
5472
+ --chart-1: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "60%" : v).join(" ")});
5473
+ --chart-2: #4ade80;
5474
+ --chart-3: hsl(${designSystem.accentColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "60%" : v).join(" ")});
5475
+ --chart-4: #fca5a5;
5476
+ --chart-5: #9ba3b0;
5477
+
5478
+ --sidebar: #0b0d11;
5479
+ --sidebar-foreground: #f5f7fa;
5480
+ --sidebar-primary: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "60%" : v).join(" ")});
5481
+ --sidebar-primary-foreground: #ffffff;
5482
+ --sidebar-accent: hsla(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "60%" : v).join(" ")}, 0.1);
5483
+ --sidebar-accent-foreground: #f5f7fa;
5484
+ --sidebar-border: rgba(255, 255, 255, 0.08);
5485
+ --sidebar-ring: hsl(${designSystem.primaryColor.replace("%", "").split(" ").map((v, i) => i === 2 ? "60%" : v).join(" ")});
5486
+ }
5487
+
5488
+ /* Tailwind Theme Mapping */
5489
+ @theme inline {
5490
+ --radius-sm: calc(var(--radius) - 4px);
5491
+ --radius-md: calc(var(--radius) - 2px);
5492
+ --radius-lg: var(--radius);
5493
+ --radius-xl: calc(var(--radius) + 4px);
5494
+
5495
+ --color-background: var(--background);
5496
+ --color-foreground: var(--foreground);
5497
+ --color-card: var(--card);
5498
+ --color-card-foreground: var(--card-foreground);
5499
+ --color-popover: var(--popover);
5500
+ --color-popover-foreground: var(--popover-foreground);
5501
+ --color-primary: var(--primary);
5502
+ --color-primary-foreground: var(--primary-foreground);
5503
+ --color-secondary: var(--secondary);
5504
+ --color-secondary-foreground: var(--secondary-foreground);
5505
+ --color-muted: var(--muted);
5506
+ --color-muted-foreground: var(--muted-foreground);
5507
+ --color-accent: var(--accent);
5508
+ --color-accent-foreground: var(--accent-foreground);
5509
+ --color-destructive: var(--destructive);
5510
+ --color-destructive-foreground: var(--destructive-foreground);
5511
+ --color-border: var(--border);
5512
+ --color-input: var(--input);
5513
+ --color-ring: var(--ring);
5514
+ --color-success: var(--success);
5515
+ --color-warning: var(--warning);
5516
+
5517
+ --color-chart-1: var(--chart-1);
5518
+ --color-chart-2: var(--chart-2);
5519
+ --color-chart-3: var(--chart-3);
5520
+ --color-chart-4: var(--chart-4);
5521
+ --color-chart-5: var(--chart-5);
5522
+
5523
+ --color-sidebar: var(--sidebar);
5524
+ --color-sidebar-foreground: var(--sidebar-foreground);
5525
+ --color-sidebar-primary: var(--sidebar-primary);
5526
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
5527
+ --color-sidebar-accent: var(--sidebar-accent);
5528
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
5529
+ --color-sidebar-border: var(--sidebar-border);
5530
+ --color-sidebar-ring: var(--sidebar-ring);
5531
+ }
5532
+
5533
+ /* Typography */
5534
+ @theme {
5535
+ --font-size-display-hero: 3.5rem;
5536
+ --font-size-display-02: 3rem;
5537
+ --font-size-display-01: 2.5rem;
5538
+ --font-size-h1: 2rem;
5539
+ --font-size-h2: 1.5rem;
5540
+ --font-size-h3: 1.25rem;
5541
+ --font-size-h4: 1.125rem;
5542
+ --font-size-body-lg: 1.125rem;
5543
+ --font-size-body: 1rem;
5544
+ --font-size-body-sm: 0.875rem;
5545
+
5546
+ --line-height-display-hero: 1.1;
5547
+ --line-height-display: 1.2;
5548
+ --line-height-heading: 1.2;
5549
+ --line-height-body: 1.5;
5550
+ --line-height-body-relaxed: 1.75;
5551
+ }
5552
+
5553
+ /* Base styles */
5554
+ html, body {
5555
+ min-height: 100%;
5556
+ overflow-x: hidden;
5557
+ max-width: 100vw;
5558
+ }
5559
+
5560
+ h1, h2, h3, h4, h5, h6 {
5561
+ font-family: var(--font-heading), system-ui, sans-serif;
5562
+ }
5563
+
5564
+ /* Typography Utility Classes */
5565
+ .text-display-hero {
5566
+ font-size: var(--font-size-display-hero);
5567
+ line-height: var(--line-height-display-hero);
5568
+ font-weight: 600;
5569
+ }
5570
+
5571
+ .text-display-02 {
5572
+ font-size: var(--font-size-display-02);
5573
+ line-height: var(--line-height-display);
5574
+ font-weight: 600;
5575
+ }
5576
+
5577
+ .text-display-01 {
5578
+ font-size: var(--font-size-display-01);
5579
+ line-height: var(--line-height-display);
5580
+ font-weight: 600;
5581
+ }
5582
+
5583
+ .text-h1 {
5584
+ font-size: var(--font-size-h1);
5585
+ line-height: var(--line-height-heading);
5586
+ font-weight: 600;
5587
+ }
5588
+
5589
+ .text-h2 {
5590
+ font-size: var(--font-size-h2);
5591
+ line-height: var(--line-height-heading);
5592
+ font-weight: 600;
5593
+ }
5594
+
5595
+ .text-h3 {
5596
+ font-size: var(--font-size-h3);
5597
+ line-height: var(--line-height-heading);
5598
+ font-weight: 500;
5599
+ }
5600
+
5601
+ .text-h4 {
5602
+ font-size: var(--font-size-h4);
5603
+ line-height: var(--line-height-heading);
5604
+ font-weight: 500;
5605
+ }
5606
+
5607
+ .text-body-lg {
5608
+ font-size: var(--font-size-body-lg);
5609
+ line-height: var(--line-height-body-relaxed);
5610
+ }
5611
+
5612
+ .text-body {
5613
+ font-size: var(--font-size-body);
5614
+ line-height: var(--line-height-body);
5615
+ }
5616
+
5617
+ .text-body-sm {
5618
+ font-size: var(--font-size-body-sm);
5619
+ line-height: var(--line-height-body);
5620
+ }
5621
+
5622
+ @layer base {
5623
+ * {
5624
+ @apply border-border outline-ring/50;
5625
+ }
5626
+ body {
5627
+ @apply bg-background text-foreground;
5628
+ }
5629
+ }
5630
+ `;
5631
+ await writeFile(path18.join(appDir, "src/app/globals.css"), content);
5632
+ }
5633
+ async function generateLayoutTsx(config, appDir) {
5634
+ const { designSystem } = config;
5635
+ const headingFont = fontImports[designSystem.headingFont];
5636
+ const bodyFont = fontImports[designSystem.bodyFont];
5637
+ const imports = [];
5638
+ const fontConfigs = [];
5639
+ const fontVars = [];
5640
+ if (headingFont) {
5641
+ imports.push(headingFont.import);
5642
+ fontConfigs.push(headingFont.config.replace(/const \w+/, "const headingFont"));
5643
+ fontVars.push("${headingFont.variable}");
5644
+ }
5645
+ if (bodyFont && bodyFont.variable !== headingFont?.variable) {
5646
+ imports.push(bodyFont.import);
5647
+ fontConfigs.push(bodyFont.config.replace(/const \w+/, "const bodyFont"));
5648
+ fontVars.push("${bodyFont.variable}");
5649
+ }
5650
+ const uniqueImports = [...new Set(imports)];
5651
+ const content = `import type { Metadata } from 'next'
5652
+ ${uniqueImports.join("\n")}
5653
+ import { ThemeProvider } from 'next-themes'
5654
+ import './globals.css'
5655
+
5656
+ ${fontConfigs.join("\n\n")}
5657
+
5658
+ export const metadata: Metadata = {
5659
+ title: '${config.name} Design System',
5660
+ description: 'Design system documentation for ${config.name}',
5661
+ }
5662
+
5663
+ export default function RootLayout({
5664
+ children,
5665
+ }: Readonly<{
5666
+ children: React.ReactNode
5667
+ }>) {
5668
+ return (
5669
+ <html lang="en" suppressHydrationWarning>
5670
+ <body
5671
+ className={\`\${headingFont.variable}${bodyFont && bodyFont.variable !== headingFont?.variable ? " ${bodyFont.variable}" : ""} font-sans antialiased bg-background text-foreground\`}
5672
+ style={{ '--font-heading': 'var(${headingFont.variable})' } as React.CSSProperties}
5673
+ >
5674
+ <ThemeProvider attribute="class" defaultTheme="light" enableSystem>
5675
+ <div className="min-h-screen flex">
5676
+ <Sidebar projectName="${config.name}" />
5677
+ <main className="flex-1 overflow-auto">{children}</main>
5678
+ </div>
5679
+ </ThemeProvider>
5680
+ </body>
5681
+ </html>
5682
+ )
5683
+ }
5684
+
5685
+ const components = [
5686
+ 'Accordion', 'Alert', 'Alert Dialog', 'Aspect Ratio', 'Avatar', 'Badge',
5687
+ 'Breadcrumb', 'Button', 'Calendar', 'Card', 'Carousel', 'Chart', 'Checkbox',
5688
+ 'Collapsible', 'Command', 'Context Menu', 'Dialog', 'Drawer', 'Dropdown Menu',
5689
+ 'Form', 'Hover Card', 'Input', 'Input OTP', 'Label', 'Menubar', 'Navigation Menu',
5690
+ 'Pagination', 'Popover', 'Progress', 'Radio Group', 'Resizable', 'Scroll Area',
5691
+ 'Select', 'Separator', 'Sheet', 'Sidebar', 'Skeleton', 'Slider', 'Sonner',
5692
+ 'Switch', 'Table', 'Tabs', 'Textarea', 'Toast', 'Toggle', 'Toggle Group', 'Tooltip',
5693
+ ]
5694
+
5695
+ function Sidebar({ projectName }: { projectName: string }) {
5696
+ const foundationItems = [
5697
+ { href: '/', label: 'Overview', icon: 'home' },
5698
+ { href: '/colors', label: 'Colors', icon: 'palette' },
5699
+ { href: '/typography', label: 'Typography', icon: 'type' },
5700
+ { href: '/spacing', label: 'Spacing', icon: 'ruler' },
5701
+ { href: '/brand', label: 'Brand', icon: 'badge' },
5702
+ ]
5703
+
5704
+ return (
5705
+ <aside className="w-64 border-r border-border bg-card hidden md:flex md:flex-col h-screen sticky top-0">
5706
+ <div className="p-6">
5707
+ <a href="/" className="flex items-center gap-3">
5708
+ <div className="h-8 w-8 rounded-lg bg-primary flex items-center justify-center text-primary-foreground font-semibold">
5709
+ {projectName.charAt(0).toUpperCase()}
5710
+ </div>
5711
+ <span className="text-h4 font-semibold text-foreground">
5712
+ {projectName} Design
5713
+ </span>
5714
+ </a>
5715
+ </div>
5716
+ <nav className="flex-1 overflow-y-auto px-3 pb-6">
5717
+ <div className="mb-4">
5718
+ <p className="px-3 mb-2 text-xs font-semibold text-muted-foreground uppercase tracking-wider">
5719
+ Foundation
5720
+ </p>
5721
+ <div className="space-y-0.5">
5722
+ {foundationItems.map((item) => (
5723
+ <a
5724
+ key={item.href}
5725
+ href={item.href}
5726
+ className="flex items-center gap-3 px-3 py-2 rounded-md text-sm text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
5727
+ >
5728
+ <NavIcon name={item.icon} />
5729
+ <span>{item.label}</span>
5730
+ </a>
5731
+ ))}
5732
+ </div>
5733
+ </div>
5734
+
5735
+ <div className="mb-4">
5736
+ <p className="px-3 mb-2 text-xs font-semibold text-muted-foreground uppercase tracking-wider">
5737
+ Blocks
5738
+ </p>
5739
+ <div className="space-y-0.5">
5740
+ <a
5741
+ href="/blocks"
5742
+ className="flex items-center gap-3 px-3 py-2 rounded-md text-sm text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
5743
+ >
5744
+ <NavIcon name="grid" />
5745
+ <span>All Blocks</span>
5746
+ </a>
5747
+ </div>
5748
+ </div>
5749
+
5750
+ <div>
5751
+ <p className="px-3 mb-2 text-xs font-semibold text-muted-foreground uppercase tracking-wider">
5752
+ Components
5753
+ </p>
5754
+ <div className="space-y-0.5">
5755
+ {components.map((component) => {
5756
+ const slug = component.toLowerCase().replace(/\\s+/g, '-')
5757
+ return (
5758
+ <a
5759
+ key={slug}
5760
+ href={\`/components/\${slug}\`}
5761
+ className="block px-3 py-1.5 rounded-md text-sm text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
5762
+ >
5763
+ {component}
5764
+ </a>
5765
+ )
5766
+ })}
5767
+ </div>
5768
+ </div>
5769
+ </nav>
5770
+ <div className="p-4 border-t border-border">
5771
+ <ThemeToggle />
5772
+ </div>
5773
+ </aside>
5774
+ )
5775
+ }
5776
+
5777
+ function NavIcon({ name }: { name: string }) {
5778
+ const icons: Record<string, React.ReactNode> = {
5779
+ home: (
5780
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5781
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
5782
+ </svg>
5783
+ ),
5784
+ palette: (
5785
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5786
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" />
5787
+ </svg>
5788
+ ),
5789
+ type: (
5790
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5791
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4 6h16M4 12h16m-7 6h7" />
5792
+ </svg>
5793
+ ),
5794
+ ruler: (
5795
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5796
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
5797
+ </svg>
5798
+ ),
5799
+ badge: (
5800
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5801
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
5802
+ </svg>
5803
+ ),
5804
+ grid: (
5805
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5806
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
5807
+ </svg>
5808
+ ),
5809
+ }
5810
+ return icons[name] || null
5811
+ }
5812
+
5813
+ function ThemeToggle() {
5814
+ return (
5815
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
5816
+ <button className="p-2 rounded-lg hover:bg-muted transition-colors" title="Light mode">
5817
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5818
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
5819
+ </svg>
5820
+ </button>
5821
+ <button className="p-2 rounded-lg hover:bg-muted transition-colors" title="Dark mode">
5822
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5823
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
5824
+ </svg>
5825
+ </button>
5826
+ </div>
5827
+ )
5828
+ }
5829
+ `;
5830
+ await writeFile(path18.join(appDir, "src/app/layout.tsx"), content);
5831
+ }
5832
+ async function generateHomePage(config, appDir) {
5833
+ const content = `export default function DesignSystemHome() {
5834
+ return (
5835
+ <div className="p-8 max-w-4xl">
5836
+ <header className="mb-12">
5837
+ <h1 className="text-display-01 text-foreground mb-4">
5838
+ ${config.name} Design System
5839
+ </h1>
5840
+ <p className="text-body-lg text-muted-foreground max-w-2xl">
5841
+ A comprehensive design system for building consistent, accessible, and
5842
+ beautiful interfaces across all ${config.name} products.
5843
+ </p>
5844
+ </header>
5845
+
5846
+ <section className="mb-12">
5847
+ <h2 className="text-h2 text-foreground mb-6">Quick Start</h2>
5848
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
5849
+ <QuickLink
5850
+ href="/colors"
5851
+ title="Colors"
5852
+ description="Brand colors, semantic tokens, and usage guidelines"
5853
+ icon="palette"
5854
+ />
5855
+ <QuickLink
5856
+ href="/typography"
5857
+ title="Typography"
5858
+ description="Font families, type scale, and text styles"
5859
+ icon="type"
5860
+ />
5861
+ <QuickLink
5862
+ href="/spacing"
5863
+ title="Spacing"
5864
+ description="Spacing scale, layout guidelines, and border radius"
5865
+ icon="ruler"
5866
+ />
5867
+ <QuickLink
5868
+ href="/components"
5869
+ title="Components"
5870
+ description="UI components with examples and code"
5871
+ icon="box"
5872
+ />
5873
+ </div>
5874
+ </section>
5875
+
5876
+ <section className="mb-12">
5877
+ <h2 className="text-h2 text-foreground mb-6">Design Principles</h2>
5878
+ <div className="space-y-4">
5879
+ <Principle
5880
+ title="Consistency"
5881
+ description="Use the defined design tokens consistently across all interfaces for a cohesive experience."
5882
+ />
5883
+ <Principle
5884
+ title="Accessibility"
5885
+ description="All color combinations meet WCAG AA contrast requirements. Design for everyone."
5886
+ />
5887
+ <Principle
5888
+ title="Simplicity"
5889
+ description="Keep interfaces clean and focused. Every element should serve a purpose."
5890
+ />
5891
+ <Principle
5892
+ title="Flexibility"
5893
+ description="Components are designed to be adaptable while maintaining visual harmony."
5894
+ />
5895
+ </div>
5896
+ </section>
5897
+
5898
+ <section>
5899
+ <h2 className="text-h2 text-foreground mb-6">Resources</h2>
5900
+ <div className="flex flex-wrap gap-4">
5901
+ <a
5902
+ href="/brand"
5903
+ className="inline-flex items-center gap-2 px-4 py-2 rounded-lg border border-border hover:bg-muted transition-colors text-sm"
5904
+ >
5905
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5906
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
5907
+ </svg>
5908
+ Brand Assets
5909
+ </a>
5910
+ <a
5911
+ href="/blocks"
5912
+ className="inline-flex items-center gap-2 px-4 py-2 rounded-lg border border-border hover:bg-muted transition-colors text-sm"
5913
+ >
5914
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5915
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6z" />
5916
+ </svg>
5917
+ UI Blocks
5918
+ </a>
5919
+ </div>
5920
+ </section>
5921
+ </div>
5922
+ )
5923
+ }
5924
+
5925
+ function QuickLink({
5926
+ href,
5927
+ title,
5928
+ description,
5929
+ icon,
5930
+ }: {
5931
+ href: string
5932
+ title: string
5933
+ description: string
5934
+ icon: string
5935
+ }) {
5936
+ const icons: Record<string, React.ReactNode> = {
5937
+ palette: (
5938
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5939
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" />
5940
+ </svg>
5941
+ ),
5942
+ type: (
5943
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5944
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4 6h16M4 12h16m-7 6h7" />
5945
+ </svg>
5946
+ ),
5947
+ ruler: (
5948
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5949
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
5950
+ </svg>
5951
+ ),
5952
+ box: (
5953
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5954
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
5955
+ </svg>
5956
+ ),
5957
+ }
5958
+
5959
+ return (
5960
+ <a
5961
+ href={href}
5962
+ className="group block p-6 rounded-xl border border-border hover:border-primary/30 hover:bg-muted/50 transition-all"
5963
+ >
5964
+ <div className="flex items-start gap-4">
5965
+ <div className="p-2 rounded-lg bg-primary/10 text-primary">
5966
+ {icons[icon]}
5967
+ </div>
5968
+ <div>
5969
+ <h3 className="text-h4 text-foreground group-hover:text-primary transition-colors">
5970
+ {title}
5971
+ </h3>
5972
+ <p className="text-body-sm text-muted-foreground mt-1">
5973
+ {description}
5974
+ </p>
5975
+ </div>
5976
+ </div>
5977
+ </a>
5978
+ )
5979
+ }
5980
+
5981
+ function Principle({
5982
+ title,
5983
+ description,
5984
+ }: {
5985
+ title: string
5986
+ description: string
5987
+ }) {
5988
+ return (
5989
+ <div className="p-4 rounded-lg border border-border">
5990
+ <h3 className="text-h4 text-foreground mb-1">{title}</h3>
5991
+ <p className="text-body-sm text-muted-foreground">{description}</p>
5992
+ </div>
5993
+ )
5994
+ }
5995
+ `;
5996
+ await writeFile(path18.join(appDir, "src/app/page.tsx"), content);
5997
+ }
5998
+ async function generateColorsPage(config, appDir) {
5999
+ const content = `export default function ColorsPage() {
6000
+ return (
6001
+ <div className="p-8 max-w-5xl">
6002
+ <header className="mb-12">
6003
+ <h1 className="text-display-01 text-foreground mb-4">Colors</h1>
6004
+ <p className="text-body-lg text-muted-foreground max-w-2xl">
6005
+ The color system is built on a foundation of brand colors
6006
+ with semantic tokens for consistent application across all interfaces.
6007
+ </p>
6008
+ </header>
6009
+
6010
+ <section className="mb-12">
6011
+ <h2 className="text-h2 text-foreground mb-6">Brand Colors</h2>
6012
+ <p className="text-body text-muted-foreground mb-6">
6013
+ Core brand colors used across all products.
6014
+ </p>
6015
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
6016
+ <ColorCard
6017
+ name="Primary"
6018
+ cssVar="--primary"
6019
+ usage="CTAs, buttons, links, interactive elements"
6020
+ />
6021
+ <ColorCard
6022
+ name="Secondary"
6023
+ cssVar="--secondary"
6024
+ usage="Secondary buttons, subtle backgrounds"
6025
+ />
6026
+ <ColorCard
6027
+ name="Accent"
6028
+ cssVar="--accent"
6029
+ usage="Highlights, badges, special elements"
6030
+ />
6031
+ </div>
6032
+ </section>
6033
+
6034
+ <section className="mb-12">
6035
+ <h2 className="text-h2 text-foreground mb-6">Semantic Colors</h2>
6036
+ <p className="text-body text-muted-foreground mb-6">
6037
+ Colors with specific meaning used for feedback and status indication.
6038
+ </p>
6039
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
6040
+ <ColorCard
6041
+ name="Success"
6042
+ cssVar="--success"
6043
+ usage="Success states, confirmations"
6044
+ />
6045
+ <ColorCard
6046
+ name="Warning"
6047
+ cssVar="--warning"
6048
+ usage="Warnings, caution states"
6049
+ />
6050
+ <ColorCard
6051
+ name="Destructive"
6052
+ cssVar="--destructive"
6053
+ usage="Errors, destructive actions"
6054
+ />
6055
+ </div>
6056
+ </section>
6057
+
6058
+ <section className="mb-12">
6059
+ <h2 className="text-h2 text-foreground mb-6">Background Colors</h2>
6060
+ <p className="text-body text-muted-foreground mb-6">
6061
+ Surface colors for different elevation levels and contexts.
6062
+ </p>
6063
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
6064
+ <ColorCard
6065
+ name="Background"
6066
+ cssVar="--background"
6067
+ usage="Page background"
6068
+ />
6069
+ <ColorCard
6070
+ name="Card"
6071
+ cssVar="--card"
6072
+ usage="Card surfaces"
6073
+ />
6074
+ <ColorCard
6075
+ name="Muted"
6076
+ cssVar="--muted"
6077
+ usage="Subtle backgrounds"
6078
+ />
6079
+ </div>
6080
+ </section>
6081
+
6082
+ <section className="mb-12">
6083
+ <h2 className="text-h2 text-foreground mb-6">Text Colors</h2>
6084
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
6085
+ <ColorCard
6086
+ name="Foreground"
6087
+ cssVar="--foreground"
6088
+ usage="Primary text, headings"
6089
+ />
6090
+ <ColorCard
6091
+ name="Muted Foreground"
6092
+ cssVar="--muted-foreground"
6093
+ usage="Secondary text, descriptions"
6094
+ />
6095
+ <ColorCard
6096
+ name="Primary"
6097
+ cssVar="--primary"
6098
+ usage="Links, emphasis"
6099
+ />
6100
+ </div>
6101
+ </section>
6102
+
6103
+ <section>
6104
+ <h2 className="text-h2 text-foreground mb-6">CSS Variables</h2>
6105
+ <p className="text-body text-muted-foreground mb-4">
6106
+ Use these CSS variables in your styles for consistent theming:
6107
+ </p>
6108
+ <div className="bg-muted rounded-lg p-4 overflow-x-auto">
6109
+ <pre className="text-sm text-foreground">
6110
+ {\`/* Primary colors */
6111
+ var(--primary)
6112
+ var(--secondary)
6113
+ var(--accent)
6114
+
6115
+ /* Backgrounds */
6116
+ var(--background)
6117
+ var(--card)
6118
+ var(--muted)
6119
+
6120
+ /* Text */
6121
+ var(--foreground)
6122
+ var(--muted-foreground)
6123
+
6124
+ /* Semantic */
6125
+ var(--success)
6126
+ var(--warning)
6127
+ var(--destructive)
6128
+
6129
+ /* Borders */
6130
+ var(--border)
6131
+ var(--ring)\`}
6132
+ </pre>
6133
+ </div>
6134
+ </section>
6135
+ </div>
6136
+ )
6137
+ }
6138
+
6139
+ function ColorCard({
6140
+ name,
6141
+ cssVar,
6142
+ usage,
6143
+ }: {
6144
+ name: string
6145
+ cssVar: string
6146
+ usage: string
6147
+ }) {
6148
+ return (
6149
+ <div className="rounded-xl border border-border overflow-hidden">
6150
+ <div
6151
+ className="h-24"
6152
+ style={{ backgroundColor: \`var(\${cssVar})\` }}
6153
+ />
6154
+ <div className="p-4 bg-card">
6155
+ <h3 className="text-h4 text-foreground mb-1">{name}</h3>
6156
+ <p className="text-xs text-muted-foreground mb-2">
6157
+ <code className="bg-muted px-1 rounded">{cssVar}</code>
6158
+ </p>
6159
+ <p className="text-xs text-muted-foreground">{usage}</p>
6160
+ </div>
6161
+ </div>
6162
+ )
6163
+ }
6164
+ `;
6165
+ await writeFile(path18.join(appDir, "src/app/colors/page.tsx"), content);
6166
+ }
6167
+ async function generateTypographyPage(config, appDir) {
6168
+ const { designSystem } = config;
6169
+ const headingFontName = designSystem.headingFont.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
6170
+ const bodyFontName = designSystem.bodyFont.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
6171
+ const content = `export default function TypographyPage() {
6172
+ return (
6173
+ <div className="p-8 max-w-5xl">
6174
+ <header className="mb-12">
6175
+ <h1 className="text-display-01 text-foreground mb-4">Typography</h1>
6176
+ <p className="text-body-lg text-muted-foreground max-w-2xl">
6177
+ The typography system uses ${headingFontName} for headings and ${bodyFontName}
6178
+ for body text, creating a modern and professional aesthetic.
6179
+ </p>
6180
+ </header>
6181
+
6182
+ <section className="mb-12">
6183
+ <h2 className="text-h2 text-foreground mb-6">Font Families</h2>
6184
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
6185
+ <FontFamilyCard
6186
+ name="${headingFontName}"
6187
+ variable="--font-heading"
6188
+ usage="Headings, display text"
6189
+ sample="The quick brown fox jumps over the lazy dog"
6190
+ />
6191
+ <FontFamilyCard
6192
+ name="${bodyFontName}"
6193
+ variable="--font-body"
6194
+ usage="Body text, UI elements"
6195
+ sample="The quick brown fox jumps over the lazy dog"
6196
+ />
6197
+ </div>
6198
+ </section>
6199
+
6200
+ <section className="mb-12">
6201
+ <h2 className="text-h2 text-foreground mb-6">Type Scale</h2>
6202
+ <p className="text-body text-muted-foreground mb-6">
6203
+ A comprehensive scale from display headings down to small body text.
6204
+ </p>
6205
+ <div className="space-y-6">
6206
+ <TypeScaleItem name="Display Hero" size="56px (3.5rem)" className="text-display-hero" />
6207
+ <TypeScaleItem name="Display 02" size="48px (3rem)" className="text-display-02" />
6208
+ <TypeScaleItem name="Display 01" size="40px (2.5rem)" className="text-display-01" />
6209
+ <TypeScaleItem name="Heading 1" size="32px (2rem)" className="text-h1" />
6210
+ <TypeScaleItem name="Heading 2" size="24px (1.5rem)" className="text-h2" />
6211
+ <TypeScaleItem name="Heading 3" size="20px (1.25rem)" className="text-h3" />
6212
+ <TypeScaleItem name="Heading 4" size="18px (1.125rem)" className="text-h4" />
6213
+ <TypeScaleItem name="Body Large" size="18px (1.125rem)" className="text-body-lg" />
6214
+ <TypeScaleItem name="Body" size="16px (1rem)" className="text-body" />
6215
+ <TypeScaleItem name="Body Small" size="14px (0.875rem)" className="text-body-sm" />
6216
+ </div>
6217
+ </section>
6218
+
6219
+ <section className="mb-12">
6220
+ <h2 className="text-h2 text-foreground mb-6">Font Weights</h2>
6221
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
6222
+ <WeightCard weight="400" name="Regular" />
6223
+ <WeightCard weight="500" name="Medium" />
6224
+ <WeightCard weight="600" name="Semibold" />
6225
+ <WeightCard weight="700" name="Bold" />
6226
+ </div>
6227
+ </section>
6228
+
6229
+ <section>
6230
+ <h2 className="text-h2 text-foreground mb-6">CSS Classes</h2>
6231
+ <p className="text-body text-muted-foreground mb-4">
6232
+ Use these utility classes for consistent typography:
6233
+ </p>
6234
+ <div className="bg-muted rounded-lg p-4 overflow-x-auto">
6235
+ <pre className="text-sm text-foreground">
6236
+ {\`/* Display & Headings */
6237
+ .text-display-hero /* 56px, weight 600 */
6238
+ .text-display-02 /* 48px, weight 600 */
6239
+ .text-display-01 /* 40px, weight 600 */
6240
+ .text-h1 /* 32px, weight 600 */
6241
+ .text-h2 /* 24px, weight 600 */
6242
+ .text-h3 /* 20px, weight 500 */
6243
+ .text-h4 /* 18px, weight 500 */
6244
+
6245
+ /* Body Text */
6246
+ .text-body-lg /* 18px, line-height 175% */
6247
+ .text-body /* 16px, line-height 150% */
6248
+ .text-body-sm /* 14px, line-height 150% */
6249
+
6250
+ /* Colors */
6251
+ .text-foreground /* Primary text color */
6252
+ .text-muted-foreground /* Secondary text color */
6253
+ .text-primary /* Brand primary color */\`}
6254
+ </pre>
6255
+ </div>
6256
+ </section>
6257
+ </div>
6258
+ )
6259
+ }
6260
+
6261
+ function FontFamilyCard({
6262
+ name,
6263
+ variable,
6264
+ usage,
6265
+ sample,
6266
+ }: {
6267
+ name: string
6268
+ variable: string
6269
+ usage: string
6270
+ sample: string
6271
+ }) {
6272
+ return (
6273
+ <div className="rounded-xl border border-border p-6">
6274
+ <h3 className="text-h3 text-foreground mb-2">{name}</h3>
6275
+ <p className="text-body-sm text-muted-foreground mb-4">{usage}</p>
6276
+ <div className="p-4 bg-muted rounded-lg mb-4">
6277
+ <p className="text-xl text-foreground">{sample}</p>
6278
+ </div>
6279
+ <code className="text-xs text-muted-foreground bg-muted px-2 py-1 rounded">
6280
+ {variable}
6281
+ </code>
6282
+ </div>
6283
+ )
6284
+ }
6285
+
6286
+ function TypeScaleItem({
6287
+ name,
6288
+ size,
6289
+ className,
6290
+ }: {
6291
+ name: string
6292
+ size: string
6293
+ className: string
6294
+ }) {
6295
+ return (
6296
+ <div className="flex flex-col md:flex-row md:items-center gap-4 pb-6 border-b border-border">
6297
+ <div className="md:w-48 shrink-0">
6298
+ <p className="text-body-sm font-medium text-foreground">{name}</p>
6299
+ <p className="text-xs text-muted-foreground">{size}</p>
6300
+ </div>
6301
+ <div className="flex-1 overflow-hidden">
6302
+ <p className={\`text-foreground truncate \${className}\`}>
6303
+ The quick brown fox jumps
6304
+ </p>
6305
+ </div>
6306
+ </div>
6307
+ )
6308
+ }
6309
+
6310
+ function WeightCard({ weight, name }: { weight: string; name: string }) {
6311
+ return (
6312
+ <div className="rounded-lg border border-border p-4 text-center">
6313
+ <p className="text-2xl text-foreground mb-2" style={{ fontWeight: weight }}>
6314
+ Aa
6315
+ </p>
6316
+ <p className="text-body-sm font-medium text-foreground">{name}</p>
6317
+ <p className="text-xs text-muted-foreground">{weight}</p>
6318
+ </div>
6319
+ )
6320
+ }
6321
+ `;
6322
+ await writeFile(path18.join(appDir, "src/app/typography/page.tsx"), content);
6323
+ }
6324
+ async function generateSpacingPage(config, appDir) {
6325
+ const { designSystem } = config;
6326
+ const radiusValue = radiusValues[designSystem.borderRadius];
6327
+ const content = `export default function SpacingPage() {
6328
+ return (
6329
+ <div className="p-8 max-w-5xl">
6330
+ <header className="mb-12">
6331
+ <h1 className="text-display-01 text-foreground mb-4">Spacing</h1>
6332
+ <p className="text-body-lg text-muted-foreground max-w-2xl">
6333
+ Consistent spacing creates visual harmony and improves readability.
6334
+ Uses Tailwind&apos;s default spacing scale with specific guidelines for common patterns.
6335
+ </p>
6336
+ </header>
6337
+
6338
+ <section className="mb-12">
6339
+ <h2 className="text-h2 text-foreground mb-6">Spacing Scale</h2>
6340
+ <p className="text-body text-muted-foreground mb-6">
6341
+ Based on a 4px base unit. Use these values for margins, padding, and gaps.
6342
+ </p>
6343
+ <div className="space-y-3">
6344
+ <SpacingRow value="1" pixels="4px" />
6345
+ <SpacingRow value="2" pixels="8px" />
6346
+ <SpacingRow value="3" pixels="12px" />
6347
+ <SpacingRow value="4" pixels="16px" />
6348
+ <SpacingRow value="6" pixels="24px" />
6349
+ <SpacingRow value="8" pixels="32px" />
6350
+ <SpacingRow value="12" pixels="48px" />
6351
+ <SpacingRow value="16" pixels="64px" />
6352
+ <SpacingRow value="24" pixels="96px" />
6353
+ </div>
6354
+ </section>
6355
+
6356
+ <section className="mb-12">
6357
+ <h2 className="text-h2 text-foreground mb-6">Border Radius</h2>
6358
+ <p className="text-body text-muted-foreground mb-6">
6359
+ Default border radius: <code className="bg-muted px-1 rounded">${radiusValue}</code>
6360
+ </p>
6361
+ <div className="grid grid-cols-2 md:grid-cols-5 gap-4">
6362
+ <RadiusCard name="XS" value="calc(var(--radius) * 0.5)" />
6363
+ <RadiusCard name="SM" value="calc(var(--radius) * 0.75)" />
6364
+ <RadiusCard name="Default" value="var(--radius)" />
6365
+ <RadiusCard name="LG" value="calc(var(--radius) * 1.5)" />
6366
+ <RadiusCard name="Pill" value="9999px" />
6367
+ </div>
6368
+ </section>
6369
+
6370
+ <section className="mb-12">
6371
+ <h2 className="text-h2 text-foreground mb-6">Common Patterns</h2>
6372
+ <div className="space-y-6">
6373
+ <PatternCard
6374
+ title="Page Padding"
6375
+ description="Standard page content padding"
6376
+ code="p-8 or px-8 py-12"
6377
+ />
6378
+ <PatternCard
6379
+ title="Section Spacing"
6380
+ description="Space between major sections"
6381
+ code="mb-12 or space-y-12"
6382
+ />
6383
+ <PatternCard
6384
+ title="Card Padding"
6385
+ description="Internal card padding"
6386
+ code="p-4 or p-6"
6387
+ />
6388
+ <PatternCard
6389
+ title="Grid Gap"
6390
+ description="Space between grid items"
6391
+ code="gap-4 or gap-6"
6392
+ />
6393
+ </div>
6394
+ </section>
6395
+
6396
+ <section>
6397
+ <h2 className="text-h2 text-foreground mb-6">CSS Variables</h2>
6398
+ <div className="bg-muted rounded-lg p-4 overflow-x-auto">
6399
+ <pre className="text-sm text-foreground">
6400
+ {\`/* Border Radius */
6401
+ --radius: ${radiusValue};
6402
+ --radius-xs: calc(var(--radius) * 0.5);
6403
+ --radius-sm: calc(var(--radius) * 0.75);
6404
+ --radius-lg: calc(var(--radius) * 1.5);
6405
+ --radius-pill: 9999px;\`}
6406
+ </pre>
6407
+ </div>
6408
+ </section>
6409
+ </div>
6410
+ )
6411
+ }
6412
+
6413
+ function SpacingRow({ value, pixels }: { value: string; pixels: string }) {
6414
+ return (
6415
+ <div className="flex items-center gap-4">
6416
+ <div className="w-16 text-right">
6417
+ <code className="text-sm text-muted-foreground">{value}</code>
6418
+ </div>
6419
+ <div className="flex-1 flex items-center gap-2">
6420
+ <div className="h-6 bg-primary rounded" style={{ width: pixels }} />
6421
+ <span className="text-sm text-muted-foreground">{pixels}</span>
6422
+ </div>
6423
+ </div>
6424
+ )
6425
+ }
6426
+
6427
+ function RadiusCard({ name, value }: { name: string; value: string }) {
6428
+ return (
6429
+ <div className="text-center">
6430
+ <div className="h-20 w-full bg-primary mb-3" style={{ borderRadius: value }} />
6431
+ <p className="text-body-sm font-medium text-foreground">{name}</p>
6432
+ <code className="text-xs text-muted-foreground">{value}</code>
6433
+ </div>
6434
+ )
6435
+ }
6436
+
6437
+ function PatternCard({
6438
+ title,
6439
+ description,
6440
+ code,
6441
+ }: {
6442
+ title: string
6443
+ description: string
6444
+ code: string
6445
+ }) {
6446
+ return (
6447
+ <div className="rounded-lg border border-border p-4">
6448
+ <h3 className="text-h4 text-foreground mb-1">{title}</h3>
6449
+ <p className="text-body-sm text-muted-foreground mb-2">{description}</p>
6450
+ <code className="text-xs text-primary bg-primary/10 px-2 py-1 rounded">{code}</code>
6451
+ </div>
6452
+ )
6453
+ }
6454
+ `;
6455
+ await writeFile(path18.join(appDir, "src/app/spacing/page.tsx"), content);
6456
+ }
6457
+ async function generateBrandPage(config, appDir) {
6458
+ const content = `export default function BrandPage() {
6459
+ return (
6460
+ <div className="p-8 max-w-5xl">
6461
+ <header className="mb-12">
6462
+ <h1 className="text-display-01 text-foreground mb-4">Brand</h1>
6463
+ <p className="text-body-lg text-muted-foreground max-w-2xl">
6464
+ Brand assets and guidelines for ${config.name}. Download logos, icons,
6465
+ and learn about proper usage.
6466
+ </p>
6467
+ </header>
6468
+
6469
+ <section className="mb-12">
6470
+ <h2 className="text-h2 text-foreground mb-6">Logo</h2>
6471
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
6472
+ <div className="rounded-xl border border-border p-8 bg-white flex items-center justify-center">
6473
+ <div className="h-16 w-16 rounded-xl bg-primary flex items-center justify-center text-primary-foreground text-2xl font-bold">
6474
+ ${config.name.charAt(0).toUpperCase()}
6475
+ </div>
6476
+ </div>
6477
+ <div className="rounded-xl border border-border p-8 bg-zinc-900 flex items-center justify-center">
6478
+ <div className="h-16 w-16 rounded-xl bg-primary flex items-center justify-center text-primary-foreground text-2xl font-bold">
6479
+ ${config.name.charAt(0).toUpperCase()}
6480
+ </div>
6481
+ </div>
6482
+ </div>
6483
+ <p className="text-body-sm text-muted-foreground mt-4">
6484
+ The logo should maintain adequate spacing from other elements. Minimum clear space
6485
+ equals the height of the logo mark.
6486
+ </p>
6487
+ </section>
6488
+
6489
+ <section className="mb-12">
6490
+ <h2 className="text-h2 text-foreground mb-6">Logo Usage</h2>
6491
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
6492
+ <UsageCard
6493
+ title="Do"
6494
+ items={[
6495
+ 'Use the logo on clean backgrounds',
6496
+ 'Maintain the aspect ratio',
6497
+ 'Use approved color variants',
6498
+ 'Keep adequate clear space',
6499
+ ]}
6500
+ type="do"
6501
+ />
6502
+ <UsageCard
6503
+ title="Don\\'t"
6504
+ items={[
6505
+ 'Stretch or distort the logo',
6506
+ 'Add effects like shadows or gradients',
6507
+ 'Place on busy backgrounds',
6508
+ 'Change the logo colors',
6509
+ ]}
6510
+ type="dont"
6511
+ />
6512
+ </div>
6513
+ </section>
6514
+
6515
+ <section>
6516
+ <h2 className="text-h2 text-foreground mb-6">Downloads</h2>
6517
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
6518
+ <DownloadCard
6519
+ title="Logo Pack"
6520
+ description="SVG, PNG in various sizes"
6521
+ icon="image"
6522
+ />
6523
+ <DownloadCard
6524
+ title="Icon Set"
6525
+ description="App icons for all platforms"
6526
+ icon="grid"
6527
+ />
6528
+ <DownloadCard
6529
+ title="Brand Guidelines"
6530
+ description="Complete brand documentation"
6531
+ icon="file"
6532
+ />
6533
+ </div>
6534
+ </section>
6535
+ </div>
6536
+ )
6537
+ }
6538
+
6539
+ function UsageCard({
6540
+ title,
6541
+ items,
6542
+ type,
6543
+ }: {
6544
+ title: string
6545
+ items: string[]
6546
+ type: 'do' | 'dont'
6547
+ }) {
6548
+ const borderColor = type === 'do' ? 'border-l-success' : 'border-l-destructive'
6549
+
6550
+ return (
6551
+ <div className={\`rounded-lg border border-border border-l-4 \${borderColor} p-4\`}>
6552
+ <h3 className="text-h4 text-foreground mb-3">{title}</h3>
6553
+ <ul className="space-y-2">
6554
+ {items.map((item, i) => (
6555
+ <li key={i} className="flex items-start gap-2 text-body-sm text-muted-foreground">
6556
+ <span className={type === 'do' ? 'text-success' : 'text-destructive'}>
6557
+ {type === 'do' ? '\u2713' : '\u2717'}
6558
+ </span>
6559
+ {item}
6560
+ </li>
6561
+ ))}
6562
+ </ul>
6563
+ </div>
6564
+ )
6565
+ }
6566
+
6567
+ function DownloadCard({
6568
+ title,
6569
+ description,
6570
+ icon,
6571
+ }: {
6572
+ title: string
6573
+ description: string
6574
+ icon: string
6575
+ }) {
6576
+ return (
6577
+ <button className="rounded-lg border border-border p-4 text-left hover:bg-muted transition-colors w-full">
6578
+ <div className="flex items-center gap-3">
6579
+ <div className="p-2 rounded-lg bg-primary/10 text-primary">
6580
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6581
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
6582
+ </svg>
6583
+ </div>
6584
+ <div>
6585
+ <h3 className="text-h4 text-foreground">{title}</h3>
6586
+ <p className="text-body-sm text-muted-foreground">{description}</p>
6587
+ </div>
6588
+ </div>
6589
+ </button>
6590
+ )
6591
+ }
6592
+ `;
6593
+ await writeFile(path18.join(appDir, "src/app/brand/page.tsx"), content);
6594
+ }
6595
+ async function generateBlocksPage(appDir) {
6596
+ const content = `export default function BlocksPage() {
6597
+ return (
6598
+ <div className="p-8 max-w-5xl">
6599
+ <header className="mb-12">
6600
+ <h1 className="text-display-01 text-foreground mb-4">Blocks</h1>
6601
+ <p className="text-body-lg text-muted-foreground max-w-2xl">
6602
+ Pre-built UI blocks for common patterns. Copy and paste into your projects.
6603
+ </p>
6604
+ </header>
6605
+
6606
+ <section className="mb-12">
6607
+ <h2 className="text-h2 text-foreground mb-6">Marketing</h2>
6608
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
6609
+ <BlockCard title="Hero" description="Hero sections with CTA" />
6610
+ <BlockCard title="Features" description="Feature grids and lists" />
6611
+ <BlockCard title="Pricing" description="Pricing tables and cards" />
6612
+ <BlockCard title="Testimonials" description="Customer testimonials" />
6613
+ <BlockCard title="CTA" description="Call-to-action sections" />
6614
+ <BlockCard title="FAQ" description="FAQ accordions" />
6615
+ </div>
6616
+ </section>
6617
+
6618
+ <section className="mb-12">
6619
+ <h2 className="text-h2 text-foreground mb-6">Dashboard</h2>
6620
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
6621
+ <BlockCard title="Stats" description="Metric and stat cards" />
6622
+ <BlockCard title="Tables" description="Data tables with actions" />
6623
+ <BlockCard title="Charts" description="Chart components" />
6624
+ <BlockCard title="Sidebar" description="Navigation sidebars" />
6625
+ <BlockCard title="Header" description="Dashboard headers" />
6626
+ </div>
6627
+ </section>
6628
+
6629
+ <section>
6630
+ <h2 className="text-h2 text-foreground mb-6">Widgets</h2>
6631
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
6632
+ <BlockCard title="Chat" description="Chat windows and bubbles" />
6633
+ <BlockCard title="Forms" description="Contact and input forms" />
6634
+ <BlockCard title="Cards" description="Content cards" />
6635
+ </div>
6636
+ </section>
6637
+ </div>
6638
+ )
6639
+ }
6640
+
6641
+ function BlockCard({ title, description }: { title: string; description: string }) {
6642
+ return (
6643
+ <a
6644
+ href="#"
6645
+ className="group block rounded-lg border border-border p-4 hover:border-primary/30 hover:bg-muted/50 transition-all"
6646
+ >
6647
+ <h3 className="text-h4 text-foreground group-hover:text-primary transition-colors">
6648
+ {title}
6649
+ </h3>
6650
+ <p className="text-body-sm text-muted-foreground mt-1">{description}</p>
6651
+ </a>
6652
+ )
6653
+ }
6654
+ `;
6655
+ await writeFile(path18.join(appDir, "src/app/blocks/page.tsx"), content);
6656
+ }
6657
+ async function generateComponentsPage(appDir) {
6658
+ const content = `export default function ComponentsPage() {
6659
+ return (
6660
+ <div className="p-8 max-w-5xl">
6661
+ <header className="mb-12">
6662
+ <h1 className="text-display-01 text-foreground mb-4">Components</h1>
6663
+ <p className="text-body-lg text-muted-foreground max-w-2xl">
6664
+ A collection of reusable UI components built with shadcn/ui.
6665
+ Browse the sidebar to explore individual components.
6666
+ </p>
6667
+ </header>
6668
+
6669
+ <section className="mb-12">
6670
+ <h2 className="text-h2 text-foreground mb-6">Getting Started</h2>
6671
+ <div className="bg-muted rounded-lg p-6">
6672
+ <p className="text-body text-muted-foreground mb-4">
6673
+ Components are available from the @repo/ui package. Import them directly:
6674
+ </p>
6675
+ <pre className="text-sm text-foreground bg-background rounded p-4 overflow-x-auto">
6676
+ {\`import { Button } from '@repo/ui/button'
6677
+ import { Card, CardHeader, CardContent } from '@repo/ui/card'\`}
6678
+ </pre>
6679
+ </div>
6680
+ </section>
6681
+
6682
+ <section>
6683
+ <h2 className="text-h2 text-foreground mb-6">Categories</h2>
6684
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
6685
+ <CategoryCard
6686
+ title="Inputs"
6687
+ components={['Button', 'Input', 'Textarea', 'Select', 'Checkbox', 'Radio Group', 'Switch', 'Slider']}
6688
+ />
6689
+ <CategoryCard
6690
+ title="Display"
6691
+ components={['Card', 'Badge', 'Avatar', 'Alert', 'Progress', 'Skeleton', 'Table']}
6692
+ />
6693
+ <CategoryCard
6694
+ title="Navigation"
6695
+ components={['Tabs', 'Breadcrumb', 'Pagination', 'Navigation Menu', 'Sidebar']}
6696
+ />
6697
+ <CategoryCard
6698
+ title="Overlays"
6699
+ components={['Dialog', 'Drawer', 'Sheet', 'Popover', 'Tooltip', 'Dropdown Menu']}
6700
+ />
6701
+ </div>
6702
+ </section>
6703
+ </div>
6704
+ )
6705
+ }
6706
+
6707
+ function CategoryCard({
6708
+ title,
6709
+ components,
6710
+ }: {
6711
+ title: string
6712
+ components: string[]
6713
+ }) {
6714
+ return (
6715
+ <div className="rounded-xl border border-border p-6">
6716
+ <h3 className="text-h3 text-foreground mb-4">{title}</h3>
6717
+ <div className="flex flex-wrap gap-2">
6718
+ {components.map((component) => {
6719
+ const slug = component.toLowerCase().replace(/\\s+/g, '-')
6720
+ return (
6721
+ <a
6722
+ key={slug}
6723
+ href={\`/components/\${slug}\`}
6724
+ className="px-3 py-1 rounded-full bg-muted text-sm text-muted-foreground hover:text-foreground hover:bg-muted/80 transition-colors"
6725
+ >
6726
+ {component}
6727
+ </a>
6728
+ )
6729
+ })}
6730
+ </div>
6731
+ </div>
6732
+ )
6733
+ }
6734
+ `;
6735
+ await writeFile(path18.join(appDir, "src/app/components/page.tsx"), content);
6736
+ }
6737
+ async function generateUtils(appDir) {
6738
+ const content = `import { clsx, type ClassValue } from 'clsx'
6739
+ import { twMerge } from 'tailwind-merge'
6740
+
6741
+ export function cn(...inputs: ClassValue[]) {
6742
+ return twMerge(clsx(inputs))
6743
+ }
6744
+ `;
6745
+ await writeFile(path18.join(appDir, "src/lib/utils.ts"), content);
6746
+ }
6747
+
5012
6748
  // src/generators/index.ts
5013
6749
  async function generateProject(config) {
5014
6750
  const spinner = ora();
@@ -5049,7 +6785,7 @@ async function generateSingleProject(config, spinner) {
5049
6785
  await generateShadcn(config, targetDir);
5050
6786
  spinner.succeed("shadcn/ui configured");
5051
6787
  spinner.start("Setting up Convex...");
5052
- await generateConvex(config, path18.join(targetDir, "convex"));
6788
+ await generateConvex(config, path19.join(targetDir, "convex"));
5053
6789
  spinner.succeed("Convex configured");
5054
6790
  spinner.start("Configuring Better-Auth...");
5055
6791
  await generateBetterAuth(config, targetDir);
@@ -5092,7 +6828,7 @@ async function generateMonorepoProject(config, spinner) {
5092
6828
  spinner.start("Creating shared UI package...");
5093
6829
  await generateUIPackage(config, targetDir);
5094
6830
  spinner.succeed("Shared UI package created");
5095
- const webDir = path18.join(targetDir, "apps/web");
6831
+ const webDir = path19.join(targetDir, "apps/web");
5096
6832
  spinner.start("Generating web application...");
5097
6833
  await generateBaseNextjs(config, webDir);
5098
6834
  await generateTailwind(config, webDir);
@@ -5102,10 +6838,10 @@ async function generateMonorepoProject(config, spinner) {
5102
6838
  await generateEmail(config, webDir);
5103
6839
  await updateWebTsConfig(webDir);
5104
6840
  spinner.succeed("Web application generated");
5105
- const backendDir = path18.join(targetDir, "packages/backend");
6841
+ const backendDir = path19.join(targetDir, "packages/backend");
5106
6842
  spinner.start("Setting up Convex backend...");
5107
6843
  await ensureDir(backendDir);
5108
- await generateConvex(config, path18.join(backendDir, "convex"));
6844
+ await generateConvex(config, path19.join(backendDir, "convex"));
5109
6845
  spinner.succeed("Convex backend configured");
5110
6846
  if (config.integrations.analytics !== "none") {
5111
6847
  spinner.start(`Setting up ${config.integrations.analytics} analytics...`);
@@ -5128,7 +6864,7 @@ async function generateMonorepoProject(config, spinner) {
5128
6864
  spinner.succeed(`${config.integrations.monitoring} monitoring configured`);
5129
6865
  }
5130
6866
  if (config.marketingSite !== "none") {
5131
- const marketingDir = path18.join(targetDir, "apps/marketing");
6867
+ const marketingDir = path19.join(targetDir, "apps/marketing");
5132
6868
  spinner.start(`Generating ${config.marketingSite} marketing site...`);
5133
6869
  if (config.marketingSite === "payload") {
5134
6870
  await generatePayload(config, marketingDir);
@@ -5140,11 +6876,14 @@ async function generateMonorepoProject(config, spinner) {
5140
6876
  spinner.succeed(`${config.marketingSite} marketing site generated`);
5141
6877
  }
5142
6878
  if (config.includeDocs) {
5143
- const docsDir = path18.join(targetDir, "apps/docs");
6879
+ const docsDir = path19.join(targetDir, "apps/docs");
5144
6880
  spinner.start("Generating Fumadocs documentation site...");
5145
6881
  await generateFumadocs(config, docsDir);
5146
6882
  spinner.succeed("Fumadocs documentation site generated");
5147
6883
  }
6884
+ spinner.start("Generating design system app...");
6885
+ await generateDesignSystemApp(config, targetDir);
6886
+ spinner.succeed("Design system app generated");
5148
6887
  await generateGitignore(targetDir);
5149
6888
  }
5150
6889
  async function runPostGenerationSteps(config, spinner) {
@@ -5158,7 +6897,7 @@ async function runPostGenerationSteps(config, spinner) {
5158
6897
  }
5159
6898
  spinner.start("Installing shadcn/ui components...");
5160
6899
  try {
5161
- const shadcnDir = config.structure === "monorepo" ? path18.join(targetDir, "packages/ui") : targetDir;
6900
+ const shadcnDir = config.structure === "monorepo" ? path19.join(targetDir, "packages/ui") : targetDir;
5162
6901
  await runShadcnAdd(shadcnDir);
5163
6902
  spinner.succeed("shadcn/ui components installed");
5164
6903
  } catch (error) {
@@ -5218,7 +6957,7 @@ async function generateBiomeConfig(targetDir) {
5218
6957
  }
5219
6958
  };
5220
6959
  await writeFile(
5221
- path18.join(targetDir, "biome.json"),
6960
+ path19.join(targetDir, "biome.json"),
5222
6961
  JSON.stringify(biomeJson, null, 2)
5223
6962
  );
5224
6963
  }
@@ -5269,13 +7008,13 @@ yarn-error.log*
5269
7008
  *.pem
5270
7009
  .cache
5271
7010
  `;
5272
- await writeFile(path18.join(targetDir, ".gitignore"), gitignoreContent);
7011
+ await writeFile(path19.join(targetDir, ".gitignore"), gitignoreContent);
5273
7012
  }
5274
7013
  async function generateHuskyHooks(targetDir) {
5275
7014
  const preCommitContent = `pnpm lint-staged
5276
7015
  `;
5277
- await ensureDir(path18.join(targetDir, ".husky"));
5278
- await writeFile(path18.join(targetDir, ".husky/pre-commit"), preCommitContent);
7016
+ await ensureDir(path19.join(targetDir, ".husky"));
7017
+ await writeFile(path19.join(targetDir, ".husky/pre-commit"), preCommitContent);
5279
7018
  }
5280
7019
  async function updateWebTsConfig(webDir) {
5281
7020
  const tsConfig = {
@@ -5289,14 +7028,14 @@ async function updateWebTsConfig(webDir) {
5289
7028
  exclude: ["node_modules"]
5290
7029
  };
5291
7030
  await writeFile(
5292
- path18.join(webDir, "tsconfig.json"),
7031
+ path19.join(webDir, "tsconfig.json"),
5293
7032
  JSON.stringify(tsConfig, null, 2)
5294
7033
  );
5295
7034
  }
5296
7035
  async function generateNextjsMarketing(config, marketingDir) {
5297
- await ensureDir(path18.join(marketingDir, "src/app"));
5298
- await ensureDir(path18.join(marketingDir, "src/components"));
5299
- await ensureDir(path18.join(marketingDir, "public"));
7036
+ await ensureDir(path19.join(marketingDir, "src/app"));
7037
+ await ensureDir(path19.join(marketingDir, "src/components"));
7038
+ await ensureDir(path19.join(marketingDir, "public"));
5300
7039
  const packageJson = {
5301
7040
  name: "@repo/marketing",
5302
7041
  version: "0.1.0",
@@ -5327,7 +7066,7 @@ async function generateNextjsMarketing(config, marketingDir) {
5327
7066
  }
5328
7067
  };
5329
7068
  await writeFile(
5330
- path18.join(marketingDir, "package.json"),
7069
+ path19.join(marketingDir, "package.json"),
5331
7070
  JSON.stringify(packageJson, null, 2)
5332
7071
  );
5333
7072
  const homePageContent = `export default function HomePage() {
@@ -5350,7 +7089,7 @@ async function generateNextjsMarketing(config, marketingDir) {
5350
7089
  }
5351
7090
  `;
5352
7091
  await writeFile(
5353
- path18.join(marketingDir, "src/app/page.tsx"),
7092
+ path19.join(marketingDir, "src/app/page.tsx"),
5354
7093
  homePageContent
5355
7094
  );
5356
7095
  const layoutContent = `import type { Metadata } from 'next'
@@ -5374,7 +7113,7 @@ export default function RootLayout({
5374
7113
  }
5375
7114
  `;
5376
7115
  await writeFile(
5377
- path18.join(marketingDir, "src/app/layout.tsx"),
7116
+ path19.join(marketingDir, "src/app/layout.tsx"),
5378
7117
  layoutContent
5379
7118
  );
5380
7119
  const globalsCss = `@import "tailwindcss";
@@ -5386,7 +7125,7 @@ export default function RootLayout({
5386
7125
  }
5387
7126
  `;
5388
7127
  await writeFile(
5389
- path18.join(marketingDir, "src/app/globals.css"),
7128
+ path19.join(marketingDir, "src/app/globals.css"),
5390
7129
  globalsCss
5391
7130
  );
5392
7131
  const tsConfig = {
@@ -5400,7 +7139,7 @@ export default function RootLayout({
5400
7139
  exclude: ["node_modules"]
5401
7140
  };
5402
7141
  await writeFile(
5403
- path18.join(marketingDir, "tsconfig.json"),
7142
+ path19.join(marketingDir, "tsconfig.json"),
5404
7143
  JSON.stringify(tsConfig, null, 2)
5405
7144
  );
5406
7145
  const nextConfig = `import type { NextConfig } from 'next'
@@ -5411,14 +7150,14 @@ const nextConfig: NextConfig = {
5411
7150
 
5412
7151
  export default nextConfig
5413
7152
  `;
5414
- await writeFile(path18.join(marketingDir, "next.config.ts"), nextConfig);
7153
+ await writeFile(path19.join(marketingDir, "next.config.ts"), nextConfig);
5415
7154
  const postcssConfig = `export default {
5416
7155
  plugins: {
5417
7156
  '@tailwindcss/postcss': {},
5418
7157
  },
5419
7158
  }
5420
7159
  `;
5421
- await writeFile(path18.join(marketingDir, "postcss.config.mjs"), postcssConfig);
7160
+ await writeFile(path19.join(marketingDir, "postcss.config.mjs"), postcssConfig);
5422
7161
  }
5423
7162
  function displaySuccessMessage(config) {
5424
7163
  const apps = ["web"];
@@ -5429,6 +7168,7 @@ function displaySuccessMessage(config) {
5429
7168
  if (config.includeDocs) {
5430
7169
  apps.push("docs");
5431
7170
  }
7171
+ apps.push("design-system");
5432
7172
  }
5433
7173
  console.log();
5434
7174
  p6.outro(pc2.green("Project created successfully!"));