@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,599 @@
|
|
|
1
|
+
# ContactSection
|
|
2
|
+
|
|
3
|
+
Complete contact section with form, contact information, and location details. Essential for lead generation and customer communication.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { ContactSection } from '@zoyth/simple-site-framework';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Type:** Server Component (default export)
|
|
12
|
+
|
|
13
|
+
## Basic Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
<ContactSection
|
|
17
|
+
heading="Get in Touch"
|
|
18
|
+
description="We'd love to hear from you"
|
|
19
|
+
email="contact@yourcompany.com"
|
|
20
|
+
phone="+1 (555) 123-4567"
|
|
21
|
+
/>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
### Required Props
|
|
27
|
+
|
|
28
|
+
| Prop | Type | Description |
|
|
29
|
+
|------|------|-------------|
|
|
30
|
+
| `heading` | `string \| LocalizedString` | Section heading |
|
|
31
|
+
|
|
32
|
+
### Optional Props
|
|
33
|
+
|
|
34
|
+
| Prop | Type | Default | Description |
|
|
35
|
+
|------|------|---------|-------------|
|
|
36
|
+
| `description` | `string \| LocalizedString` | - | Section description |
|
|
37
|
+
| `email` | `string` | - | Contact email address |
|
|
38
|
+
| `phone` | `string` | - | Contact phone number |
|
|
39
|
+
| `locations` | `Location[]` | - | Physical locations |
|
|
40
|
+
| `formConfig` | `ContactFormConfig` | - | Contact form configuration |
|
|
41
|
+
| `showForm` | `boolean` | `true` | Show contact form |
|
|
42
|
+
| `showContactInfo` | `boolean` | `true` | Show contact details |
|
|
43
|
+
| `variant` | `'default' \| 'split'` | `'default'` | Layout variant |
|
|
44
|
+
| `maxWidth` | `MaxWidth` | `'2xl'` | Maximum content width |
|
|
45
|
+
| `className` | `string` | - | Custom CSS classes |
|
|
46
|
+
| `locale` | `string` | - | Current locale |
|
|
47
|
+
|
|
48
|
+
### Type Definitions
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
interface Location {
|
|
52
|
+
city: string | LocalizedString;
|
|
53
|
+
address: string | LocalizedString;
|
|
54
|
+
mapUrl?: string;
|
|
55
|
+
phone?: string;
|
|
56
|
+
email?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface ContactFormConfig {
|
|
60
|
+
fields: ContactFormField[];
|
|
61
|
+
submitText?: string | LocalizedString;
|
|
62
|
+
successMessage?: string | LocalizedString;
|
|
63
|
+
errorMessage?: string | LocalizedString;
|
|
64
|
+
onSubmit?: (data: ContactFormData) => Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface ContactFormField {
|
|
68
|
+
name: string;
|
|
69
|
+
type?: 'text' | 'email' | 'tel' | 'url' | 'textarea';
|
|
70
|
+
label: string | LocalizedString;
|
|
71
|
+
placeholder?: string | LocalizedString;
|
|
72
|
+
required?: boolean;
|
|
73
|
+
rows?: number;
|
|
74
|
+
helperText?: string | LocalizedString;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Examples
|
|
79
|
+
|
|
80
|
+
### Basic Contact Section
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
<ContactSection
|
|
84
|
+
heading="Contact Us"
|
|
85
|
+
description="We're here to help"
|
|
86
|
+
email="hello@company.com"
|
|
87
|
+
phone="+1 (555) 123-4567"
|
|
88
|
+
/>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### With Multiple Locations
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
<ContactSection
|
|
95
|
+
heading="Visit Our Offices"
|
|
96
|
+
description="We have locations worldwide"
|
|
97
|
+
locations={[
|
|
98
|
+
{
|
|
99
|
+
city: 'New York',
|
|
100
|
+
address: '123 Main St, Suite 100, New York, NY 10001',
|
|
101
|
+
mapUrl: 'https://maps.google.com/?q=123+Main+St+New+York',
|
|
102
|
+
phone: '+1 (555) 123-4567',
|
|
103
|
+
email: 'ny@company.com',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
city: 'London',
|
|
107
|
+
address: '456 Oxford Street, London, UK',
|
|
108
|
+
mapUrl: 'https://maps.google.com/?q=456+Oxford+St+London',
|
|
109
|
+
phone: '+44 20 1234 5678',
|
|
110
|
+
email: 'london@company.com',
|
|
111
|
+
},
|
|
112
|
+
]}
|
|
113
|
+
/>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### With Custom Contact Form
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
<ContactSection
|
|
120
|
+
heading="Get a Quote"
|
|
121
|
+
description="Tell us about your project"
|
|
122
|
+
email="quotes@company.com"
|
|
123
|
+
formConfig={{
|
|
124
|
+
fields: [
|
|
125
|
+
{
|
|
126
|
+
name: 'name',
|
|
127
|
+
type: 'text',
|
|
128
|
+
label: 'Full Name',
|
|
129
|
+
required: true,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'email',
|
|
133
|
+
type: 'email',
|
|
134
|
+
label: 'Email Address',
|
|
135
|
+
required: true,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'company',
|
|
139
|
+
type: 'text',
|
|
140
|
+
label: 'Company Name',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'budget',
|
|
144
|
+
type: 'text',
|
|
145
|
+
label: 'Project Budget',
|
|
146
|
+
placeholder: 'e.g., $10,000 - $25,000',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: 'message',
|
|
150
|
+
type: 'textarea',
|
|
151
|
+
label: 'Project Details',
|
|
152
|
+
required: true,
|
|
153
|
+
rows: 6,
|
|
154
|
+
helperText: 'Please provide as much detail as possible',
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
submitText: 'Request Quote',
|
|
158
|
+
successMessage: 'Thanks! We\'ll send you a quote within 24 hours.',
|
|
159
|
+
onSubmit: async (data) => {
|
|
160
|
+
await fetch('/api/contact', {
|
|
161
|
+
method: 'POST',
|
|
162
|
+
body: JSON.stringify(data),
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
}}
|
|
166
|
+
/>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Form Only (No Contact Info)
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
<ContactSection
|
|
173
|
+
heading="Send Us a Message"
|
|
174
|
+
description="Fill out the form below"
|
|
175
|
+
showContactInfo={false}
|
|
176
|
+
formConfig={{
|
|
177
|
+
fields: [
|
|
178
|
+
{ name: 'name', type: 'text', label: 'Name', required: true },
|
|
179
|
+
{ name: 'email', type: 'email', label: 'Email', required: true },
|
|
180
|
+
{ name: 'message', type: 'textarea', label: 'Message', required: true },
|
|
181
|
+
],
|
|
182
|
+
}}
|
|
183
|
+
/>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Contact Info Only (No Form)
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
<ContactSection
|
|
190
|
+
heading="Reach Out"
|
|
191
|
+
description="Multiple ways to get in touch"
|
|
192
|
+
email="support@company.com"
|
|
193
|
+
phone="+1 (555) 123-4567"
|
|
194
|
+
showForm={false}
|
|
195
|
+
locations={[
|
|
196
|
+
{
|
|
197
|
+
city: 'Headquarters',
|
|
198
|
+
address: '123 Business Blvd, Suite 500',
|
|
199
|
+
mapUrl: 'https://maps.google.com/?q=123+Business+Blvd',
|
|
200
|
+
},
|
|
201
|
+
]}
|
|
202
|
+
/>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Multi-Language
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
<ContactSection
|
|
209
|
+
heading={{
|
|
210
|
+
en: 'Contact Us',
|
|
211
|
+
fr: 'Contactez-nous',
|
|
212
|
+
es: 'Contáctenos',
|
|
213
|
+
}}
|
|
214
|
+
description={{
|
|
215
|
+
en: 'We\'d love to hear from you',
|
|
216
|
+
fr: 'Nous aimerions avoir de vos nouvelles',
|
|
217
|
+
es: 'Nos encantaría saber de usted',
|
|
218
|
+
}}
|
|
219
|
+
email="contact@company.com"
|
|
220
|
+
locations={[
|
|
221
|
+
{
|
|
222
|
+
city: { en: 'New York', fr: 'New York', es: 'Nueva York' },
|
|
223
|
+
address: {
|
|
224
|
+
en: '123 Main Street',
|
|
225
|
+
fr: '123 rue principale',
|
|
226
|
+
es: '123 Calle Principal',
|
|
227
|
+
},
|
|
228
|
+
mapUrl: 'https://maps.google.com/?q=123+Main+St+New+York',
|
|
229
|
+
},
|
|
230
|
+
]}
|
|
231
|
+
formConfig={{
|
|
232
|
+
fields: [
|
|
233
|
+
{
|
|
234
|
+
name: 'name',
|
|
235
|
+
type: 'text',
|
|
236
|
+
label: { en: 'Full Name', fr: 'Nom complet', es: 'Nombre completo' },
|
|
237
|
+
required: true,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: 'email',
|
|
241
|
+
type: 'email',
|
|
242
|
+
label: { en: 'Email', fr: 'Courriel', es: 'Correo electrónico' },
|
|
243
|
+
required: true,
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: 'message',
|
|
247
|
+
type: 'textarea',
|
|
248
|
+
label: { en: 'Message', fr: 'Message', es: 'Mensaje' },
|
|
249
|
+
required: true,
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
submitText: {
|
|
253
|
+
en: 'Send Message',
|
|
254
|
+
fr: 'Envoyer le message',
|
|
255
|
+
es: 'Enviar mensaje',
|
|
256
|
+
},
|
|
257
|
+
successMessage: {
|
|
258
|
+
en: 'Thank you! We\'ll respond within 24 hours.',
|
|
259
|
+
fr: 'Merci! Nous répondrons dans les 24 heures.',
|
|
260
|
+
es: 'Gracias! Responderemos en 24 horas.',
|
|
261
|
+
},
|
|
262
|
+
}}
|
|
263
|
+
locale={locale}
|
|
264
|
+
/>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Split Layout Variant
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
<ContactSection
|
|
271
|
+
heading="Let's Talk"
|
|
272
|
+
description="Schedule a consultation"
|
|
273
|
+
variant="split"
|
|
274
|
+
email="sales@company.com"
|
|
275
|
+
phone="+1 (555) 123-4567"
|
|
276
|
+
formConfig={{
|
|
277
|
+
fields: [
|
|
278
|
+
{ name: 'name', type: 'text', label: 'Name', required: true },
|
|
279
|
+
{ name: 'email', type: 'email', label: 'Email', required: true },
|
|
280
|
+
{ name: 'phone', type: 'tel', label: 'Phone' },
|
|
281
|
+
{ name: 'message', type: 'textarea', label: 'How can we help?', required: true },
|
|
282
|
+
],
|
|
283
|
+
}}
|
|
284
|
+
/>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Form Integration
|
|
288
|
+
|
|
289
|
+
### With Custom API Endpoint
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
<ContactSection
|
|
293
|
+
heading="Contact"
|
|
294
|
+
formConfig={{
|
|
295
|
+
fields: [...],
|
|
296
|
+
onSubmit: async (data) => {
|
|
297
|
+
const response = await fetch('/api/contact', {
|
|
298
|
+
method: 'POST',
|
|
299
|
+
headers: { 'Content-Type': 'application/json' },
|
|
300
|
+
body: JSON.stringify(data),
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
if (!response.ok) {
|
|
304
|
+
throw new Error('Failed to send message');
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
}}
|
|
308
|
+
/>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### With Email Service (Resend)
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
// pages/api/contact.ts
|
|
315
|
+
import { Resend } from 'resend';
|
|
316
|
+
|
|
317
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
318
|
+
|
|
319
|
+
export default async function handler(req, res) {
|
|
320
|
+
const { name, email, message } = req.body;
|
|
321
|
+
|
|
322
|
+
await resend.emails.send({
|
|
323
|
+
from: 'noreply@yourcompany.com',
|
|
324
|
+
to: 'contact@yourcompany.com',
|
|
325
|
+
subject: `New contact from ${name}`,
|
|
326
|
+
html: `
|
|
327
|
+
<p><strong>From:</strong> ${name} (${email})</p>
|
|
328
|
+
<p><strong>Message:</strong></p>
|
|
329
|
+
<p>${message}</p>
|
|
330
|
+
`,
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
res.status(200).json({ success: true });
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Component
|
|
337
|
+
<ContactSection
|
|
338
|
+
heading="Contact"
|
|
339
|
+
formConfig={{
|
|
340
|
+
fields: [...],
|
|
341
|
+
onSubmit: async (data) => {
|
|
342
|
+
await fetch('/api/contact', {
|
|
343
|
+
method: 'POST',
|
|
344
|
+
headers: { 'Content-Type': 'application/json' },
|
|
345
|
+
body: JSON.stringify(data),
|
|
346
|
+
});
|
|
347
|
+
},
|
|
348
|
+
}}
|
|
349
|
+
/>
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### With Analytics Tracking
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { trackEvent } from '@/lib/analytics';
|
|
356
|
+
|
|
357
|
+
<ContactSection
|
|
358
|
+
heading="Contact"
|
|
359
|
+
formConfig={{
|
|
360
|
+
fields: [...],
|
|
361
|
+
onSubmit: async (data) => {
|
|
362
|
+
// Track form submission
|
|
363
|
+
trackEvent('contact_form_submit', {
|
|
364
|
+
form_location: 'contact_page',
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
await fetch('/api/contact', {
|
|
368
|
+
method: 'POST',
|
|
369
|
+
body: JSON.stringify(data),
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// Track successful submission
|
|
373
|
+
trackEvent('lead_generated', {
|
|
374
|
+
lead_source: 'contact_form',
|
|
375
|
+
});
|
|
376
|
+
},
|
|
377
|
+
}}
|
|
378
|
+
/>
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Styling
|
|
382
|
+
|
|
383
|
+
### Custom Background
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
<ContactSection
|
|
387
|
+
heading="Get in Touch"
|
|
388
|
+
className="bg-gradient-to-br from-blue-50 to-indigo-50"
|
|
389
|
+
email="contact@company.com"
|
|
390
|
+
/>
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Custom Form Styling
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
<ContactSection
|
|
397
|
+
heading="Contact"
|
|
398
|
+
formConfig={{
|
|
399
|
+
fields: [...],
|
|
400
|
+
className: 'bg-white shadow-xl rounded-lg p-8',
|
|
401
|
+
}}
|
|
402
|
+
/>
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Accessibility
|
|
406
|
+
|
|
407
|
+
ContactSection includes:
|
|
408
|
+
|
|
409
|
+
- ✅ Semantic HTML (`<section>`, `<form>`, `<address>`)
|
|
410
|
+
- ✅ Proper form labels and associations
|
|
411
|
+
- ✅ ARIA attributes for validation states
|
|
412
|
+
- ✅ Error announcements to screen readers
|
|
413
|
+
- ✅ Keyboard navigation for all interactive elements
|
|
414
|
+
- ✅ Focus management on form submission
|
|
415
|
+
- ✅ Required field indicators
|
|
416
|
+
- ✅ Clickable phone numbers (`tel:` links)
|
|
417
|
+
- ✅ Clickable email addresses (`mailto:` links)
|
|
418
|
+
|
|
419
|
+
## Validation
|
|
420
|
+
|
|
421
|
+
Built-in validation includes:
|
|
422
|
+
|
|
423
|
+
- **Required fields** - Shows error if empty
|
|
424
|
+
- **Email format** - Validates email addresses
|
|
425
|
+
- **Phone format** - Validates phone numbers (optional)
|
|
426
|
+
- **Custom validation** - Add custom rules per field
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
<ContactSection
|
|
430
|
+
formConfig={{
|
|
431
|
+
fields: [
|
|
432
|
+
{
|
|
433
|
+
name: 'email',
|
|
434
|
+
type: 'email',
|
|
435
|
+
label: 'Email',
|
|
436
|
+
required: true,
|
|
437
|
+
// Automatic email validation
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
name: 'phone',
|
|
441
|
+
type: 'tel',
|
|
442
|
+
label: 'Phone',
|
|
443
|
+
// Automatic phone validation
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
}}
|
|
447
|
+
/>
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## SEO
|
|
451
|
+
|
|
452
|
+
- Email and phone are automatically wrapped in proper links
|
|
453
|
+
- Structured data can be added via JSON-LD
|
|
454
|
+
- Location information is semantic
|
|
455
|
+
|
|
456
|
+
### Add Structured Data
|
|
457
|
+
|
|
458
|
+
```typescript
|
|
459
|
+
<script type="application/ld+json">
|
|
460
|
+
{
|
|
461
|
+
"@context": "https://schema.org",
|
|
462
|
+
"@type": "Organization",
|
|
463
|
+
"name": "Your Company",
|
|
464
|
+
"contactPoint": {
|
|
465
|
+
"@type": "ContactPoint",
|
|
466
|
+
"telephone": "+1-555-123-4567",
|
|
467
|
+
"contactType": "Customer Service",
|
|
468
|
+
"email": "contact@company.com"
|
|
469
|
+
},
|
|
470
|
+
"address": {
|
|
471
|
+
"@type": "PostalAddress",
|
|
472
|
+
"streetAddress": "123 Main St",
|
|
473
|
+
"addressLocality": "New York",
|
|
474
|
+
"postalCode": "10001",
|
|
475
|
+
"addressCountry": "US"
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
</script>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## Common Patterns
|
|
482
|
+
|
|
483
|
+
### Contact Page
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
export default function ContactPage() {
|
|
487
|
+
return (
|
|
488
|
+
<main>
|
|
489
|
+
<ContactSection
|
|
490
|
+
heading="Contact Our Team"
|
|
491
|
+
description="We're here to help with any questions"
|
|
492
|
+
email="support@company.com"
|
|
493
|
+
phone="+1 (555) 123-4567"
|
|
494
|
+
locations={[
|
|
495
|
+
{
|
|
496
|
+
city: 'San Francisco',
|
|
497
|
+
address: '123 Market Street, San Francisco, CA 94105',
|
|
498
|
+
mapUrl: 'https://maps.google.com/?q=123+Market+St+SF',
|
|
499
|
+
},
|
|
500
|
+
]}
|
|
501
|
+
formConfig={{
|
|
502
|
+
fields: [
|
|
503
|
+
{ name: 'name', type: 'text', label: 'Name', required: true },
|
|
504
|
+
{ name: 'email', type: 'email', label: 'Email', required: true },
|
|
505
|
+
{ name: 'subject', type: 'text', label: 'Subject', required: true },
|
|
506
|
+
{ name: 'message', type: 'textarea', label: 'Message', required: true, rows: 6 },
|
|
507
|
+
],
|
|
508
|
+
submitText: 'Send Message',
|
|
509
|
+
successMessage: 'Thanks! We\'ll get back to you soon.',
|
|
510
|
+
}}
|
|
511
|
+
/>
|
|
512
|
+
</main>
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Sales Inquiry Form
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
<ContactSection
|
|
521
|
+
heading="Request a Demo"
|
|
522
|
+
description="See how our platform can help your business"
|
|
523
|
+
formConfig={{
|
|
524
|
+
fields: [
|
|
525
|
+
{ name: 'name', type: 'text', label: 'Full Name', required: true },
|
|
526
|
+
{ name: 'email', type: 'email', label: 'Work Email', required: true },
|
|
527
|
+
{ name: 'company', type: 'text', label: 'Company', required: true },
|
|
528
|
+
{ name: 'employees', type: 'text', label: 'Company Size', placeholder: 'e.g., 50-100' },
|
|
529
|
+
{ name: 'message', type: 'textarea', label: 'Tell us about your needs', rows: 4 },
|
|
530
|
+
],
|
|
531
|
+
submitText: 'Schedule Demo',
|
|
532
|
+
onSubmit: async (data) => {
|
|
533
|
+
await fetch('/api/demo-request', {
|
|
534
|
+
method: 'POST',
|
|
535
|
+
body: JSON.stringify(data),
|
|
536
|
+
});
|
|
537
|
+
},
|
|
538
|
+
}}
|
|
539
|
+
/>
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### Support Contact
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
545
|
+
<ContactSection
|
|
546
|
+
heading="Customer Support"
|
|
547
|
+
description="We're available 24/7 to assist you"
|
|
548
|
+
email="support@company.com"
|
|
549
|
+
phone="+1 (800) 555-HELP"
|
|
550
|
+
showForm={false}
|
|
551
|
+
locations={[
|
|
552
|
+
{
|
|
553
|
+
city: 'Support Center',
|
|
554
|
+
address: 'Available via email and phone',
|
|
555
|
+
},
|
|
556
|
+
]}
|
|
557
|
+
/>
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
## Troubleshooting
|
|
561
|
+
|
|
562
|
+
### Form not submitting
|
|
563
|
+
|
|
564
|
+
**Check:**
|
|
565
|
+
1. `onSubmit` function is provided
|
|
566
|
+
2. API endpoint is accessible
|
|
567
|
+
3. CORS is configured if calling external API
|
|
568
|
+
4. Form fields are valid
|
|
569
|
+
|
|
570
|
+
### Validation errors not showing
|
|
571
|
+
|
|
572
|
+
**Check:**
|
|
573
|
+
1. Field has `required: true`
|
|
574
|
+
2. Form has been submitted at least once
|
|
575
|
+
3. Error messages are defined in config
|
|
576
|
+
|
|
577
|
+
### Map links not working
|
|
578
|
+
|
|
579
|
+
**Check:**
|
|
580
|
+
1. `mapUrl` is a valid Google Maps URL
|
|
581
|
+
2. URL is properly encoded
|
|
582
|
+
3. Link is not disabled by CSS
|
|
583
|
+
|
|
584
|
+
### Multi-language content not displaying
|
|
585
|
+
|
|
586
|
+
**Check:**
|
|
587
|
+
1. `locale` prop is provided
|
|
588
|
+
2. All LocalizedStrings have entry for that locale
|
|
589
|
+
3. Fallback locale exists
|
|
590
|
+
|
|
591
|
+
## Related Components
|
|
592
|
+
|
|
593
|
+
- **[ContactForm](../forms/ContactForm.md)** - Standalone contact form
|
|
594
|
+
- **[FormField](../forms/FormField.md)** - Individual form field component
|
|
595
|
+
- **[HeroSection](./HeroSection.md)** - Page header
|
|
596
|
+
|
|
597
|
+
## API Reference
|
|
598
|
+
|
|
599
|
+
Full TypeScript definitions: **[API Reference](../../api/components.md#contactsection)**
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# FeatureSection
|
|
2
|
+
|
|
3
|
+
Individual feature highlight section.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { FeatureSection } from '@zoyth/simple-site-framework';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Type:** Server Component
|
|
12
|
+
|
|
13
|
+
## Basic Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
<FeatureSection
|
|
17
|
+
heading="Fast Performance"
|
|
18
|
+
description="Lightning-fast load times for better user experience"
|
|
19
|
+
image="/features/performance.png"
|
|
20
|
+
features={[
|
|
21
|
+
'Optimized assets',
|
|
22
|
+
'CDN delivery',
|
|
23
|
+
'Lazy loading',
|
|
24
|
+
]}
|
|
25
|
+
reverse
|
|
26
|
+
/>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Props
|
|
30
|
+
|
|
31
|
+
| Prop | Type | Required | Description |
|
|
32
|
+
|------|------|----------|-------------|
|
|
33
|
+
| `heading` | `string \| LocalizedString` | Yes | Feature heading |
|
|
34
|
+
| `description` | `string \| LocalizedString` | Yes | Feature description |
|
|
35
|
+
| `image` | `string` | No | Feature image |
|
|
36
|
+
| `features` | `string[]` | No | Feature list |
|
|
37
|
+
| `reverse` | `boolean` | No | Reverse layout |
|
|
38
|
+
| `className` | `string` | No | Custom classes |
|
|
39
|
+
| `locale` | `string` | No | Current locale |
|
|
40
|
+
|
|
41
|
+
## See Also
|
|
42
|
+
|
|
43
|
+
- [FeaturesGrid](../FeaturesGrid.md)
|
|
44
|
+
- [HeroSection](./HeroSection.md)
|