bsmnt 0.2.9 → 0.2.11
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/README.md +84 -146
- package/dist/configs/skills.d.ts +27 -0
- package/dist/configs/skills.d.ts.map +1 -0
- package/dist/configs/skills.js +18 -0
- package/dist/configs/skills.js.map +1 -0
- package/dist/configs/skills.json +26 -0
- package/dist/helpers/add/hooks-config.d.ts.map +1 -1
- package/dist/helpers/add/hooks-config.js +0 -6
- package/dist/helpers/add/hooks-config.js.map +1 -1
- package/dist/helpers/create/setup-agent.d.ts.map +1 -1
- package/dist/helpers/create/setup-agent.js +15 -5
- package/dist/helpers/create/setup-agent.js.map +1 -1
- package/dist/helpers/integrate/merge-config.d.ts.map +1 -1
- package/dist/helpers/integrate/merge-config.js +1 -0
- package/dist/helpers/integrate/merge-config.js.map +1 -1
- package/dist/helpers/integrate/sanity/config.d.ts.map +1 -1
- package/dist/helpers/integrate/sanity/config.js +8 -2
- package/dist/helpers/integrate/sanity/config.js.map +1 -1
- package/dist/helpers/integrate/sanity/mergers/layout-merger.d.ts.map +1 -1
- package/dist/helpers/integrate/sanity/mergers/layout-merger.js +13 -12
- package/dist/helpers/integrate/sanity/mergers/layout-merger.js.map +1 -1
- package/dist/helpers/skills/index.d.ts +10 -0
- package/dist/helpers/skills/index.d.ts.map +1 -0
- package/dist/helpers/skills/index.js +136 -0
- package/dist/helpers/skills/index.js.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/helpers/integrate/sanity/files/app/api/blog/[slug]/route.ts +2 -1
- package/src/helpers/integrate/sanity/files/lib/integrations/sanity/confirm-publish-action.ts +31 -0
- package/src/helpers/integrate/sanity/files/lib/integrations/sanity/sanity.config.ts +17 -0
- package/src/helpers/integrate/sanity/files/lib/utils/json-ld.tsx +249 -0
- package/src/template-hooks/config.js +0 -6
- package/src/templates/next-default/README.md +28 -199
- package/src/templates/next-default/app/layout.tsx +20 -3
- package/src/templates/next-default/biome.json +1 -14
- package/src/templates/next-default/components/layout/theme/index.tsx +2 -5
- package/src/templates/next-default/components/layout/wrapper/index.tsx +1 -2
- package/src/templates/next-default/components/ui/README.md +2 -3
- package/src/templates/next-default/components/ui/image/index.tsx +3 -3
- package/src/templates/next-default/lib/README.md +3 -3
- package/src/templates/next-default/lib/hooks/use-device-detection.ts +4 -3
- package/src/templates/next-default/lib/hooks/use-media-breakpoint.ts +11 -4
- package/src/templates/next-default/lib/hooks/use-media.ts +29 -0
- package/src/templates/next-default/lib/scripts/dev.ts +9 -29
- package/src/templates/next-default/lib/styles/README.md +7 -58
- package/src/templates/next-default/lib/styles/fonts.ts +7 -15
- package/src/templates/next-default/lib/styles/global.css +198 -0
- package/src/templates/next-default/lib/styles/index.css +3 -0
- package/src/templates/next-default/lib/styles/tokens.css +179 -0
- package/src/templates/next-default/lib/utils/global-css.d.ts +1 -0
- package/src/templates/next-default/lib/utils/json-ld.tsx +199 -0
- package/src/templates/next-default/lib/utils/viewport.ts +11 -5
- package/src/templates/next-default/next.config.ts +0 -1
- package/src/templates/next-default/package.json +11 -18
- package/src/templates/next-default/postcss.config.mjs +0 -14
- package/src/templates/next-default/tsconfig.json +1 -0
- package/src/templates/next-default/tsconfig.tsbuildinfo +1 -0
- package/src/templates/next-experiments/README.md +29 -200
- package/src/templates/next-experiments/app/layout.tsx +20 -3
- package/src/templates/next-experiments/app/page.tsx +46 -39
- package/src/templates/next-experiments/biome.json +1 -14
- package/src/templates/next-experiments/components/layout/theme/index.tsx +2 -5
- package/src/templates/next-experiments/components/layout/wrapper/index.tsx +1 -2
- package/src/templates/next-experiments/components/ui/README.md +2 -3
- package/src/templates/next-experiments/components/ui/image/index.tsx +3 -2
- package/src/templates/next-experiments/lib/README.md +3 -3
- package/src/templates/next-experiments/lib/hooks/use-device-detection.ts +4 -3
- package/src/templates/next-experiments/lib/hooks/use-media-breakpoint.ts +11 -4
- package/src/templates/next-experiments/lib/hooks/use-media.ts +29 -0
- package/src/templates/next-experiments/lib/scripts/dev.ts +9 -29
- package/src/templates/next-experiments/lib/styles/README.md +7 -58
- package/src/templates/next-experiments/lib/styles/fonts.ts +7 -15
- package/src/templates/next-experiments/lib/styles/global.css +198 -0
- package/src/templates/next-experiments/lib/styles/index.css +3 -0
- package/src/templates/next-experiments/lib/styles/tokens.css +179 -0
- package/src/templates/next-experiments/lib/utils/global-css.d.ts +1 -0
- package/src/templates/next-experiments/lib/utils/json-ld.tsx +199 -0
- package/src/templates/next-experiments/lib/utils/viewport.ts +11 -5
- package/src/templates/next-experiments/next.config.ts +0 -1
- package/src/templates/next-experiments/package.json +11 -22
- package/src/templates/next-experiments/postcss.config.mjs +0 -14
- package/src/templates/next-experiments/tsconfig.json +1 -0
- package/src/templates/next-experiments/tsconfig.tsbuildinfo +1 -0
- package/src/templates/next-webgl/README.md +30 -200
- package/src/templates/next-webgl/app/layout.tsx +20 -3
- package/src/templates/next-webgl/biome.json +1 -14
- package/src/templates/next-webgl/components/layout/theme/index.tsx +2 -5
- package/src/templates/next-webgl/components/layout/wrapper/index.tsx +1 -2
- package/src/templates/next-webgl/components/ui/README.md +2 -3
- package/src/templates/next-webgl/components/ui/image/index.tsx +3 -3
- package/src/templates/next-webgl/lib/README.md +3 -3
- package/src/templates/next-webgl/lib/hooks/use-device-detection.ts +4 -3
- package/src/templates/next-webgl/lib/hooks/use-media-breakpoint.ts +11 -4
- package/src/templates/next-webgl/lib/hooks/use-media.ts +29 -0
- package/src/templates/next-webgl/lib/scripts/dev.ts +9 -29
- package/src/templates/next-webgl/lib/styles/README.md +7 -58
- package/src/templates/next-webgl/lib/styles/fonts.ts +7 -15
- package/src/templates/next-webgl/lib/styles/global.css +198 -0
- package/src/templates/next-webgl/lib/styles/index.css +3 -0
- package/src/templates/next-webgl/lib/styles/tokens.css +179 -0
- package/src/templates/next-webgl/lib/utils/global-css.d.ts +1 -0
- package/src/templates/next-webgl/lib/utils/json-ld.tsx +199 -0
- package/src/templates/next-webgl/lib/utils/viewport.ts +11 -5
- package/src/templates/next-webgl/next.config.ts +0 -1
- package/src/templates/next-webgl/package.json +11 -20
- package/src/templates/next-webgl/postcss.config.mjs +0 -14
- package/src/templates/next-webgl/tsconfig.json +1 -0
- package/src/templates/next-webgl/tsconfig.tsbuildinfo +1 -0
- package/plugins/no-anchor-element.grit +0 -11
- package/plugins/no-relative-parent-imports.grit +0 -6
- package/plugins/no-unnecessary-forwardref.grit +0 -5
- package/src/template-hooks/use-media.ts +0 -33
- package/src/templates/next-default/components/ui/image/image.module.css +0 -5
- package/src/templates/next-default/lib/scripts/generate-component.ts +0 -322
- package/src/templates/next-default/lib/scripts/generate-page.ts +0 -193
- package/src/templates/next-default/lib/scripts/generate.ts +0 -79
- package/src/templates/next-default/lib/store/app.ts +0 -11
- package/src/templates/next-default/lib/store/index.ts +0 -11
- package/src/templates/next-default/lib/styles/colors.ts +0 -63
- package/src/templates/next-default/lib/styles/config.ts +0 -34
- package/src/templates/next-default/lib/styles/css/global.css +0 -85
- package/src/templates/next-default/lib/styles/css/index.css +0 -6
- package/src/templates/next-default/lib/styles/css/reset.css +0 -166
- package/src/templates/next-default/lib/styles/css/root.css +0 -68
- package/src/templates/next-default/lib/styles/css/tailwind.css +0 -132
- package/src/templates/next-default/lib/styles/easings.ts +0 -21
- package/src/templates/next-default/lib/styles/index.ts +0 -12
- package/src/templates/next-default/lib/styles/layout.mjs +0 -27
- package/src/templates/next-default/lib/styles/scripts/README.md +0 -29
- package/src/templates/next-default/lib/styles/scripts/generate-root.ts +0 -57
- package/src/templates/next-default/lib/styles/scripts/generate-tailwind.ts +0 -162
- package/src/templates/next-default/lib/styles/scripts/postcss-functions.mjs +0 -168
- package/src/templates/next-default/lib/styles/scripts/setup-styles.ts +0 -24
- package/src/templates/next-default/lib/styles/scripts/utils.ts +0 -20
- package/src/templates/next-default/lib/styles/typography.ts +0 -36
- package/src/templates/next-default/lib/utils/css.d.ts +0 -21
- package/src/templates/next-default/lib/utils/math.test.ts +0 -221
- package/src/templates/next-default/lib/utils/strings.test.ts +0 -166
- package/src/templates/next-default/lib/utils/viewport.test.ts +0 -256
- package/src/templates/next-default/public/fonts/geist/Geist-Mono.woff2 +0 -0
- package/src/templates/next-experiments/components/ui/image/image.module.css +0 -5
- package/src/templates/next-experiments/lib/scripts/generate-component.ts +0 -322
- package/src/templates/next-experiments/lib/scripts/generate-page.ts +0 -193
- package/src/templates/next-experiments/lib/scripts/generate.ts +0 -79
- package/src/templates/next-experiments/lib/store/app.ts +0 -11
- package/src/templates/next-experiments/lib/store/index.ts +0 -11
- package/src/templates/next-experiments/lib/styles/colors.ts +0 -63
- package/src/templates/next-experiments/lib/styles/config.ts +0 -34
- package/src/templates/next-experiments/lib/styles/css/global.css +0 -85
- package/src/templates/next-experiments/lib/styles/css/index.css +0 -6
- package/src/templates/next-experiments/lib/styles/css/reset.css +0 -166
- package/src/templates/next-experiments/lib/styles/css/root.css +0 -68
- package/src/templates/next-experiments/lib/styles/css/tailwind.css +0 -132
- package/src/templates/next-experiments/lib/styles/easings.ts +0 -21
- package/src/templates/next-experiments/lib/styles/index.ts +0 -12
- package/src/templates/next-experiments/lib/styles/layout.mjs +0 -27
- package/src/templates/next-experiments/lib/styles/scripts/README.md +0 -29
- package/src/templates/next-experiments/lib/styles/scripts/generate-root.ts +0 -57
- package/src/templates/next-experiments/lib/styles/scripts/generate-tailwind.ts +0 -162
- package/src/templates/next-experiments/lib/styles/scripts/postcss-functions.mjs +0 -168
- package/src/templates/next-experiments/lib/styles/scripts/setup-styles.ts +0 -24
- package/src/templates/next-experiments/lib/styles/scripts/utils.ts +0 -20
- package/src/templates/next-experiments/lib/styles/typography.ts +0 -36
- package/src/templates/next-experiments/lib/utils/css.d.ts +0 -21
- package/src/templates/next-experiments/lib/utils/math.test.ts +0 -221
- package/src/templates/next-experiments/lib/utils/strings.test.ts +0 -166
- package/src/templates/next-experiments/lib/utils/viewport.test.ts +0 -256
- package/src/templates/next-experiments/public/fonts/geist/Geist-Mono.woff2 +0 -0
- package/src/templates/next-webgl/components/ui/image/image.module.css +0 -5
- package/src/templates/next-webgl/lib/scripts/generate-component.ts +0 -322
- package/src/templates/next-webgl/lib/scripts/generate-page.ts +0 -193
- package/src/templates/next-webgl/lib/scripts/generate.ts +0 -79
- package/src/templates/next-webgl/lib/store/app.ts +0 -11
- package/src/templates/next-webgl/lib/store/index.ts +0 -11
- package/src/templates/next-webgl/lib/styles/colors.ts +0 -63
- package/src/templates/next-webgl/lib/styles/config.ts +0 -34
- package/src/templates/next-webgl/lib/styles/css/global.css +0 -85
- package/src/templates/next-webgl/lib/styles/css/index.css +0 -6
- package/src/templates/next-webgl/lib/styles/css/reset.css +0 -166
- package/src/templates/next-webgl/lib/styles/css/root.css +0 -68
- package/src/templates/next-webgl/lib/styles/css/tailwind.css +0 -132
- package/src/templates/next-webgl/lib/styles/easings.ts +0 -21
- package/src/templates/next-webgl/lib/styles/index.ts +0 -12
- package/src/templates/next-webgl/lib/styles/layout.mjs +0 -27
- package/src/templates/next-webgl/lib/styles/scripts/README.md +0 -29
- package/src/templates/next-webgl/lib/styles/scripts/generate-root.ts +0 -57
- package/src/templates/next-webgl/lib/styles/scripts/generate-tailwind.ts +0 -162
- package/src/templates/next-webgl/lib/styles/scripts/postcss-functions.mjs +0 -168
- package/src/templates/next-webgl/lib/styles/scripts/setup-styles.ts +0 -24
- package/src/templates/next-webgl/lib/styles/scripts/utils.ts +0 -20
- package/src/templates/next-webgl/lib/styles/typography.ts +0 -36
- package/src/templates/next-webgl/lib/utils/css.d.ts +0 -21
- package/src/templates/next-webgl/lib/utils/math.test.ts +0 -221
- package/src/templates/next-webgl/lib/utils/strings.test.ts +0 -166
- package/src/templates/next-webgl/lib/utils/viewport.test.ts +0 -256
- package/src/templates/next-webgl/public/fonts/geist/Geist-Mono.woff2 +0 -0
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
language js
|
|
2
|
-
|
|
3
|
-
`<a $attrs>$content</a>` as $anchor where {
|
|
4
|
-
! $anchor <: within `if ($condition) { return ($jsx) }` where {
|
|
5
|
-
$condition <: contains or {
|
|
6
|
-
`isExternal`,
|
|
7
|
-
`isExternalSSR`
|
|
8
|
-
}
|
|
9
|
-
} ,
|
|
10
|
-
register_diagnostic(span=$anchor, message="Use custom Link component instead of <a> element. The Link component handles both internal and external links automatically.", severity="error")
|
|
11
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
language js
|
|
2
|
-
|
|
3
|
-
`import $imports from $source` as $import where {
|
|
4
|
-
$source <: r"['\"]\.\.\/\.\.\/.*['\"]",
|
|
5
|
-
register_diagnostic(span=$import, message="Use alias imports (~/dir/) instead of deep relative imports (../../). Single level imports (../) are allowed for colocated files.", severity="error")
|
|
6
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import { isApiSupported } from "@/utils";
|
|
4
|
-
|
|
5
|
-
export const useMedia = (mediaQuery: string, initialValue?: boolean) => {
|
|
6
|
-
const [isVerified, setIsVerified] = React.useState<boolean | undefined>(
|
|
7
|
-
initialValue,
|
|
8
|
-
);
|
|
9
|
-
|
|
10
|
-
React.useEffect(() => {
|
|
11
|
-
if (!isApiSupported("matchMedia")) {
|
|
12
|
-
console.warn("matchMedia is not supported by your current browser");
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const mediaQueryList = window.matchMedia(mediaQuery);
|
|
16
|
-
const changeHandler = () => setIsVerified(!!mediaQueryList.matches);
|
|
17
|
-
|
|
18
|
-
changeHandler();
|
|
19
|
-
if (typeof mediaQueryList.addEventListener === "function") {
|
|
20
|
-
mediaQueryList.addEventListener("change", changeHandler);
|
|
21
|
-
return () => {
|
|
22
|
-
mediaQueryList.removeEventListener("change", changeHandler);
|
|
23
|
-
};
|
|
24
|
-
} else if (typeof mediaQueryList.addListener === "function") {
|
|
25
|
-
mediaQueryList.addListener(changeHandler);
|
|
26
|
-
return () => {
|
|
27
|
-
mediaQueryList.removeListener(changeHandler);
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
}, [mediaQuery]);
|
|
31
|
-
|
|
32
|
-
return isVerified;
|
|
33
|
-
};
|
|
@@ -1,322 +0,0 @@
|
|
|
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
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* Generate Page Module
|
|
4
|
-
*
|
|
5
|
-
* Generates new pages 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 PageOptions {
|
|
15
|
-
theme?: string
|
|
16
|
-
css?: boolean
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface PageConfig {
|
|
20
|
-
name: string
|
|
21
|
-
options: PageOptions
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Interactive prompts for page configuration
|
|
26
|
-
*/
|
|
27
|
-
export const promptPageConfig = async (): Promise<PageConfig> => {
|
|
28
|
-
const name = await p.text({
|
|
29
|
-
message: "What should the page be called?",
|
|
30
|
-
placeholder: "about, contact, products",
|
|
31
|
-
validate: (value) => {
|
|
32
|
-
if (!value) return "Page name is required"
|
|
33
|
-
if (!/^[a-zA-Z][a-zA-Z0-9-_]*$/.test(value)) {
|
|
34
|
-
return "Page name must start with a letter and contain only letters, numbers, hyphens, and underscores"
|
|
35
|
-
}
|
|
36
|
-
return undefined
|
|
37
|
-
},
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
if (p.isCancel(name)) {
|
|
41
|
-
p.cancel("Page generation cancelled")
|
|
42
|
-
process.exit(0)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const theme = await p.select({
|
|
46
|
-
message: "Choose a theme for the page",
|
|
47
|
-
options: [
|
|
48
|
-
{ value: "dark", label: "Dark (default)", hint: "Standard dark theme" },
|
|
49
|
-
{ value: "light", label: "Light", hint: "Light theme" },
|
|
50
|
-
{ value: "red", label: "Red", hint: "Red accent theme" },
|
|
51
|
-
],
|
|
52
|
-
initialValue: "dark",
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
if (p.isCancel(theme)) {
|
|
56
|
-
p.cancel("Page generation cancelled")
|
|
57
|
-
process.exit(0)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const includeCss = await p.confirm({
|
|
61
|
-
message: "Include a CSS module file?",
|
|
62
|
-
initialValue: false,
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
if (p.isCancel(includeCss)) {
|
|
66
|
-
p.cancel("Page generation cancelled")
|
|
67
|
-
process.exit(0)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
name,
|
|
72
|
-
options: {
|
|
73
|
-
theme,
|
|
74
|
-
css: includeCss,
|
|
75
|
-
},
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Generate page.tsx content
|
|
81
|
-
*/
|
|
82
|
-
const generatePageContent = (
|
|
83
|
-
pageName: string,
|
|
84
|
-
options: PageOptions
|
|
85
|
-
): string => {
|
|
86
|
-
const { theme = "dark" } = options
|
|
87
|
-
|
|
88
|
-
// Capitalize first letter for title
|
|
89
|
-
const title = pageName.charAt(0).toUpperCase() + pageName.slice(1)
|
|
90
|
-
|
|
91
|
-
// Build imports
|
|
92
|
-
const imports: string[] = []
|
|
93
|
-
imports.push(`import type { Metadata } from 'next'`)
|
|
94
|
-
imports.push(`import { Wrapper } from '@/components/layout/wrapper'`)
|
|
95
|
-
|
|
96
|
-
// Build wrapper props
|
|
97
|
-
const wrapperProps: string[] = [`theme="${theme}"`]
|
|
98
|
-
|
|
99
|
-
const componentBody: string = `(
|
|
100
|
-
<Wrapper ${wrapperProps.join(" ")}>
|
|
101
|
-
<section className="py-44">
|
|
102
|
-
<div className="container">
|
|
103
|
-
<h1>${title}</h1>
|
|
104
|
-
{/* Your content here */}
|
|
105
|
-
</div>
|
|
106
|
-
</section>
|
|
107
|
-
</Wrapper>
|
|
108
|
-
)`
|
|
109
|
-
|
|
110
|
-
// Build metadata export
|
|
111
|
-
const metadataExport: string = `
|
|
112
|
-
export const metadata: Metadata = {
|
|
113
|
-
title: '${title}',
|
|
114
|
-
description: '${title} page description',
|
|
115
|
-
}`
|
|
116
|
-
|
|
117
|
-
return `${imports.join("\n")}
|
|
118
|
-
${metadataExport}
|
|
119
|
-
|
|
120
|
-
export default function ${title}Page() {
|
|
121
|
-
return ${componentBody}
|
|
122
|
-
}
|
|
123
|
-
`
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Create page files and directories
|
|
128
|
-
*/
|
|
129
|
-
export const createPage = async (
|
|
130
|
-
pageName: string,
|
|
131
|
-
options: PageOptions
|
|
132
|
-
): Promise<void> => {
|
|
133
|
-
const s = p.spinner()
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
// Create directory structure
|
|
137
|
-
const pageDir = `app/${pageName}`
|
|
138
|
-
const componentsDir = `${pageDir}/_components`
|
|
139
|
-
|
|
140
|
-
s.start(`Creating page structure for "${pageName}"`)
|
|
141
|
-
|
|
142
|
-
// Create main page directory (cross-platform)
|
|
143
|
-
await createDir(pageDir)
|
|
144
|
-
|
|
145
|
-
// Create _components subdirectory (cross-platform)
|
|
146
|
-
await createDir(componentsDir)
|
|
147
|
-
|
|
148
|
-
// Create .gitkeep in _components
|
|
149
|
-
await Bun.write(`${componentsDir}/.gitkeep`, "")
|
|
150
|
-
|
|
151
|
-
// Generate and write page.tsx
|
|
152
|
-
const pageContent = generatePageContent(pageName, options)
|
|
153
|
-
await Bun.write(`${pageDir}/page.tsx`, pageContent)
|
|
154
|
-
|
|
155
|
-
// Create CSS module if requested
|
|
156
|
-
if (options.css) {
|
|
157
|
-
const cssContent = `/* ${pageName}.module.css */
|
|
158
|
-
|
|
159
|
-
.container {
|
|
160
|
-
/* Add your styles here */
|
|
161
|
-
}
|
|
162
|
-
`
|
|
163
|
-
await Bun.write(`${pageDir}/${pageName}.module.css`, cssContent)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
s.stop(`Page "${pageName}" generated successfully!`)
|
|
167
|
-
|
|
168
|
-
// Show what was created
|
|
169
|
-
p.log.success(`Generated files:`)
|
|
170
|
-
p.log.message(` 📄 ${pageDir}/page.tsx`)
|
|
171
|
-
p.log.message(` 📁 ${componentsDir}/`)
|
|
172
|
-
if (options.css) {
|
|
173
|
-
p.log.message(` 🎨 ${pageDir}/${pageName}.module.css`)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Build next steps message
|
|
177
|
-
const nextSteps = [`1. Customize ${pageDir}/page.tsx`]
|
|
178
|
-
|
|
179
|
-
nextSteps.push(
|
|
180
|
-
`${nextSteps.length + 1}. Add components to ${componentsDir}/`
|
|
181
|
-
)
|
|
182
|
-
nextSteps.push(
|
|
183
|
-
`${nextSteps.length + 1}. Visit /${pageName} to see your page`
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
p.note(`Next steps:\n ${nextSteps.join("\n ")}`)
|
|
187
|
-
} catch (error) {
|
|
188
|
-
s.stop(`Failed to generate page "${pageName}"`)
|
|
189
|
-
throw error
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Export functions for use by unified generate script
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* Basement Generator CLI
|
|
4
|
-
*
|
|
5
|
-
* Interactive scaffolding for new pages and components.
|
|
6
|
-
* Generates pre-configured templates following project conventions.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* bun run generate
|
|
10
|
-
*
|
|
11
|
-
* Options:
|
|
12
|
-
* - Page: Creates route with layout, metadata, and optional integrations
|
|
13
|
-
* - Component: Creates UI component with CSS module and barrel export
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import * as p from "@clack/prompts"
|
|
17
|
-
import { createComponent, promptComponentConfig } from "./generate-component"
|
|
18
|
-
// Import the existing generators
|
|
19
|
-
import { createPage, promptPageConfig } from "./generate-page"
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Main CLI function
|
|
23
|
-
*/
|
|
24
|
-
const main = async (): Promise<void> => {
|
|
25
|
-
console.clear()
|
|
26
|
-
|
|
27
|
-
p.intro("Basement Generator")
|
|
28
|
-
|
|
29
|
-
// Ask what to create
|
|
30
|
-
const createType = await p.select({
|
|
31
|
-
message: "What would you like to generate?",
|
|
32
|
-
options: [
|
|
33
|
-
{
|
|
34
|
-
value: "page",
|
|
35
|
-
label: "Page",
|
|
36
|
-
hint: "New route/page with layout and components",
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
value: "component",
|
|
40
|
-
label: "Component",
|
|
41
|
-
hint: "New reusable UI component",
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
if (p.isCancel(createType)) {
|
|
47
|
-
p.cancel("Generation cancelled")
|
|
48
|
-
process.exit(0)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
if (createType === "page") {
|
|
53
|
-
// Get page configuration through interactive prompts
|
|
54
|
-
const { name: pageName, options } = await promptPageConfig()
|
|
55
|
-
|
|
56
|
-
// Create the page
|
|
57
|
-
await createPage(pageName, options)
|
|
58
|
-
} else if (createType === "component") {
|
|
59
|
-
// Get component configuration through interactive prompts
|
|
60
|
-
const { path: componentPath, options } = await promptComponentConfig()
|
|
61
|
-
|
|
62
|
-
// Create the component
|
|
63
|
-
await createComponent(componentPath, options)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
p.outro("Generation completed successfully! 🚀")
|
|
67
|
-
} catch (error) {
|
|
68
|
-
p.log.error(
|
|
69
|
-
`Generation failed: ${error instanceof Error ? error.message : String(error)}`
|
|
70
|
-
)
|
|
71
|
-
process.exit(1)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Run the CLI
|
|
76
|
-
main().catch((err) => {
|
|
77
|
-
p.log.error(`Unexpected error: ${err.message}`)
|
|
78
|
-
process.exit(1)
|
|
79
|
-
})
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { create } from "zustand"
|
|
2
|
-
|
|
3
|
-
type Store = {
|
|
4
|
-
isNavOpened: boolean
|
|
5
|
-
setIsNavOpened: (value: boolean) => void
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export const useStore = create<Store>((set) => ({
|
|
9
|
-
isNavOpened: false,
|
|
10
|
-
setIsNavOpened: (value: boolean) => set({ isNavOpened: value }),
|
|
11
|
-
}))
|