bsmnt 0.2.8 → 0.2.10

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 (157) hide show
  1. package/README.md +84 -146
  2. package/package.json +2 -2
  3. package/src/helpers/integrate/sanity/files/lib/utils/metadata.ts +1 -1
  4. package/src/templates/next-default/README.md +28 -199
  5. package/src/templates/next-default/app/layout.tsx +2 -3
  6. package/src/templates/next-default/biome.json +1 -14
  7. package/src/templates/next-default/components/layout/theme/index.tsx +2 -5
  8. package/src/templates/next-default/components/layout/wrapper/index.tsx +1 -2
  9. package/src/templates/next-default/components/ui/README.md +2 -3
  10. package/src/templates/next-default/components/ui/image/index.tsx +3 -3
  11. package/src/templates/next-default/lib/README.md +3 -3
  12. package/src/templates/next-default/lib/hooks/use-device-detection.ts +3 -2
  13. package/src/templates/next-default/lib/hooks/use-media-breakpoint.ts +10 -3
  14. package/src/templates/next-default/lib/scripts/dev.ts +9 -29
  15. package/src/templates/next-default/lib/styles/README.md +7 -58
  16. package/src/templates/next-default/lib/styles/fonts.ts +7 -15
  17. package/src/templates/next-default/lib/styles/global.css +198 -0
  18. package/src/templates/next-default/lib/styles/index.css +3 -0
  19. package/src/templates/next-default/lib/styles/tokens.css +179 -0
  20. package/src/templates/next-default/lib/utils/global-css.d.ts +1 -0
  21. package/src/templates/next-default/lib/utils/metadata.ts +1 -1
  22. package/src/templates/next-default/lib/utils/viewport.ts +11 -5
  23. package/src/templates/next-default/next.config.ts +0 -1
  24. package/src/templates/next-default/package.json +10 -17
  25. package/src/templates/next-default/postcss.config.mjs +0 -14
  26. package/src/templates/next-default/tsconfig.tsbuildinfo +1 -0
  27. package/src/templates/next-experiments/README.md +29 -200
  28. package/src/templates/next-experiments/app/layout.tsx +2 -3
  29. package/src/templates/next-experiments/app/page.tsx +46 -39
  30. package/src/templates/next-experiments/biome.json +1 -14
  31. package/src/templates/next-experiments/components/layout/theme/index.tsx +2 -5
  32. package/src/templates/next-experiments/components/layout/wrapper/index.tsx +1 -2
  33. package/src/templates/next-experiments/components/ui/README.md +2 -3
  34. package/src/templates/next-experiments/components/ui/image/index.tsx +3 -2
  35. package/src/templates/next-experiments/lib/README.md +3 -3
  36. package/src/templates/next-experiments/lib/hooks/use-device-detection.ts +3 -2
  37. package/src/templates/next-experiments/lib/hooks/use-media-breakpoint.ts +10 -3
  38. package/src/templates/next-experiments/lib/scripts/dev.ts +9 -29
  39. package/src/templates/next-experiments/lib/styles/README.md +7 -58
  40. package/src/templates/next-experiments/lib/styles/fonts.ts +7 -15
  41. package/src/templates/next-experiments/lib/styles/global.css +198 -0
  42. package/src/templates/next-experiments/lib/styles/index.css +3 -0
  43. package/src/templates/next-experiments/lib/styles/tokens.css +179 -0
  44. package/src/templates/next-experiments/lib/utils/global-css.d.ts +1 -0
  45. package/src/templates/next-experiments/lib/utils/metadata.ts +1 -1
  46. package/src/templates/next-experiments/lib/utils/viewport.ts +11 -5
  47. package/src/templates/next-experiments/next.config.ts +0 -1
  48. package/src/templates/next-experiments/package.json +10 -21
  49. package/src/templates/next-experiments/postcss.config.mjs +0 -14
  50. package/src/templates/next-experiments/tsconfig.tsbuildinfo +1 -0
  51. package/src/templates/next-webgl/README.md +30 -200
  52. package/src/templates/next-webgl/app/layout.tsx +2 -3
  53. package/src/templates/next-webgl/biome.json +1 -14
  54. package/src/templates/next-webgl/components/layout/theme/index.tsx +2 -5
  55. package/src/templates/next-webgl/components/layout/wrapper/index.tsx +1 -2
  56. package/src/templates/next-webgl/components/ui/README.md +2 -3
  57. package/src/templates/next-webgl/components/ui/image/index.tsx +3 -3
  58. package/src/templates/next-webgl/lib/README.md +3 -3
  59. package/src/templates/next-webgl/lib/hooks/use-device-detection.ts +3 -2
  60. package/src/templates/next-webgl/lib/hooks/use-media-breakpoint.ts +10 -3
  61. package/src/templates/next-webgl/lib/scripts/dev.ts +9 -29
  62. package/src/templates/next-webgl/lib/styles/README.md +7 -58
  63. package/src/templates/next-webgl/lib/styles/fonts.ts +7 -15
  64. package/src/templates/next-webgl/lib/styles/global.css +198 -0
  65. package/src/templates/next-webgl/lib/styles/index.css +3 -0
  66. package/src/templates/next-webgl/lib/styles/tokens.css +179 -0
  67. package/src/templates/next-webgl/lib/utils/global-css.d.ts +1 -0
  68. package/src/templates/next-webgl/lib/utils/metadata.ts +1 -1
  69. package/src/templates/next-webgl/lib/utils/viewport.ts +11 -5
  70. package/src/templates/next-webgl/next.config.ts +0 -1
  71. package/src/templates/next-webgl/package.json +10 -19
  72. package/src/templates/next-webgl/postcss.config.mjs +0 -14
  73. package/src/templates/next-webgl/tsconfig.tsbuildinfo +1 -0
  74. package/src/templates/next-default/components/ui/image/image.module.css +0 -5
  75. package/src/templates/next-default/lib/scripts/generate-component.ts +0 -322
  76. package/src/templates/next-default/lib/scripts/generate-page.ts +0 -193
  77. package/src/templates/next-default/lib/scripts/generate.ts +0 -79
  78. package/src/templates/next-default/lib/store/app.ts +0 -11
  79. package/src/templates/next-default/lib/store/index.ts +0 -11
  80. package/src/templates/next-default/lib/styles/colors.ts +0 -63
  81. package/src/templates/next-default/lib/styles/config.ts +0 -34
  82. package/src/templates/next-default/lib/styles/css/global.css +0 -85
  83. package/src/templates/next-default/lib/styles/css/index.css +0 -6
  84. package/src/templates/next-default/lib/styles/css/reset.css +0 -166
  85. package/src/templates/next-default/lib/styles/css/root.css +0 -68
  86. package/src/templates/next-default/lib/styles/css/tailwind.css +0 -132
  87. package/src/templates/next-default/lib/styles/easings.ts +0 -21
  88. package/src/templates/next-default/lib/styles/index.ts +0 -12
  89. package/src/templates/next-default/lib/styles/layout.mjs +0 -27
  90. package/src/templates/next-default/lib/styles/scripts/README.md +0 -29
  91. package/src/templates/next-default/lib/styles/scripts/generate-root.ts +0 -57
  92. package/src/templates/next-default/lib/styles/scripts/generate-tailwind.ts +0 -162
  93. package/src/templates/next-default/lib/styles/scripts/postcss-functions.mjs +0 -168
  94. package/src/templates/next-default/lib/styles/scripts/setup-styles.ts +0 -24
  95. package/src/templates/next-default/lib/styles/scripts/utils.ts +0 -20
  96. package/src/templates/next-default/lib/styles/typography.ts +0 -36
  97. package/src/templates/next-default/lib/utils/css.d.ts +0 -21
  98. package/src/templates/next-default/lib/utils/math.test.ts +0 -221
  99. package/src/templates/next-default/lib/utils/strings.test.ts +0 -166
  100. package/src/templates/next-default/lib/utils/viewport.test.ts +0 -256
  101. package/src/templates/next-default/public/fonts/geist/Geist-Mono.woff2 +0 -0
  102. package/src/templates/next-experiments/components/ui/image/image.module.css +0 -5
  103. package/src/templates/next-experiments/lib/scripts/generate-component.ts +0 -322
  104. package/src/templates/next-experiments/lib/scripts/generate-page.ts +0 -193
  105. package/src/templates/next-experiments/lib/scripts/generate.ts +0 -79
  106. package/src/templates/next-experiments/lib/store/app.ts +0 -11
  107. package/src/templates/next-experiments/lib/store/index.ts +0 -11
  108. package/src/templates/next-experiments/lib/styles/colors.ts +0 -63
  109. package/src/templates/next-experiments/lib/styles/config.ts +0 -34
  110. package/src/templates/next-experiments/lib/styles/css/global.css +0 -85
  111. package/src/templates/next-experiments/lib/styles/css/index.css +0 -6
  112. package/src/templates/next-experiments/lib/styles/css/reset.css +0 -166
  113. package/src/templates/next-experiments/lib/styles/css/root.css +0 -68
  114. package/src/templates/next-experiments/lib/styles/css/tailwind.css +0 -132
  115. package/src/templates/next-experiments/lib/styles/easings.ts +0 -21
  116. package/src/templates/next-experiments/lib/styles/index.ts +0 -12
  117. package/src/templates/next-experiments/lib/styles/layout.mjs +0 -27
  118. package/src/templates/next-experiments/lib/styles/scripts/README.md +0 -29
  119. package/src/templates/next-experiments/lib/styles/scripts/generate-root.ts +0 -57
  120. package/src/templates/next-experiments/lib/styles/scripts/generate-tailwind.ts +0 -162
  121. package/src/templates/next-experiments/lib/styles/scripts/postcss-functions.mjs +0 -168
  122. package/src/templates/next-experiments/lib/styles/scripts/setup-styles.ts +0 -24
  123. package/src/templates/next-experiments/lib/styles/scripts/utils.ts +0 -20
  124. package/src/templates/next-experiments/lib/styles/typography.ts +0 -36
  125. package/src/templates/next-experiments/lib/utils/css.d.ts +0 -21
  126. package/src/templates/next-experiments/lib/utils/math.test.ts +0 -221
  127. package/src/templates/next-experiments/lib/utils/strings.test.ts +0 -166
  128. package/src/templates/next-experiments/lib/utils/viewport.test.ts +0 -256
  129. package/src/templates/next-experiments/public/fonts/geist/Geist-Mono.woff2 +0 -0
  130. package/src/templates/next-webgl/components/ui/image/image.module.css +0 -5
  131. package/src/templates/next-webgl/lib/scripts/generate-component.ts +0 -322
  132. package/src/templates/next-webgl/lib/scripts/generate-page.ts +0 -193
  133. package/src/templates/next-webgl/lib/scripts/generate.ts +0 -79
  134. package/src/templates/next-webgl/lib/store/app.ts +0 -11
  135. package/src/templates/next-webgl/lib/store/index.ts +0 -11
  136. package/src/templates/next-webgl/lib/styles/colors.ts +0 -63
  137. package/src/templates/next-webgl/lib/styles/config.ts +0 -34
  138. package/src/templates/next-webgl/lib/styles/css/global.css +0 -85
  139. package/src/templates/next-webgl/lib/styles/css/index.css +0 -6
  140. package/src/templates/next-webgl/lib/styles/css/reset.css +0 -166
  141. package/src/templates/next-webgl/lib/styles/css/root.css +0 -68
  142. package/src/templates/next-webgl/lib/styles/css/tailwind.css +0 -132
  143. package/src/templates/next-webgl/lib/styles/easings.ts +0 -21
  144. package/src/templates/next-webgl/lib/styles/index.ts +0 -12
  145. package/src/templates/next-webgl/lib/styles/layout.mjs +0 -27
  146. package/src/templates/next-webgl/lib/styles/scripts/README.md +0 -29
  147. package/src/templates/next-webgl/lib/styles/scripts/generate-root.ts +0 -57
  148. package/src/templates/next-webgl/lib/styles/scripts/generate-tailwind.ts +0 -162
  149. package/src/templates/next-webgl/lib/styles/scripts/postcss-functions.mjs +0 -168
  150. package/src/templates/next-webgl/lib/styles/scripts/setup-styles.ts +0 -24
  151. package/src/templates/next-webgl/lib/styles/scripts/utils.ts +0 -20
  152. package/src/templates/next-webgl/lib/styles/typography.ts +0 -36
  153. package/src/templates/next-webgl/lib/utils/css.d.ts +0 -21
  154. package/src/templates/next-webgl/lib/utils/math.test.ts +0 -221
  155. package/src/templates/next-webgl/lib/utils/strings.test.ts +0 -166
  156. package/src/templates/next-webgl/lib/utils/viewport.test.ts +0 -256
  157. package/src/templates/next-webgl/public/fonts/geist/Geist-Mono.woff2 +0 -0
@@ -1,5 +0,0 @@
1
- .block {
2
- display: block;
3
- width: 100%;
4
- height: auto;
5
- }
@@ -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
- * Satūs 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("Satūs 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
- }))
@@ -1,11 +0,0 @@
1
- /**
2
- * Custom Zustand Stores
3
- *
4
- * Import individual hooks:
5
- * import { useStore } from '@/store/app'
6
- *
7
- * Or import from barrel:
8
- * import { useStore } from '@/store/app'
9
- */
10
-
11
- export { useStore } from "./app"
@@ -1,63 +0,0 @@
1
- const palettes = {
2
- gray: {
3
- 50: "#F5F5F5",
4
- 100: "#E0E0E0",
5
- 200: "#C2C2C2",
6
- 300: "#A3A3A3",
7
- 400: "#858585",
8
- 500: "#666666",
9
- 600: "#4D4D4D",
10
- 700: "#333333",
11
- 800: "#1A1A1A",
12
- },
13
- blue: {
14
- 500: "#487CFF",
15
- },
16
- green: {
17
- 500: "#00FF9B",
18
- },
19
- violet: {
20
- 500: "#F101A5",
21
- },
22
- pink: {
23
- 500: "#FF73A6",
24
- },
25
- orange: {
26
- 500: "#FF4D00",
27
- },
28
- }
29
-
30
- const colors = {
31
- black: "#000000",
32
- white: "#ffffff",
33
- orange: palettes.orange[500],
34
- blue: palettes.blue[500],
35
- green: palettes.green[500],
36
- violet: palettes.violet[500],
37
- pink: palettes.pink[500],
38
- gray: palettes.gray[500],
39
- } as const
40
-
41
- const themeNames = ["light", "dark"] as const
42
- const colorNames = ["primary", "secondary", "contrast"] as const
43
-
44
- const themes = {
45
- light: {
46
- primary: colors.white,
47
- secondary: colors.black,
48
- contrast: colors.orange,
49
- },
50
- dark: {
51
- primary: colors.black,
52
- secondary: colors.white,
53
- contrast: colors.orange,
54
- },
55
- } as const satisfies Themes
56
-
57
- export { colors, palettes, themeNames, themes }
58
-
59
- // UTIL TYPES
60
- export type Themes = Record<
61
- (typeof themeNames)[number],
62
- Record<(typeof colorNames)[number], string>
63
- >