@zoyth/simple-site-framework 1.0.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/LICENSE +21 -0
- package/README.md +572 -0
- package/bin/create-simple-site.js +390 -0
- package/bin/simple-site.js +664 -0
- package/dist/client.js +135 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +107 -0
- package/dist/client.mjs.map +1 -0
- package/dist/components/index.d.mts +3936 -0
- package/dist/components/index.d.ts +3936 -0
- package/dist/components/index.js +38265 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +38173 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/config/index.d.mts +298 -0
- package/dist/config/index.d.ts +298 -0
- package/dist/config/index.js +19 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/index.mjs +1 -0
- package/dist/config/index.mjs.map +1 -0
- package/dist/index.d.mts +2184 -0
- package/dist/index.d.ts +2184 -0
- package/dist/index.js +1713 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1605 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib/i18n/index.js +665 -0
- package/dist/lib/i18n/index.js.map +1 -0
- package/dist/lib/i18n/index.mjs +621 -0
- package/dist/lib/i18n/index.mjs.map +1 -0
- package/docs/DOCUMENTATION-STRUCTURE.md +1156 -0
- package/docs/EXPORTS.md +125 -0
- package/docs/PERFORMANCE.md +757 -0
- package/docs/POLICY-PAGES.md +867 -0
- package/docs/ROADMAP.md +334 -0
- package/docs/SEO.md +455 -0
- package/docs/SITEMAP.md +708 -0
- package/docs/STRUCTURED-DATA.md +671 -0
- package/docs/accessibility/common-patterns.md +529 -0
- package/docs/accessibility/keyboard-navigation.md +263 -0
- package/docs/accessibility/overview.md +122 -0
- package/docs/accessibility/screen-readers.md +311 -0
- package/docs/accessibility/wcag-compliance.md +159 -0
- package/docs/api/README.md +164 -0
- package/docs/api/components/Accessibility.md +356 -0
- package/docs/api/components/Button.md +240 -0
- package/docs/api/components/HeroSection.md +306 -0
- package/docs/architecture/decisions.md +449 -0
- package/docs/components/AnalyticsTracker.md +58 -0
- package/docs/components/AnimatedCounter.md +48 -0
- package/docs/components/AnimatedSection.md +56 -0
- package/docs/components/BlogCard.md +42 -0
- package/docs/components/Checkbox.md +56 -0
- package/docs/components/CodeBlock.md +52 -0
- package/docs/components/ComparisonTable.md +40 -0
- package/docs/components/ComponentDemo.md +38 -0
- package/docs/components/CountdownTimer.md +51 -0
- package/docs/components/ExitIntentModal.md +56 -0
- package/docs/components/FAQAccordion.md +66 -0
- package/docs/components/FeaturesGrid.md +55 -0
- package/docs/components/FileUpload.md +54 -0
- package/docs/components/I18nMetaTags.md +55 -0
- package/docs/components/Icon.md +53 -0
- package/docs/components/LazySection.md +46 -0
- package/docs/components/LiveProof.md +53 -0
- package/docs/components/LoadingSpinner.md +46 -0
- package/docs/components/MultiStepForm.md +48 -0
- package/docs/components/PolicyLayout.md +55 -0
- package/docs/components/PricingTable.md +49 -0
- package/docs/components/Radio.md +59 -0
- package/docs/components/SEOMetaTags.md +58 -0
- package/docs/components/ScriptInjector.md +50 -0
- package/docs/components/Select.md +72 -0
- package/docs/components/Skeleton.md +47 -0
- package/docs/components/StatsSection.md +48 -0
- package/docs/components/StickyBar.md +62 -0
- package/docs/components/StructuredData.md +99 -0
- package/docs/components/StyleGuide.md +46 -0
- package/docs/components/TableOfContents.md +47 -0
- package/docs/components/TestimonialCarousel.md +42 -0
- package/docs/components/Timeline.md +51 -0
- package/docs/components/Toast.md +59 -0
- package/docs/components/TrackedLink.md +62 -0
- package/docs/components/TrustBadges.md +44 -0
- package/docs/components/conversion/MobileCTA.md +363 -0
- package/docs/components/forms/ContactForm.md +75 -0
- package/docs/components/forms/FormField.md +74 -0
- package/docs/components/layout/Footer.md +601 -0
- package/docs/components/layout/Header.md +549 -0
- package/docs/components/layout/LanguageSelector.md +54 -0
- package/docs/components/layout/LanguageSwitcher.md +24 -0
- package/docs/components/overview.md +447 -0
- package/docs/components/sections/AboutSection.md +48 -0
- package/docs/components/sections/CTASection.md +596 -0
- package/docs/components/sections/CaseStudySection.md +47 -0
- package/docs/components/sections/ContactSection.md +599 -0
- package/docs/components/sections/FeatureSection.md +44 -0
- package/docs/components/sections/HeroSection.md +404 -0
- package/docs/components/sections/LogosSection.md +47 -0
- package/docs/components/sections/PersonalTaxesSection.md +23 -0
- package/docs/components/sections/RecruitingSection.md +23 -0
- package/docs/components/sections/SecurePortalSection.md +23 -0
- package/docs/components/sections/ServicePageLayout.md +52 -0
- package/docs/components/sections/ServicesSection.md +49 -0
- package/docs/components/sections/TestimonialSection.md +44 -0
- package/docs/components/sections/WhyChooseUsSection.md +54 -0
- package/docs/components/ui/Breadcrumb.md +70 -0
- package/docs/components/ui/Button.md +514 -0
- package/docs/components/ui/Card.md +501 -0
- package/docs/components/ui/Input.md +54 -0
- package/docs/components/ui/MobileLinks.md +43 -0
- package/docs/components/ui/Modal.md +60 -0
- package/docs/components/ui/Tabs.md +62 -0
- package/docs/components/ui/Textarea.md +52 -0
- package/docs/core-concepts/configuration-driven.md +552 -0
- package/docs/core-concepts/overview.md +351 -0
- package/docs/features/accessibility/README.md +73 -0
- package/docs/features/accessibility/aria-support.md +177 -0
- package/docs/features/accessibility/color-contrast.md +155 -0
- package/docs/features/accessibility/focus-management.md +187 -0
- package/docs/features/accessibility/testing.md +196 -0
- package/docs/features/analytics/README.md +51 -0
- package/docs/features/analytics/ab-testing.md +171 -0
- package/docs/features/analytics/conversion-tracking.md +207 -0
- package/docs/features/analytics/custom-events.md +219 -0
- package/docs/features/analytics/privacy.md +198 -0
- package/docs/features/analytics/setup.md +114 -0
- package/docs/features/analytics/tracking-events.md +224 -0
- package/docs/features/i18n/README.md +51 -0
- package/docs/features/i18n/best-practices.md +273 -0
- package/docs/features/i18n/configuration.md +84 -0
- package/docs/features/i18n/formatting.md +133 -0
- package/docs/features/i18n/locale-detection.md +122 -0
- package/docs/features/i18n/routing.md +99 -0
- package/docs/features/i18n/rtl-support.md +191 -0
- package/docs/features/i18n/translations.md +129 -0
- package/docs/features/internationalization.md +595 -0
- package/docs/features/performance/README.md +77 -0
- package/docs/features/performance/bundle-size.md +134 -0
- package/docs/features/performance/caching.md +131 -0
- package/docs/features/performance/code-splitting.md +121 -0
- package/docs/features/performance/image-optimization.md +110 -0
- package/docs/features/performance/lazy-loading.md +92 -0
- package/docs/features/performance/monitoring.md +148 -0
- package/docs/features/seo/README.md +51 -0
- package/docs/features/seo/best-practices.md +184 -0
- package/docs/features/seo/canonical-urls.md +182 -0
- package/docs/features/seo/meta-tags.md +126 -0
- package/docs/features/seo/open-graph.md +166 -0
- package/docs/features/seo/robots-txt.md +146 -0
- package/docs/features/seo/sitemaps.md +162 -0
- package/docs/features/seo/structured-data.md +166 -0
- package/docs/getting-started/installation.md +292 -0
- package/docs/getting-started/introduction.md +195 -0
- package/docs/getting-started/quick-start.md +460 -0
- package/docs/guides/analytics-setup.md +616 -0
- package/docs/i18n/CONFIGURATION.md +353 -0
- package/docs/i18n/EXAMPLES.md +402 -0
- package/docs/i18n/MIGRATION.md +260 -0
- package/docs/i18n/SEO.md +392 -0
- package/docs/i18n/STATIC-GENERATION-FIX.md +71 -0
- package/docs/migration/changelog.md +136 -0
- package/docs/migration/overview.md +233 -0
- package/docs/recipes/adding-animations.md +475 -0
- package/docs/recipes/forms-with-validation.md +393 -0
- package/package.json +152 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* create-simple-site CLI tool
|
|
5
|
+
* Scaffolds new projects with the Simple Site Framework
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { Command } = require('commander');
|
|
9
|
+
const inquirer = require('inquirer');
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
const ora = require('ora');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const fs = require('fs-extra');
|
|
14
|
+
const { execSync } = require('child_process');
|
|
15
|
+
|
|
16
|
+
const program = new Command();
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.name('create-simple-site')
|
|
20
|
+
.description('Create a new Simple Site Framework project')
|
|
21
|
+
.argument('[project-name]', 'Name of your project')
|
|
22
|
+
.option('-t, --template <template>', 'Template to use (service-business, saas, portfolio, blog, blank)')
|
|
23
|
+
.option('--skip-install', 'Skip npm install')
|
|
24
|
+
.option('--skip-git', 'Skip git initialization')
|
|
25
|
+
.action(async (projectName, options) => {
|
|
26
|
+
try {
|
|
27
|
+
await createProject(projectName, options);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(chalk.red('\n✖ Error:'), error.message);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
program.parse();
|
|
35
|
+
|
|
36
|
+
async function createProject(projectName, options) {
|
|
37
|
+
console.log(chalk.bold.cyan('\n🚀 Simple Site Framework\n'));
|
|
38
|
+
|
|
39
|
+
// Get project name if not provided
|
|
40
|
+
if (!projectName) {
|
|
41
|
+
const answers = await inquirer.prompt([
|
|
42
|
+
{
|
|
43
|
+
type: 'input',
|
|
44
|
+
name: 'projectName',
|
|
45
|
+
message: 'Project name:',
|
|
46
|
+
default: 'my-site',
|
|
47
|
+
validate: (input) => {
|
|
48
|
+
if (/^([A-Za-z\-\_\d])+$/.test(input)) return true;
|
|
49
|
+
return 'Project name may only include letters, numbers, underscores and hashes.';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
]);
|
|
53
|
+
projectName = answers.projectName;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const projectPath = path.join(process.cwd(), projectName);
|
|
57
|
+
|
|
58
|
+
// Check if directory exists
|
|
59
|
+
if (fs.existsSync(projectPath)) {
|
|
60
|
+
const { overwrite } = await inquirer.prompt([
|
|
61
|
+
{
|
|
62
|
+
type: 'confirm',
|
|
63
|
+
name: 'overwrite',
|
|
64
|
+
message: `Directory ${projectName} already exists. Overwrite?`,
|
|
65
|
+
default: false
|
|
66
|
+
}
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
if (!overwrite) {
|
|
70
|
+
console.log(chalk.yellow('\n✖ Cancelled'));
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fs.removeSync(projectPath);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Interactive setup
|
|
78
|
+
const config = await interactiveSetup(options);
|
|
79
|
+
|
|
80
|
+
// Create project
|
|
81
|
+
const spinner = ora('Creating project...').start();
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
// Create directory
|
|
85
|
+
fs.ensureDirSync(projectPath);
|
|
86
|
+
|
|
87
|
+
// Copy template
|
|
88
|
+
await copyTemplate(projectPath, config.template);
|
|
89
|
+
|
|
90
|
+
// Update configuration files
|
|
91
|
+
await updateConfig(projectPath, config);
|
|
92
|
+
|
|
93
|
+
spinner.succeed('Project created!');
|
|
94
|
+
|
|
95
|
+
// Install dependencies
|
|
96
|
+
if (!options.skipInstall) {
|
|
97
|
+
const installSpinner = ora('Installing dependencies...').start();
|
|
98
|
+
try {
|
|
99
|
+
execSync('npm install', {
|
|
100
|
+
cwd: projectPath,
|
|
101
|
+
stdio: 'ignore'
|
|
102
|
+
});
|
|
103
|
+
installSpinner.succeed('Dependencies installed!');
|
|
104
|
+
} catch (error) {
|
|
105
|
+
installSpinner.fail('Failed to install dependencies');
|
|
106
|
+
console.log(chalk.yellow(' Run `npm install` manually in the project directory'));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Initialize git
|
|
111
|
+
if (!options.skipGit) {
|
|
112
|
+
const gitSpinner = ora('Initializing git repository...').start();
|
|
113
|
+
try {
|
|
114
|
+
execSync('git init', { cwd: projectPath, stdio: 'ignore' });
|
|
115
|
+
execSync('git add -A', { cwd: projectPath, stdio: 'ignore' });
|
|
116
|
+
execSync('git commit -m "Initial commit from create-simple-site"', {
|
|
117
|
+
cwd: projectPath,
|
|
118
|
+
stdio: 'ignore'
|
|
119
|
+
});
|
|
120
|
+
gitSpinner.succeed('Git repository initialized!');
|
|
121
|
+
} catch (error) {
|
|
122
|
+
gitSpinner.fail('Failed to initialize git');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Success message
|
|
127
|
+
console.log(chalk.green('\n✓ Project ready!\n'));
|
|
128
|
+
console.log(chalk.bold('Next steps:'));
|
|
129
|
+
console.log(chalk.gray(` cd ${projectName}`));
|
|
130
|
+
if (options.skipInstall) {
|
|
131
|
+
console.log(chalk.gray(' npm install'));
|
|
132
|
+
}
|
|
133
|
+
console.log(chalk.gray(' npm run dev\n'));
|
|
134
|
+
|
|
135
|
+
} catch (error) {
|
|
136
|
+
spinner.fail('Failed to create project');
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function interactiveSetup(options) {
|
|
142
|
+
const questions = [];
|
|
143
|
+
|
|
144
|
+
// Template selection
|
|
145
|
+
if (!options.template) {
|
|
146
|
+
questions.push({
|
|
147
|
+
type: 'list',
|
|
148
|
+
name: 'template',
|
|
149
|
+
message: 'Choose a template:',
|
|
150
|
+
choices: [
|
|
151
|
+
{ name: 'Service Business - Professional services (law, consulting)', value: 'service-business' },
|
|
152
|
+
{ name: 'SaaS - Software-as-a-service marketing site', value: 'saas' },
|
|
153
|
+
{ name: 'Portfolio - Personal/agency portfolio', value: 'portfolio' },
|
|
154
|
+
{ name: 'Blog - Content-focused blog', value: 'blog' },
|
|
155
|
+
{ name: 'Blank - Minimal starter', value: 'blank' }
|
|
156
|
+
],
|
|
157
|
+
default: 'service-business'
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Theme configuration
|
|
162
|
+
questions.push(
|
|
163
|
+
{
|
|
164
|
+
type: 'input',
|
|
165
|
+
name: 'primaryColor',
|
|
166
|
+
message: 'Primary color (hex):',
|
|
167
|
+
default: '#f97316',
|
|
168
|
+
validate: (input) => /^#[0-9A-F]{6}$/i.test(input) || 'Please enter a valid hex color'
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
type: 'list',
|
|
172
|
+
name: 'fontHeading',
|
|
173
|
+
message: 'Heading font:',
|
|
174
|
+
choices: ['Inter', 'Poppins', 'Montserrat', 'Roboto', 'Open Sans'],
|
|
175
|
+
default: 'Inter'
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
type: 'list',
|
|
179
|
+
name: 'fontBody',
|
|
180
|
+
message: 'Body font:',
|
|
181
|
+
choices: ['Inter', 'Roboto', 'Open Sans', 'Lato', 'Source Sans Pro'],
|
|
182
|
+
default: 'Inter'
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
type: 'checkbox',
|
|
186
|
+
name: 'locales',
|
|
187
|
+
message: 'Languages to support:',
|
|
188
|
+
choices: [
|
|
189
|
+
{ name: 'English', value: 'en', checked: true },
|
|
190
|
+
{ name: 'French', value: 'fr' }
|
|
191
|
+
],
|
|
192
|
+
validate: (answer) => answer.length > 0 || 'You must choose at least one language'
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
// Company info
|
|
197
|
+
questions.push(
|
|
198
|
+
{
|
|
199
|
+
type: 'input',
|
|
200
|
+
name: 'companyName',
|
|
201
|
+
message: 'Company name:',
|
|
202
|
+
default: 'My Company'
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
type: 'input',
|
|
206
|
+
name: 'companyEmail',
|
|
207
|
+
message: 'Contact email:',
|
|
208
|
+
default: 'contact@example.com'
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
type: 'input',
|
|
212
|
+
name: 'companyPhone',
|
|
213
|
+
message: 'Phone number (optional):',
|
|
214
|
+
default: ''
|
|
215
|
+
}
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const answers = await inquirer.prompt(questions);
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
template: options.template || answers.template,
|
|
222
|
+
theme: {
|
|
223
|
+
primaryColor: answers.primaryColor,
|
|
224
|
+
fontHeading: answers.fontHeading,
|
|
225
|
+
fontBody: answers.fontBody
|
|
226
|
+
},
|
|
227
|
+
locales: answers.locales,
|
|
228
|
+
company: {
|
|
229
|
+
name: answers.companyName,
|
|
230
|
+
email: answers.companyEmail,
|
|
231
|
+
phone: answers.companyPhone
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function copyTemplate(projectPath, template) {
|
|
237
|
+
const templatesDir = path.join(__dirname, '..', 'templates');
|
|
238
|
+
const templatePath = path.join(templatesDir, template);
|
|
239
|
+
|
|
240
|
+
if (!fs.existsSync(templatePath)) {
|
|
241
|
+
// Fallback to blank template
|
|
242
|
+
const blankPath = path.join(templatesDir, 'blank');
|
|
243
|
+
if (fs.existsSync(blankPath)) {
|
|
244
|
+
fs.copySync(blankPath, projectPath);
|
|
245
|
+
} else {
|
|
246
|
+
// Create minimal structure if no template exists
|
|
247
|
+
createMinimalStructure(projectPath);
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
fs.copySync(templatePath, projectPath);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function createMinimalStructure(projectPath) {
|
|
255
|
+
// Create basic Next.js App Router structure
|
|
256
|
+
const structure = {
|
|
257
|
+
'app': {
|
|
258
|
+
'layout.tsx': `import './globals.css'
|
|
259
|
+
|
|
260
|
+
export default function RootLayout({
|
|
261
|
+
children,
|
|
262
|
+
}: {
|
|
263
|
+
children: React.ReactNode
|
|
264
|
+
}) {
|
|
265
|
+
return (
|
|
266
|
+
<html lang="en">
|
|
267
|
+
<body>{children}</body>
|
|
268
|
+
</html>
|
|
269
|
+
)
|
|
270
|
+
}`,
|
|
271
|
+
'page.tsx': `export default function Home() {
|
|
272
|
+
return <main className="min-h-screen p-8">
|
|
273
|
+
<h1 className="text-4xl font-bold">Welcome to Simple Site Framework</h1>
|
|
274
|
+
</main>
|
|
275
|
+
}`,
|
|
276
|
+
'globals.css': `@tailwind base;
|
|
277
|
+
@tailwind components;
|
|
278
|
+
@tailwind utilities;`
|
|
279
|
+
},
|
|
280
|
+
'config': {
|
|
281
|
+
'theme.ts': `export const theme = {
|
|
282
|
+
colors: {
|
|
283
|
+
primary: '#f97316'
|
|
284
|
+
}
|
|
285
|
+
}`
|
|
286
|
+
},
|
|
287
|
+
'public': {},
|
|
288
|
+
'package.json': JSON.stringify({
|
|
289
|
+
name: 'my-site',
|
|
290
|
+
version: '0.1.0',
|
|
291
|
+
private: true,
|
|
292
|
+
scripts: {
|
|
293
|
+
dev: 'next dev',
|
|
294
|
+
build: 'next build',
|
|
295
|
+
start: 'next start',
|
|
296
|
+
lint: 'next lint'
|
|
297
|
+
},
|
|
298
|
+
dependencies: {
|
|
299
|
+
'@zoyth/simple-site-framework': 'latest',
|
|
300
|
+
'next': '^14.0.0',
|
|
301
|
+
'react': '^18.0.0',
|
|
302
|
+
'react-dom': '^18.0.0'
|
|
303
|
+
},
|
|
304
|
+
devDependencies: {
|
|
305
|
+
'@types/node': '^20.0.0',
|
|
306
|
+
'@types/react': '^18.0.0',
|
|
307
|
+
'@types/react-dom': '^18.0.0',
|
|
308
|
+
'typescript': '^5.0.0',
|
|
309
|
+
'tailwindcss': '^3.4.0'
|
|
310
|
+
}
|
|
311
|
+
}, null, 2),
|
|
312
|
+
'tsconfig.json': JSON.stringify({
|
|
313
|
+
compilerOptions: {
|
|
314
|
+
target: 'es5',
|
|
315
|
+
lib: ['dom', 'dom.iterable', 'esnext'],
|
|
316
|
+
allowJs: true,
|
|
317
|
+
skipLibCheck: true,
|
|
318
|
+
strict: true,
|
|
319
|
+
forceConsistentCasingInFileNames: true,
|
|
320
|
+
noEmit: true,
|
|
321
|
+
esModuleInterop: true,
|
|
322
|
+
module: 'esnext',
|
|
323
|
+
moduleResolution: 'bundler',
|
|
324
|
+
resolveJsonModule: true,
|
|
325
|
+
isolatedModules: true,
|
|
326
|
+
jsx: 'preserve',
|
|
327
|
+
incremental: true,
|
|
328
|
+
plugins: [{ name: 'next' }],
|
|
329
|
+
paths: { '@/*': ['./*'] }
|
|
330
|
+
},
|
|
331
|
+
include: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],
|
|
332
|
+
exclude: ['node_modules']
|
|
333
|
+
}, null, 2),
|
|
334
|
+
'next.config.js': `/** @type {import('next').NextConfig} */
|
|
335
|
+
const nextConfig = {}
|
|
336
|
+
|
|
337
|
+
module.exports = nextConfig`,
|
|
338
|
+
'tailwind.config.ts': `import type { Config } from 'tailwindcss'
|
|
339
|
+
|
|
340
|
+
const config: Config = {
|
|
341
|
+
content: [
|
|
342
|
+
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
|
343
|
+
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
|
344
|
+
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
|
345
|
+
],
|
|
346
|
+
theme: {
|
|
347
|
+
extend: {},
|
|
348
|
+
},
|
|
349
|
+
plugins: [],
|
|
350
|
+
}
|
|
351
|
+
export default config`,
|
|
352
|
+
'.gitignore': `node_modules
|
|
353
|
+
.next
|
|
354
|
+
out
|
|
355
|
+
.env*.local
|
|
356
|
+
.DS_Store`
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
function createStructure(basePath, struct) {
|
|
360
|
+
for (const [key, value] of Object.entries(struct)) {
|
|
361
|
+
const itemPath = path.join(basePath, key);
|
|
362
|
+
if (typeof value === 'string') {
|
|
363
|
+
fs.writeFileSync(itemPath, value);
|
|
364
|
+
} else {
|
|
365
|
+
fs.ensureDirSync(itemPath);
|
|
366
|
+
createStructure(itemPath, value);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
createStructure(projectPath, structure);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
async function updateConfig(projectPath, config) {
|
|
375
|
+
// Update theme config
|
|
376
|
+
const themeConfigPath = path.join(projectPath, 'config', 'theme.ts');
|
|
377
|
+
if (fs.existsSync(themeConfigPath)) {
|
|
378
|
+
let themeContent = fs.readFileSync(themeConfigPath, 'utf-8');
|
|
379
|
+
themeContent = themeContent.replace(/#[0-9A-F]{6}/gi, config.theme.primaryColor);
|
|
380
|
+
fs.writeFileSync(themeConfigPath, themeContent);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Update package.json with company name
|
|
384
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
385
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
386
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
387
|
+
packageJson.name = config.company.name.toLowerCase().replace(/\s+/g, '-');
|
|
388
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
389
|
+
}
|
|
390
|
+
}
|