underpost 2.90.1 → 2.90.4

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.
@@ -0,0 +1,579 @@
1
+ /**
2
+ * Custom Page SSR Component Example
3
+ * @module examples/ssr-components/CustomPage
4
+ *
5
+ * @description
6
+ * This is an example SSR component demonstrating best practices for creating
7
+ * custom static pages with the Underpost Static Site Generator.
8
+ *
9
+ * @example
10
+ * // Usage with static generator
11
+ * underpost static \
12
+ * --page ./examples/ssr-components/CustomPage.js \
13
+ * --output-path ./dist/custom.html
14
+ *
15
+ * @example
16
+ * // Usage in configuration file
17
+ * {
18
+ * "page": "./examples/ssr-components/CustomPage.js",
19
+ * "outputPath": "./dist/custom.html"
20
+ * }
21
+ */
22
+
23
+ /**
24
+ * Main SSR Component for rendering a custom landing page
25
+ *
26
+ * This component demonstrates:
27
+ * - Semantic HTML structure
28
+ * - Accessibility best practices
29
+ * - Responsive design patterns
30
+ * - Progressive enhancement
31
+ * - Clean, maintainable code
32
+ *
33
+ * @function SrrComponent
34
+ * @returns {string} HTML string for the page body
35
+ */
36
+ SrrComponent = () => html`
37
+ <!-- Main Container -->
38
+ <div class="custom-page">
39
+ <!-- Hero Section -->
40
+ <section class="hero" role="banner">
41
+ <div class="hero-content">
42
+ <h1 class="hero-title">Welcome to Our Application</h1>
43
+ <p class="hero-subtitle">Building amazing experiences with Underpost</p>
44
+ <div class="hero-actions">
45
+ <button class="btn btn-primary" id="get-started">Get Started</button>
46
+ <button class="btn btn-secondary" id="learn-more">Learn More</button>
47
+ </div>
48
+ </div>
49
+ <div class="hero-image" role="img" aria-label="Application preview">
50
+ <!-- Hero image background via CSS -->
51
+ </div>
52
+ </section>
53
+
54
+ <!-- Features Section -->
55
+ <section class="features" role="region" aria-labelledby="features-heading">
56
+ <h2 id="features-heading" class="section-title">Features</h2>
57
+ <div class="features-grid">
58
+ <article class="feature-card">
59
+ <div class="feature-icon" aria-hidden="true">🚀</div>
60
+ <h3 class="feature-title">Fast Performance</h3>
61
+ <p class="feature-description">Lightning-fast static pages with optimized delivery</p>
62
+ </article>
63
+
64
+ <article class="feature-card">
65
+ <div class="feature-icon" aria-hidden="true">🎨</div>
66
+ <h3 class="feature-title">Customizable</h3>
67
+ <p class="feature-description">Fully customizable with metadata, scripts, and styles</p>
68
+ </article>
69
+
70
+ <article class="feature-card">
71
+ <div class="feature-icon" aria-hidden="true">📱</div>
72
+ <h3 class="feature-title">Responsive</h3>
73
+ <p class="feature-description">Works seamlessly across all devices and screen sizes</p>
74
+ </article>
75
+
76
+ <article class="feature-card">
77
+ <div class="feature-icon" aria-hidden="true">♿</div>
78
+ <h3 class="feature-title">Accessible</h3>
79
+ <p class="feature-description">Built with accessibility in mind for all users</p>
80
+ </article>
81
+ </div>
82
+ </section>
83
+
84
+ <!-- Content Section -->
85
+ <section class="content" role="region" aria-labelledby="content-heading">
86
+ <div class="content-container">
87
+ <h2 id="content-heading" class="section-title">Why Choose Us?</h2>
88
+ <div class="content-grid">
89
+ <div class="content-text">
90
+ <p>
91
+ Our static site generator provides everything you need to create modern, performant web pages with
92
+ comprehensive SEO support, PWA capabilities, and full customization options.
93
+ </p>
94
+ <ul class="content-list">
95
+ <li>✓ Complete metadata control</li>
96
+ <li>✓ Script and stylesheet injection</li>
97
+ <li>✓ SSR component system</li>
98
+ <li>✓ JSON-LD structured data</li>
99
+ <li>✓ Production-ready builds</li>
100
+ </ul>
101
+ </div>
102
+ <div class="content-media">
103
+ <div class="placeholder-image" role="img" aria-label="Feature showcase">
104
+ <!-- Image placeholder -->
105
+ </div>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </section>
110
+
111
+ <!-- Call to Action -->
112
+ <section class="cta" role="region" aria-labelledby="cta-heading">
113
+ <div class="cta-container">
114
+ <h2 id="cta-heading" class="cta-title">Ready to Get Started?</h2>
115
+ <p class="cta-text">Join thousands of developers building with Underpost</p>
116
+ <form class="cta-form" id="signup-form" aria-label="Sign up form">
117
+ <input type="email" class="cta-input" placeholder="Enter your email" aria-label="Email address" required />
118
+ <button type="submit" class="btn btn-primary">Sign Up</button>
119
+ </form>
120
+ </div>
121
+ </section>
122
+
123
+ <!-- Footer -->
124
+ <footer class="footer" role="contentinfo">
125
+ <div class="footer-content">
126
+ <div class="footer-section">
127
+ <h3 class="footer-heading">About</h3>
128
+ <ul class="footer-links">
129
+ <li><a href="/about">About Us</a></li>
130
+ <li><a href="/team">Team</a></li>
131
+ <li><a href="/careers">Careers</a></li>
132
+ </ul>
133
+ </div>
134
+ <div class="footer-section">
135
+ <h3 class="footer-heading">Resources</h3>
136
+ <ul class="footer-links">
137
+ <li><a href="/docs">Documentation</a></li>
138
+ <li><a href="/guides">Guides</a></li>
139
+ <li><a href="/api">API Reference</a></li>
140
+ </ul>
141
+ </div>
142
+ <div class="footer-section">
143
+ <h3 class="footer-heading">Community</h3>
144
+ <ul class="footer-links">
145
+ <li><a href="/github">GitHub</a></li>
146
+ <li><a href="/discord">Discord</a></li>
147
+ <li><a href="/twitter">Twitter</a></li>
148
+ </ul>
149
+ </div>
150
+ <div class="footer-section">
151
+ <h3 class="footer-heading">Legal</h3>
152
+ <ul class="footer-links">
153
+ <li><a href="/privacy">Privacy Policy</a></li>
154
+ <li><a href="/terms">Terms of Service</a></li>
155
+ <li><a href="/cookies">Cookie Policy</a></li>
156
+ </ul>
157
+ </div>
158
+ </div>
159
+ <div class="footer-bottom">
160
+ <p class="footer-copyright">&copy; ${new Date().getFullYear()} Underpost. All rights reserved.</p>
161
+ </div>
162
+ </footer>
163
+ </div>
164
+
165
+ <!-- Inline Styles (Critical CSS) -->
166
+ <style>
167
+ /* CSS Reset and Base Styles */
168
+ * {
169
+ margin: 0;
170
+ padding: 0;
171
+ box-sizing: border-box;
172
+ }
173
+
174
+ body {
175
+ font-family:
176
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',
177
+ 'Droid Sans', 'Helvetica Neue', sans-serif;
178
+ line-height: 1.6;
179
+ color: #333;
180
+ background: #f8f9fa;
181
+ }
182
+
183
+ .custom-page {
184
+ min-height: 100vh;
185
+ display: flex;
186
+ flex-direction: column;
187
+ }
188
+
189
+ /* Hero Section */
190
+ .hero {
191
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
192
+ color: white;
193
+ padding: 80px 20px;
194
+ text-align: center;
195
+ min-height: 500px;
196
+ display: flex;
197
+ align-items: center;
198
+ justify-content: center;
199
+ position: relative;
200
+ overflow: hidden;
201
+ }
202
+
203
+ .hero-content {
204
+ max-width: 800px;
205
+ z-index: 1;
206
+ }
207
+
208
+ .hero-title {
209
+ font-size: 3rem;
210
+ font-weight: 700;
211
+ margin-bottom: 1rem;
212
+ animation: fadeInUp 0.8s ease-out;
213
+ }
214
+
215
+ .hero-subtitle {
216
+ font-size: 1.5rem;
217
+ margin-bottom: 2rem;
218
+ opacity: 0.9;
219
+ animation: fadeInUp 0.8s ease-out 0.2s backwards;
220
+ }
221
+
222
+ .hero-actions {
223
+ display: flex;
224
+ gap: 1rem;
225
+ justify-content: center;
226
+ animation: fadeInUp 0.8s ease-out 0.4s backwards;
227
+ }
228
+
229
+ /* Buttons */
230
+ .btn {
231
+ padding: 12px 32px;
232
+ font-size: 1rem;
233
+ font-weight: 600;
234
+ border: none;
235
+ border-radius: 8px;
236
+ cursor: pointer;
237
+ transition: all 0.3s ease;
238
+ text-decoration: none;
239
+ display: inline-block;
240
+ }
241
+
242
+ .btn-primary {
243
+ background: white;
244
+ color: #667eea;
245
+ }
246
+
247
+ .btn-primary:hover {
248
+ transform: translateY(-2px);
249
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
250
+ }
251
+
252
+ .btn-secondary {
253
+ background: transparent;
254
+ color: white;
255
+ border: 2px solid white;
256
+ }
257
+
258
+ .btn-secondary:hover {
259
+ background: white;
260
+ color: #667eea;
261
+ }
262
+
263
+ /* Section Styles */
264
+ section {
265
+ padding: 60px 20px;
266
+ }
267
+
268
+ .section-title {
269
+ font-size: 2.5rem;
270
+ text-align: center;
271
+ margin-bottom: 3rem;
272
+ color: #2d3748;
273
+ }
274
+
275
+ /* Features Section */
276
+ .features {
277
+ background: white;
278
+ }
279
+
280
+ .features-grid {
281
+ display: grid;
282
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
283
+ gap: 2rem;
284
+ max-width: 1200px;
285
+ margin: 0 auto;
286
+ }
287
+
288
+ .feature-card {
289
+ background: #f8f9fa;
290
+ padding: 2rem;
291
+ border-radius: 12px;
292
+ text-align: center;
293
+ transition:
294
+ transform 0.3s ease,
295
+ box-shadow 0.3s ease;
296
+ }
297
+
298
+ .feature-card:hover {
299
+ transform: translateY(-5px);
300
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
301
+ }
302
+
303
+ .feature-icon {
304
+ font-size: 3rem;
305
+ margin-bottom: 1rem;
306
+ }
307
+
308
+ .feature-title {
309
+ font-size: 1.5rem;
310
+ margin-bottom: 1rem;
311
+ color: #2d3748;
312
+ }
313
+
314
+ .feature-description {
315
+ color: #4a5568;
316
+ }
317
+
318
+ /* Content Section */
319
+ .content {
320
+ background: #f8f9fa;
321
+ }
322
+
323
+ .content-container {
324
+ max-width: 1200px;
325
+ margin: 0 auto;
326
+ }
327
+
328
+ .content-grid {
329
+ display: grid;
330
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
331
+ gap: 3rem;
332
+ align-items: center;
333
+ }
334
+
335
+ .content-list {
336
+ list-style: none;
337
+ margin-top: 1.5rem;
338
+ }
339
+
340
+ .content-list li {
341
+ padding: 0.5rem 0;
342
+ font-size: 1.1rem;
343
+ color: #4a5568;
344
+ }
345
+
346
+ .placeholder-image {
347
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
348
+ height: 300px;
349
+ border-radius: 12px;
350
+ }
351
+
352
+ /* CTA Section */
353
+ .cta {
354
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
355
+ color: white;
356
+ text-align: center;
357
+ }
358
+
359
+ .cta-container {
360
+ max-width: 600px;
361
+ margin: 0 auto;
362
+ }
363
+
364
+ .cta-title {
365
+ font-size: 2.5rem;
366
+ margin-bottom: 1rem;
367
+ }
368
+
369
+ .cta-text {
370
+ font-size: 1.2rem;
371
+ margin-bottom: 2rem;
372
+ opacity: 0.9;
373
+ }
374
+
375
+ .cta-form {
376
+ display: flex;
377
+ gap: 1rem;
378
+ max-width: 500px;
379
+ margin: 0 auto;
380
+ }
381
+
382
+ .cta-input {
383
+ flex: 1;
384
+ padding: 12px 20px;
385
+ border: none;
386
+ border-radius: 8px;
387
+ font-size: 1rem;
388
+ }
389
+
390
+ /* Footer */
391
+ .footer {
392
+ background: #2d3748;
393
+ color: white;
394
+ padding: 60px 20px 20px;
395
+ }
396
+
397
+ .footer-content {
398
+ max-width: 1200px;
399
+ margin: 0 auto;
400
+ display: grid;
401
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
402
+ gap: 2rem;
403
+ margin-bottom: 2rem;
404
+ }
405
+
406
+ .footer-heading {
407
+ margin-bottom: 1rem;
408
+ font-size: 1.2rem;
409
+ }
410
+
411
+ .footer-links {
412
+ list-style: none;
413
+ }
414
+
415
+ .footer-links a {
416
+ color: #a0aec0;
417
+ text-decoration: none;
418
+ display: block;
419
+ padding: 0.3rem 0;
420
+ transition: color 0.3s ease;
421
+ }
422
+
423
+ .footer-links a:hover {
424
+ color: white;
425
+ }
426
+
427
+ .footer-bottom {
428
+ text-align: center;
429
+ padding-top: 2rem;
430
+ border-top: 1px solid #4a5568;
431
+ }
432
+
433
+ .footer-copyright {
434
+ color: #a0aec0;
435
+ }
436
+
437
+ /* Animations */
438
+ @keyframes fadeInUp {
439
+ from {
440
+ opacity: 0;
441
+ transform: translateY(30px);
442
+ }
443
+ to {
444
+ opacity: 1;
445
+ transform: translateY(0);
446
+ }
447
+ }
448
+
449
+ /* Responsive Design */
450
+ @media (max-width: 768px) {
451
+ .hero-title {
452
+ font-size: 2rem;
453
+ }
454
+
455
+ .hero-subtitle {
456
+ font-size: 1.2rem;
457
+ }
458
+
459
+ .hero-actions {
460
+ flex-direction: column;
461
+ }
462
+
463
+ .section-title {
464
+ font-size: 2rem;
465
+ }
466
+
467
+ .cta-form {
468
+ flex-direction: column;
469
+ }
470
+
471
+ .cta-title {
472
+ font-size: 2rem;
473
+ }
474
+ }
475
+
476
+ /* Accessibility - Focus Styles */
477
+ *:focus {
478
+ outline: 3px solid #667eea;
479
+ outline-offset: 2px;
480
+ }
481
+
482
+ /* Print Styles */
483
+ @media print {
484
+ .hero,
485
+ .cta {
486
+ background: white !important;
487
+ color: black !important;
488
+ }
489
+
490
+ .btn {
491
+ display: none;
492
+ }
493
+ }
494
+ </style>
495
+
496
+ <!-- Inline JavaScript (Progressive Enhancement) -->
497
+ <script>
498
+ // Wait for DOM to be ready
499
+ document.addEventListener('DOMContentLoaded', function () {
500
+ console.log('Custom page loaded successfully');
501
+
502
+ // Get Started button handler
503
+ const getStartedBtn = document.getElementById('get-started');
504
+ if (getStartedBtn) {
505
+ getStartedBtn.addEventListener('click', function () {
506
+ window.location.href = '/signup';
507
+ });
508
+ }
509
+
510
+ // Learn More button handler
511
+ const learnMoreBtn = document.getElementById('learn-more');
512
+ if (learnMoreBtn) {
513
+ learnMoreBtn.addEventListener('click', function () {
514
+ document.querySelector('.features').scrollIntoView({
515
+ behavior: 'smooth',
516
+ });
517
+ });
518
+ }
519
+
520
+ // Signup form handler
521
+ const signupForm = document.getElementById('signup-form');
522
+ if (signupForm) {
523
+ signupForm.addEventListener('submit', function (e) {
524
+ e.preventDefault();
525
+ const email = this.querySelector('input[type="email"]').value;
526
+
527
+ // Basic email validation
528
+ if (email && /^[^s@]+@[^s@]+.[^s@]+$/.test(email)) {
529
+ alert('Thank you for signing up! We will contact you soon.');
530
+ this.reset();
531
+ } else {
532
+ alert('Please enter a valid email address.');
533
+ }
534
+ });
535
+ }
536
+
537
+ // Intersection Observer for animations
538
+ if ('IntersectionObserver' in window) {
539
+ const observerOptions = {
540
+ threshold: 0.1,
541
+ rootMargin: '0px 0px -50px 0px',
542
+ };
543
+
544
+ const observer = new IntersectionObserver(function (entries) {
545
+ entries.forEach(function (entry) {
546
+ if (entry.isIntersecting) {
547
+ entry.target.style.opacity = '1';
548
+ entry.target.style.transform = 'translateY(0)';
549
+ }
550
+ });
551
+ }, observerOptions);
552
+
553
+ // Observe feature cards
554
+ document.querySelectorAll('.feature-card').forEach(function (card, index) {
555
+ card.style.opacity = '0';
556
+ card.style.transform = 'translateY(30px)';
557
+ card.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
558
+ card.style.transitionDelay = index * 0.1 + 's';
559
+ observer.observe(card);
560
+ });
561
+ }
562
+
563
+ // Accessibility: Skip to content link
564
+ const skipLink = document.createElement('a');
565
+ skipLink.href = '#main-content';
566
+ skipLink.textContent = 'Skip to main content';
567
+ skipLink.className = 'skip-link';
568
+ skipLink.style.cssText =
569
+ 'position: absolute; top: -40px; left: 0; background: #667eea; color: white; padding: 8px 16px; text-decoration: none; z-index: 100;';
570
+ skipLink.addEventListener('focus', function () {
571
+ this.style.top = '0';
572
+ });
573
+ skipLink.addEventListener('blur', function () {
574
+ this.style.top = '-40px';
575
+ });
576
+ document.body.insertBefore(skipLink, document.body.firstChild);
577
+ });
578
+ </script>
579
+ `;