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.
Files changed (214) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +264 -63
  3. package/dist/adapters/gemini.d.ts +1 -0
  4. package/dist/adapters/gemini.d.ts.map +1 -1
  5. package/dist/adapters/gemini.js +9 -4
  6. package/dist/adapters/gemini.js.map +1 -1
  7. package/dist/adapters/grok.d.ts +1 -0
  8. package/dist/adapters/grok.d.ts.map +1 -1
  9. package/dist/adapters/grok.js +9 -4
  10. package/dist/adapters/grok.js.map +1 -1
  11. package/dist/adapters/openai.d.ts +1 -1
  12. package/dist/adapters/openai.d.ts.map +1 -1
  13. package/dist/adapters/openai.js +35 -9
  14. package/dist/adapters/openai.js.map +1 -1
  15. package/dist/cli/commands/create.d.ts.map +1 -1
  16. package/dist/cli/commands/create.js +54 -4
  17. package/dist/cli/commands/create.js.map +1 -1
  18. package/dist/cli/interactive.d.ts +29 -0
  19. package/dist/cli/interactive.d.ts.map +1 -1
  20. package/dist/cli/interactive.js +132 -7
  21. package/dist/cli/interactive.js.map +1 -1
  22. package/dist/generators/all.d.ts +8 -2
  23. package/dist/generators/all.d.ts.map +1 -1
  24. package/dist/generators/all.js +37 -316
  25. package/dist/generators/all.js.map +1 -1
  26. package/dist/generators/doc-parser.d.ts +64 -0
  27. package/dist/generators/doc-parser.d.ts.map +1 -0
  28. package/dist/generators/doc-parser.js +407 -0
  29. package/dist/generators/doc-parser.js.map +1 -0
  30. package/dist/generators/frontend-design-analyzer.d.ts +30 -0
  31. package/dist/generators/frontend-design-analyzer.d.ts.map +1 -0
  32. package/dist/generators/frontend-design-analyzer.js +208 -0
  33. package/dist/generators/frontend-design-analyzer.js.map +1 -0
  34. package/dist/generators/shared-packages.d.ts +45 -0
  35. package/dist/generators/shared-packages.d.ts.map +1 -0
  36. package/dist/generators/shared-packages.js +456 -0
  37. package/dist/generators/shared-packages.js.map +1 -0
  38. package/dist/generators/templates/index.d.ts +8 -0
  39. package/dist/generators/templates/index.d.ts.map +1 -1
  40. package/dist/generators/templates/index.js +8 -0
  41. package/dist/generators/templates/index.js.map +1 -1
  42. package/dist/generators/templates/website-components.d.ts +33 -0
  43. package/dist/generators/templates/website-components.d.ts.map +1 -0
  44. package/dist/generators/templates/website-components.js +303 -0
  45. package/dist/generators/templates/website-components.js.map +1 -0
  46. package/dist/generators/templates/website-config.d.ts +55 -0
  47. package/dist/generators/templates/website-config.d.ts.map +1 -0
  48. package/dist/generators/templates/website-config.js +425 -0
  49. package/dist/generators/templates/website-config.js.map +1 -0
  50. package/dist/generators/templates/website-conversion.d.ts +27 -0
  51. package/dist/generators/templates/website-conversion.d.ts.map +1 -0
  52. package/dist/generators/templates/website-conversion.js +326 -0
  53. package/dist/generators/templates/website-conversion.js.map +1 -0
  54. package/dist/generators/templates/website-landing.d.ts +24 -0
  55. package/dist/generators/templates/website-landing.d.ts.map +1 -0
  56. package/dist/generators/templates/website-landing.js +276 -0
  57. package/dist/generators/templates/website-landing.js.map +1 -0
  58. package/dist/generators/templates/website-layout.d.ts +42 -0
  59. package/dist/generators/templates/website-layout.d.ts.map +1 -0
  60. package/dist/generators/templates/website-layout.js +408 -0
  61. package/dist/generators/templates/website-layout.js.map +1 -0
  62. package/dist/generators/templates/website-pricing.d.ts +11 -0
  63. package/dist/generators/templates/website-pricing.d.ts.map +1 -0
  64. package/dist/generators/templates/website-pricing.js +313 -0
  65. package/dist/generators/templates/website-pricing.js.map +1 -0
  66. package/dist/generators/templates/website-sections.d.ts +102 -0
  67. package/dist/generators/templates/website-sections.d.ts.map +1 -0
  68. package/dist/generators/templates/website-sections.js +444 -0
  69. package/dist/generators/templates/website-sections.js.map +1 -0
  70. package/dist/generators/templates/website-seo.d.ts +76 -0
  71. package/dist/generators/templates/website-seo.d.ts.map +1 -0
  72. package/dist/generators/templates/website-seo.js +326 -0
  73. package/dist/generators/templates/website-seo.js.map +1 -0
  74. package/dist/generators/templates/website.d.ts +10 -83
  75. package/dist/generators/templates/website.d.ts.map +1 -1
  76. package/dist/generators/templates/website.js +12 -875
  77. package/dist/generators/templates/website.js.map +1 -1
  78. package/dist/generators/website-content-scanner.d.ts +37 -0
  79. package/dist/generators/website-content-scanner.d.ts.map +1 -0
  80. package/dist/generators/website-content-scanner.js +165 -0
  81. package/dist/generators/website-content-scanner.js.map +1 -0
  82. package/dist/generators/website-context.d.ts +119 -0
  83. package/dist/generators/website-context.d.ts.map +1 -0
  84. package/dist/generators/website-context.js +350 -0
  85. package/dist/generators/website-context.js.map +1 -0
  86. package/dist/generators/website-debug.d.ts +68 -0
  87. package/dist/generators/website-debug.d.ts.map +1 -0
  88. package/dist/generators/website-debug.js +93 -0
  89. package/dist/generators/website-debug.js.map +1 -0
  90. package/dist/generators/website.d.ts +5 -0
  91. package/dist/generators/website.d.ts.map +1 -1
  92. package/dist/generators/website.js +136 -11
  93. package/dist/generators/website.js.map +1 -1
  94. package/dist/generators/workspace-root.d.ts +27 -0
  95. package/dist/generators/workspace-root.d.ts.map +1 -0
  96. package/dist/generators/workspace-root.js +100 -0
  97. package/dist/generators/workspace-root.js.map +1 -0
  98. package/dist/state/index.d.ts +35 -0
  99. package/dist/state/index.d.ts.map +1 -1
  100. package/dist/state/index.js +40 -0
  101. package/dist/state/index.js.map +1 -1
  102. package/dist/types/consensus.d.ts +3 -0
  103. package/dist/types/consensus.d.ts.map +1 -1
  104. package/dist/types/consensus.js +1 -0
  105. package/dist/types/consensus.js.map +1 -1
  106. package/dist/types/website-strategy.d.ts +263 -0
  107. package/dist/types/website-strategy.d.ts.map +1 -0
  108. package/dist/types/website-strategy.js +105 -0
  109. package/dist/types/website-strategy.js.map +1 -0
  110. package/dist/types/workflow.d.ts +21 -0
  111. package/dist/types/workflow.d.ts.map +1 -1
  112. package/dist/types/workflow.js +8 -0
  113. package/dist/types/workflow.js.map +1 -1
  114. package/dist/upgrade/handlers.d.ts +15 -0
  115. package/dist/upgrade/handlers.d.ts.map +1 -1
  116. package/dist/upgrade/handlers.js +52 -0
  117. package/dist/upgrade/handlers.js.map +1 -1
  118. package/dist/workflow/auto-fix-bundler.d.ts +37 -0
  119. package/dist/workflow/auto-fix-bundler.d.ts.map +1 -0
  120. package/dist/workflow/auto-fix-bundler.js +320 -0
  121. package/dist/workflow/auto-fix-bundler.js.map +1 -0
  122. package/dist/workflow/auto-fix.d.ts.map +1 -1
  123. package/dist/workflow/auto-fix.js +10 -3
  124. package/dist/workflow/auto-fix.js.map +1 -1
  125. package/dist/workflow/consensus.d.ts.map +1 -1
  126. package/dist/workflow/consensus.js +2 -0
  127. package/dist/workflow/consensus.js.map +1 -1
  128. package/dist/workflow/execution-mode.d.ts.map +1 -1
  129. package/dist/workflow/execution-mode.js +18 -0
  130. package/dist/workflow/execution-mode.js.map +1 -1
  131. package/dist/workflow/index.d.ts +4 -0
  132. package/dist/workflow/index.d.ts.map +1 -1
  133. package/dist/workflow/index.js +37 -0
  134. package/dist/workflow/index.js.map +1 -1
  135. package/dist/workflow/overview.d.ts +89 -0
  136. package/dist/workflow/overview.d.ts.map +1 -0
  137. package/dist/workflow/overview.js +358 -0
  138. package/dist/workflow/overview.js.map +1 -0
  139. package/dist/workflow/plan-mode.d.ts +6 -4
  140. package/dist/workflow/plan-mode.d.ts.map +1 -1
  141. package/dist/workflow/plan-mode.js +148 -6
  142. package/dist/workflow/plan-mode.js.map +1 -1
  143. package/dist/workflow/website-strategy.d.ts +79 -0
  144. package/dist/workflow/website-strategy.d.ts.map +1 -0
  145. package/dist/workflow/website-strategy.js +310 -0
  146. package/dist/workflow/website-strategy.js.map +1 -0
  147. package/dist/workflow/website-updater.d.ts +17 -0
  148. package/dist/workflow/website-updater.d.ts.map +1 -0
  149. package/dist/workflow/website-updater.js +116 -0
  150. package/dist/workflow/website-updater.js.map +1 -0
  151. package/dist/workflow/workflow-logger.d.ts +1 -1
  152. package/dist/workflow/workflow-logger.d.ts.map +1 -1
  153. package/dist/workflow/workflow-logger.js.map +1 -1
  154. package/package.json +1 -1
  155. package/src/adapters/gemini.ts +10 -4
  156. package/src/adapters/grok.ts +10 -4
  157. package/src/adapters/openai.ts +38 -6
  158. package/src/cli/commands/create.ts +58 -4
  159. package/src/cli/interactive.ts +143 -7
  160. package/src/generators/all.ts +49 -332
  161. package/src/generators/doc-parser.ts +449 -0
  162. package/src/generators/frontend-design-analyzer.ts +261 -0
  163. package/src/generators/shared-packages.ts +500 -0
  164. package/src/generators/templates/index.ts +8 -0
  165. package/src/generators/templates/website-components.ts +330 -0
  166. package/src/generators/templates/website-config.ts +444 -0
  167. package/src/generators/templates/website-conversion.ts +341 -0
  168. package/src/generators/templates/website-landing.ts +331 -0
  169. package/src/generators/templates/website-layout.ts +443 -0
  170. package/src/generators/templates/website-pricing.ts +330 -0
  171. package/src/generators/templates/website-sections.ts +541 -0
  172. package/src/generators/templates/website-seo.ts +370 -0
  173. package/src/generators/templates/website.ts +38 -905
  174. package/src/generators/website-content-scanner.ts +208 -0
  175. package/src/generators/website-context.ts +493 -0
  176. package/src/generators/website-debug.ts +130 -0
  177. package/src/generators/website.ts +178 -20
  178. package/src/generators/workspace-root.ts +113 -0
  179. package/src/state/index.ts +56 -0
  180. package/src/types/consensus.ts +3 -0
  181. package/src/types/website-strategy.ts +243 -0
  182. package/src/types/workflow.ts +21 -0
  183. package/src/upgrade/handlers.ts +65 -0
  184. package/src/workflow/auto-fix-bundler.ts +392 -0
  185. package/src/workflow/auto-fix.ts +11 -3
  186. package/src/workflow/consensus.ts +2 -0
  187. package/src/workflow/execution-mode.ts +21 -0
  188. package/src/workflow/index.ts +37 -0
  189. package/src/workflow/overview.ts +475 -0
  190. package/src/workflow/plan-mode.ts +193 -8
  191. package/src/workflow/website-strategy.ts +379 -0
  192. package/src/workflow/website-updater.ts +142 -0
  193. package/src/workflow/workflow-logger.ts +1 -0
  194. package/tests/adapters/persona-switching.test.ts +63 -0
  195. package/tests/cli/project-naming.test.ts +136 -0
  196. package/tests/generators/doc-parser.test.ts +121 -0
  197. package/tests/generators/frontend-design-analyzer.test.ts +90 -0
  198. package/tests/generators/quality-gate.test.ts +183 -0
  199. package/tests/generators/shared-packages.test.ts +83 -0
  200. package/tests/generators/website-components.test.ts +159 -0
  201. package/tests/generators/website-config.test.ts +84 -0
  202. package/tests/generators/website-content-scanner.test.ts +181 -0
  203. package/tests/generators/website-context.test.ts +331 -0
  204. package/tests/generators/website-debug.test.ts +77 -0
  205. package/tests/generators/website-landing.test.ts +188 -0
  206. package/tests/generators/website-pricing.test.ts +98 -0
  207. package/tests/generators/website-sections.test.ts +245 -0
  208. package/tests/generators/website-seo-quality.test.ts +246 -0
  209. package/tests/generators/workspace-root.test.ts +105 -0
  210. package/tests/upgrade/handlers.test.ts +162 -0
  211. package/tests/workflow/auto-fix-bundler.test.ts +242 -0
  212. package/tests/workflow/overview.test.ts +392 -0
  213. package/tests/workflow/plan-mode.test.ts +111 -1
  214. package/tests/workflow/website-strategy.test.ts +246 -0
@@ -1,906 +1,39 @@
1
1
  /**
2
- * Website templates for Next.js marketing sites
3
- * Generates SEO-ready Next.js App Router projects
4
- */
5
-
6
- /**
7
- * Generate Next.js package.json
8
- */
9
- export function generateWebsitePackageJson(projectName: string): string {
10
- return `{
11
- "name": "${projectName}-website",
12
- "version": "1.0.0",
13
- "private": true,
14
- "scripts": {
15
- "dev": "next dev -p 3001",
16
- "build": "next build",
17
- "start": "next start -p 3001",
18
- "lint": "next lint",
19
- "test": "vitest run",
20
- "test:watch": "vitest",
21
- "typecheck": "tsc --noEmit"
22
- },
23
- "dependencies": {
24
- "next": "^14.1.0",
25
- "react": "^18.2.0",
26
- "react-dom": "^18.2.0",
27
- "lucide-react": "^0.312.0",
28
- "clsx": "^2.1.0",
29
- "tailwind-merge": "^2.2.0"
30
- },
31
- "devDependencies": {
32
- "@types/node": "^20.11.0",
33
- "@types/react": "^18.2.0",
34
- "@types/react-dom": "^18.2.0",
35
- "autoprefixer": "^10.4.17",
36
- "postcss": "^8.4.33",
37
- "tailwindcss": "^3.4.1",
38
- "typescript": "^5.3.3",
39
- "@testing-library/react": "^14.1.2",
40
- "@vitejs/plugin-react": "^4.2.1",
41
- "vitest": "^1.2.0",
42
- "jsdom": "^24.0.0"
43
- }
44
- }
45
- `;
46
- }
47
-
48
- /**
49
- * Generate Next.js config
50
- */
51
- export function generateNextConfig(): string {
52
- return `/** @type {import('next').NextConfig} */
53
- const nextConfig = {
54
- // Enable React Strict Mode for better development
55
- reactStrictMode: true,
56
-
57
- // Image optimization
58
- images: {
59
- domains: [],
60
- formats: ['image/avif', 'image/webp'],
61
- },
62
-
63
- // Disable x-powered-by header
64
- poweredByHeader: false,
65
-
66
- // Trailing slash config
67
- trailingSlash: false,
68
-
69
- // Headers for security
70
- async headers() {
71
- return [
72
- {
73
- source: '/:path*',
74
- headers: [
75
- {
76
- key: 'X-DNS-Prefetch-Control',
77
- value: 'on',
78
- },
79
- {
80
- key: 'X-Content-Type-Options',
81
- value: 'nosniff',
82
- },
83
- ],
84
- },
85
- ];
86
- },
87
- };
88
-
89
- module.exports = nextConfig;
90
- `;
91
- }
92
-
93
- /**
94
- * Generate website tsconfig.json
95
- */
96
- export function generateWebsiteTsconfig(): string {
97
- return `{
98
- "compilerOptions": {
99
- "target": "ES2017",
100
- "lib": ["dom", "dom.iterable", "esnext"],
101
- "allowJs": true,
102
- "skipLibCheck": true,
103
- "strict": true,
104
- "noEmit": true,
105
- "esModuleInterop": true,
106
- "module": "esnext",
107
- "moduleResolution": "bundler",
108
- "resolveJsonModule": true,
109
- "isolatedModules": true,
110
- "jsx": "preserve",
111
- "incremental": true,
112
- "plugins": [
113
- {
114
- "name": "next"
115
- }
116
- ],
117
- "paths": {
118
- "@/*": ["./src/*"]
119
- }
120
- },
121
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
122
- "exclude": ["node_modules"]
123
- }
124
- `;
125
- }
126
-
127
- /**
128
- * Generate Tailwind config for website
129
- */
130
- export function generateWebsiteTailwindConfig(): string {
131
- return `import type { Config } from 'tailwindcss';
132
-
133
- const config: Config = {
134
- content: [
135
- './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
136
- './src/components/**/*.{js,ts,jsx,tsx,mdx}',
137
- './src/app/**/*.{js,ts,jsx,tsx,mdx}',
138
- ],
139
- theme: {
140
- extend: {
141
- colors: {
142
- primary: {
143
- 50: '#f0f9ff',
144
- 100: '#e0f2fe',
145
- 200: '#bae6fd',
146
- 300: '#7dd3fc',
147
- 400: '#38bdf8',
148
- 500: '#0ea5e9',
149
- 600: '#0284c7',
150
- 700: '#0369a1',
151
- 800: '#075985',
152
- 900: '#0c4a6e',
153
- },
154
- },
155
- fontFamily: {
156
- sans: ['var(--font-inter)', 'system-ui', 'sans-serif'],
157
- },
158
- },
159
- },
160
- plugins: [],
161
- };
162
-
163
- export default config;
164
- `;
165
- }
166
-
167
- /**
168
- * Generate PostCSS config for website
169
- */
170
- export function generateWebsitePostcssConfig(): string {
171
- return `module.exports = {
172
- plugins: {
173
- tailwindcss: {},
174
- autoprefixer: {},
175
- },
176
- };
177
- `;
178
- }
179
-
180
- /**
181
- * Generate root layout.tsx with metadata
182
- */
183
- export function generateWebsiteLayout(projectName: string): string {
184
- const title = projectName
185
- .split('-')
186
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
187
- .join(' ');
188
-
189
- return `import type { Metadata } from 'next';
190
- import { Inter } from 'next/font/google';
191
- import './globals.css';
192
-
193
- const inter = Inter({
194
- subsets: ['latin'],
195
- variable: '--font-inter',
196
- });
197
-
198
- export const metadata: Metadata = {
199
- title: {
200
- default: '${title}',
201
- template: '%s | ${title}',
202
- },
203
- description: '${title} - Your modern web application',
204
- keywords: ['${projectName}', 'web app', 'nextjs'],
205
- authors: [{ name: '${title} Team' }],
206
- creator: '${title}',
207
- openGraph: {
208
- type: 'website',
209
- locale: 'en_US',
210
- url: 'https://${projectName}.com',
211
- siteName: '${title}',
212
- title: '${title}',
213
- description: '${title} - Your modern web application',
214
- },
215
- twitter: {
216
- card: 'summary_large_image',
217
- title: '${title}',
218
- description: '${title} - Your modern web application',
219
- },
220
- robots: {
221
- index: true,
222
- follow: true,
223
- },
224
- };
225
-
226
- export default function RootLayout({
227
- children,
228
- }: {
229
- children: React.ReactNode;
230
- }) {
231
- return (
232
- <html lang="en" className={inter.variable}>
233
- <body className="min-h-screen bg-white antialiased">
234
- {children}
235
- </body>
236
- </html>
237
- );
238
- }
239
- `;
240
- }
241
-
242
- /**
243
- * Generate globals.css
244
- */
245
- export function generateWebsiteGlobalsCss(): string {
246
- return `@tailwind base;
247
- @tailwind components;
248
- @tailwind utilities;
249
-
250
- @layer base {
251
- :root {
252
- --background: 0 0% 100%;
253
- --foreground: 222.2 84% 4.9%;
254
- --primary: 199 89% 48%;
255
- --primary-foreground: 210 40% 98%;
256
- }
257
-
258
- body {
259
- @apply bg-background text-foreground;
260
- }
261
- }
262
-
263
- @layer components {
264
- .container {
265
- @apply mx-auto max-w-7xl px-4 sm:px-6 lg:px-8;
266
- }
267
- }
268
- `;
269
- }
270
-
271
- /**
272
- * Generate landing page.tsx
273
- */
274
- export function generateWebsiteLandingPage(projectName: string): string {
275
- const title = projectName
276
- .split('-')
277
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
278
- .join(' ');
279
-
280
- return `import type { Metadata } from 'next';
281
- import Link from 'next/link';
282
-
283
- export const metadata: Metadata = {
284
- title: 'Welcome',
285
- description: 'Welcome to ${title} - Your modern web application',
286
- };
287
-
288
- export default function HomePage() {
289
- return (
290
- <main className="flex min-h-screen flex-col">
291
- {/* Hero Section */}
292
- <section className="relative overflow-hidden bg-gradient-to-b from-primary-50 to-white py-20 sm:py-32">
293
- <div className="container">
294
- <div className="mx-auto max-w-2xl text-center">
295
- <h1 className="text-4xl font-bold tracking-tight text-gray-900 sm:text-6xl">
296
- ${title}
297
- </h1>
298
- <p className="mt-6 text-lg leading-8 text-gray-600">
299
- Build something amazing with our modern, scalable platform.
300
- Get started today and see the difference.
301
- </p>
302
- <div className="mt-10 flex items-center justify-center gap-x-6">
303
- <Link
304
- href="/pricing"
305
- className="rounded-md bg-primary-600 px-6 py-3 text-sm font-semibold text-white shadow-sm hover:bg-primary-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600"
306
- >
307
- Get started
308
- </Link>
309
- <Link
310
- href="/docs"
311
- className="text-sm font-semibold leading-6 text-gray-900 hover:text-primary-600"
312
- >
313
- Learn more <span aria-hidden="true">-&gt;</span>
314
- </Link>
315
- </div>
316
- </div>
317
- </div>
318
- </section>
319
-
320
- {/* Features Section */}
321
- <section className="py-20 sm:py-32">
322
- <div className="container">
323
- <div className="mx-auto max-w-2xl text-center">
324
- <h2 className="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
325
- Everything you need
326
- </h2>
327
- <p className="mt-4 text-lg text-gray-600">
328
- All the features you need to build amazing products.
329
- </p>
330
- </div>
331
- <div className="mx-auto mt-16 max-w-5xl">
332
- <div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
333
- {[
334
- {
335
- title: 'Fast',
336
- description: 'Optimized for speed and performance.',
337
- },
338
- {
339
- title: 'Secure',
340
- description: 'Built with security best practices.',
341
- },
342
- {
343
- title: 'Scalable',
344
- description: 'Grows with your business needs.',
345
- },
346
- ].map((feature) => (
347
- <div
348
- key={feature.title}
349
- className="rounded-2xl border border-gray-200 p-8"
350
- >
351
- <h3 className="text-lg font-semibold text-gray-900">
352
- {feature.title}
353
- </h3>
354
- <p className="mt-2 text-gray-600">{feature.description}</p>
355
- </div>
356
- ))}
357
- </div>
358
- </div>
359
- </div>
360
- </section>
361
-
362
- {/* Footer */}
363
- <footer className="border-t border-gray-200 py-12">
364
- <div className="container">
365
- <p className="text-center text-sm text-gray-500">
366
- &copy; {new Date().getFullYear()} ${title}. All rights reserved.
367
- </p>
368
- </div>
369
- </footer>
370
- </main>
371
- );
372
- }
373
- `;
374
- }
375
-
376
- /**
377
- * Generate pricing page
378
- */
379
- export function generateWebsitePricingPage(projectName: string): string {
380
- const title = projectName
381
- .split('-')
382
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
383
- .join(' ');
384
-
385
- return `import type { Metadata } from 'next';
386
-
387
- export const metadata: Metadata = {
388
- title: 'Pricing',
389
- description: 'Choose the perfect plan for your needs - ${title}',
390
- };
391
-
392
- const tiers = [
393
- {
394
- name: 'Free',
395
- price: '$0',
396
- description: 'Perfect for getting started',
397
- features: ['Up to 3 projects', 'Basic support', 'Community access'],
398
- cta: 'Get started',
399
- featured: false,
400
- },
401
- {
402
- name: 'Pro',
403
- price: '$29',
404
- description: 'For growing teams',
405
- features: [
406
- 'Unlimited projects',
407
- 'Priority support',
408
- 'Advanced analytics',
409
- 'Custom integrations',
410
- ],
411
- cta: 'Start free trial',
412
- featured: true,
413
- },
414
- {
415
- name: 'Enterprise',
416
- price: 'Custom',
417
- description: 'For large organizations',
418
- features: [
419
- 'Everything in Pro',
420
- 'Dedicated support',
421
- 'SLA guarantee',
422
- 'Custom contracts',
423
- ],
424
- cta: 'Contact sales',
425
- featured: false,
426
- },
427
- ];
428
-
429
- export default function PricingPage() {
430
- return (
431
- <main className="py-20 sm:py-32">
432
- <div className="container">
433
- <div className="mx-auto max-w-2xl text-center">
434
- <h1 className="text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl">
435
- Simple, transparent pricing
436
- </h1>
437
- <p className="mt-6 text-lg text-gray-600">
438
- Choose the plan that works best for you.
439
- </p>
440
- </div>
441
-
442
- <div className="mx-auto mt-16 grid max-w-lg grid-cols-1 gap-8 lg:max-w-5xl lg:grid-cols-3">
443
- {tiers.map((tier) => (
444
- <div
445
- key={tier.name}
446
- className={\`rounded-2xl p-8 \${
447
- tier.featured
448
- ? 'bg-primary-600 text-white ring-2 ring-primary-600'
449
- : 'border border-gray-200 bg-white'
450
- }\`}
451
- >
452
- <h2
453
- className={\`text-lg font-semibold \${
454
- tier.featured ? 'text-white' : 'text-gray-900'
455
- }\`}
456
- >
457
- {tier.name}
458
- </h2>
459
- <p
460
- className={\`mt-2 text-sm \${
461
- tier.featured ? 'text-primary-100' : 'text-gray-600'
462
- }\`}
463
- >
464
- {tier.description}
465
- </p>
466
- <p className="mt-6">
467
- <span
468
- className={\`text-4xl font-bold \${
469
- tier.featured ? 'text-white' : 'text-gray-900'
470
- }\`}
471
- >
472
- {tier.price}
473
- </span>
474
- {tier.price !== 'Custom' && (
475
- <span
476
- className={\`text-sm \${
477
- tier.featured ? 'text-primary-100' : 'text-gray-600'
478
- }\`}
479
- >
480
- /month
481
- </span>
482
- )}
483
- </p>
484
- <ul className="mt-8 space-y-4">
485
- {tier.features.map((feature) => (
486
- <li
487
- key={feature}
488
- className={\`flex text-sm \${
489
- tier.featured ? 'text-primary-100' : 'text-gray-600'
490
- }\`}
491
- >
492
- <svg
493
- className={\`h-5 w-5 flex-shrink-0 \${
494
- tier.featured ? 'text-white' : 'text-primary-600'
495
- }\`}
496
- viewBox="0 0 20 20"
497
- fill="currentColor"
498
- >
499
- <path
500
- fillRule="evenodd"
501
- d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
502
- clipRule="evenodd"
503
- />
504
- </svg>
505
- <span className="ml-3">{feature}</span>
506
- </li>
507
- ))}
508
- </ul>
509
- <button
510
- className={\`mt-8 w-full rounded-md px-4 py-2 text-sm font-semibold \${
511
- tier.featured
512
- ? 'bg-white text-primary-600 hover:bg-primary-50'
513
- : 'bg-primary-600 text-white hover:bg-primary-500'
514
- }\`}
515
- >
516
- {tier.cta}
517
- </button>
518
- </div>
519
- ))}
520
- </div>
521
- </div>
522
- </main>
523
- );
524
- }
525
- `;
526
- }
527
-
528
- /**
529
- * Generate sitemap.ts
530
- */
531
- export function generateWebsiteSitemap(projectName: string): string {
532
- return `import { MetadataRoute } from 'next';
533
-
534
- export default function sitemap(): MetadataRoute.Sitemap {
535
- const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://${projectName}.com';
536
-
537
- return [
538
- {
539
- url: baseUrl,
540
- lastModified: new Date(),
541
- changeFrequency: 'weekly',
542
- priority: 1,
543
- },
544
- {
545
- url: \`\${baseUrl}/pricing\`,
546
- lastModified: new Date(),
547
- changeFrequency: 'monthly',
548
- priority: 0.8,
549
- },
550
- {
551
- url: \`\${baseUrl}/docs\`,
552
- lastModified: new Date(),
553
- changeFrequency: 'weekly',
554
- priority: 0.8,
555
- },
556
- {
557
- url: \`\${baseUrl}/blog\`,
558
- lastModified: new Date(),
559
- changeFrequency: 'daily',
560
- priority: 0.7,
561
- },
562
- ];
563
- }
564
- `;
565
- }
566
-
567
- /**
568
- * Generate robots.ts
569
- */
570
- export function generateWebsiteRobots(projectName: string): string {
571
- return `import { MetadataRoute } from 'next';
572
-
573
- export default function robots(): MetadataRoute.Robots {
574
- const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://${projectName}.com';
575
-
576
- return {
577
- rules: [
578
- {
579
- userAgent: '*',
580
- allow: '/',
581
- disallow: ['/api/', '/admin/'],
582
- },
583
- ],
584
- sitemap: \`\${baseUrl}/sitemap.xml\`,
585
- };
586
- }
587
- `;
588
- }
589
-
590
- /**
591
- * Generate website Dockerfile
592
- */
593
- export function generateWebsiteDockerfile(): string {
594
- return `# Build stage
595
- FROM node:20-alpine AS builder
596
-
597
- WORKDIR /app
598
-
599
- # Copy package files
600
- COPY package*.json ./
601
-
602
- # Install dependencies
603
- RUN npm ci
604
-
605
- # Copy source
606
- COPY . .
607
-
608
- # Build
609
- RUN npm run build
610
-
611
- # Production stage
612
- FROM node:20-alpine AS runner
613
-
614
- WORKDIR /app
615
-
616
- ENV NODE_ENV=production
617
- ENV NEXT_TELEMETRY_DISABLED=1
618
-
619
- # Create non-root user
620
- RUN addgroup --system --gid 1001 nodejs
621
- RUN adduser --system --uid 1001 nextjs
622
-
623
- # Copy built assets
624
- COPY --from=builder /app/public ./public
625
- COPY --from=builder /app/.next/standalone ./
626
- COPY --from=builder /app/.next/static ./.next/static
627
-
628
- USER nextjs
629
-
630
- EXPOSE 3000
631
-
632
- ENV PORT=3000
633
- ENV HOSTNAME="0.0.0.0"
634
-
635
- CMD ["node", "server.js"]
636
- `;
637
- }
638
-
639
- /**
640
- * Generate website README
641
- */
642
- export function generateWebsiteReadme(projectName: string): string {
643
- const title = projectName
644
- .split('-')
645
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
646
- .join(' ');
647
-
648
- return `# ${title} Website
649
-
650
- Next.js marketing website with SEO optimization.
651
-
652
- ## Getting Started
653
-
654
- \`\`\`bash
655
- # Install dependencies
656
- npm install
657
-
658
- # Run development server (port 3001)
659
- npm run dev
660
-
661
- # Build for production
662
- npm run build
663
-
664
- # Run production server
665
- npm start
666
- \`\`\`
667
-
668
- ## SEO Features
669
-
670
- - Server-side rendering (SSR)
671
- - Auto-generated sitemap
672
- - robots.txt configuration
673
- - OpenGraph and Twitter meta tags
674
- - Structured data support
675
-
676
- ## Project Structure
677
-
678
- \`\`\`
679
- src/
680
- app/
681
- layout.tsx # Root layout with metadata
682
- page.tsx # Landing page
683
- pricing/ # Pricing page
684
- docs/ # Documentation
685
- blog/ # Blog
686
- sitemap.ts # Auto-generated sitemap
687
- robots.ts # robots.txt config
688
- components/ # UI components
689
- lib/ # Utilities
690
- content/
691
- blog/ # MDX blog posts
692
- docs/ # MDX documentation
693
- \`\`\`
694
-
695
- ## Development
696
-
697
- - Port: 3001 (to avoid conflicts with frontend on 5173)
698
- - API URL: Configure via NEXT_PUBLIC_APP_URL
699
- `;
700
- }
701
-
702
- /**
703
- * Generate website spec JSON
704
- */
705
- export function generateWebsiteSpec(projectName: string): string {
706
- const title = projectName
707
- .split('-')
708
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
709
- .join(' ');
710
-
711
- return JSON.stringify(
712
- {
713
- version: '1.0',
714
- brand: {
715
- name: title,
716
- tagline: 'Build something amazing',
717
- colors: {
718
- primary: '#0ea5e9',
719
- secondary: '#64748b',
720
- accent: '#f59e0b',
721
- background: '#ffffff',
722
- foreground: '#0f172a',
723
- },
724
- typography: {
725
- headingFont: 'Inter',
726
- bodyFont: 'Inter',
727
- },
728
- },
729
- seo: {
730
- title: title,
731
- description: `${title} - Your modern web application`,
732
- keywords: [projectName, 'web app', 'nextjs', 'saas'],
733
- locale: 'en_US',
734
- },
735
- pages: [
736
- { name: 'Home', path: '/', type: 'landing' },
737
- { name: 'Pricing', path: '/pricing', type: 'pricing' },
738
- { name: 'Documentation', path: '/docs', type: 'docs' },
739
- { name: 'Blog', path: '/blog', type: 'blog' },
740
- ],
741
- cta: {
742
- primary: { text: 'Get Started', href: '/pricing' },
743
- secondary: { text: 'Learn More', href: '/docs' },
744
- },
745
- features: {
746
- analytics: true,
747
- newsletter: false,
748
- mdxBlog: true,
749
- docsSearch: false,
750
- },
751
- },
752
- null,
753
- 2
754
- );
755
- }
756
-
757
- /**
758
- * Generate vitest config for website
759
- */
760
- export function generateWebsiteVitestConfig(): string {
761
- return `import { defineConfig } from 'vitest/config';
762
- import react from '@vitejs/plugin-react';
763
- import path from 'path';
764
-
765
- export default defineConfig({
766
- plugins: [react()],
767
- test: {
768
- environment: 'jsdom',
769
- include: ['**/*.test.{ts,tsx}'],
770
- globals: true,
771
- setupFiles: ['./tests/setup.ts'],
772
- },
773
- resolve: {
774
- alias: {
775
- '@': path.resolve(__dirname, './src'),
776
- },
777
- },
778
- });
779
- `;
780
- }
781
-
782
- /**
783
- * Generate vitest setup for website
784
- */
785
- export function generateWebsiteVitestSetup(): string {
786
- return `import '@testing-library/jest-dom';
787
-
788
- // Mock next/navigation
789
- vi.mock('next/navigation', () => ({
790
- useRouter: () => ({
791
- push: vi.fn(),
792
- replace: vi.fn(),
793
- prefetch: vi.fn(),
794
- }),
795
- useSearchParams: () => new URLSearchParams(),
796
- usePathname: () => '/',
797
- }));
798
-
799
- // Mock next/image
800
- vi.mock('next/image', () => ({
801
- default: (props: Record<string, unknown>) => {
802
- // eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
803
- return <img {...props} />;
804
- },
805
- }));
806
- `;
807
- }
808
-
809
- /**
810
- * Generate sample test for website
811
- */
812
- export function generateWebsiteTest(projectName: string): string {
813
- const title = projectName
814
- .split('-')
815
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
816
- .join(' ');
817
-
818
- return `import { describe, it, expect } from 'vitest';
819
- import { render, screen } from '@testing-library/react';
820
- import HomePage from '@/app/page';
821
-
822
- describe('HomePage', () => {
823
- it('renders the title', () => {
824
- render(<HomePage />);
825
- expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent('${title}');
826
- });
827
-
828
- it('renders the call-to-action buttons', () => {
829
- render(<HomePage />);
830
- expect(screen.getByRole('link', { name: /get started/i })).toBeInTheDocument();
831
- expect(screen.getByRole('link', { name: /learn more/i })).toBeInTheDocument();
832
- });
833
-
834
- it('renders feature cards', () => {
835
- render(<HomePage />);
836
- expect(screen.getByText('Fast')).toBeInTheDocument();
837
- expect(screen.getByText('Secure')).toBeInTheDocument();
838
- expect(screen.getByText('Scalable')).toBeInTheDocument();
839
- });
840
- });
841
- `;
842
- }
843
-
844
- /**
845
- * Generate docs page placeholder
846
- */
847
- export function generateWebsiteDocsPage(): string {
848
- return `import type { Metadata } from 'next';
849
-
850
- export const metadata: Metadata = {
851
- title: 'Documentation',
852
- description: 'Learn how to use our platform with comprehensive documentation.',
853
- };
854
-
855
- export default function DocsPage() {
856
- return (
857
- <main className="py-20">
858
- <div className="container">
859
- <h1 className="text-4xl font-bold text-gray-900">Documentation</h1>
860
- <p className="mt-4 text-lg text-gray-600">
861
- Documentation coming soon...
862
- </p>
863
- </div>
864
- </main>
865
- );
866
- }
867
- `;
868
- }
869
-
870
- /**
871
- * Generate blog listing page placeholder
872
- */
873
- export function generateWebsiteBlogPage(): string {
874
- return `import type { Metadata } from 'next';
875
-
876
- export const metadata: Metadata = {
877
- title: 'Blog',
878
- description: 'Latest news, updates, and insights from our team.',
879
- };
880
-
881
- export default function BlogPage() {
882
- return (
883
- <main className="py-20">
884
- <div className="container">
885
- <h1 className="text-4xl font-bold text-gray-900">Blog</h1>
886
- <p className="mt-4 text-lg text-gray-600">
887
- Blog posts coming soon...
888
- </p>
889
- </div>
890
- </main>
891
- );
892
- }
893
- `;
894
- }
895
-
896
- /**
897
- * Generate Next.js environment declaration
898
- */
899
- export function generateWebsiteNextEnv(): string {
900
- return `/// <reference types="next" />
901
- /// <reference types="next/image-types/global" />
902
-
903
- // NOTE: This file should not be edited
904
- // see https://nextjs.org/docs/basic-features/typescript for more information.
905
- `;
906
- }
2
+ * Website content templates - re-export module
3
+ * Backward compatibility: all functions are available from their new homes
4
+ * but can still be imported from this file
5
+ */
6
+
7
+ // Landing page (10-section redesign)
8
+ export { generateWebsiteLandingPage, generateWebsiteLandingPageWithInfo } from './website-landing.js';
9
+ export type { LandingPageResult } from './website-landing.js';
10
+
11
+ // Pricing page (with toggle + comparison)
12
+ export { generateWebsitePricingPage } from './website-pricing.js';
13
+
14
+ // Layout, CSS, utility pages
15
+ export {
16
+ generateWebsiteLayout,
17
+ generateWebsiteGlobalsCss,
18
+ generateWebsiteSitemap,
19
+ generateWebsiteRobots,
20
+ generateWebsiteReadme,
21
+ generateWebsiteSpec,
22
+ generateWebsiteTest,
23
+ generateWebsiteDocsPage,
24
+ generateWebsiteBlogPage,
25
+ } from './website-layout.js';
26
+
27
+ // Reusable section generators
28
+ export {
29
+ mapFeatureIcon,
30
+ isNumericMetric,
31
+ generatePainPointsSection,
32
+ generateDifferentiatorsSection,
33
+ generateHowItWorksSection,
34
+ generateStatsSection,
35
+ generateSocialProofSection,
36
+ generatePricingTeaserSection,
37
+ generateFaqSection,
38
+ } from './website-sections.js';
39
+ export type { SectionRenderInfo } from './website-sections.js';