popeye-cli 1.4.7 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/README.md +264 -63
- package/dist/adapters/gemini.d.ts +1 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +9 -4
- package/dist/adapters/gemini.js.map +1 -1
- package/dist/adapters/grok.d.ts +1 -0
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js +9 -4
- package/dist/adapters/grok.js.map +1 -1
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +35 -9
- package/dist/adapters/openai.js.map +1 -1
- package/dist/cli/commands/create.d.ts.map +1 -1
- package/dist/cli/commands/create.js +54 -4
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/interactive.d.ts +29 -0
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +132 -7
- package/dist/cli/interactive.js.map +1 -1
- package/dist/generators/all.d.ts +8 -2
- package/dist/generators/all.d.ts.map +1 -1
- package/dist/generators/all.js +37 -316
- package/dist/generators/all.js.map +1 -1
- package/dist/generators/doc-parser.d.ts +64 -0
- package/dist/generators/doc-parser.d.ts.map +1 -0
- package/dist/generators/doc-parser.js +407 -0
- package/dist/generators/doc-parser.js.map +1 -0
- package/dist/generators/frontend-design-analyzer.d.ts +30 -0
- package/dist/generators/frontend-design-analyzer.d.ts.map +1 -0
- package/dist/generators/frontend-design-analyzer.js +208 -0
- package/dist/generators/frontend-design-analyzer.js.map +1 -0
- package/dist/generators/shared-packages.d.ts +45 -0
- package/dist/generators/shared-packages.d.ts.map +1 -0
- package/dist/generators/shared-packages.js +456 -0
- package/dist/generators/shared-packages.js.map +1 -0
- package/dist/generators/templates/index.d.ts +8 -0
- package/dist/generators/templates/index.d.ts.map +1 -1
- package/dist/generators/templates/index.js +8 -0
- package/dist/generators/templates/index.js.map +1 -1
- package/dist/generators/templates/website-components.d.ts +33 -0
- package/dist/generators/templates/website-components.d.ts.map +1 -0
- package/dist/generators/templates/website-components.js +303 -0
- package/dist/generators/templates/website-components.js.map +1 -0
- package/dist/generators/templates/website-config.d.ts +55 -0
- package/dist/generators/templates/website-config.d.ts.map +1 -0
- package/dist/generators/templates/website-config.js +425 -0
- package/dist/generators/templates/website-config.js.map +1 -0
- package/dist/generators/templates/website-conversion.d.ts +27 -0
- package/dist/generators/templates/website-conversion.d.ts.map +1 -0
- package/dist/generators/templates/website-conversion.js +326 -0
- package/dist/generators/templates/website-conversion.js.map +1 -0
- package/dist/generators/templates/website-landing.d.ts +24 -0
- package/dist/generators/templates/website-landing.d.ts.map +1 -0
- package/dist/generators/templates/website-landing.js +276 -0
- package/dist/generators/templates/website-landing.js.map +1 -0
- package/dist/generators/templates/website-layout.d.ts +42 -0
- package/dist/generators/templates/website-layout.d.ts.map +1 -0
- package/dist/generators/templates/website-layout.js +408 -0
- package/dist/generators/templates/website-layout.js.map +1 -0
- package/dist/generators/templates/website-pricing.d.ts +11 -0
- package/dist/generators/templates/website-pricing.d.ts.map +1 -0
- package/dist/generators/templates/website-pricing.js +313 -0
- package/dist/generators/templates/website-pricing.js.map +1 -0
- package/dist/generators/templates/website-sections.d.ts +102 -0
- package/dist/generators/templates/website-sections.d.ts.map +1 -0
- package/dist/generators/templates/website-sections.js +444 -0
- package/dist/generators/templates/website-sections.js.map +1 -0
- package/dist/generators/templates/website-seo.d.ts +76 -0
- package/dist/generators/templates/website-seo.d.ts.map +1 -0
- package/dist/generators/templates/website-seo.js +326 -0
- package/dist/generators/templates/website-seo.js.map +1 -0
- package/dist/generators/templates/website.d.ts +10 -83
- package/dist/generators/templates/website.d.ts.map +1 -1
- package/dist/generators/templates/website.js +12 -875
- package/dist/generators/templates/website.js.map +1 -1
- package/dist/generators/website-content-scanner.d.ts +37 -0
- package/dist/generators/website-content-scanner.d.ts.map +1 -0
- package/dist/generators/website-content-scanner.js +165 -0
- package/dist/generators/website-content-scanner.js.map +1 -0
- package/dist/generators/website-context.d.ts +119 -0
- package/dist/generators/website-context.d.ts.map +1 -0
- package/dist/generators/website-context.js +350 -0
- package/dist/generators/website-context.js.map +1 -0
- package/dist/generators/website-debug.d.ts +68 -0
- package/dist/generators/website-debug.d.ts.map +1 -0
- package/dist/generators/website-debug.js +93 -0
- package/dist/generators/website-debug.js.map +1 -0
- package/dist/generators/website.d.ts +5 -0
- package/dist/generators/website.d.ts.map +1 -1
- package/dist/generators/website.js +136 -11
- package/dist/generators/website.js.map +1 -1
- package/dist/generators/workspace-root.d.ts +27 -0
- package/dist/generators/workspace-root.d.ts.map +1 -0
- package/dist/generators/workspace-root.js +100 -0
- package/dist/generators/workspace-root.js.map +1 -0
- package/dist/state/index.d.ts +35 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +40 -0
- package/dist/state/index.js.map +1 -1
- package/dist/types/consensus.d.ts +3 -0
- package/dist/types/consensus.d.ts.map +1 -1
- package/dist/types/consensus.js +1 -0
- package/dist/types/consensus.js.map +1 -1
- package/dist/types/website-strategy.d.ts +263 -0
- package/dist/types/website-strategy.d.ts.map +1 -0
- package/dist/types/website-strategy.js +105 -0
- package/dist/types/website-strategy.js.map +1 -0
- package/dist/types/workflow.d.ts +21 -0
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workflow.js +8 -0
- package/dist/types/workflow.js.map +1 -1
- package/dist/upgrade/handlers.d.ts +15 -0
- package/dist/upgrade/handlers.d.ts.map +1 -1
- package/dist/upgrade/handlers.js +52 -0
- package/dist/upgrade/handlers.js.map +1 -1
- package/dist/workflow/auto-fix-bundler.d.ts +37 -0
- package/dist/workflow/auto-fix-bundler.d.ts.map +1 -0
- package/dist/workflow/auto-fix-bundler.js +320 -0
- package/dist/workflow/auto-fix-bundler.js.map +1 -0
- package/dist/workflow/auto-fix.d.ts.map +1 -1
- package/dist/workflow/auto-fix.js +10 -3
- package/dist/workflow/auto-fix.js.map +1 -1
- package/dist/workflow/consensus.d.ts.map +1 -1
- package/dist/workflow/consensus.js +2 -0
- package/dist/workflow/consensus.js.map +1 -1
- package/dist/workflow/execution-mode.d.ts.map +1 -1
- package/dist/workflow/execution-mode.js +18 -0
- package/dist/workflow/execution-mode.js.map +1 -1
- package/dist/workflow/index.d.ts +4 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +37 -0
- package/dist/workflow/index.js.map +1 -1
- package/dist/workflow/overview.d.ts +89 -0
- package/dist/workflow/overview.d.ts.map +1 -0
- package/dist/workflow/overview.js +358 -0
- package/dist/workflow/overview.js.map +1 -0
- package/dist/workflow/plan-mode.d.ts +6 -4
- package/dist/workflow/plan-mode.d.ts.map +1 -1
- package/dist/workflow/plan-mode.js +148 -6
- package/dist/workflow/plan-mode.js.map +1 -1
- package/dist/workflow/website-strategy.d.ts +79 -0
- package/dist/workflow/website-strategy.d.ts.map +1 -0
- package/dist/workflow/website-strategy.js +310 -0
- package/dist/workflow/website-strategy.js.map +1 -0
- package/dist/workflow/website-updater.d.ts +17 -0
- package/dist/workflow/website-updater.d.ts.map +1 -0
- package/dist/workflow/website-updater.js +116 -0
- package/dist/workflow/website-updater.js.map +1 -0
- package/dist/workflow/workflow-logger.d.ts +1 -1
- package/dist/workflow/workflow-logger.d.ts.map +1 -1
- package/dist/workflow/workflow-logger.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/gemini.ts +10 -4
- package/src/adapters/grok.ts +10 -4
- package/src/adapters/openai.ts +38 -6
- package/src/cli/commands/create.ts +58 -4
- package/src/cli/interactive.ts +143 -7
- package/src/generators/all.ts +49 -332
- package/src/generators/doc-parser.ts +449 -0
- package/src/generators/frontend-design-analyzer.ts +261 -0
- package/src/generators/shared-packages.ts +500 -0
- package/src/generators/templates/index.ts +8 -0
- package/src/generators/templates/website-components.ts +330 -0
- package/src/generators/templates/website-config.ts +444 -0
- package/src/generators/templates/website-conversion.ts +341 -0
- package/src/generators/templates/website-landing.ts +331 -0
- package/src/generators/templates/website-layout.ts +443 -0
- package/src/generators/templates/website-pricing.ts +330 -0
- package/src/generators/templates/website-sections.ts +541 -0
- package/src/generators/templates/website-seo.ts +370 -0
- package/src/generators/templates/website.ts +38 -905
- package/src/generators/website-content-scanner.ts +208 -0
- package/src/generators/website-context.ts +493 -0
- package/src/generators/website-debug.ts +130 -0
- package/src/generators/website.ts +178 -20
- package/src/generators/workspace-root.ts +113 -0
- package/src/state/index.ts +56 -0
- package/src/types/consensus.ts +3 -0
- package/src/types/website-strategy.ts +243 -0
- package/src/types/workflow.ts +21 -0
- package/src/upgrade/handlers.ts +65 -0
- package/src/workflow/auto-fix-bundler.ts +392 -0
- package/src/workflow/auto-fix.ts +11 -3
- package/src/workflow/consensus.ts +2 -0
- package/src/workflow/execution-mode.ts +21 -0
- package/src/workflow/index.ts +37 -0
- package/src/workflow/overview.ts +475 -0
- package/src/workflow/plan-mode.ts +193 -8
- package/src/workflow/website-strategy.ts +379 -0
- package/src/workflow/website-updater.ts +142 -0
- package/src/workflow/workflow-logger.ts +1 -0
- package/tests/adapters/persona-switching.test.ts +63 -0
- package/tests/cli/project-naming.test.ts +136 -0
- package/tests/generators/doc-parser.test.ts +121 -0
- package/tests/generators/frontend-design-analyzer.test.ts +90 -0
- package/tests/generators/quality-gate.test.ts +183 -0
- package/tests/generators/shared-packages.test.ts +83 -0
- package/tests/generators/website-components.test.ts +159 -0
- package/tests/generators/website-config.test.ts +84 -0
- package/tests/generators/website-content-scanner.test.ts +181 -0
- package/tests/generators/website-context.test.ts +331 -0
- package/tests/generators/website-debug.test.ts +77 -0
- package/tests/generators/website-landing.test.ts +188 -0
- package/tests/generators/website-pricing.test.ts +98 -0
- package/tests/generators/website-sections.test.ts +245 -0
- package/tests/generators/website-seo-quality.test.ts +246 -0
- package/tests/generators/workspace-root.test.ts +105 -0
- package/tests/upgrade/handlers.test.ts +162 -0
- package/tests/workflow/auto-fix-bundler.test.ts +242 -0
- package/tests/workflow/overview.test.ts +392 -0
- package/tests/workflow/plan-mode.test.ts +111 -1
- package/tests/workflow/website-strategy.test.ts +246 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared package generators for monorepo workspaces
|
|
3
|
+
* Generates design-tokens and UI component packages
|
|
4
|
+
* with support for brand-specific color palettes
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Brand color options for design tokens
|
|
9
|
+
*/
|
|
10
|
+
export interface BrandColorOptions {
|
|
11
|
+
primaryColor?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Generate a color scale from a single hex color
|
|
16
|
+
* Converts hex to HSL and varies lightness across 10 stops (50-900)
|
|
17
|
+
*
|
|
18
|
+
* @param hex - Primary hex color (e.g., "#2563EB")
|
|
19
|
+
* @returns Record of color stops (50-900) with hex values
|
|
20
|
+
*/
|
|
21
|
+
export function generateColorScale(hex: string): Record<string, string> {
|
|
22
|
+
const rgb = hexToRgb(hex);
|
|
23
|
+
if (!rgb) {
|
|
24
|
+
// Fallback to default sky-blue on parse failure
|
|
25
|
+
return getDefaultPrimaryScale();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
|
|
29
|
+
const stops = [
|
|
30
|
+
{ key: '50', lightness: 0.95 },
|
|
31
|
+
{ key: '100', lightness: 0.90 },
|
|
32
|
+
{ key: '200', lightness: 0.80 },
|
|
33
|
+
{ key: '300', lightness: 0.68 },
|
|
34
|
+
{ key: '400', lightness: 0.56 },
|
|
35
|
+
{ key: '500', lightness: 0.48 },
|
|
36
|
+
{ key: '600', lightness: 0.40 },
|
|
37
|
+
{ key: '700', lightness: 0.32 },
|
|
38
|
+
{ key: '800', lightness: 0.24 },
|
|
39
|
+
{ key: '900', lightness: 0.15 },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const scale: Record<string, string> = {};
|
|
43
|
+
for (const stop of stops) {
|
|
44
|
+
scale[stop.key] = hslToHex(hsl.h, hsl.s, stop.lightness);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return scale;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Default sky-blue primary color scale (backward compatible)
|
|
52
|
+
*/
|
|
53
|
+
function getDefaultPrimaryScale(): Record<string, string> {
|
|
54
|
+
return {
|
|
55
|
+
50: '#f0f9ff',
|
|
56
|
+
100: '#e0f2fe',
|
|
57
|
+
200: '#bae6fd',
|
|
58
|
+
300: '#7dd3fc',
|
|
59
|
+
400: '#38bdf8',
|
|
60
|
+
500: '#0ea5e9',
|
|
61
|
+
600: '#0284c7',
|
|
62
|
+
700: '#0369a1',
|
|
63
|
+
800: '#075985',
|
|
64
|
+
900: '#0c4a6e',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Generate design tokens package with optional brand colors
|
|
70
|
+
*
|
|
71
|
+
* @param projectName - Project name for package naming
|
|
72
|
+
* @param brandColors - Optional brand color configuration
|
|
73
|
+
* @returns Package files array
|
|
74
|
+
*/
|
|
75
|
+
export function generateDesignTokensPackage(
|
|
76
|
+
projectName: string,
|
|
77
|
+
brandColors?: BrandColorOptions
|
|
78
|
+
): {
|
|
79
|
+
files: Array<{ path: string; content: string }>;
|
|
80
|
+
} {
|
|
81
|
+
const primaryScale = brandColors?.primaryColor
|
|
82
|
+
? generateColorScale(brandColors.primaryColor)
|
|
83
|
+
: getDefaultPrimaryScale();
|
|
84
|
+
|
|
85
|
+
const colorsContent = generateColorsModule(primaryScale);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
files: [
|
|
89
|
+
{
|
|
90
|
+
path: 'package.json',
|
|
91
|
+
content: JSON.stringify(
|
|
92
|
+
{
|
|
93
|
+
name: `@${projectName}/design-tokens`,
|
|
94
|
+
version: '1.0.0',
|
|
95
|
+
type: 'module',
|
|
96
|
+
main: './dist/index.js',
|
|
97
|
+
types: './dist/index.d.ts',
|
|
98
|
+
exports: {
|
|
99
|
+
'.': './dist/index.js',
|
|
100
|
+
'./tailwind': './dist/tailwind-preset.js',
|
|
101
|
+
},
|
|
102
|
+
scripts: {
|
|
103
|
+
build: 'tsc',
|
|
104
|
+
dev: 'tsc --watch',
|
|
105
|
+
},
|
|
106
|
+
devDependencies: {
|
|
107
|
+
typescript: '^5.3.3',
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
null,
|
|
111
|
+
2
|
|
112
|
+
),
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
path: 'tsconfig.json',
|
|
116
|
+
content: JSON.stringify(
|
|
117
|
+
{
|
|
118
|
+
compilerOptions: {
|
|
119
|
+
target: 'ES2020',
|
|
120
|
+
module: 'ESNext',
|
|
121
|
+
moduleResolution: 'bundler',
|
|
122
|
+
declaration: true,
|
|
123
|
+
outDir: './dist',
|
|
124
|
+
strict: true,
|
|
125
|
+
esModuleInterop: true,
|
|
126
|
+
skipLibCheck: true,
|
|
127
|
+
},
|
|
128
|
+
include: ['src'],
|
|
129
|
+
},
|
|
130
|
+
null,
|
|
131
|
+
2
|
|
132
|
+
),
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
path: 'src/index.ts',
|
|
136
|
+
content: `/**
|
|
137
|
+
* Design tokens for ${projectName}
|
|
138
|
+
*/
|
|
139
|
+
|
|
140
|
+
export * from './colors.js';
|
|
141
|
+
export * from './typography.js';
|
|
142
|
+
`,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
path: 'src/colors.ts',
|
|
146
|
+
content: colorsContent,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
path: 'src/typography.ts',
|
|
150
|
+
content: `/**
|
|
151
|
+
* Typography settings
|
|
152
|
+
*/
|
|
153
|
+
|
|
154
|
+
export const typography = {
|
|
155
|
+
fontFamily: {
|
|
156
|
+
sans: ['Inter', 'system-ui', 'sans-serif'],
|
|
157
|
+
mono: ['JetBrains Mono', 'Fira Code', 'monospace'],
|
|
158
|
+
},
|
|
159
|
+
fontSize: {
|
|
160
|
+
xs: ['0.75rem', { lineHeight: '1rem' }],
|
|
161
|
+
sm: ['0.875rem', { lineHeight: '1.25rem' }],
|
|
162
|
+
base: ['1rem', { lineHeight: '1.5rem' }],
|
|
163
|
+
lg: ['1.125rem', { lineHeight: '1.75rem' }],
|
|
164
|
+
xl: ['1.25rem', { lineHeight: '1.75rem' }],
|
|
165
|
+
'2xl': ['1.5rem', { lineHeight: '2rem' }],
|
|
166
|
+
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
|
|
167
|
+
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
|
|
168
|
+
'5xl': ['3rem', { lineHeight: '1' }],
|
|
169
|
+
'6xl': ['3.75rem', { lineHeight: '1' }],
|
|
170
|
+
},
|
|
171
|
+
} as const;
|
|
172
|
+
|
|
173
|
+
export type Typography = typeof typography;
|
|
174
|
+
`,
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
path: 'src/tailwind-preset.ts',
|
|
178
|
+
content: `/**
|
|
179
|
+
* Tailwind CSS preset with design tokens
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
import { colors } from './colors.js';
|
|
183
|
+
import { typography } from './typography.js';
|
|
184
|
+
|
|
185
|
+
export const preset = {
|
|
186
|
+
theme: {
|
|
187
|
+
extend: {
|
|
188
|
+
colors,
|
|
189
|
+
fontFamily: typography.fontFamily,
|
|
190
|
+
fontSize: typography.fontSize,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export default preset;
|
|
196
|
+
`,
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Generate the colors.ts module content with given primary scale
|
|
204
|
+
*/
|
|
205
|
+
function generateColorsModule(primaryScale: Record<string, string>): string {
|
|
206
|
+
const entries = Object.entries(primaryScale)
|
|
207
|
+
.map(([key, value]) => ` ${key}: '${value}',`)
|
|
208
|
+
.join('\n');
|
|
209
|
+
|
|
210
|
+
return `/**
|
|
211
|
+
* Color palette
|
|
212
|
+
*/
|
|
213
|
+
|
|
214
|
+
export const colors = {
|
|
215
|
+
primary: {
|
|
216
|
+
${entries}
|
|
217
|
+
},
|
|
218
|
+
secondary: {
|
|
219
|
+
50: '#f8fafc',
|
|
220
|
+
100: '#f1f5f9',
|
|
221
|
+
200: '#e2e8f0',
|
|
222
|
+
300: '#cbd5e1',
|
|
223
|
+
400: '#94a3b8',
|
|
224
|
+
500: '#64748b',
|
|
225
|
+
600: '#475569',
|
|
226
|
+
700: '#334155',
|
|
227
|
+
800: '#1e293b',
|
|
228
|
+
900: '#0f172a',
|
|
229
|
+
},
|
|
230
|
+
} as const;
|
|
231
|
+
|
|
232
|
+
export type ColorScale = typeof colors.primary;
|
|
233
|
+
export type Colors = typeof colors;
|
|
234
|
+
`;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Generate UI components package
|
|
239
|
+
*
|
|
240
|
+
* @param projectName - Project name for package naming
|
|
241
|
+
* @returns Package files array
|
|
242
|
+
*/
|
|
243
|
+
export function generateUiPackage(projectName: string): {
|
|
244
|
+
files: Array<{ path: string; content: string }>;
|
|
245
|
+
} {
|
|
246
|
+
return {
|
|
247
|
+
files: [
|
|
248
|
+
{
|
|
249
|
+
path: 'package.json',
|
|
250
|
+
content: JSON.stringify(
|
|
251
|
+
{
|
|
252
|
+
name: `@${projectName}/ui`,
|
|
253
|
+
version: '1.0.0',
|
|
254
|
+
type: 'module',
|
|
255
|
+
main: './dist/index.js',
|
|
256
|
+
types: './dist/index.d.ts',
|
|
257
|
+
exports: {
|
|
258
|
+
'.': './dist/index.js',
|
|
259
|
+
'./button': './dist/button.js',
|
|
260
|
+
'./card': './dist/card.js',
|
|
261
|
+
},
|
|
262
|
+
scripts: {
|
|
263
|
+
build: 'tsc',
|
|
264
|
+
dev: 'tsc --watch',
|
|
265
|
+
},
|
|
266
|
+
dependencies: {
|
|
267
|
+
clsx: '^2.1.0',
|
|
268
|
+
'tailwind-merge': '^2.2.0',
|
|
269
|
+
},
|
|
270
|
+
peerDependencies: {
|
|
271
|
+
react: '>=18.0.0',
|
|
272
|
+
'react-dom': '>=18.0.0',
|
|
273
|
+
},
|
|
274
|
+
devDependencies: {
|
|
275
|
+
'@types/react': '^18.2.0',
|
|
276
|
+
'@types/react-dom': '^18.2.0',
|
|
277
|
+
typescript: '^5.3.3',
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
null,
|
|
281
|
+
2
|
|
282
|
+
),
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
path: 'tsconfig.json',
|
|
286
|
+
content: JSON.stringify(
|
|
287
|
+
{
|
|
288
|
+
compilerOptions: {
|
|
289
|
+
target: 'ES2020',
|
|
290
|
+
module: 'ESNext',
|
|
291
|
+
moduleResolution: 'bundler',
|
|
292
|
+
declaration: true,
|
|
293
|
+
outDir: './dist',
|
|
294
|
+
strict: true,
|
|
295
|
+
esModuleInterop: true,
|
|
296
|
+
skipLibCheck: true,
|
|
297
|
+
jsx: 'react-jsx',
|
|
298
|
+
},
|
|
299
|
+
include: ['src'],
|
|
300
|
+
},
|
|
301
|
+
null,
|
|
302
|
+
2
|
|
303
|
+
),
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
path: 'src/index.ts',
|
|
307
|
+
content: `/**
|
|
308
|
+
* Shared UI components for ${projectName}
|
|
309
|
+
*/
|
|
310
|
+
|
|
311
|
+
export * from './button.js';
|
|
312
|
+
export * from './card.js';
|
|
313
|
+
export * from './utils.js';
|
|
314
|
+
`,
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
path: 'src/utils.ts',
|
|
318
|
+
content: `import { clsx, type ClassValue } from 'clsx';
|
|
319
|
+
import { twMerge } from 'tailwind-merge';
|
|
320
|
+
|
|
321
|
+
export function cn(...inputs: ClassValue[]) {
|
|
322
|
+
return twMerge(clsx(inputs));
|
|
323
|
+
}
|
|
324
|
+
`,
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
path: 'src/button.tsx',
|
|
328
|
+
content: `import * as React from 'react';
|
|
329
|
+
import { cn } from './utils.js';
|
|
330
|
+
|
|
331
|
+
export interface ButtonProps
|
|
332
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
333
|
+
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
|
334
|
+
size?: 'sm' | 'md' | 'lg';
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
338
|
+
({ className, variant = 'primary', size = 'md', ...props }, ref) => {
|
|
339
|
+
return (
|
|
340
|
+
<button
|
|
341
|
+
className={cn(
|
|
342
|
+
'inline-flex items-center justify-center rounded-md font-medium transition-colors',
|
|
343
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2',
|
|
344
|
+
'disabled:pointer-events-none disabled:opacity-50',
|
|
345
|
+
{
|
|
346
|
+
// Variants
|
|
347
|
+
'bg-primary-600 text-white hover:bg-primary-500': variant === 'primary',
|
|
348
|
+
'bg-secondary-100 text-secondary-900 hover:bg-secondary-200': variant === 'secondary',
|
|
349
|
+
'border border-secondary-300 bg-transparent hover:bg-secondary-50': variant === 'outline',
|
|
350
|
+
'bg-transparent hover:bg-secondary-100': variant === 'ghost',
|
|
351
|
+
// Sizes
|
|
352
|
+
'h-8 px-3 text-sm': size === 'sm',
|
|
353
|
+
'h-10 px-4 text-sm': size === 'md',
|
|
354
|
+
'h-12 px-6 text-base': size === 'lg',
|
|
355
|
+
},
|
|
356
|
+
className
|
|
357
|
+
)}
|
|
358
|
+
ref={ref}
|
|
359
|
+
{...props}
|
|
360
|
+
/>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
Button.displayName = 'Button';
|
|
366
|
+
`,
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
path: 'src/card.tsx',
|
|
370
|
+
content: `import * as React from 'react';
|
|
371
|
+
import { cn } from './utils.js';
|
|
372
|
+
|
|
373
|
+
export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
374
|
+
|
|
375
|
+
export const Card = React.forwardRef<HTMLDivElement, CardProps>(
|
|
376
|
+
({ className, ...props }, ref) => (
|
|
377
|
+
<div
|
|
378
|
+
ref={ref}
|
|
379
|
+
className={cn(
|
|
380
|
+
'rounded-lg border border-secondary-200 bg-white shadow-sm',
|
|
381
|
+
className
|
|
382
|
+
)}
|
|
383
|
+
{...props}
|
|
384
|
+
/>
|
|
385
|
+
)
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
Card.displayName = 'Card';
|
|
389
|
+
|
|
390
|
+
export const CardHeader = React.forwardRef<
|
|
391
|
+
HTMLDivElement,
|
|
392
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
393
|
+
>(({ className, ...props }, ref) => (
|
|
394
|
+
<div
|
|
395
|
+
ref={ref}
|
|
396
|
+
className={cn('flex flex-col space-y-1.5 p-6', className)}
|
|
397
|
+
{...props}
|
|
398
|
+
/>
|
|
399
|
+
));
|
|
400
|
+
|
|
401
|
+
CardHeader.displayName = 'CardHeader';
|
|
402
|
+
|
|
403
|
+
export const CardTitle = React.forwardRef<
|
|
404
|
+
HTMLParagraphElement,
|
|
405
|
+
React.HTMLAttributes<HTMLHeadingElement>
|
|
406
|
+
>(({ className, ...props }, ref) => (
|
|
407
|
+
<h3
|
|
408
|
+
ref={ref}
|
|
409
|
+
className={cn('text-lg font-semibold leading-none tracking-tight', className)}
|
|
410
|
+
{...props}
|
|
411
|
+
/>
|
|
412
|
+
));
|
|
413
|
+
|
|
414
|
+
CardTitle.displayName = 'CardTitle';
|
|
415
|
+
|
|
416
|
+
export const CardContent = React.forwardRef<
|
|
417
|
+
HTMLDivElement,
|
|
418
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
419
|
+
>(({ className, ...props }, ref) => (
|
|
420
|
+
<div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
|
|
421
|
+
));
|
|
422
|
+
|
|
423
|
+
CardContent.displayName = 'CardContent';
|
|
424
|
+
`,
|
|
425
|
+
},
|
|
426
|
+
],
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// --- Color conversion helpers ---
|
|
431
|
+
|
|
432
|
+
function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
|
|
433
|
+
const cleaned = hex.replace(/^#/, '');
|
|
434
|
+
if (cleaned.length !== 6) return null;
|
|
435
|
+
|
|
436
|
+
const r = parseInt(cleaned.substring(0, 2), 16);
|
|
437
|
+
const g = parseInt(cleaned.substring(2, 4), 16);
|
|
438
|
+
const b = parseInt(cleaned.substring(4, 6), 16);
|
|
439
|
+
|
|
440
|
+
if (isNaN(r) || isNaN(g) || isNaN(b)) return null;
|
|
441
|
+
return { r, g, b };
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function rgbToHsl(r: number, g: number, b: number): { h: number; s: number; l: number } {
|
|
445
|
+
const rn = r / 255;
|
|
446
|
+
const gn = g / 255;
|
|
447
|
+
const bn = b / 255;
|
|
448
|
+
|
|
449
|
+
const max = Math.max(rn, gn, bn);
|
|
450
|
+
const min = Math.min(rn, gn, bn);
|
|
451
|
+
const l = (max + min) / 2;
|
|
452
|
+
let h = 0;
|
|
453
|
+
let s = 0;
|
|
454
|
+
|
|
455
|
+
if (max !== min) {
|
|
456
|
+
const d = max - min;
|
|
457
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
458
|
+
|
|
459
|
+
if (max === rn) {
|
|
460
|
+
h = ((gn - bn) / d + (gn < bn ? 6 : 0)) / 6;
|
|
461
|
+
} else if (max === gn) {
|
|
462
|
+
h = ((bn - rn) / d + 2) / 6;
|
|
463
|
+
} else {
|
|
464
|
+
h = ((rn - gn) / d + 4) / 6;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return { h, s, l };
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function hslToHex(h: number, s: number, l: number): string {
|
|
472
|
+
const hue2rgb = (p: number, q: number, t: number): number => {
|
|
473
|
+
let tn = t;
|
|
474
|
+
if (tn < 0) tn += 1;
|
|
475
|
+
if (tn > 1) tn -= 1;
|
|
476
|
+
if (tn < 1 / 6) return p + (q - p) * 6 * tn;
|
|
477
|
+
if (tn < 1 / 2) return q;
|
|
478
|
+
if (tn < 2 / 3) return p + (q - p) * (2 / 3 - tn) * 6;
|
|
479
|
+
return p;
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
let r: number, g: number, b: number;
|
|
483
|
+
|
|
484
|
+
if (s === 0) {
|
|
485
|
+
r = g = b = l;
|
|
486
|
+
} else {
|
|
487
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
488
|
+
const p = 2 * l - q;
|
|
489
|
+
r = hue2rgb(p, q, h + 1 / 3);
|
|
490
|
+
g = hue2rgb(p, q, h);
|
|
491
|
+
b = hue2rgb(p, q, h - 1 / 3);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const toHex = (n: number): string => {
|
|
495
|
+
const hex = Math.round(n * 255).toString(16);
|
|
496
|
+
return hex.length === 1 ? '0' + hex : hex;
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
500
|
+
}
|
|
@@ -6,3 +6,11 @@ export * as pythonTemplates from './python.js';
|
|
|
6
6
|
export * as typescriptTemplates from './typescript.js';
|
|
7
7
|
export * as fullstackTemplates from './fullstack.js';
|
|
8
8
|
export * as websiteTemplates from './website.js';
|
|
9
|
+
export * as websiteConfigTemplates from './website-config.js';
|
|
10
|
+
export * as websiteComponentTemplates from './website-components.js';
|
|
11
|
+
export * as websiteSeoTemplates from './website-seo.js';
|
|
12
|
+
export * as websiteConversionTemplates from './website-conversion.js';
|
|
13
|
+
export * as websiteLandingTemplates from './website-landing.js';
|
|
14
|
+
export * as websitePricingTemplates from './website-pricing.js';
|
|
15
|
+
export * as websiteLayoutTemplates from './website-layout.js';
|
|
16
|
+
export * as websiteSectionTemplates from './website-sections.js';
|