@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,52 @@
|
|
|
1
|
+
# Textarea
|
|
2
|
+
|
|
3
|
+
Multi-line text input component.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { Textarea } from '@zoyth/simple-site-framework';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Type:** Server Component
|
|
12
|
+
|
|
13
|
+
## Basic Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
<Textarea
|
|
17
|
+
name="message"
|
|
18
|
+
placeholder="Enter your message"
|
|
19
|
+
rows={4}
|
|
20
|
+
/>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Props
|
|
24
|
+
|
|
25
|
+
| Prop | Type | Required | Description |
|
|
26
|
+
|------|------|----------|-------------|
|
|
27
|
+
| `name` | `string` | Yes | Textarea name |
|
|
28
|
+
| `placeholder` | `string` | No | Placeholder text |
|
|
29
|
+
| `rows` | `number` | No | Number of rows |
|
|
30
|
+
| `value` | `string` | No | Textarea value |
|
|
31
|
+
| `disabled` | `boolean` | No | Disable textarea |
|
|
32
|
+
| `required` | `boolean` | No | Mark as required |
|
|
33
|
+
| `className` | `string` | No | Custom classes |
|
|
34
|
+
| `onChange` | `function` | No | Change handler |
|
|
35
|
+
|
|
36
|
+
## Examples
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// Basic textarea
|
|
40
|
+
<Textarea name="message" rows={6} />
|
|
41
|
+
|
|
42
|
+
// With placeholder
|
|
43
|
+
<Textarea name="bio" placeholder="Tell us about yourself" rows={4} />
|
|
44
|
+
|
|
45
|
+
// Required field
|
|
46
|
+
<Textarea name="details" required rows={8} />
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## See Also
|
|
50
|
+
|
|
51
|
+
- [Input](./Input.md)
|
|
52
|
+
- [FormField](../forms/FormField.md)
|
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
# Configuration-Driven Design
|
|
2
|
+
|
|
3
|
+
Simple Site Framework uses a configuration-driven approach where you define your site's structure, content, and appearance in configuration files rather than writing repetitive component markup.
|
|
4
|
+
|
|
5
|
+
## Why Configuration-Driven?
|
|
6
|
+
|
|
7
|
+
### Problem: Repetitive Code
|
|
8
|
+
|
|
9
|
+
Traditional component-based development leads to repetition:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// page1.tsx
|
|
13
|
+
<section className="py-20 bg-gray-50">
|
|
14
|
+
<div className="max-w-6xl mx-auto px-4">
|
|
15
|
+
<h1 className="text-4xl font-bold text-center">About Us</h1>
|
|
16
|
+
<p className="text-xl text-gray-600 text-center max-w-2xl mx-auto mt-4">
|
|
17
|
+
Learn about our company
|
|
18
|
+
</p>
|
|
19
|
+
</div>
|
|
20
|
+
</section>
|
|
21
|
+
|
|
22
|
+
// page2.tsx - almost identical
|
|
23
|
+
<section className="py-20 bg-gray-50">
|
|
24
|
+
<div className="max-w-6xl mx-auto px-4">
|
|
25
|
+
<h1 className="text-4xl font-bold text-center">Our Services</h1>
|
|
26
|
+
<p className="text-xl text-gray-600 text-center max-w-2xl mx-auto mt-4">
|
|
27
|
+
Discover what we offer
|
|
28
|
+
</p>
|
|
29
|
+
</div>
|
|
30
|
+
</section>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Problems:
|
|
34
|
+
- **Inconsistency** - Easy to use wrong spacing, colors, or fonts
|
|
35
|
+
- **Maintenance** - Design changes require updating every instance
|
|
36
|
+
- **No reusability** - Content and structure are tightly coupled
|
|
37
|
+
- **Error-prone** - Missing classes, wrong values, accessibility issues
|
|
38
|
+
|
|
39
|
+
### Solution: Configuration
|
|
40
|
+
|
|
41
|
+
Define the structure once, vary only the content:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// Consistent structure, different content
|
|
45
|
+
<HeroSection
|
|
46
|
+
heading="About Us"
|
|
47
|
+
description="Learn about our company"
|
|
48
|
+
/>
|
|
49
|
+
|
|
50
|
+
<HeroSection
|
|
51
|
+
heading="Our Services"
|
|
52
|
+
description="Discover what we offer"
|
|
53
|
+
/>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Benefits:
|
|
57
|
+
- **Consistency** - Components enforce design system
|
|
58
|
+
- **Maintainability** - Change structure in one place
|
|
59
|
+
- **Type safety** - TypeScript prevents configuration errors
|
|
60
|
+
- **Accessibility** - Built-in, can't forget it
|
|
61
|
+
- **Performance** - Optimizations applied automatically
|
|
62
|
+
|
|
63
|
+
## Configuration Layers
|
|
64
|
+
|
|
65
|
+
The framework uses multiple configuration layers:
|
|
66
|
+
|
|
67
|
+
### 1. Framework Defaults
|
|
68
|
+
|
|
69
|
+
Built-in sensible defaults:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// You don't configure this - it's built into components
|
|
73
|
+
const defaults = {
|
|
74
|
+
spacing: 'py-20',
|
|
75
|
+
maxWidth: 'max-w-6xl',
|
|
76
|
+
textAlign: 'center',
|
|
77
|
+
// ... accessibility, responsive behavior, etc.
|
|
78
|
+
};
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 2. Theme Configuration
|
|
82
|
+
|
|
83
|
+
Define your brand once in `tailwind.config.ts`:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
const config: Config = {
|
|
87
|
+
theme: {
|
|
88
|
+
extend: {
|
|
89
|
+
colors: {
|
|
90
|
+
primary: '#F16531',
|
|
91
|
+
secondary: '#2D3748',
|
|
92
|
+
},
|
|
93
|
+
fontFamily: {
|
|
94
|
+
heading: ['Playfair Display', 'serif'],
|
|
95
|
+
body: ['Inter', 'sans-serif'],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
All components automatically use these tokens.
|
|
103
|
+
|
|
104
|
+
### 3. Site Configuration
|
|
105
|
+
|
|
106
|
+
Global site settings in `src/config/site.ts`:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
export const siteConfig = {
|
|
110
|
+
name: 'Acme Corporation',
|
|
111
|
+
description: 'Professional consulting services',
|
|
112
|
+
url: 'https://acme.com',
|
|
113
|
+
contact: {
|
|
114
|
+
email: 'hello@acme.com',
|
|
115
|
+
phone: '+1 (555) 123-4567',
|
|
116
|
+
},
|
|
117
|
+
social: {
|
|
118
|
+
twitter: 'https://twitter.com/acme',
|
|
119
|
+
linkedin: 'https://linkedin.com/company/acme',
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Use across your site:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { siteConfig } from '@/config/site';
|
|
128
|
+
|
|
129
|
+
<Footer companyName={siteConfig.name} />
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 4. Content Configuration
|
|
133
|
+
|
|
134
|
+
Organize content by page or section:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
// src/config/content/home.ts
|
|
138
|
+
export const homeContent = {
|
|
139
|
+
hero: {
|
|
140
|
+
heading: {
|
|
141
|
+
en: 'Transform Your Business',
|
|
142
|
+
fr: 'Transformez votre entreprise'
|
|
143
|
+
},
|
|
144
|
+
description: {
|
|
145
|
+
en: 'Professional consulting services that deliver real results',
|
|
146
|
+
fr: 'Services de conseil professionnels qui produisent de vrais résultats'
|
|
147
|
+
},
|
|
148
|
+
cta: {
|
|
149
|
+
text: { en: 'Get Started', fr: 'Commencer' },
|
|
150
|
+
href: '/contact'
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
features: {
|
|
154
|
+
heading: { en: 'Why Choose Us', fr: 'Pourquoi nous choisir' },
|
|
155
|
+
items: [
|
|
156
|
+
{
|
|
157
|
+
title: { en: 'Expert Team', fr: 'Équipe experte' },
|
|
158
|
+
description: { en: '15+ years experience', fr: '15+ ans d\'expérience' },
|
|
159
|
+
icon: 'users'
|
|
160
|
+
},
|
|
161
|
+
// ...
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// src/app/[locale]/page.tsx
|
|
167
|
+
import { homeContent } from '@/config/content/home';
|
|
168
|
+
|
|
169
|
+
export default function HomePage({ params: { locale } }) {
|
|
170
|
+
return (
|
|
171
|
+
<>
|
|
172
|
+
<HeroSection {...homeContent.hero} locale={locale} />
|
|
173
|
+
<FeaturesGrid {...homeContent.features} locale={locale} />
|
|
174
|
+
</>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 5. Component-Level Configuration
|
|
180
|
+
|
|
181
|
+
Fine-tune individual component instances:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
<HeroSection
|
|
185
|
+
heading="Welcome"
|
|
186
|
+
description="..."
|
|
187
|
+
variant="split" // Structural variant
|
|
188
|
+
maxWidth="xl" // Width constraint
|
|
189
|
+
className="bg-blue-900" // Custom styling
|
|
190
|
+
/>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Configuration Patterns
|
|
194
|
+
|
|
195
|
+
### Pattern 1: Centralized Content
|
|
196
|
+
|
|
197
|
+
Best for: Sites with clear content ownership, CMS-like workflows
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
// src/config/content/index.ts
|
|
201
|
+
export const content = {
|
|
202
|
+
pages: {
|
|
203
|
+
home: {
|
|
204
|
+
hero: { heading: '...', description: '...' },
|
|
205
|
+
features: { ... },
|
|
206
|
+
},
|
|
207
|
+
about: {
|
|
208
|
+
hero: { heading: '...', description: '...' },
|
|
209
|
+
story: { ... },
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
common: {
|
|
213
|
+
navigation: [ ... ],
|
|
214
|
+
footer: { ... },
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Use throughout app
|
|
219
|
+
import { content } from '@/config/content';
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Pros:**
|
|
223
|
+
- Single source of truth
|
|
224
|
+
- Easy to audit all content
|
|
225
|
+
- Simple to sync with CMS
|
|
226
|
+
- Content reviewers can focus on one file
|
|
227
|
+
|
|
228
|
+
**Cons:**
|
|
229
|
+
- Large file can be unwieldy
|
|
230
|
+
- May need to import entire config even for small pieces
|
|
231
|
+
|
|
232
|
+
### Pattern 2: Colocated Content
|
|
233
|
+
|
|
234
|
+
Best for: Developer-driven sites, component-focused workflows
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
// src/app/about/content.ts
|
|
238
|
+
export const aboutContent = {
|
|
239
|
+
hero: { heading: '...', description: '...' },
|
|
240
|
+
story: { ... },
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// src/app/about/page.tsx
|
|
244
|
+
import { aboutContent } from './content';
|
|
245
|
+
|
|
246
|
+
export default function AboutPage() {
|
|
247
|
+
return <AboutSection {...aboutContent} />;
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Pros:**
|
|
252
|
+
- Content lives near where it's used
|
|
253
|
+
- Easier to find and update
|
|
254
|
+
- Smaller imports
|
|
255
|
+
- Better code splitting
|
|
256
|
+
|
|
257
|
+
**Cons:**
|
|
258
|
+
- Harder to get full content overview
|
|
259
|
+
- Potential for inconsistent patterns
|
|
260
|
+
|
|
261
|
+
### Pattern 3: Hybrid Approach
|
|
262
|
+
|
|
263
|
+
Best for: Medium to large sites
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// Global/shared content
|
|
267
|
+
// src/config/common.ts
|
|
268
|
+
export const commonContent = {
|
|
269
|
+
navigation: [ ... ],
|
|
270
|
+
footer: { ... },
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// Page-specific content colocated
|
|
274
|
+
// src/app/services/content.ts
|
|
275
|
+
export const servicesContent = { ... };
|
|
276
|
+
|
|
277
|
+
// Use both
|
|
278
|
+
import { commonContent } from '@/config/common';
|
|
279
|
+
import { servicesContent } from './content';
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Pattern 4: Type-Safe Variants
|
|
283
|
+
|
|
284
|
+
Create reusable content templates:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// src/config/cta-variants.ts
|
|
288
|
+
import type { CTASectionProps } from '@zoyth/simple-site-framework';
|
|
289
|
+
|
|
290
|
+
export const ctaVariants = {
|
|
291
|
+
trial: {
|
|
292
|
+
heading: { en: 'Start Your Free Trial', fr: 'Commencez votre essai gratuit' },
|
|
293
|
+
description: { en: 'No credit card required', fr: 'Aucune carte de crédit requise' },
|
|
294
|
+
primaryCTA: {
|
|
295
|
+
text: { en: 'Start Free Trial', fr: 'Essai gratuit' },
|
|
296
|
+
href: '/signup'
|
|
297
|
+
}
|
|
298
|
+
} satisfies Omit<CTASectionProps, 'locale'>,
|
|
299
|
+
|
|
300
|
+
demo: {
|
|
301
|
+
heading: { en: 'See It In Action', fr: 'Voyez-le en action' },
|
|
302
|
+
primaryCTA: {
|
|
303
|
+
text: { en: 'Schedule Demo', fr: 'Planifier une démo' },
|
|
304
|
+
href: '/demo'
|
|
305
|
+
}
|
|
306
|
+
} satisfies Omit<CTASectionProps, 'locale'>,
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// Use anywhere
|
|
310
|
+
<CTASection {...ctaVariants.trial} locale={locale} />
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Best Practices
|
|
314
|
+
|
|
315
|
+
### 1. Use TypeScript
|
|
316
|
+
|
|
317
|
+
Always type your configurations:
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import type { LocalizedString, NavigationItem } from '@zoyth/simple-site-framework';
|
|
321
|
+
|
|
322
|
+
interface SiteConfig {
|
|
323
|
+
name: string;
|
|
324
|
+
description: LocalizedString;
|
|
325
|
+
navigation: NavigationItem[];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export const siteConfig: SiteConfig = {
|
|
329
|
+
// TypeScript ensures correctness
|
|
330
|
+
};
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### 2. Separate Content from Structure
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
// ✅ Good - content separate from structure
|
|
337
|
+
const heroContent = {
|
|
338
|
+
heading: 'Welcome',
|
|
339
|
+
description: '...',
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
<HeroSection {...heroContent} variant="centered" />
|
|
343
|
+
|
|
344
|
+
// ❌ Bad - mixed concerns
|
|
345
|
+
<HeroSection heading="Welcome" description="..." variant="centered" />
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 3. Use Constants for Repeated Values
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
// src/config/constants.ts
|
|
352
|
+
export const COMPANY_NAME = 'Acme Corp';
|
|
353
|
+
export const SUPPORT_EMAIL = 'support@acme.com';
|
|
354
|
+
export const TRIAL_DAYS = 14;
|
|
355
|
+
|
|
356
|
+
// Use throughout config
|
|
357
|
+
export const ctaText = {
|
|
358
|
+
en: `Start Your ${TRIAL_DAYS}-Day Trial`,
|
|
359
|
+
fr: `Commencez votre essai de ${TRIAL_DAYS} jours`
|
|
360
|
+
};
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### 4. Environment-Specific Configuration
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
// src/config/site.ts
|
|
367
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
368
|
+
|
|
369
|
+
export const siteConfig = {
|
|
370
|
+
url: process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000',
|
|
371
|
+
apiEndpoint: isDevelopment
|
|
372
|
+
? 'http://localhost:3001'
|
|
373
|
+
: 'https://api.acme.com',
|
|
374
|
+
};
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### 5. Document Your Configuration Schema
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
/**
|
|
381
|
+
* Site-wide configuration
|
|
382
|
+
*
|
|
383
|
+
* @property name - Company/site name (used in header, footer, metadata)
|
|
384
|
+
* @property description - Site description for SEO
|
|
385
|
+
* @property url - Canonical URL (without trailing slash)
|
|
386
|
+
* @property contact - Contact information
|
|
387
|
+
*/
|
|
388
|
+
export interface SiteConfig {
|
|
389
|
+
name: string;
|
|
390
|
+
description: LocalizedString;
|
|
391
|
+
url: string;
|
|
392
|
+
contact: {
|
|
393
|
+
email: string;
|
|
394
|
+
phone?: string;
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## Configuration Validation
|
|
400
|
+
|
|
401
|
+
### Runtime Validation with Zod
|
|
402
|
+
|
|
403
|
+
For user-provided or CMS-sourced configuration:
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
import { z } from 'zod';
|
|
407
|
+
|
|
408
|
+
const siteConfigSchema = z.object({
|
|
409
|
+
name: z.string().min(1),
|
|
410
|
+
description: z.record(z.string(), z.string()),
|
|
411
|
+
url: z.string().url(),
|
|
412
|
+
contact: z.object({
|
|
413
|
+
email: z.string().email(),
|
|
414
|
+
phone: z.string().optional(),
|
|
415
|
+
}),
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// Validate configuration
|
|
419
|
+
export const siteConfig = siteConfigSchema.parse({
|
|
420
|
+
// ... your config
|
|
421
|
+
});
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Build-Time Validation
|
|
425
|
+
|
|
426
|
+
Use TypeScript's type system:
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
// Ensure all required locales are present
|
|
430
|
+
type RequireLocales<T> = {
|
|
431
|
+
[K in 'en' | 'fr']: T;
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
const heading: RequireLocales<string> = {
|
|
435
|
+
en: 'Welcome',
|
|
436
|
+
fr: 'Bienvenue',
|
|
437
|
+
// TypeScript error if missing either locale
|
|
438
|
+
};
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Integration with CMS
|
|
442
|
+
|
|
443
|
+
### Pattern: CMS as Content Source
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
// src/lib/cms.ts
|
|
447
|
+
export async function getPageContent(slug: string, locale: string) {
|
|
448
|
+
const response = await fetch(`https://cms.acme.com/api/pages/${slug}?locale=${locale}`);
|
|
449
|
+
return response.json();
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// src/app/[locale]/[slug]/page.tsx
|
|
453
|
+
export default async function DynamicPage({ params }) {
|
|
454
|
+
const content = await getPageContent(params.slug, params.locale);
|
|
455
|
+
|
|
456
|
+
return (
|
|
457
|
+
<>
|
|
458
|
+
<HeroSection
|
|
459
|
+
heading={content.hero.heading}
|
|
460
|
+
description={content.hero.description}
|
|
461
|
+
locale={params.locale}
|
|
462
|
+
/>
|
|
463
|
+
{/* ... other sections */}
|
|
464
|
+
</>
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Pattern: CMS with Type Safety
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
import type { HeroSectionProps } from '@zoyth/simple-site-framework';
|
|
473
|
+
|
|
474
|
+
interface CMSHeroContent {
|
|
475
|
+
heading: string;
|
|
476
|
+
description: string;
|
|
477
|
+
ctaText: string;
|
|
478
|
+
ctaUrl: string;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function transformCMSContent(cms: CMSHeroContent, locale: string): HeroSectionProps {
|
|
482
|
+
return {
|
|
483
|
+
heading: cms.heading,
|
|
484
|
+
description: cms.description,
|
|
485
|
+
cta: {
|
|
486
|
+
text: cms.ctaText,
|
|
487
|
+
href: cms.ctaUrl,
|
|
488
|
+
},
|
|
489
|
+
locale,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
## Common Pitfalls
|
|
495
|
+
|
|
496
|
+
### ❌ Hardcoding Content in Components
|
|
497
|
+
|
|
498
|
+
```typescript
|
|
499
|
+
// Bad - content in component files
|
|
500
|
+
export default function HomePage() {
|
|
501
|
+
return <HeroSection heading="Welcome to Acme" description="We help businesses grow" />;
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**Why it's bad:**
|
|
506
|
+
- Content changes require code changes
|
|
507
|
+
- No separation of concerns
|
|
508
|
+
- Harder to internationalize
|
|
509
|
+
- Can't sync with CMS
|
|
510
|
+
|
|
511
|
+
### ✅ Using Configuration
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
// Good - content in config
|
|
515
|
+
import { homeContent } from '@/config/content/home';
|
|
516
|
+
|
|
517
|
+
export default function HomePage() {
|
|
518
|
+
return <HeroSection {...homeContent.hero} />;
|
|
519
|
+
}
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### ❌ Mixing Configuration Patterns
|
|
523
|
+
|
|
524
|
+
```typescript
|
|
525
|
+
// Bad - inconsistent configuration sources
|
|
526
|
+
<HeroSection
|
|
527
|
+
heading={siteConfig.homeHeading} // From site config
|
|
528
|
+
description={content.pages.home.description} // From content config
|
|
529
|
+
cta={heroCtaConfig.primary} // From CTA config
|
|
530
|
+
/>
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
**Why it's bad:**
|
|
534
|
+
- Hard to track where content comes from
|
|
535
|
+
- Difficult to maintain
|
|
536
|
+
- No clear pattern for other developers
|
|
537
|
+
|
|
538
|
+
### ✅ Consistent Pattern
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
// Good - single content source per section
|
|
542
|
+
import { homeContent } from '@/config/content/home';
|
|
543
|
+
|
|
544
|
+
<HeroSection {...homeContent.hero} />
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
## Next Steps
|
|
548
|
+
|
|
549
|
+
- **[Internationalization](./internationalization.md)** - Multi-language configuration
|
|
550
|
+
- **[Theme System](./theme-system.md)** - Visual configuration
|
|
551
|
+
- **[Components Overview](../components/overview.md)** - Available components to configure
|
|
552
|
+
- **[Examples](../examples/landing-page-simple.md)** - See configuration patterns in action
|