bsmnt 0.0.2 → 0.1.1
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/.github/workflows/release.yml +2 -0
- package/CHANGELOG.md +31 -0
- package/CLAUDE.md +42 -24
- package/README.md +33 -12
- package/biome.json +1 -0
- package/bun.lock +2 -1
- package/docs/architecture.drawio +250 -0
- package/docs/architecture.mermaid +85 -0
- package/package.json +42 -42
- package/{bin → packages/cli/bin}/index.js +28 -31
- package/packages/cli/package.json +16 -0
- package/{src → packages/cli/src}/commands/add-integration.js +22 -37
- package/{src → packages/cli/src}/commands/create.js +125 -131
- package/packages/create-basement-app/integrations/sanity/config.js +46 -0
- package/{src → packages/create-basement-app/integrations/sanity}/mergers/check-integration-merger.js +1 -1
- package/{src → packages/create-basement-app/integrations/sanity}/mergers/layout-merger.js +1 -1
- package/{src → packages/create-basement-app/integrations/sanity}/mergers/sitemap-merger.js +1 -1
- package/packages/create-basement-app/package.json +10 -0
- package/packages/create-basement-app/src/configs/animations.js +28 -0
- package/packages/create-basement-app/src/index.js +15 -0
- package/packages/create-basement-app/src/mergers/check-integration-merger.js +105 -0
- package/{src → packages/create-basement-app/src}/mergers/config.js +5 -33
- package/{src → packages/create-basement-app/src}/mergers/index.js +89 -98
- package/packages/create-basement-app/src/mergers/layout-merger.js +223 -0
- package/packages/create-basement-app/src/mergers/sitemap-merger.js +121 -0
- package/packages/create-basement-app/template-hooks/config.js +38 -0
- package/packages/create-basement-app/templates/default/.biome/plugins/README.md +21 -0
- package/packages/create-basement-app/templates/default/.biome/plugins/no-anchor-element.grit +12 -0
- package/packages/create-basement-app/templates/default/.biome/plugins/no-relative-parent-imports.grit +10 -0
- package/packages/create-basement-app/templates/default/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
- package/packages/create-basement-app/templates/default/.cursor/rules/README.md +184 -0
- package/packages/create-basement-app/templates/default/.cursor/rules/architecture.mdc +437 -0
- package/packages/create-basement-app/templates/default/.cursor/rules/components.mdc +436 -0
- package/packages/create-basement-app/templates/default/.cursor/rules/integrations.mdc +447 -0
- package/packages/create-basement-app/templates/default/.cursor/rules/main.mdc +278 -0
- package/packages/create-basement-app/templates/default/.cursor/rules/styling.mdc +433 -0
- package/packages/create-basement-app/templates/default/.editorconfig +40 -0
- package/packages/create-basement-app/templates/default/.env.example +81 -0
- package/packages/create-basement-app/templates/default/.gitattributes +19 -0
- package/packages/create-basement-app/templates/default/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- package/packages/create-basement-app/templates/default/.github/workflows/lighthouse-to-slack.yml +136 -0
- package/packages/create-basement-app/templates/default/.vscode/extensions.json +20 -0
- package/packages/create-basement-app/templates/default/.vscode/settings.json +105 -0
- package/packages/create-basement-app/templates/default/README.md +221 -0
- package/packages/create-basement-app/templates/default/_gitignore +67 -0
- package/packages/create-basement-app/templates/default/app/favicon.ico +0 -0
- package/packages/create-basement-app/templates/default/app/layout.tsx +104 -0
- package/packages/create-basement-app/templates/default/app/page.tsx +275 -0
- package/packages/create-basement-app/templates/default/app/robots.ts +15 -0
- package/packages/create-basement-app/templates/default/app/sitemap.ts +16 -0
- package/packages/create-basement-app/templates/default/biome.json +250 -0
- package/packages/create-basement-app/templates/default/components/basement.svg +1 -0
- package/packages/create-basement-app/templates/default/components/layout/footer/index.tsx +27 -0
- package/packages/create-basement-app/templates/default/components/layout/header/index.tsx +11 -0
- package/packages/create-basement-app/templates/default/components/layout/theme/index.tsx +66 -0
- package/packages/create-basement-app/templates/default/components/layout/wrapper/index.tsx +65 -0
- package/packages/create-basement-app/templates/default/components/ui/README.md +77 -0
- package/packages/create-basement-app/templates/default/components/ui/image/README.md +37 -0
- package/packages/create-basement-app/templates/default/components/ui/image/index.tsx +224 -0
- package/packages/create-basement-app/templates/default/components/ui/link/index.tsx +146 -0
- package/packages/create-basement-app/templates/default/lib/README.md +33 -0
- package/packages/create-basement-app/templates/default/lib/hooks/index.ts +12 -0
- package/packages/create-basement-app/templates/default/lib/hooks/use-device-detection.ts +81 -0
- package/packages/create-basement-app/templates/default/lib/hooks/use-media-breakpoint.ts +15 -0
- package/packages/create-basement-app/templates/default/lib/hooks/use-prefetch.ts +74 -0
- package/packages/create-basement-app/templates/default/lib/scripts/dev.ts +52 -0
- package/packages/create-basement-app/templates/default/lib/scripts/generate-component.ts +322 -0
- package/packages/create-basement-app/templates/default/lib/scripts/generate-page.ts +193 -0
- package/packages/create-basement-app/templates/default/lib/scripts/generate.ts +79 -0
- package/packages/create-basement-app/templates/default/lib/scripts/utils.ts +246 -0
- package/packages/create-basement-app/templates/default/lib/store/app.ts +11 -0
- package/packages/create-basement-app/templates/default/lib/store/index.ts +11 -0
- package/packages/create-basement-app/templates/default/lib/styles/README.md +64 -0
- package/packages/create-basement-app/templates/default/lib/styles/cn.ts +7 -0
- package/packages/create-basement-app/templates/default/lib/styles/colors.ts +63 -0
- package/packages/create-basement-app/templates/default/lib/styles/config.ts +34 -0
- package/packages/create-basement-app/templates/default/lib/styles/css/global.css +85 -0
- package/packages/create-basement-app/templates/default/lib/styles/css/index.css +6 -0
- package/packages/create-basement-app/templates/default/lib/styles/css/reset.css +166 -0
- package/packages/create-basement-app/templates/default/lib/styles/css/root.css +68 -0
- package/packages/create-basement-app/templates/default/lib/styles/css/tailwind.css +132 -0
- package/packages/create-basement-app/templates/default/lib/styles/easings.ts +21 -0
- package/packages/create-basement-app/templates/default/lib/styles/fonts.ts +28 -0
- package/packages/create-basement-app/templates/default/lib/styles/index.ts +12 -0
- package/packages/create-basement-app/templates/default/lib/styles/layout.mjs +27 -0
- package/packages/create-basement-app/templates/default/lib/styles/scripts/README.md +29 -0
- package/packages/create-basement-app/templates/default/lib/styles/scripts/generate-root.ts +57 -0
- package/packages/create-basement-app/templates/default/lib/styles/scripts/generate-tailwind.ts +162 -0
- package/packages/create-basement-app/templates/default/lib/styles/scripts/postcss-functions.mjs +168 -0
- package/packages/create-basement-app/templates/default/lib/styles/scripts/setup-styles.ts +24 -0
- package/packages/create-basement-app/templates/default/lib/styles/scripts/utils.ts +20 -0
- package/packages/create-basement-app/templates/default/lib/styles/typography.ts +36 -0
- package/packages/create-basement-app/templates/default/lib/utils/README.md +40 -0
- package/packages/create-basement-app/templates/default/lib/utils/css.d.ts +21 -0
- package/packages/create-basement-app/templates/default/lib/utils/easings.ts +240 -0
- package/packages/create-basement-app/templates/default/lib/utils/fetch.ts +84 -0
- package/packages/create-basement-app/templates/default/lib/utils/math.test.ts +221 -0
- package/packages/create-basement-app/templates/default/lib/utils/math.ts +236 -0
- package/packages/create-basement-app/templates/default/lib/utils/metadata.ts +126 -0
- package/packages/create-basement-app/templates/default/lib/utils/strings.test.ts +166 -0
- package/packages/create-basement-app/templates/default/lib/utils/strings.ts +246 -0
- package/packages/create-basement-app/templates/default/lib/utils/types.d.ts +15 -0
- package/packages/create-basement-app/templates/default/lib/utils/viewport.test.ts +256 -0
- package/packages/create-basement-app/templates/default/lib/utils/viewport.ts +193 -0
- package/packages/create-basement-app/templates/default/next.config.ts +142 -0
- package/packages/create-basement-app/templates/default/package.json +62 -0
- package/packages/create-basement-app/templates/default/postcss.config.mjs +42 -0
- package/packages/create-basement-app/templates/default/public/fonts/geist/Geist-Mono.woff2 +0 -0
- package/packages/create-basement-app/templates/default/tsconfig.json +43 -0
- package/packages/create-basement-app/templates/experiment/.biome/plugins/README.md +21 -0
- package/packages/create-basement-app/templates/experiment/.biome/plugins/no-anchor-element.grit +12 -0
- package/packages/create-basement-app/templates/experiment/.biome/plugins/no-relative-parent-imports.grit +10 -0
- package/packages/create-basement-app/templates/experiment/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
- package/packages/create-basement-app/templates/experiment/.cursor/rules/README.md +184 -0
- package/packages/create-basement-app/templates/experiment/.cursor/rules/architecture.mdc +437 -0
- package/packages/create-basement-app/templates/experiment/.cursor/rules/components.mdc +436 -0
- package/packages/create-basement-app/templates/experiment/.cursor/rules/integrations.mdc +447 -0
- package/packages/create-basement-app/templates/experiment/.cursor/rules/main.mdc +278 -0
- package/packages/create-basement-app/templates/experiment/.cursor/rules/styling.mdc +433 -0
- package/packages/create-basement-app/templates/experiment/.editorconfig +40 -0
- package/packages/create-basement-app/templates/experiment/.env.example +81 -0
- package/packages/create-basement-app/templates/experiment/.gitattributes +19 -0
- package/packages/create-basement-app/templates/experiment/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- package/packages/create-basement-app/templates/experiment/.github/workflows/lighthouse-to-slack.yml +136 -0
- package/packages/create-basement-app/templates/experiment/.vscode/extensions.json +20 -0
- package/packages/create-basement-app/templates/experiment/.vscode/settings.json +105 -0
- package/packages/create-basement-app/templates/experiment/README.md +221 -0
- package/packages/create-basement-app/templates/experiment/_gitignore +67 -0
- package/packages/create-basement-app/templates/experiment/app/favicon.ico +0 -0
- package/packages/create-basement-app/templates/experiment/app/layout.tsx +104 -0
- package/packages/create-basement-app/templates/experiment/app/page.tsx +275 -0
- package/packages/create-basement-app/templates/experiment/app/robots.ts +15 -0
- package/packages/create-basement-app/templates/experiment/app/sitemap.ts +16 -0
- package/packages/create-basement-app/templates/experiment/biome.json +250 -0
- package/packages/create-basement-app/templates/experiment/components/basement.svg +1 -0
- package/packages/create-basement-app/templates/experiment/components/layout/footer/index.tsx +27 -0
- package/packages/create-basement-app/templates/experiment/components/layout/header/index.tsx +58 -0
- package/packages/create-basement-app/templates/experiment/components/layout/navigation-menu.tsx +127 -0
- package/packages/create-basement-app/templates/experiment/components/layout/theme/index.tsx +66 -0
- package/packages/create-basement-app/templates/experiment/components/layout/wrapper/index.tsx +65 -0
- package/packages/create-basement-app/templates/experiment/components/ui/README.md +77 -0
- package/packages/create-basement-app/templates/experiment/components/ui/image/README.md +37 -0
- package/packages/create-basement-app/templates/experiment/components/ui/image/index.tsx +224 -0
- package/packages/create-basement-app/templates/experiment/components/ui/link/index.tsx +146 -0
- package/packages/create-basement-app/templates/experiment/lib/README.md +33 -0
- package/packages/create-basement-app/templates/experiment/lib/constants.ts +12 -0
- package/packages/create-basement-app/templates/experiment/lib/hooks/index.ts +12 -0
- package/packages/create-basement-app/templates/experiment/lib/hooks/use-device-detection.ts +81 -0
- package/packages/create-basement-app/templates/experiment/lib/hooks/use-media-breakpoint.ts +15 -0
- package/packages/create-basement-app/templates/experiment/lib/hooks/use-prefetch.ts +74 -0
- package/packages/create-basement-app/templates/experiment/lib/integrations/.gitkeep +0 -0
- package/packages/create-basement-app/templates/experiment/lib/scripts/dev.ts +52 -0
- package/packages/create-basement-app/templates/experiment/lib/scripts/generate-component.ts +322 -0
- package/packages/create-basement-app/templates/experiment/lib/scripts/generate-page.ts +193 -0
- package/packages/create-basement-app/templates/experiment/lib/scripts/generate.ts +79 -0
- package/packages/create-basement-app/templates/experiment/lib/scripts/utils.ts +246 -0
- package/packages/create-basement-app/templates/experiment/lib/store/app.ts +11 -0
- package/packages/create-basement-app/templates/experiment/lib/store/index.ts +11 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/README.md +64 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/cn.ts +7 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/colors.ts +63 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/config.ts +34 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/css/global.css +85 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/css/index.css +6 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/css/reset.css +166 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/css/root.css +68 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/css/tailwind.css +132 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/easings.ts +21 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/fonts.ts +28 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/index.ts +12 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/layout.mjs +27 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/scripts/README.md +29 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/scripts/generate-root.ts +57 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/scripts/generate-tailwind.ts +162 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/scripts/postcss-functions.mjs +168 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/scripts/setup-styles.ts +24 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/scripts/utils.ts +20 -0
- package/packages/create-basement-app/templates/experiment/lib/styles/typography.ts +36 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/README.md +40 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/css.d.ts +21 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/easings.ts +240 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/fetch.ts +84 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/math.test.ts +221 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/math.ts +236 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/metadata.ts +126 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/strings.test.ts +166 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/strings.ts +246 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/types.d.ts +15 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/viewport.test.ts +256 -0
- package/packages/create-basement-app/templates/experiment/lib/utils/viewport.ts +193 -0
- package/packages/create-basement-app/templates/experiment/next.config.ts +142 -0
- package/packages/create-basement-app/templates/experiment/package.json +69 -0
- package/packages/create-basement-app/templates/experiment/postcss.config.mjs +42 -0
- package/packages/create-basement-app/templates/experiment/public/fonts/geist/Geist-Mono.woff2 +0 -0
- package/packages/create-basement-app/templates/experiment/tsconfig.json +43 -0
- package/packages/create-basement-app/templates/webgl/.biome/plugins/README.md +21 -0
- package/packages/create-basement-app/templates/webgl/.biome/plugins/no-anchor-element.grit +12 -0
- package/packages/create-basement-app/templates/webgl/.biome/plugins/no-relative-parent-imports.grit +10 -0
- package/packages/create-basement-app/templates/webgl/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
- package/packages/create-basement-app/templates/webgl/.cursor/rules/README.md +184 -0
- package/packages/create-basement-app/templates/webgl/.cursor/rules/architecture.mdc +437 -0
- package/packages/create-basement-app/templates/webgl/.cursor/rules/components.mdc +436 -0
- package/packages/create-basement-app/templates/webgl/.cursor/rules/integrations.mdc +447 -0
- package/packages/create-basement-app/templates/webgl/.cursor/rules/main.mdc +278 -0
- package/packages/create-basement-app/templates/webgl/.cursor/rules/styling.mdc +433 -0
- package/packages/create-basement-app/templates/webgl/.editorconfig +40 -0
- package/packages/create-basement-app/templates/webgl/.env.example +81 -0
- package/packages/create-basement-app/templates/webgl/.gitattributes +19 -0
- package/packages/create-basement-app/templates/webgl/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- package/packages/create-basement-app/templates/webgl/.github/workflows/lighthouse-to-slack.yml +136 -0
- package/packages/create-basement-app/templates/webgl/.vscode/extensions.json +20 -0
- package/packages/create-basement-app/templates/webgl/.vscode/settings.json +105 -0
- package/packages/create-basement-app/templates/webgl/README.md +221 -0
- package/packages/create-basement-app/templates/webgl/_gitignore +67 -0
- package/packages/create-basement-app/templates/webgl/app/favicon.ico +0 -0
- package/packages/create-basement-app/templates/webgl/app/layout.tsx +104 -0
- package/packages/create-basement-app/templates/webgl/app/page.tsx +10 -0
- package/packages/create-basement-app/templates/webgl/app/robots.ts +15 -0
- package/packages/create-basement-app/templates/webgl/app/sitemap.ts +16 -0
- package/packages/create-basement-app/templates/webgl/biome.json +250 -0
- package/packages/create-basement-app/templates/webgl/components/basement.svg +1 -0
- package/packages/create-basement-app/templates/webgl/components/layout/footer/index.tsx +27 -0
- package/packages/create-basement-app/templates/webgl/components/layout/header/index.tsx +11 -0
- package/packages/create-basement-app/templates/webgl/components/layout/theme/index.tsx +66 -0
- package/packages/create-basement-app/templates/webgl/components/layout/wrapper/index.tsx +65 -0
- package/packages/create-basement-app/templates/webgl/components/ui/README.md +77 -0
- package/packages/create-basement-app/templates/webgl/components/ui/image/README.md +37 -0
- package/packages/create-basement-app/templates/webgl/components/ui/image/index.tsx +224 -0
- package/packages/create-basement-app/templates/webgl/components/ui/link/index.tsx +146 -0
- package/packages/create-basement-app/templates/webgl/components/webgl/canvas/dynamic.tsx +34 -0
- package/packages/create-basement-app/templates/webgl/components/webgl/canvas/index.tsx +38 -0
- package/packages/create-basement-app/templates/webgl/components/webgl/components/scene/index.tsx +29 -0
- package/packages/create-basement-app/templates/webgl/lib/README.md +33 -0
- package/packages/create-basement-app/templates/webgl/lib/hooks/index.ts +12 -0
- package/packages/create-basement-app/templates/webgl/lib/hooks/use-device-detection.ts +81 -0
- package/packages/create-basement-app/templates/webgl/lib/hooks/use-media-breakpoint.ts +15 -0
- package/packages/create-basement-app/templates/webgl/lib/hooks/use-prefetch.ts +74 -0
- package/packages/create-basement-app/templates/webgl/lib/integrations/.gitkeep +0 -0
- package/packages/create-basement-app/templates/webgl/lib/renderer.ts +7 -0
- package/packages/create-basement-app/templates/webgl/lib/scripts/dev.ts +52 -0
- package/packages/create-basement-app/templates/webgl/lib/scripts/generate-component.ts +322 -0
- package/packages/create-basement-app/templates/webgl/lib/scripts/generate-page.ts +193 -0
- package/packages/create-basement-app/templates/webgl/lib/scripts/generate.ts +79 -0
- package/packages/create-basement-app/templates/webgl/lib/scripts/utils.ts +246 -0
- package/packages/create-basement-app/templates/webgl/lib/store/app.ts +11 -0
- package/packages/create-basement-app/templates/webgl/lib/store/index.ts +11 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/README.md +64 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/cn.ts +7 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/colors.ts +63 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/config.ts +34 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/css/global.css +85 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/css/index.css +6 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/css/reset.css +166 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/css/root.css +68 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/css/tailwind.css +132 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/easings.ts +21 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/fonts.ts +28 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/index.ts +12 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/layout.mjs +27 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/scripts/README.md +29 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/scripts/generate-root.ts +57 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/scripts/generate-tailwind.ts +162 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/scripts/postcss-functions.mjs +168 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/scripts/setup-styles.ts +24 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/scripts/utils.ts +20 -0
- package/packages/create-basement-app/templates/webgl/lib/styles/typography.ts +36 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/README.md +40 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/css.d.ts +21 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/easings.ts +240 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/fetch.ts +84 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/math.test.ts +221 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/math.ts +236 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/metadata.ts +126 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/strings.test.ts +166 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/strings.ts +246 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/types.d.ts +15 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/viewport.test.ts +256 -0
- package/packages/create-basement-app/templates/webgl/lib/utils/viewport.ts +193 -0
- package/packages/create-basement-app/templates/webgl/next.config.ts +142 -0
- package/packages/create-basement-app/templates/webgl/package.json +68 -0
- package/packages/create-basement-app/templates/webgl/postcss.config.mjs +42 -0
- package/packages/create-basement-app/templates/webgl/public/fonts/geist/Geist-Mono.woff2 +0 -0
- package/packages/create-basement-app/templates/webgl/tsconfig.json +43 -0
- package/tasks/.last-branch +1 -0
- package/tasks/CLAUDE.md +104 -0
- package/tasks/archive/2026-02-09-next-starter-dynamic-layers/prd.json +153 -0
- package/tasks/archive/2026-02-09-next-starter-dynamic-layers/progress.txt +115 -0
- package/tasks/prd-project-restructure.md +375 -0
- package/tasks/prd.json +227 -91
- package/tasks/progress.txt +281 -87
- package/tasks/ralph.sh +113 -0
- package/integrations/basehub/README.md +0 -3
- package/layers/experiment/components/layout/header/index.tsx +0 -58
- package/layers/experiment/components/layout/navigation-menu.tsx +0 -127
- package/layers/experiment/lib/constants.ts +0 -12
- package/layers/webgl/app/page.tsx +0 -10
- package/layers/webgl/components/webgl/canvas/dynamic.tsx +0 -34
- package/layers/webgl/components/webgl/canvas/index.tsx +0 -43
- package/layers/webgl/components/webgl/components/scene/index.tsx +0 -21
- package/src/mergers/next-config-merger.js +0 -63
- /package/{src → packages/cli/src}/commands/setup-sanity.js +0 -0
- /package/{src → packages/cli/src}/commands/worktree.js +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/api/draft-mode/disable/route.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/api/draft-mode/enable/route.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/api/revalidate/route.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/layout.tsx +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/sitemap.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/studio/[[...tool]]/page.tsx +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/studio/layout.tsx +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/components/ui/sanity-image/index.tsx +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/README.md +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/check-integration.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/README.md +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/client.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/components/disable-draft-mode.tsx +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/components/rich-text.tsx +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/env.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/live/index.tsx +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/queries.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/sanity.cli.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/sanity.config.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/sanity.types.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schema.json +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/article.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/example.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/index.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/link.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/metadata.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/navigation.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/page.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/richText.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/structure.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/utils/image.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/utils/link.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/scripts/copy-sanity-mcp.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/scripts/generate-page.ts +0 -0
- /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/utils/metadata.ts +0 -0
- /package/{plugins → packages/create-basement-app/plugins}/README.md +0 -0
- /package/{plugins → packages/create-basement-app/plugins}/no-anchor-element.grit +0 -0
- /package/{plugins → packages/create-basement-app/plugins}/no-relative-parent-imports.grit +0 -0
- /package/{plugins → packages/create-basement-app/plugins}/no-unnecessary-forwardref.grit +0 -0
- /package/{template-hooks → packages/create-basement-app/template-hooks}/use-battery.ts +0 -0
- /package/{template-hooks → packages/create-basement-app/template-hooks}/use-device-perf.ts +0 -0
- /package/{template-hooks → packages/create-basement-app/template-hooks}/use-intersection-observer.ts +0 -0
- /package/{template-hooks → packages/create-basement-app/template-hooks}/use-media.ts +0 -0
- /package/{layers/webgpu → packages/create-basement-app/templates/default/lib/integrations}/.gitkeep +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { useEffect, useState } from "react"
|
|
2
|
+
import { useMedia } from "react-use"
|
|
3
|
+
import { breakpoints } from "@/lib/styles/config"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook for detecting device capabilities and characteristics.
|
|
7
|
+
*
|
|
8
|
+
* Provides comprehensive device detection including screen size, input methods,
|
|
9
|
+
* performance preferences, and browser capabilities. Useful for responsive design,
|
|
10
|
+
* performance optimization, and feature detection.
|
|
11
|
+
*
|
|
12
|
+
* @returns Object with device detection results
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* import { useDeviceDetection } from '@/hooks/use-device-detection'
|
|
17
|
+
*
|
|
18
|
+
* function ResponsiveComponent() {
|
|
19
|
+
* const {
|
|
20
|
+
* isMobile,
|
|
21
|
+
* isDesktop,
|
|
22
|
+
* isReducedMotion,
|
|
23
|
+
* isWebGL,
|
|
24
|
+
* isLowPowerMode,
|
|
25
|
+
* dpr,
|
|
26
|
+
* isSafari
|
|
27
|
+
* } = useDeviceDetection()
|
|
28
|
+
*
|
|
29
|
+
* // Adapt behavior based on device capabilities
|
|
30
|
+
* if (isReducedMotion) {
|
|
31
|
+
* // Disable animations
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* if (isWebGL && !isLowPowerMode) {
|
|
35
|
+
* // Enable WebGL features
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* return (
|
|
39
|
+
* <div>
|
|
40
|
+
* {isMobile ? <MobileLayout /> : <DesktopLayout />}
|
|
41
|
+
* {isSafari && <SafariSpecificStyles />}
|
|
42
|
+
* </div>
|
|
43
|
+
* )
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```tsx
|
|
49
|
+
* // Performance optimizations
|
|
50
|
+
* const { isLowPowerMode, dpr, isReducedMotion } = useDeviceDetection()
|
|
51
|
+
*
|
|
52
|
+
* // Reduce quality on low-power devices
|
|
53
|
+
* const quality = isLowPowerMode ? 'low' : 'high'
|
|
54
|
+
* const pixelRatio = Math.min(dpr || 1, 2) // Cap DPR
|
|
55
|
+
*
|
|
56
|
+
* // Respect user motion preferences
|
|
57
|
+
* const enableAnimations = !isReducedMotion
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function useDeviceDetection() {
|
|
61
|
+
const isMobile = useMedia(`(max-width: ${breakpoints.mobile - 1}px)`, true)
|
|
62
|
+
const isReducedMotion = useMedia("(prefers-reduced-motion: reduce)")
|
|
63
|
+
const [dpr, setDpr] = useState<number | undefined>(undefined)
|
|
64
|
+
const [isSafari, setIsSafari] = useState<boolean | undefined>(undefined)
|
|
65
|
+
|
|
66
|
+
// Check for low power mode with fallback for unsupported browsers
|
|
67
|
+
const isTouchDevice = useMedia("(any-pointer: coarse) and (hover: none)")
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
setDpr(window.devicePixelRatio)
|
|
71
|
+
setIsSafari(/^((?!chrome|android).)*safari/i.test(navigator.userAgent))
|
|
72
|
+
}, [])
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
isMobile,
|
|
76
|
+
isReducedMotion,
|
|
77
|
+
isTouchDevice,
|
|
78
|
+
dpr,
|
|
79
|
+
isSafari,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useMedia } from "react-use"
|
|
2
|
+
import { breakpoints } from "@/lib/styles/config"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook for detecting if the viewport is at a specific breakpoint.
|
|
6
|
+
*
|
|
7
|
+
* @param breakpoint - The breakpoint to detect
|
|
8
|
+
* @returns True if the viewport is at the breakpoint
|
|
9
|
+
*/
|
|
10
|
+
export function useMediaBreakpoint(
|
|
11
|
+
breakpoint: keyof typeof breakpoints,
|
|
12
|
+
defaultState = false
|
|
13
|
+
) {
|
|
14
|
+
return useMedia(`(min-width: ${breakpoints[breakpoint]}px)`, defaultState)
|
|
15
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Route } from "next"
|
|
2
|
+
import { useRouter } from "next/navigation"
|
|
3
|
+
import { useEffect, useRef } from "react"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook to prefetch a route when an element becomes visible in the viewport
|
|
7
|
+
* @param href - The route to prefetch
|
|
8
|
+
* @param options - Intersection Observer options
|
|
9
|
+
* @returns ref to attach to the element that should trigger prefetching
|
|
10
|
+
*/
|
|
11
|
+
export function usePrefetch<T extends HTMLElement = HTMLElement>(
|
|
12
|
+
href: Route | null | undefined,
|
|
13
|
+
options?: IntersectionObserverInit
|
|
14
|
+
) {
|
|
15
|
+
const ref = useRef<T>(null)
|
|
16
|
+
const router = useRouter()
|
|
17
|
+
const prefetchedRef = useRef(false)
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
// Early return if no href or already prefetched
|
|
21
|
+
if (!href || prefetchedRef.current) return
|
|
22
|
+
|
|
23
|
+
const element = ref.current
|
|
24
|
+
if (!element) return
|
|
25
|
+
|
|
26
|
+
// Reset prefetched state when href changes
|
|
27
|
+
prefetchedRef.current = false
|
|
28
|
+
|
|
29
|
+
const handleIntersection = (entries: IntersectionObserverEntry[]) => {
|
|
30
|
+
const [entry] = entries
|
|
31
|
+
if (entry?.isIntersecting && !prefetchedRef.current) {
|
|
32
|
+
// Check network conditions before prefetching
|
|
33
|
+
const connection = (
|
|
34
|
+
navigator as Navigator & {
|
|
35
|
+
connection?: NetworkInformation
|
|
36
|
+
}
|
|
37
|
+
).connection
|
|
38
|
+
|
|
39
|
+
const shouldPrefetch =
|
|
40
|
+
!connection ||
|
|
41
|
+
(connection.effectiveType !== "slow-2g" &&
|
|
42
|
+
connection.effectiveType !== "2g" &&
|
|
43
|
+
!connection.saveData)
|
|
44
|
+
|
|
45
|
+
if (shouldPrefetch) {
|
|
46
|
+
router.prefetch(href)
|
|
47
|
+
prefetchedRef.current = true
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const observer = new IntersectionObserver(handleIntersection, {
|
|
53
|
+
rootMargin: "50px",
|
|
54
|
+
...options,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
observer.observe(element)
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
observer.disconnect()
|
|
61
|
+
}
|
|
62
|
+
}, [href, options, router])
|
|
63
|
+
|
|
64
|
+
// Return null ref if href is not provided
|
|
65
|
+
return href ? ref : { current: null }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// TypeScript types for Network Information API
|
|
69
|
+
interface NetworkInformation {
|
|
70
|
+
readonly effectiveType: "slow-2g" | "2g" | "3g" | "4g"
|
|
71
|
+
readonly saveData: boolean
|
|
72
|
+
readonly rtt?: number
|
|
73
|
+
readonly downlink?: number
|
|
74
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform parallel dev script
|
|
3
|
+
* Replaces npm-run-all for running multiple processes simultaneously
|
|
4
|
+
* Works on Windows, macOS, and Linux using Bun's native APIs
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { bunExecutable, colorEnv } from "./utils"
|
|
8
|
+
|
|
9
|
+
const isHttps = process.argv.includes("--https")
|
|
10
|
+
const isInspect = process.argv.includes("--inspect")
|
|
11
|
+
|
|
12
|
+
// Build next dev command args
|
|
13
|
+
const nextDevArgs = [bunExecutable, "next", "dev"]
|
|
14
|
+
if (isHttps) nextDevArgs.push("--experimental-https")
|
|
15
|
+
if (isInspect) nextDevArgs.push("--inspect")
|
|
16
|
+
|
|
17
|
+
// Build environment with FORCE_COLOR
|
|
18
|
+
const devEnv = colorEnv()
|
|
19
|
+
|
|
20
|
+
const processes = [
|
|
21
|
+
// Style watcher
|
|
22
|
+
Bun.spawn(
|
|
23
|
+
[bunExecutable, "--watch", "./lib/styles/scripts/setup-styles.ts"],
|
|
24
|
+
{
|
|
25
|
+
stdout: "inherit",
|
|
26
|
+
stderr: "inherit",
|
|
27
|
+
env: devEnv,
|
|
28
|
+
}
|
|
29
|
+
),
|
|
30
|
+
|
|
31
|
+
// Next.js dev server
|
|
32
|
+
Bun.spawn(nextDevArgs, {
|
|
33
|
+
stdout: "inherit",
|
|
34
|
+
stderr: "inherit",
|
|
35
|
+
env: devEnv,
|
|
36
|
+
}),
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
// Handle graceful shutdown
|
|
40
|
+
const cleanup = () => {
|
|
41
|
+
for (const proc of processes) {
|
|
42
|
+
proc.kill()
|
|
43
|
+
}
|
|
44
|
+
process.exit(0)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
process.on("SIGINT", cleanup)
|
|
48
|
+
process.on("SIGTERM", cleanup)
|
|
49
|
+
|
|
50
|
+
// Wait for any process to exit (if one crashes, we want to know)
|
|
51
|
+
await Promise.race(processes.map((p) => p.exited))
|
|
52
|
+
cleanup()
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Generate Component Module
|
|
4
|
+
*
|
|
5
|
+
* Generates new components with pre-configured templates through interactive prompts.
|
|
6
|
+
* Used by the unified generator: `bun run generate`
|
|
7
|
+
*
|
|
8
|
+
* Cross-platform compatible (Windows, macOS, Linux)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as p from "@clack/prompts"
|
|
12
|
+
import { createDir } from "./utils"
|
|
13
|
+
|
|
14
|
+
interface ComponentOptions {
|
|
15
|
+
client?: boolean
|
|
16
|
+
category?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ComponentConfig {
|
|
20
|
+
path: string
|
|
21
|
+
options: ComponentOptions
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Interactive prompts for component configuration
|
|
26
|
+
*/
|
|
27
|
+
export const promptComponentConfig = async (): Promise<ComponentConfig> => {
|
|
28
|
+
const category = await p.select({
|
|
29
|
+
message: "Which category should this component belong to?",
|
|
30
|
+
options: [
|
|
31
|
+
{
|
|
32
|
+
value: "ui",
|
|
33
|
+
label: "UI Components",
|
|
34
|
+
hint: "Reusable primitives (buttons, inputs, etc.)",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
value: "layout",
|
|
38
|
+
label: "Layout Components",
|
|
39
|
+
hint: "Site structure (navigation, footer, etc.)",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
value: "magic",
|
|
43
|
+
label: "Magic Components",
|
|
44
|
+
hint: "Animations and visual enhancements",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
value: "blocks",
|
|
48
|
+
label: "Block Components",
|
|
49
|
+
hint: "Pre-built page sections",
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
if (p.isCancel(category)) {
|
|
55
|
+
p.cancel("Component generation cancelled")
|
|
56
|
+
process.exit(0)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const name = await p.text({
|
|
60
|
+
message: "What should the component be called?",
|
|
61
|
+
placeholder: "button, hero-section, animated-text",
|
|
62
|
+
validate: (value) => {
|
|
63
|
+
if (!value) return "Component name is required"
|
|
64
|
+
if (!/^[a-z][a-z0-9-]*$/.test(value)) {
|
|
65
|
+
return "Component name must be kebab-case (lowercase with hyphens)"
|
|
66
|
+
}
|
|
67
|
+
return undefined
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
if (p.isCancel(name)) {
|
|
72
|
+
p.cancel("Component generation cancelled")
|
|
73
|
+
process.exit(0)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const componentPath = `${category}/${name}`
|
|
77
|
+
|
|
78
|
+
const isClientComponent = await p.confirm({
|
|
79
|
+
message: "Should this be a client component ('use client')?",
|
|
80
|
+
initialValue: false,
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
if (p.isCancel(isClientComponent)) {
|
|
84
|
+
p.cancel("Component generation cancelled")
|
|
85
|
+
process.exit(0)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
path: componentPath,
|
|
90
|
+
options: {
|
|
91
|
+
client: isClientComponent,
|
|
92
|
+
category,
|
|
93
|
+
},
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Convert kebab-case to PascalCase
|
|
99
|
+
*/
|
|
100
|
+
const toPascalCase = (str: string): string =>
|
|
101
|
+
str
|
|
102
|
+
.split("-")
|
|
103
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
104
|
+
.join("")
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Convert kebab-case to camelCase
|
|
108
|
+
*/
|
|
109
|
+
const toCamelCase = (str: string): string =>
|
|
110
|
+
str
|
|
111
|
+
.split("-")
|
|
112
|
+
.map((word, index) =>
|
|
113
|
+
index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)
|
|
114
|
+
)
|
|
115
|
+
.join("")
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Generate component index.tsx content
|
|
119
|
+
*/
|
|
120
|
+
const generateComponentContent = (
|
|
121
|
+
componentName: string,
|
|
122
|
+
options: ComponentOptions
|
|
123
|
+
): string => {
|
|
124
|
+
const { client } = options
|
|
125
|
+
const pascalName = toPascalCase(componentName)
|
|
126
|
+
const camelCaseName = toCamelCase(componentName)
|
|
127
|
+
const directive = client ? `'use client'\n\n` : ""
|
|
128
|
+
|
|
129
|
+
return `${directive}import { cn } from '@/styles/cn'
|
|
130
|
+
import type { HTMLAttributes, ReactNode } from 'react'
|
|
131
|
+
import s from './${componentName}.module.css'
|
|
132
|
+
|
|
133
|
+
interface ${pascalName}Props extends HTMLAttributes<HTMLDivElement> {
|
|
134
|
+
/** Component content */
|
|
135
|
+
children?: ReactNode
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const ${camelCaseName}Variants = cva({
|
|
139
|
+
base: 'bg-primary text-white',
|
|
140
|
+
variants: {
|
|
141
|
+
variant: {
|
|
142
|
+
primary: 'bg-primary text-white',
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* ${pascalName} component.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* \`\`\`tsx
|
|
152
|
+
* import { ${pascalName} } from '@/components/${options.category}/${componentName}'
|
|
153
|
+
*
|
|
154
|
+
* <${pascalName}>
|
|
155
|
+
* Content here
|
|
156
|
+
* </${pascalName}>
|
|
157
|
+
* \`\`\`
|
|
158
|
+
*/
|
|
159
|
+
export function ${pascalName}({
|
|
160
|
+
children,
|
|
161
|
+
className,
|
|
162
|
+
variant = 'primary',
|
|
163
|
+
...props
|
|
164
|
+
}: ${pascalName}Props) {
|
|
165
|
+
return (
|
|
166
|
+
<div className={cn(s.${camelCaseName}, className, ${pascalName}Variants({ variant: 'primary' }))} {...props}>
|
|
167
|
+
{children}
|
|
168
|
+
</div>
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
`
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Generate CSS module content
|
|
176
|
+
*/
|
|
177
|
+
const generateCssContent = (componentName: string): string => {
|
|
178
|
+
const cssClassName = toCamelCase(componentName)
|
|
179
|
+
|
|
180
|
+
return `/* ${componentName}.module.css */
|
|
181
|
+
|
|
182
|
+
.${cssClassName} {
|
|
183
|
+
/* Add your component styles here */
|
|
184
|
+
}
|
|
185
|
+
`
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Update barrel export file
|
|
190
|
+
*/
|
|
191
|
+
const updateBarrelExport = async (
|
|
192
|
+
componentPath: string,
|
|
193
|
+
componentName: string
|
|
194
|
+
): Promise<void> => {
|
|
195
|
+
const pathParts = componentPath.split("/")
|
|
196
|
+
const category = pathParts[0] ?? "components"
|
|
197
|
+
const barrelPath = `components/${category}/index.ts`
|
|
198
|
+
const pascalName = toPascalCase(componentName)
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
// Check if barrel file exists
|
|
202
|
+
const file = Bun.file(barrelPath)
|
|
203
|
+
const exists = await file.exists()
|
|
204
|
+
|
|
205
|
+
if (!exists) {
|
|
206
|
+
// Create new barrel file with header comment based on category
|
|
207
|
+
const categoryTitles: Record<string, string> = {
|
|
208
|
+
ui: "UI Primitives - Reusable across any project",
|
|
209
|
+
layout: "Layout Components - Site chrome (customize per project)",
|
|
210
|
+
magic: "Magic Components - Animations and visual enhancements",
|
|
211
|
+
blocks: "Block Components - Pre-built page sections",
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const header =
|
|
215
|
+
categoryTitles[category] || `${toPascalCase(category)} Components`
|
|
216
|
+
const content = `// ${header}
|
|
217
|
+
// Import from '@/components/${category}' or '@/components/${category}/[component]'
|
|
218
|
+
|
|
219
|
+
export { ${pascalName} } from './${componentName}'
|
|
220
|
+
`
|
|
221
|
+
await Bun.write(barrelPath, content)
|
|
222
|
+
p.log.success(`Created barrel export: ${barrelPath}`)
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Update existing barrel file
|
|
227
|
+
const content = await file.text()
|
|
228
|
+
|
|
229
|
+
// Check if already exported
|
|
230
|
+
if (content.includes(`from './${componentName}'`)) {
|
|
231
|
+
p.log.warn(`Component already exported in ${barrelPath}`)
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Add export at the end, maintaining the file's style
|
|
236
|
+
const lines = content.split("\n")
|
|
237
|
+
|
|
238
|
+
// Find the last non-empty line to append after
|
|
239
|
+
let insertIndex = lines.length
|
|
240
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
241
|
+
if (lines[i]?.trim()) {
|
|
242
|
+
insertIndex = i + 1
|
|
243
|
+
break
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Insert the new export
|
|
248
|
+
lines.splice(
|
|
249
|
+
insertIndex,
|
|
250
|
+
0,
|
|
251
|
+
`export { ${pascalName} } from './${componentName}'`
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
await Bun.write(barrelPath, lines.join("\n"))
|
|
255
|
+
p.log.success(`Updated barrel export: ${barrelPath}`)
|
|
256
|
+
} catch (error) {
|
|
257
|
+
p.log.warn(
|
|
258
|
+
`Could not update barrel export: ${error instanceof Error ? error.message : String(error)}`
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Generate component files and directories
|
|
265
|
+
*/
|
|
266
|
+
export const createComponent = async (
|
|
267
|
+
componentPath: string,
|
|
268
|
+
options: ComponentOptions
|
|
269
|
+
): Promise<void> => {
|
|
270
|
+
const s = p.spinner()
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
const pathParts = componentPath.split("/")
|
|
274
|
+
const componentName = pathParts[pathParts.length - 1] ?? ""
|
|
275
|
+
|
|
276
|
+
// Validate component name
|
|
277
|
+
if (!/^[a-z][a-z0-9-]*$/.test(componentName)) {
|
|
278
|
+
throw new Error(
|
|
279
|
+
"Component name must be kebab-case (lowercase with hyphens)"
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Create directory structure
|
|
284
|
+
const componentDir = `components/${componentPath}`
|
|
285
|
+
|
|
286
|
+
s.start(`Generating component "${componentPath}"`)
|
|
287
|
+
|
|
288
|
+
// Create component directory (cross-platform)
|
|
289
|
+
await createDir(componentDir)
|
|
290
|
+
|
|
291
|
+
// Generate and write files
|
|
292
|
+
const componentContent = generateComponentContent(componentName, options)
|
|
293
|
+
const cssContent = generateCssContent(componentName)
|
|
294
|
+
|
|
295
|
+
await Bun.write(`${componentDir}/index.tsx`, componentContent)
|
|
296
|
+
await Bun.write(`${componentDir}/${componentName}.module.css`, cssContent)
|
|
297
|
+
|
|
298
|
+
s.stop(`Component "${componentPath}" generated successfully!`)
|
|
299
|
+
|
|
300
|
+
// Show what was created
|
|
301
|
+
p.log.success(`Created files:`)
|
|
302
|
+
p.log.message(` 📄 ${componentDir}/index.tsx`)
|
|
303
|
+
p.log.message(` 🎨 ${componentDir}/${componentName}.module.css`)
|
|
304
|
+
|
|
305
|
+
// Try to update barrel exports
|
|
306
|
+
await updateBarrelExport(componentPath, componentName)
|
|
307
|
+
|
|
308
|
+
const pascalName = toPascalCase(componentName)
|
|
309
|
+
|
|
310
|
+
p.note(
|
|
311
|
+
`Next steps:\n` +
|
|
312
|
+
` 1. Customize ${componentDir}/index.tsx\n` +
|
|
313
|
+
` 2. Style in ${componentDir}/${componentName}.module.css\n` +
|
|
314
|
+
` 3. Import: \`import { ${pascalName} } from '@/components/${componentPath}'\``
|
|
315
|
+
)
|
|
316
|
+
} catch (error) {
|
|
317
|
+
s.stop(`Failed to create component "${componentPath}"`)
|
|
318
|
+
throw error instanceof Error ? error : new Error(String(error))
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Export functions for use by unified create script
|