ultimate-jekyll-manager 0.0.142 → 0.0.143

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/assets/css/core/_lazy-loading.scss +13 -0
  2. package/dist/assets/js/libs/form-manager.js +3 -3
  3. package/dist/assets/js/pages/index.js +0 -4
  4. package/dist/assets/themes/classy/_config.scss +2 -1
  5. package/dist/assets/themes/classy/_theme.js +5 -0
  6. package/dist/assets/themes/classy/css/base/_spacing.scss +4 -0
  7. package/dist/assets/themes/classy/css/components/_buttons.scss +14 -19
  8. package/dist/assets/themes/classy/js/hero-demo-form.js +42 -0
  9. package/dist/defaults/dist/_includes/core/foot.html +27 -1
  10. package/dist/defaults/dist/_layouts/blueprint/admin/firebase/index.html +9 -7
  11. package/dist/defaults/dist/_layouts/blueprint/admin/notifications/new.html +3 -1
  12. package/dist/defaults/dist/_layouts/blueprint/admin/users/index.html +4 -4
  13. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +1 -1
  14. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/post.html +2 -1
  15. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +7 -7
  16. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +188 -12
  17. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/payment/checkout.html +1 -0
  18. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +14 -2
  19. package/dist/defaults/dist/pages/test/components/hero-demo-custom.html +60 -0
  20. package/dist/defaults/dist/pages/test/components/hero-demo-form.html +83 -0
  21. package/dist/defaults/dist/pages/test/components/hero-demo-input.html +47 -0
  22. package/dist/defaults/dist/pages/test/components/hero-demo-side.html +43 -0
  23. package/dist/defaults/dist/pages/test/components/hero-demo-video.html +43 -0
  24. package/dist/defaults/dist/pages/test/translation/index.md +2 -1
  25. package/dist/defaults/dist/robots.txt +18 -0
  26. package/dist/index.js +7 -0
  27. package/firebase-debug.log +338 -0
  28. package/package.json +1 -1
@@ -12,6 +12,19 @@ img[data-lazy] {
12
12
  height: auto; // Maintain aspect ratio
13
13
  }
14
14
 
15
+ // Hide video/audio elements until loaded to prevent ugly native controls showing during shimmer
16
+ [data-lazy-load-container].lazy-loading video,
17
+ [data-lazy-load-container].lazy-loading audio {
18
+ opacity: 0;
19
+ }
20
+
21
+ // Show video/audio elements once loaded with fade-in
22
+ [data-lazy-load-container].lazy-loaded video,
23
+ [data-lazy-load-container].lazy-loaded audio {
24
+ opacity: 1;
25
+ transition: opacity 0.25s ease-in;
26
+ }
27
+
15
28
  // ============================================
16
29
  // Loading States
17
30
  // ============================================
@@ -13,7 +13,7 @@
13
13
 
14
14
  // Libraries
15
15
  import { ready as domReady } from 'web-manager/modules/dom.js';
16
- import { showNotification } from 'web-manager/modules/utilities.js';
16
+ import { showNotification, getDeviceType } from 'web-manager/modules/utilities.js';
17
17
 
18
18
  export class FormManager {
19
19
  constructor(selector, options = {}) {
@@ -150,9 +150,9 @@ export class FormManager {
150
150
  this._setState('ready');
151
151
  this._setDisabled(false);
152
152
 
153
- // Focus the field with autofocus attribute if it exists
153
+ // Focus the field with autofocus attribute if it exists (desktop only)
154
154
  const $autofocusField = this.$form.querySelector('[autofocus]');
155
- if ($autofocusField && !$autofocusField.disabled) {
155
+ if ($autofocusField && !$autofocusField.disabled && getDeviceType() === 'desktop') {
156
156
  $autofocusField.focus();
157
157
 
158
158
  // Move cursor to end of input if it has existing text
@@ -7,16 +7,12 @@ let webManager = null;
7
7
  // Module
8
8
  export default (Manager) => {
9
9
  return new Promise(async function (resolve) {
10
- console.log('[Homepage] Module loading...');
11
-
12
10
  // Shortcuts
13
11
  webManager = Manager.webManager;
14
12
 
15
13
  // Initialize when DOM is ready
16
14
  await webManager.dom().ready();
17
15
 
18
- console.log('[Homepage] DOM ready');
19
-
20
16
  // Bootstrap tabs handle all the tab switching automatically via data-bs-toggle="tab"
21
17
  // We just need to pause videos when switching tabs for better UX
22
18
  setupVideoControls();
@@ -184,5 +184,6 @@ $avatar-sizes: (
184
184
  $headings-font-weight: $headings-font-weight,
185
185
  $border-radius: $border-radius,
186
186
  $border-radius-sm: $border-radius-sm,
187
- $border-radius-lg: $border-radius-lg
187
+ $border-radius-lg: $border-radius-lg,
188
+ $enable-negative-margins: true
188
189
  );
@@ -18,6 +18,8 @@ import setupNavbarScroll from './js/navbar-scroll.js';
18
18
  import { setupInfiniteScroll } from './js/infinite-scroll.js';
19
19
  // Import tooltip initialization
20
20
  import initializeTooltips from './js/initialize-tooltips.js';
21
+ // Import hero demo form initialization
22
+ import initHeroDemoForm from './js/hero-demo-form.js';
21
23
 
22
24
  // Initialize theme components when DOM is ready
23
25
  domReady().then(() => {
@@ -27,4 +29,7 @@ domReady().then(() => {
27
29
 
28
30
  // Generic Bootstrap initializations
29
31
  initializeTooltips();
32
+
33
+ // Initialize hero demo form if present
34
+ initHeroDemoForm();
30
35
  });
@@ -28,6 +28,10 @@
28
28
  // ============================================
29
29
  // Height utilities using viewport height (vh) units
30
30
  .vh-50 { height: 50vh !important; }
31
+ .vh-75 { height: 75vh !important; }
32
+ .vh-80 { height: 80vh !important; }
33
+ .vh-90 { height: 90vh !important; }
34
+ .vh-100 { height: 100vh !important; }
31
35
 
32
36
  // Min-Height utilities using viewport height (vh) units
33
37
  .min-vh-50 { min-height: 50vh !important; }
@@ -357,25 +357,20 @@
357
357
  // ============================================
358
358
  // Adaptive Inverse Buttons
359
359
  // ============================================
360
- // .btn-adaptive-inverse {
361
- // @extend .btn-light;
362
- // // color: $dark !important;
363
-
364
- // // &:hover {
365
- // // background: $dark !important;
366
- // // color: white !important;
367
- // // }
368
- // }
369
-
370
- // [data-bs-theme="dark"] .btn-adaptive-inverse {
371
- // @extend .btn-dark;
372
- // // color: white !important;
373
-
374
- // // &:hover {
375
- // // background: white !important;
376
- // // color: $dark !important;
377
- // // }
378
- // }
360
+ .btn-adaptive-inverse {
361
+ @extend .btn-light;
362
+ }
363
+
364
+ [data-bs-theme="dark"] .btn-adaptive-inverse {
365
+ @extend .btn-dark;
366
+ }
367
+ .btn-outline-adaptive-inverse {
368
+ @extend .btn-outline-light;
369
+ }
370
+
371
+ [data-bs-theme="dark"] .btn-outline-adaptive-inverse {
372
+ @extend .btn-outline-dark;
373
+ }
379
374
 
380
375
  // ============================================
381
376
  // Gradient Rainbow Button
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Hero Demo Form
3
+ * Initializes FormManager for hero demo forms (input or form type)
4
+ */
5
+
6
+ /**
7
+ * Initialize the hero demo form if present
8
+ */
9
+ export default async function initHeroDemoForm() {
10
+ const $form = document.querySelector('#hero-demo-form');
11
+
12
+ if (!$form) {
13
+ return;
14
+ }
15
+
16
+ // Dynamic import FormManager only when needed
17
+ const { FormManager } = await import('__main_assets__/js/libs/form-manager.js');
18
+
19
+ const formManager = new FormManager($form, {
20
+ submittingText: 'Processing...',
21
+ });
22
+
23
+ formManager.on('submit', async ({ data }) => {
24
+ // Get redirect URL from form data attribute or default to /dashboard
25
+ const redirectUrl = $form.dataset.redirect || '/dashboard';
26
+
27
+ // Build query string from form data
28
+ const params = new URLSearchParams();
29
+
30
+ Object.entries(data).forEach(([key, value]) => {
31
+ if (value !== null && value !== undefined && value !== '') {
32
+ params.set(key, value);
33
+ }
34
+ });
35
+
36
+ // Redirect with form data as query params
37
+ const queryString = params.toString();
38
+ const url = queryString ? `${redirectUrl}?${queryString}` : redirectUrl;
39
+
40
+ window.location.href = url;
41
+ });
42
+ }
@@ -49,13 +49,39 @@
49
49
  </a>
50
50
  </div>
51
51
 
52
+ <hr class="my-4">
53
+
54
+ <!-- Social proof -->
55
+ <div class="d-flex align-items-center justify-content-center">
56
+ <div class="d-flex me-2">
57
+ <span class="avatar avatar-sm rounded-circle border border-2 border-body overflow-hidden me-n2">
58
+ <img src="{{ site.uj.placeholder.src }}" data-lazy="@src https://i.pravatar.cc/40?img=1" alt="">
59
+ </span>
60
+ <span class="avatar avatar-sm rounded-circle border border-2 border-body overflow-hidden me-n2">
61
+ <img src="{{ site.uj.placeholder.src }}" data-lazy="@src https://i.pravatar.cc/40?img=2" alt="">
62
+ </span>
63
+ <span class="avatar avatar-sm rounded-circle border border-2 border-body overflow-hidden me-n2">
64
+ <img src="{{ site.uj.placeholder.src }}" data-lazy="@src https://i.pravatar.cc/40?img=3" alt="">
65
+ </span>
66
+ <span class="avatar avatar-sm rounded-circle border border-2 border-body overflow-hidden">
67
+ <img src="{{ site.uj.placeholder.src }}" data-lazy="@src https://i.pravatar.cc/40?img=4" alt="">
68
+ </span>
69
+ </div>
70
+ <span class="text-muted">
71
+
72
+ </span>
73
+ <small class="ms-2 text-muted"><strong class="text-body">10k+</strong> happy subscribers</small>
74
+ </div>
75
+
52
76
  <!-- Trust indicators -->
53
- <div class="mt-4 pt-3 border-top">
77
+ {% comment %}
78
+ <div class="mt-3 pt-3 border-top">
54
79
  <small class="text-muted">
55
80
  <span class="text-success me-1">{% uj_icon "shield-alt" %}</span>
56
81
  No spam, ever. Unsubscribe anytime.
57
82
  </small>
58
83
  </div>
84
+ {% endcomment %}
59
85
  </div>
60
86
  </div>
61
87
  </div>
@@ -80,8 +80,8 @@ meta:
80
80
  </div>
81
81
  <div class="card-body">
82
82
  <div class="mb-3">
83
- <label class="form-label small">Where</label>
84
- <select class="form-select form-select-sm">
83
+ <label for="query-field" class="form-label small">Where</label>
84
+ <select class="form-select form-select-sm" id="query-field">
85
85
  <option>Select field...</option>
86
86
  <option>email</option>
87
87
  <option>name</option>
@@ -90,7 +90,8 @@ meta:
90
90
  </select>
91
91
  </div>
92
92
  <div class="mb-3">
93
- <select class="form-select form-select-sm">
93
+ <label for="query-operator" class="visually-hidden">Operator</label>
94
+ <select class="form-select form-select-sm" id="query-operator" aria-label="Comparison operator">
94
95
  <option>==</option>
95
96
  <option>!=</option>
96
97
  <option>&gt;</option>
@@ -100,7 +101,8 @@ meta:
100
101
  </select>
101
102
  </div>
102
103
  <div class="mb-3">
103
- <input type="text" class="form-control form-control-sm" placeholder="Value">
104
+ <label for="query-value" class="visually-hidden">Value</label>
105
+ <input type="text" class="form-control form-control-sm" id="query-value" placeholder="Value" aria-label="Query value">
104
106
  </div>
105
107
  <button class="btn btn-sm btn-adaptive w-100">
106
108
  {% uj_icon "magnifying-glass", "fa-sm me-2" %}
@@ -126,7 +128,7 @@ meta:
126
128
  <span class="input-group-text">
127
129
  {% uj_icon "magnifying-glass", "fa-sm" %}
128
130
  </span>
129
- <input type="text" class="form-control" placeholder="Search documents...">
131
+ <input type="text" class="form-control" id="document-search" placeholder="Search documents..." aria-label="Search documents">
130
132
  </div>
131
133
  <div class="btn-group btn-group-sm">
132
134
  <button class="btn btn-outline-adaptive active">
@@ -148,7 +150,7 @@ meta:
148
150
  <thead class="table-light">
149
151
  <tr>
150
152
  <th style="width: 30px;">
151
- <input class="form-check-input" type="checkbox">
153
+ <input class="form-check-input" type="checkbox" id="select-all-documents" aria-label="Select all documents">
152
154
  </th>
153
155
  <th>Document ID</th>
154
156
  <th>email</th>
@@ -162,7 +164,7 @@ meta:
162
164
  {% for i in (1..15) %}
163
165
  <tr>
164
166
  <td>
165
- <input class="form-check-input" type="checkbox">
167
+ <input class="form-check-input" type="checkbox" aria-label="Select document {{ i }}">
166
168
  </td>
167
169
  <td class="font-monospace small">
168
170
  {% if i < 10 %}usr00{{ i }}{% else %}usr0{{ i }}{% endif %}abc123xyz
@@ -229,18 +229,20 @@ prerender_icons:
229
229
  </h5>
230
230
 
231
231
  <div class="mb-3">
232
- <label class="form-label">Auto-submit Date & Time</label>
232
+ <span class="form-label d-block">Auto-submit Date & Time</span>
233
233
  <small class="d-block text-muted mb-2">
234
234
  Leave empty to send immediately, or schedule for later
235
235
  </small>
236
236
  <div class="row">
237
237
  <div class="col-md-5">
238
+ <label for="schedule-date" class="visually-hidden">Schedule date</label>
238
239
  <input type="date"
239
240
  class="form-control"
240
241
  name="schedule.date"
241
242
  id="schedule-date">
242
243
  </div>
243
244
  <div class="col-md-4">
245
+ <label for="schedule-time" class="visually-hidden">Schedule time</label>
244
246
  <input type="time"
245
247
  class="form-control"
246
248
  name="schedule.time"
@@ -65,12 +65,12 @@ meta:
65
65
  <span class="input-group-text">
66
66
  {% uj_icon "magnifying-glass", "fa-sm" %}
67
67
  </span>
68
- <input type="text" class="form-control" placeholder="Search users by name, email, or ID...">
68
+ <input type="text" class="form-control" id="user-search" placeholder="Search users by name, email, or ID..." aria-label="Search users">
69
69
  </div>
70
70
  </div>
71
71
  <div class="col-md-6">
72
72
  <div class="d-flex gap-2 justify-content-end">
73
- <select class="form-select" style="width: auto;">
73
+ <select class="form-select" id="user-sort" style="width: auto;" aria-label="Sort users">
74
74
  <option>Sort by: Date Created</option>
75
75
  <option>Sort by: Name</option>
76
76
  <option>Sort by: Last Active</option>
@@ -92,7 +92,7 @@ meta:
92
92
  <thead>
93
93
  <tr>
94
94
  <th>
95
- <input class="form-check-input" type="checkbox">
95
+ <input class="form-check-input" type="checkbox" id="select-all-users" aria-label="Select all users">
96
96
  </th>
97
97
  <th>User</th>
98
98
  <th>Role</th>
@@ -106,7 +106,7 @@ meta:
106
106
  {% for i in (1..10) %}
107
107
  <tr>
108
108
  <td>
109
- <input class="form-check-input" type="checkbox">
109
+ <input class="form-check-input" type="checkbox" aria-label="Select user {{ i }}">
110
110
  </td>
111
111
  <td>
112
112
  <div class="d-flex align-items-center">
@@ -1016,7 +1016,7 @@ badges:
1016
1016
 
1017
1017
  <div class="mb-0">
1018
1018
  <div class="input-group">
1019
- <input type="text" class="form-control font-monospace" id="referral-code-input" readonly value="Loading...">
1019
+ <input type="text" class="form-control font-monospace" id="referral-code-input" readonly value="Loading..." aria-label="Your referral code">
1020
1020
  <button type="button" class="btn btn-outline-adaptive" id="copy-referral-code-btn">
1021
1021
  {% uj_icon "copy", "me-2" %}
1022
1022
  <span class="button-text d-none d-sm-inline">Copy</span>
@@ -296,7 +296,8 @@ newsletter:
296
296
 
297
297
  <form class="row g-3 justify-content-center needs-validation" action="{{ site.url }}/email-subscription">
298
298
  <div class="col-md-7">
299
- <input type="email" name="email" class="form-control form-control-lg" placeholder="{% iftruthy page.resolved.newsletter.form.placeholder %}{{ page.resolved.newsletter.form.placeholder }}{% endiftruthy %}" autocomplete="email" required>
299
+ <label for="newsletter-email" class="visually-hidden">Email address</label>
300
+ <input type="email" name="email" id="newsletter-email" class="form-control form-control-lg" placeholder="{% iftruthy page.resolved.newsletter.form.placeholder %}{{ page.resolved.newsletter.form.placeholder }}{% endiftruthy %}" autocomplete="email" required>
300
301
  </div>
301
302
  <div class="col-md-auto">
302
303
  <button type="submit" class="btn btn-light btn-lg px-4">{% iftruthy page.resolved.newsletter.button.text %}{{ page.resolved.newsletter.button.text }}{% endiftruthy %}</button>
@@ -822,12 +822,12 @@ cta:
822
822
 
823
823
  <div class="position-relative mb-3">
824
824
  <div class="mb-1">
825
- <h6 class="mb-0">2. Navigate to Downloads</h6>
825
+ <h6 class="mb-0" id="linux-step-2-label">2. Navigate to Downloads</h6>
826
826
  <small class="text-muted">Run the command below</small>
827
827
  </div>
828
828
  <div class="bg-body-tertiary rounded-4 p-4 overflow-hidden position-relative">
829
829
  <div class="input-group">
830
- <input type="text" class="form-control font-monospace bg-dark text-light border-0" name="linux-command-1" value="cd ~/Downloads" readonly>
830
+ <input type="text" class="form-control font-monospace bg-dark text-light border-0" name="linux-command-1" value="cd ~/Downloads" readonly aria-labelledby="linux-step-2-label">
831
831
  <button type="button" class="btn btn-outline-adaptive copy-command-btn">
832
832
  {% uj_icon "copy", "me-2" %}
833
833
  <span class="button-text d-none d-sm-inline">Copy</span>
@@ -838,14 +838,14 @@ cta:
838
838
 
839
839
  <div class="position-relative mb-3">
840
840
  <div class="mb-1">
841
- <h6 class="mb-0">3. Install the package</h6>
841
+ <h6 class="mb-0" id="linux-step-3-label">3. Install the package</h6>
842
842
  <small class="text-muted">Run the appropriate command for your distribution</small>
843
843
  </div>
844
844
  <div class="bg-body-tertiary rounded-4 p-4 overflow-hidden position-relative">
845
845
  <div class="mb-3">
846
- <small class="text-muted d-block mb-2 fw-bold">For Debian/Ubuntu:</small>
846
+ <small class="text-muted d-block mb-2 fw-bold" id="linux-debian-label">For Debian/Ubuntu:</small>
847
847
  <div class="input-group">
848
- <input type="text" class="form-control font-monospace bg-dark text-light border-0" name="linux-command-2" value="sudo dpkg -i {{ site.brand.name | downcase }}_amd64.deb" readonly>
848
+ <input type="text" class="form-control font-monospace bg-dark text-light border-0" name="linux-command-2" value="sudo dpkg -i {{ site.brand.name | downcase }}_amd64.deb" readonly aria-labelledby="linux-debian-label">
849
849
  <button type="button" class="btn btn-outline-adaptive copy-command-btn">
850
850
  {% uj_icon "copy", "me-2" %}
851
851
  <span class="button-text d-none d-sm-inline">Copy</span>
@@ -853,9 +853,9 @@ cta:
853
853
  </div>
854
854
  </div>
855
855
  <div>
856
- <small class="text-muted d-block mb-2 fw-bold">For Fedora/RHEL:</small>
856
+ <small class="text-muted d-block mb-2 fw-bold" id="linux-fedora-label">For Fedora/RHEL:</small>
857
857
  <div class="input-group">
858
- <input type="text" class="form-control font-monospace bg-dark text-light border-0" name="linux-command-3" value="sudo rpm -i {{ site.brand.name | downcase }}_amd64.rpm" readonly>
858
+ <input type="text" class="form-control font-monospace bg-dark text-light border-0" name="linux-command-3" value="sudo rpm -i {{ site.brand.name | downcase }}_amd64.rpm" readonly aria-labelledby="linux-fedora-label">
859
859
  <button type="button" class="btn btn-outline-adaptive copy-command-btn">
860
860
  {% uj_icon "copy", "me-2" %}
861
861
  <span class="button-text d-none d-sm-inline">Copy</span>
@@ -14,14 +14,32 @@ hero:
14
14
  headline: "The #1 platform <br> for business"
15
15
  headline_accent: "success"
16
16
  description: "AI automation for modern businesses made simple"
17
+ demo:
18
+ enabled: false
19
+ type: "input"
20
+ placement: "bottom"
21
+ options:
22
+ class: "mw-md"
23
+ placeholder: "Enter your email"
24
+ name: "email"
25
+ input_type: "email"
26
+ required: true
27
+ redirect: "/dashboard"
28
+ subtext: "No credit card required"
29
+ button:
30
+ text: "Start Free Trial"
31
+ icon: "rocket"
32
+ class: "btn-adaptive-inverse"
17
33
  primary_button:
18
34
  text: "Get Started Free"
19
35
  icon: "rocket"
20
36
  href: "/dashboard"
37
+ class: "btn-light"
21
38
  secondary_button:
22
39
  text: "Explore Solutions"
23
40
  icon: "book-open"
24
41
  href: "/pricing"
42
+ class: "btn-outline-light"
25
43
  cards:
26
44
  - number: "50K+"
27
45
  label: "Active Users"
@@ -310,10 +328,157 @@ cta:
310
328
  {% endcomment %}
311
329
 
312
330
  <!-- Hero Section -->
331
+ {% assign demo = page.resolved.hero.demo %}
332
+ {% assign demo_placement = demo.placement | default: "bottom" %}
333
+ {% assign is_side_layout = false %}
334
+ {% if demo.enabled and demo_placement == "side" %}
335
+ {% assign is_side_layout = true %}
336
+ {% endif %}
337
+
338
+ {% comment %} Capture demo content once to avoid duplication {% endcomment %}
339
+ {% capture hero_demo_content %}
340
+ {% if demo.type == "input" %}
341
+ <!-- Input Demo: Single input with button -->
342
+ <div class="card bg-glassy border-0 {% unless is_side_layout %}mx-auto{% endunless %} {{ demo.options.class }}">
343
+ <div class="card-body">
344
+ <form id="hero-demo-form" class="d-flex flex-column {% unless is_side_layout %}flex-sm-row justify-content-center{% endunless %} gap-3" {% iftruthy demo.options.redirect %}data-redirect="{{ demo.options.redirect }}"{% endiftruthy %}>
345
+ <input
346
+ type="{{ demo.options.input_type | default: 'text' }}"
347
+ name="{{ demo.options.name | default: 'input' }}"
348
+ class="form-control form-control-lg border-0"
349
+ placeholder="{{ demo.options.placeholder }}"
350
+ {% iftruthy demo.options.required %}required{% endiftruthy %}
351
+ autofocus
352
+ disabled
353
+ >
354
+ {% assign demo_btn_class = demo.options.button.class | default: "btn-adaptive-inverse" %}
355
+ <button type="submit" class="btn {{ demo_btn_class }} btn-lg text-nowrap flex-shrink-0" disabled>
356
+ {% iftruthy demo.options.button.icon %}
357
+ {% uj_icon demo.options.button.icon, "me-2" %}
358
+ {% endiftruthy %}
359
+ {{ demo.options.button.text }}
360
+ </button>
361
+ </form>
362
+ </div>
363
+ </div>
364
+
365
+ {% elsif demo.type == "form" %}
366
+ <!-- Form Demo: Multiple fields with card styling -->
367
+ <div class="{% unless is_side_layout %}mx-auto{% endunless %} {{ demo.options.class }}">
368
+ <form id="hero-demo-form" {% iftruthy demo.options.redirect %}data-redirect="{{ demo.options.redirect }}"{% endiftruthy %}>
369
+ <div class="row g-3 {% unless is_side_layout %}justify-content-center{% endunless %}">
370
+ {% assign autofocus_set = false %}
371
+ {% for field in demo.options.fields %}
372
+ {% assign field_size = field.size | default: "half" %}
373
+ <div class="col-12 {% if field_size == 'half' %}col-sm-6{% endif %}">
374
+ <div class="card bg-glassy border-0">
375
+ <div class="card-body p-3">
376
+ {% iftruthy field.label %}
377
+ <label for="hero-demo-{{ field.name }}" class="form-label d-flex align-items-center mb-2">
378
+ {% iftruthy field.icon %}
379
+ {% uj_icon field.icon, "me-2" %}
380
+ {% endiftruthy %}
381
+ {{ field.label }}
382
+ {% iftruthy field.required %}<span class="text-danger ms-1">*</span>{% endiftruthy %}
383
+ </label>
384
+ {% endiftruthy %}
385
+ {% if field.type == "select" %}
386
+ <select
387
+ id="hero-demo-{{ field.name }}"
388
+ name="{{ field.name }}"
389
+ class="form-select form-select-lg border-0"
390
+ {% iftruthy field.required %}required{% endiftruthy %}
391
+ disabled
392
+ >
393
+ <option value="" disabled selected>{{ field.placeholder }}</option>
394
+ {% for option in field.options %}
395
+ <option value="{{ option.value }}">{{ option.label }}</option>
396
+ {% endfor %}
397
+ </select>
398
+ {% elsif field.type == "textarea" %}
399
+ <textarea
400
+ id="hero-demo-{{ field.name }}"
401
+ name="{{ field.name }}"
402
+ class="form-control form-control-lg border-0"
403
+ placeholder="{{ field.placeholder }}"
404
+ rows="{{ field.rows | default: 3 }}"
405
+ {% iftruthy field.required %}required{% endiftruthy %}
406
+ {% unless autofocus_set %}autofocus{% assign autofocus_set = true %}{% endunless %}
407
+ disabled
408
+ ></textarea>
409
+ {% else %}
410
+ <input
411
+ id="hero-demo-{{ field.name }}"
412
+ type="{{ field.type | default: 'text' }}"
413
+ name="{{ field.name }}"
414
+ class="form-control form-control-lg border-0"
415
+ placeholder="{{ field.placeholder }}"
416
+ {% iftruthy field.required %}required{% endiftruthy %}
417
+ {% unless autofocus_set %}autofocus{% assign autofocus_set = true %}{% endunless %}
418
+ disabled
419
+ >
420
+ {% endif %}
421
+ </div>
422
+ </div>
423
+ </div>
424
+ {% endfor %}
425
+ {% assign form_btn_class = demo.options.button.class | default: "btn-adaptive-inverse" %}
426
+ <div class="col-12 {% if demo.options.button.full_width != true %}col-sm-auto{% endif %}">
427
+ <button type="submit" class="btn {{ form_btn_class }} btn-lg w-100 h-100" disabled>
428
+ {% iftruthy demo.options.button.icon %}
429
+ {% uj_icon demo.options.button.icon, "me-2" %}
430
+ {% endiftruthy %}
431
+ {{ demo.options.button.text }}
432
+ </button>
433
+ </div>
434
+ </div>
435
+ </form>
436
+ </div>
437
+
438
+ {% elsif demo.type == "video" %}
439
+ <!-- Video Demo: Embedded video player -->
440
+ <div class="{% unless is_side_layout %}mx-auto{% endunless %} {{ demo.options.class }}">
441
+ <div class="card border-0 shadow-lg rounded-4 overflow-hidden">
442
+ <div class="ratio ratio-16x9">
443
+ {% uj_video demo.options.src, class="w-100 d-block object-fit-cover border-0", controls="{{ demo.options.controls }}", loop="{{ demo.options.loop }}", autoplay="{{ demo.options.autoplay }}", playsinline="true", muted="{{ demo.options.muted }}", preload="metadata" %}
444
+ </div>
445
+ </div>
446
+ </div>
447
+
448
+ {% elsif demo.type == "custom" %}
449
+ <!-- Custom Demo: Renders content block -->
450
+ <div id="hero-demo-custom" class="{% unless is_side_layout %}mx-auto{% endunless %} {{ demo.options.class }}">
451
+ {{ demo.options.content }}
452
+ </div>
453
+
454
+ {% endif %}
455
+
456
+ {% iftruthy demo.options.subtext %}
457
+ <p class="small mt-3 opacity-70 {% if is_side_layout %}text-center mb-0{% endif %}">{{ demo.options.subtext }}</p>
458
+ {% endiftruthy %}
459
+ {% endcapture %}
460
+
461
+ {% comment %} Capture CTA buttons {% endcomment %}
462
+ {% capture hero_cta_buttons %}
463
+ {% assign primary_btn_class = page.resolved.hero.primary_button.class | default: "btn-adaptive" %}
464
+ {% assign secondary_btn_class = page.resolved.hero.secondary_button.class | default: "btn-outline-adaptive" %}
465
+ <div class="d-flex flex-row flex-wrap gap-3 justify-content-center {% if is_side_layout %}justify-content-lg-start{% endif %}">
466
+ <a href="{{ page.resolved.hero.primary_button.href }}" class="btn {{ primary_btn_class }} btn-lg py-3 {% if is_side_layout %}px-4{% else %}px-5{% endif %}">
467
+ {% uj_icon page.resolved.hero.primary_button.icon, "me-2" %}
468
+ {{ page.resolved.hero.primary_button.text }}
469
+ </a>
470
+ <a href="{{ page.resolved.hero.secondary_button.href }}" class="btn {{ secondary_btn_class }} btn-lg py-3 {% if is_side_layout %}px-4{% else %}px-5{% endif %}">
471
+ {% uj_icon page.resolved.hero.secondary_button.icon, "me-2" %}
472
+ {{ page.resolved.hero.secondary_button.text }}
473
+ </a>
474
+ </div>
475
+ {% endcapture %}
476
+
313
477
  <section class="bg-gradient-rainbow gradient-animated gradient-grain text-light overflow-hidden position-relative min-vh-80 d-flex align-items-center rounded-bottom-4 shadow-lg">
314
478
  <div class="container py-5">
315
- <div class="row justify-content-center">
316
- <div class="col-lg-10 text-center py-5">
479
+ <div class="row justify-content-center {% if is_side_layout %}align-items-center{% endif %}">
480
+ <!-- Text Column -->
481
+ <div class="{% if is_side_layout %}col-lg-6 text-center text-lg-start{% else %}col-lg-10 text-center py-5{% endif %}">
317
482
  <div data-lazy="@class animation-slide-up">
318
483
  <p class="text-uppercase fw-semibold mb-3 opacity-80">{{ page.resolved.hero.tagline }}</p>
319
484
 
@@ -325,18 +490,29 @@ cta:
325
490
  {{ page.resolved.hero.description }}
326
491
  </p>
327
492
 
328
- <div class="d-flex flex-column flex-sm-row gap-3 justify-content-center">
329
- <a href="{{ page.resolved.hero.primary_button.href }}" class="btn btn-light btn-lg px-5 py-3">
330
- {% uj_icon page.resolved.hero.primary_button.icon, "me-2" %}
331
- {{ page.resolved.hero.primary_button.text }}
332
- </a>
333
- <a href="{{ page.resolved.hero.secondary_button.href }}" class="btn btn-outline-light btn-lg px-5 py-3">
334
- {% uj_icon page.resolved.hero.secondary_button.icon, "me-2" %}
335
- {{ page.resolved.hero.secondary_button.text }}
336
- </a>
337
- </div>
493
+ {% if is_side_layout %}
494
+ <!-- Side layout: CTA buttons go here, demo goes in right column -->
495
+ {{ hero_cta_buttons }}
496
+ {% else %}
497
+ <!-- Bottom layout: CTA buttons, then demo below -->
498
+ {{ hero_cta_buttons }}
499
+ {% if demo.enabled %}
500
+ <div class="mt-5">
501
+ {{ hero_demo_content }}
502
+ </div>
503
+ {% endif %}
504
+ {% endif %}
338
505
  </div>
339
506
  </div>
507
+
508
+ {% if is_side_layout %}
509
+ <!-- Demo Column (Side Placement) -->
510
+ <div class="col-lg-6 mt-5 mt-lg-0">
511
+ <div data-lazy="@class animation-slide-up">
512
+ {{ hero_demo_content }}
513
+ </div>
514
+ </div>
515
+ {% endif %}
340
516
  </div>
341
517
  </div>
342
518
  </section>