@deneb-ui/create-template 2.0.70 → 2.0.72

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.
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { useState, type FormEvent } from 'react';
4
- import { MapLink } from '@deneb-ui/ui';
4
+ import { EditableText, EditableBox } from '@deneb-ui/ui';
5
5
  import { contentObject, contentText, useSiteData } from '@/lib/siteDataContext';
6
6
 
7
7
  export default function ContactPage() {
@@ -15,6 +15,10 @@ export default function ContactPage() {
15
15
  contentText(contact.mapUrl) ||
16
16
  contentText(contact.addressUrl);
17
17
  const address = contentText(contact.address);
18
+ const phone = contentText(contact.phone);
19
+ const email = contentText(contact.email);
20
+ const whatsapp = contentText(contact.whatsapp);
21
+ const directMessageText = contentText(contact.directMessageText) || 'Chat on WhatsApp';
18
22
 
19
23
  async function handleSubmit(event: FormEvent<HTMLFormElement>) {
20
24
  event.preventDefault();
@@ -49,47 +53,128 @@ export default function ContactPage() {
49
53
  return (
50
54
  <div data-preview-page-key="contact">
51
55
  <section className="page-section page-heading" data-design-section="contact-heading">
52
- <h1 data-preview-field-path="contact.heading">{contentText(contact.heading)}</h1>
53
- <p data-preview-field-path="contact.intro">{contentText(contact.intro)}</p>
56
+ <EditableText
57
+ variant="h1"
58
+ size="4xl"
59
+ weight="bold"
60
+ color="heading"
61
+ data-preview-field-path="contact.heading"
62
+ defaultValue={contentText(contact.heading)}
63
+ />
64
+ <EditableText
65
+ variant="lead"
66
+ color="muted"
67
+ data-preview-field-path="contact.intro"
68
+ defaultValue={contentText(contact.intro)}
69
+ />
54
70
  </section>
71
+
55
72
  <section className="page-section contact-grid" data-design-section="contact-details">
56
- <div className="contact-details">
57
- <a href={`tel:${contentText(contact.phone)}`} data-preview-field-path="contact.phone">{contentText(contact.phone)}</a>
58
- <a href={`mailto:${contentText(contact.email)}`} data-preview-field-path="contact.email">{contentText(contact.email)}</a>
59
- <p data-preview-field-path="contact.address">{address}</p>
60
- <MapLink
61
- mapUrl={directionsUrl}
62
- address={address}
63
- label={directionsLabel}
64
- labelFieldPath="contact.directionsLabel"
65
- urlFieldPath="contact.directionsUrl"
66
- variant="outline"
67
- size="md"
73
+ <EditableBox className="card contact-details" balance radius="xl">
74
+ <EditableText
75
+ variant="h3"
76
+ size="xl"
77
+ weight="bold"
78
+ color="heading"
79
+ data-preview-static="contact-heading"
80
+ defaultValue="Direct Information"
68
81
  />
69
- </div>
70
- <form
71
- className="contact-form"
72
- onSubmit={handleSubmit}
73
- data-fivora-contact-disabled
74
- >
75
- <h2 data-preview-field-path="contact.formTitle">{contentText(contact.formTitle)}</h2>
76
- <label data-preview-static>
77
- Name
78
- <input type="text" name="name" autoComplete="name" />
79
- </label>
80
- <label data-preview-static>
81
- Email
82
- <input type="email" name="email" autoComplete="email" />
83
- </label>
84
- <label data-preview-static>
85
- Message
86
- <textarea name="message" rows={5} />
87
- </label>
88
- <button type="submit" className="button-primary">
89
- <span data-preview-field-path="contact.submitLabel">{contentText(contact.submitLabel)}</span>
90
- </button>
91
- <p role="status" aria-live="polite">{status}</p>
92
- </form>
82
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem', marginTop: '0.5rem' }}>
83
+ <a href={phone ? `tel:${phone}` : ''} data-preview-field-path="contact.phone">
84
+ {phone}
85
+ </a>
86
+ <a href={email ? `mailto:${email}` : ''} data-preview-field-path="contact.email">
87
+ {email}
88
+ </a>
89
+ <EditableText
90
+ variant="p"
91
+ color="muted"
92
+ data-preview-field-path="contact.address"
93
+ defaultValue={address}
94
+ />
95
+ </div>
96
+ <div style={{ marginTop: '1.5rem', display: 'flex', flexWrap: 'wrap', gap: '0.75rem' }}>
97
+ <a
98
+ href={directionsUrl || '#'}
99
+ data-preview-field-path="contact.directionsUrl"
100
+ target="_blank"
101
+ rel="noopener noreferrer"
102
+ className="deneb-map-link"
103
+ style={{
104
+ display: 'inline-flex',
105
+ alignItems: 'center',
106
+ justifyContent: 'center',
107
+ gap: '0.5rem',
108
+ fontWeight: 500,
109
+ textDecoration: 'none',
110
+ transition: 'all 0.2s ease',
111
+ cursor: 'pointer',
112
+ borderRadius: '0.5rem',
113
+ fontSize: '0.95rem',
114
+ padding: '0.5rem 1rem',
115
+ backgroundColor: 'transparent',
116
+ border: '1px solid var(--color-border, #e2e8f0)',
117
+ color: 'var(--color-text, #0f172a)',
118
+ }}
119
+ >
120
+ <svg data-preview-static="map-link-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
121
+ <path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" />
122
+ <circle cx="12" cy="10" r="3" />
123
+ </svg>
124
+ <span data-preview-field-path="contact.directionsLabel">{directionsLabel}</span>
125
+ </a>
126
+ <a
127
+ href={whatsapp ? `https://wa.me/${whatsapp.replace(/[^0-9]/g, '')}` : '#'}
128
+ target="_blank"
129
+ rel="noopener noreferrer"
130
+ className="button-secondary"
131
+ data-preview-field-path="contact.whatsapp"
132
+ >
133
+ <span data-preview-field-path="contact.directMessageText">
134
+ {directMessageText}
135
+ </span>
136
+ </a>
137
+ </div>
138
+ </EditableBox>
139
+
140
+ <EditableBox className="card" balance radius="xl">
141
+ <form
142
+ className="contact-form"
143
+ onSubmit={handleSubmit}
144
+ data-fivora-contact-disabled
145
+ >
146
+ <EditableText
147
+ variant="h2"
148
+ size="2xl"
149
+ weight="bold"
150
+ color="heading"
151
+ data-preview-field-path="contact.formTitle"
152
+ defaultValue={contentText(contact.formTitle)}
153
+ />
154
+ <label data-preview-static>
155
+ Name
156
+ <input type="text" name="name" autoComplete="name" required />
157
+ </label>
158
+ <label data-preview-static>
159
+ Email
160
+ <input type="email" name="email" autoComplete="email" required />
161
+ </label>
162
+ <label data-preview-static>
163
+ Message
164
+ <textarea name="message" rows={4} required />
165
+ </label>
166
+ <button type="submit" className="button-primary" style={{ marginTop: '0.5rem' }}>
167
+ <span data-preview-field-path="contact.submitLabel">
168
+ {contentText(contact.submitLabel)}
169
+ </span>
170
+ </button>
171
+ {status && (
172
+ <p role="status" aria-live="polite" style={{ marginTop: '0.75rem', fontSize: '0.9rem' }}>
173
+ {status}
174
+ </p>
175
+ )}
176
+ </form>
177
+ </EditableBox>
93
178
  </section>
94
179
  </div>
95
180
  );
@@ -6,6 +6,11 @@
6
6
  color-scheme: light;
7
7
  }
8
8
 
9
+ html.dark,
10
+ .dark {
11
+ color-scheme: dark;
12
+ }
13
+
9
14
  * {
10
15
  box-sizing: border-box;
11
16
  }
@@ -18,6 +23,7 @@ body {
18
23
  margin: 0;
19
24
  background: var(--page-background, #ffffff);
20
25
  color: var(--page-text, #0f172a);
26
+ transition: background-color 0.25s ease, color 0.25s ease;
21
27
  }
22
28
 
23
29
  button,
@@ -252,10 +258,11 @@ h3 {
252
258
 
253
259
  .card {
254
260
  padding: 1.4rem;
255
- border: 1px solid color-mix(in srgb, var(--page-text) 12%, transparent);
261
+ border: 1px solid var(--card-border, color-mix(in srgb, var(--page-text) 12%, transparent));
256
262
  border-radius: 1.35rem;
257
- background: var(--page-background);
263
+ background: var(--card-bg, var(--page-background));
258
264
  box-shadow: 0 1rem 2.5rem color-mix(in srgb, var(--brand-secondary) 8%, transparent);
265
+ transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.25s ease, border-color 0.25s ease;
259
266
  }
260
267
 
261
268
  .card h3 {
@@ -347,10 +354,11 @@ h3 {
347
354
  .contact-form textarea {
348
355
  width: 100%;
349
356
  padding: 0.85rem 1rem;
350
- border: 1px solid color-mix(in srgb, var(--page-text) 20%, transparent);
357
+ border: 1px solid var(--input-border, color-mix(in srgb, var(--page-text) 20%, transparent));
351
358
  border-radius: 0.8rem;
352
- background: var(--page-background);
353
- color: var(--page-text);
359
+ background: var(--input-bg, var(--page-background));
360
+ color: var(--input-color, var(--page-text));
361
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
354
362
  }
355
363
 
356
364
  .site-footer {
@@ -442,81 +450,3 @@ h3 {
442
450
  transform: scale(1.06) translateY(-4px);
443
451
  }
444
452
 
445
- /* Developer Quickstart Guide Section */
446
- .dev-guide-section {
447
- border-top: 1px solid color-mix(in srgb, var(--page-text) 10%, transparent);
448
- border-bottom: 1px solid color-mix(in srgb, var(--page-text) 10%, transparent);
449
- background: color-mix(in srgb, var(--brand-color) 4%, var(--page-background));
450
- }
451
-
452
- .dev-guide-header {
453
- text-align: center;
454
- max-width: 44rem;
455
- margin: 0 auto 2.5rem;
456
- }
457
-
458
- .dev-badge {
459
- display: inline-block;
460
- padding: 0.35rem 0.9rem;
461
- border-radius: 999px;
462
- font-size: 0.8rem;
463
- font-weight: 700;
464
- letter-spacing: 0.05em;
465
- background: color-mix(in srgb, var(--brand-color) 15%, transparent);
466
- color: var(--brand-color);
467
- margin-bottom: 0.85rem;
468
- }
469
-
470
- .dev-command-grid {
471
- display: grid;
472
- grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
473
- gap: 1.5rem;
474
- }
475
-
476
- .dev-cmd-card {
477
- padding: 1.5rem;
478
- border-radius: 1rem;
479
- background: var(--page-background);
480
- border: 1px solid color-mix(in srgb, var(--page-text) 12%, transparent);
481
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04);
482
- transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
483
- }
484
-
485
- .dev-cmd-card:hover {
486
- transform: translateY(-3px);
487
- border-color: var(--brand-accent);
488
- box-shadow: 0 8px 24px color-mix(in srgb, var(--brand-color) 15%, transparent);
489
- }
490
-
491
- .dev-cmd-card .cmd-header {
492
- display: flex;
493
- align-items: center;
494
- justify-content: space-between;
495
- margin-bottom: 0.75rem;
496
- gap: 0.5rem;
497
- }
498
-
499
- .dev-cmd-card .cmd-tag {
500
- font-size: 0.75rem;
501
- font-weight: 700;
502
- text-transform: uppercase;
503
- letter-spacing: 0.08em;
504
- color: var(--brand-color);
505
- }
506
-
507
- .dev-cmd-card code {
508
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
509
- font-size: 0.85rem;
510
- font-weight: 700;
511
- padding: 0.2rem 0.5rem;
512
- border-radius: 0.35rem;
513
- background: color-mix(in srgb, var(--page-text) 8%, transparent);
514
- color: var(--page-text);
515
- }
516
-
517
- .dev-cmd-card p {
518
- margin: 0;
519
- font-size: 0.9rem;
520
- line-height: 1.5;
521
- color: color-mix(in srgb, var(--page-text) 70%, transparent);
522
- }
@@ -1,7 +1,7 @@
1
1
  import type { Metadata } from 'next';
2
2
  import type { ReactNode } from 'react';
3
3
  import siteData from '@/data/site-data.json';
4
- import { SiteDataProvider } from '@/lib/siteDataContext';
4
+ import { SiteDataProvider, ThemeStyles } from '@/lib/siteDataContext';
5
5
  import SiteChrome from '@/components/SiteChrome';
6
6
  import './globals.css';
7
7
  import '../fonts/deneb-fonts.css';
@@ -15,8 +15,14 @@ export const metadata: Metadata = {
15
15
  };
16
16
 
17
17
  export default function RootLayout({ children }: { children: ReactNode }) {
18
+ const initialTheme =
19
+ (siteData as any)?.template?.structure?.theme || (siteData as any)?.theme;
20
+
18
21
  return (
19
22
  <html lang="en" suppressHydrationWarning>
23
+ <head>
24
+ <ThemeStyles theme={initialTheme} enableDualMode />
25
+ </head>
20
26
  <body suppressHydrationWarning>
21
27
  <SiteDataProvider initialSiteData={siteData}>
22
28
  <SiteChrome>{children}</SiteChrome>
@@ -13,8 +13,7 @@ import {
13
13
  EditableText,
14
14
  EditableList,
15
15
  EditableCard,
16
- EditableProductCard,
17
- ListActionCta,
16
+ EditableImage,
18
17
  } from '@deneb-ui/ui';
19
18
 
20
19
 
@@ -140,14 +139,28 @@ export default function HomePage() {
140
139
  data-preview-field-path="home.introBody"
141
140
  defaultValue={contentText(home.introBody)}
142
141
  />
143
- <div style={{ display: 'flex', justifyContent: 'center', marginTop: '1.5rem' }}>
144
- <ListActionCta
145
- listPath="home.demoPreOrderCta"
146
- editable
147
- buttonLabel={demoCtaLabel}
148
- buttonUrl={demoCtaUrl}
149
- className="button-primary"
150
- />
142
+ <div
143
+ style={{ display: 'flex', justifyContent: 'center', gap: '0.75rem', marginTop: '1.5rem', flexWrap: 'wrap' }}
144
+ data-preview-list-path="home.demoPreOrderCta"
145
+ >
146
+ {contentList(home.demoPreOrderCta).map((rawCta, index) => {
147
+ const cta = contentObject(rawCta);
148
+ const label = contentText(cta.buttonLabel) || 'Book a Consultation';
149
+ const url = contentText(cta.buttonUrl) || '#';
150
+ return (
151
+ <a
152
+ key={index}
153
+ href={url}
154
+ className="button-primary"
155
+ data-preview-item-path={`home.demoPreOrderCta[${index}]`}
156
+ data-preview-field-path={`home.demoPreOrderCta[${index}].buttonUrl`}
157
+ >
158
+ <span data-preview-field-path={`home.demoPreOrderCta[${index}].buttonLabel`}>
159
+ {label}
160
+ </span>
161
+ </a>
162
+ );
163
+ })}
151
164
  </div>
152
165
  </div>
153
166
  </section>
@@ -229,38 +242,110 @@ export default function HomePage() {
229
242
  />
230
243
  </div>
231
244
 
232
- <EditableList
233
- data-preview-list-path="products"
234
- items={products}
235
- className="card-grid"
236
- itemAs={false}
237
- >
238
- {(rawProduct, index, itemPath) => {
245
+ <div className="card-grid" data-preview-list-path="products">
246
+ {products.map((rawProduct, index) => {
239
247
  const product = contentObject(rawProduct);
240
248
  const productId =
241
249
  typeof product.id === 'string' || typeof product.id === 'number'
242
250
  ? product.id
243
251
  : null;
252
+ const price = typeof product.price === 'number' ? product.price : parseFloat(String(product.price || 0));
253
+ const compareAt = typeof product.compareAtPrice === 'number' ? product.compareAtPrice : parseFloat(String(product.compareAtPrice || 0));
254
+ const currency = contentText(product.currency) || 'LKR';
255
+ const badge = contentText(product.badge);
256
+ const category = contentText(product.category);
244
257
 
245
258
  return (
246
- <EditableProductCard
259
+ <EditableCard
247
260
  key={productId ?? index}
248
- itemPath={itemPath}
249
- product={product}
250
- currency={contentText(product.currency) || 'LKR'}
251
- actionSlot={
252
- <a
253
- href={platformProductDetailHref(productId)}
254
- className="product-detail-link"
255
- data-preview-static="Open the stable live product detail page"
256
- >
257
- View details
258
- </a>
259
- }
260
- />
261
+ className="card product-card"
262
+ item={product as any}
263
+ itemPath={`products[${index}]`}
264
+ data-preview-item-path={`products[${index}]`}
265
+ balance
266
+ radius="xl"
267
+ style={{ display: 'flex', flexDirection: 'column' }}
268
+ >
269
+ <div style={{ position: 'relative', overflow: 'hidden', borderRadius: '12px', marginBottom: '0.75rem' }}>
270
+ <EditableImage
271
+ src={contentText(product.imageUrl) || '/placeholder.svg'}
272
+ alt={contentText(product.name)}
273
+ data-preview-field-path={`products[${index}].imageUrl`}
274
+ aspectRatio="4/3"
275
+ fit="cover"
276
+ radius="lg"
277
+ />
278
+ {badge && (
279
+ <span
280
+ className="badge-primary"
281
+ data-preview-field-path={`products[${index}].badge`}
282
+ style={{ position: 'absolute', top: '10px', left: '10px', zIndex: 10 }}
283
+ >
284
+ {badge}
285
+ </span>
286
+ )}
287
+ </div>
288
+
289
+ <div style={{ display: 'flex', flexDirection: 'column', flex: 1, gap: '0.5rem' }}>
290
+ {category && (
291
+ <span
292
+ className="tag"
293
+ data-preview-field-path={`products[${index}].category`}
294
+ style={{ fontSize: '0.75rem', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.05em' }}
295
+ >
296
+ {category}
297
+ </span>
298
+ )}
299
+ <EditableText
300
+ variant="h3"
301
+ size="lg"
302
+ weight="bold"
303
+ color="heading"
304
+ data-preview-field-path={`products[${index}].name`}
305
+ defaultValue={contentText(product.name)}
306
+ />
307
+ <EditableText
308
+ variant="p"
309
+ color="muted"
310
+ data-preview-field-path={`products[${index}].description`}
311
+ defaultValue={contentText(product.description)}
312
+ />
313
+
314
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: '0.5rem', marginTop: 'auto', paddingTop: '0.75rem' }}>
315
+ <EditableText
316
+ as="span"
317
+ weight="bold"
318
+ size="xl"
319
+ color="primary"
320
+ data-preview-field-path={`products[${index}].price`}
321
+ defaultValue={`${currency} ${price}`}
322
+ />
323
+ {compareAt > 0 && (
324
+ <EditableText
325
+ as="span"
326
+ color="muted"
327
+ style={{ textDecoration: 'line-through', fontSize: '0.875rem' }}
328
+ data-preview-field-path={`products[${index}].compareAtPrice`}
329
+ defaultValue={`${currency} ${compareAt}`}
330
+ />
331
+ )}
332
+ </div>
333
+
334
+ <div style={{ marginTop: '0.75rem' }}>
335
+ <a
336
+ href={platformProductDetailHref(productId)}
337
+ className="button-secondary"
338
+ style={{ width: '100%', textAlign: 'center' }}
339
+ data-preview-static="Open the stable live product detail page"
340
+ >
341
+ View details
342
+ </a>
343
+ </div>
344
+ </div>
345
+ </EditableCard>
261
346
  );
262
- }}
263
- </EditableList>
347
+ })}
348
+ </div>
264
349
  </section>
265
350
  </div>
266
351
  );
@@ -3,5 +3,17 @@
3
3
  import { PlatformProductDetail } from '@deneb-ui/ui';
4
4
 
5
5
  export default function ProductDetailPage() {
6
- return <PlatformProductDetail backHref="/" />;
6
+ return (
7
+ <PlatformProductDetail
8
+ backHref="/"
9
+ loadingFallback={
10
+ <div
11
+ role="status"
12
+ className="mx-auto flex min-h-[40vh] max-w-7xl items-center justify-center px-4 py-16 text-sm text-slate-400"
13
+ >
14
+ <span data-preview-static="product-detail-loading">Loading product…</span>
15
+ </div>
16
+ }
17
+ />
18
+ );
7
19
  }
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
- import { contentObject, contentText, useServices, useSiteData } from '@/lib/siteDataContext';
4
- import { EditableServiceCard, EditableText } from '@deneb-ui/ui';
3
+ import { contentList, contentObject, contentText, useServices, useSiteData } from '@/lib/siteDataContext';
4
+ import { EditableCard, EditableImage, EditableText } from '@deneb-ui/ui';
5
5
 
6
6
  export default function ServicesPage() {
7
7
  const siteData = useSiteData();
@@ -31,13 +31,71 @@ export default function ServicesPage() {
31
31
  </section>
32
32
  <section className="page-section alt" data-design-section="services-list">
33
33
  <div className="card-grid" data-preview-list-path="services">
34
- {services.map((service, index) => (
35
- <EditableServiceCard
36
- key={contentText(service.id) || index}
37
- itemPath={`services[${index}]`}
38
- service={service}
39
- />
40
- ))}
34
+ {services.map((rawService, index) => {
35
+ const service = contentObject(rawService);
36
+ const features = contentList(service.features);
37
+ const imageUrl = contentText(service.imageUrl);
38
+
39
+ return (
40
+ <EditableCard
41
+ key={contentText(service.id) || index}
42
+ className="card service-card"
43
+ item={service as any}
44
+ itemPath={`services[${index}]`}
45
+ data-preview-item-path={`services[${index}]`}
46
+ balance
47
+ radius="xl"
48
+ style={{ display: 'flex', flexDirection: 'column' }}
49
+ >
50
+ {imageUrl && (
51
+ <div style={{ position: 'relative', overflow: 'hidden', borderRadius: '12px', marginBottom: '0.75rem' }}>
52
+ <EditableImage
53
+ src={imageUrl}
54
+ alt={contentText(service.name)}
55
+ data-preview-field-path={`services[${index}].imageUrl`}
56
+ aspectRatio="16/9"
57
+ fit="cover"
58
+ radius="lg"
59
+ />
60
+ </div>
61
+ )}
62
+ <EditableText
63
+ variant="h3"
64
+ size="xl"
65
+ weight="bold"
66
+ color="heading"
67
+ data-preview-field-path={`services[${index}].name`}
68
+ defaultValue={contentText(service.name)}
69
+ />
70
+ <EditableText
71
+ variant="p"
72
+ color="muted"
73
+ data-preview-field-path={`services[${index}].description`}
74
+ defaultValue={contentText(service.description)}
75
+ style={{ marginTop: '0.5rem' }}
76
+ />
77
+ {features.length > 0 && (
78
+ <ul
79
+ className="service-features-list"
80
+ data-preview-list-path={`services[${index}].features`}
81
+ style={{ marginTop: '1rem', display: 'flex', flexDirection: 'column', gap: '0.375rem', paddingLeft: '1.25rem' }}
82
+ >
83
+ {features.map((feature, fIndex) => (
84
+ <li
85
+ key={fIndex}
86
+ data-preview-item-path={`services[${index}].features[${fIndex}]`}
87
+ style={{ fontSize: '0.875rem' }}
88
+ >
89
+ <span data-preview-field-path={`services[${index}].features[${fIndex}]`}>
90
+ {contentText(feature)}
91
+ </span>
92
+ </li>
93
+ ))}
94
+ </ul>
95
+ )}
96
+ </EditableCard>
97
+ );
98
+ })}
41
99
  </div>
42
100
  </section>
43
101
  </div>
@@ -4,6 +4,7 @@ import type { ReactNode } from 'react';
4
4
  import { usePathname } from 'next/navigation';
5
5
  import { useSiteData } from '@/lib/siteDataContext';
6
6
  import { Navbar, Footer, AnnouncementBar, FloatingContactWidget, getThemeCssProperties } from '@deneb-ui/ui';
7
+ import { ThemeToggle } from './ThemeToggle';
7
8
 
8
9
  export default function SiteChrome({ children }: { children: ReactNode }) {
9
10
  const siteData = useSiteData();
@@ -19,6 +20,9 @@ export default function SiteChrome({ children }: { children: ReactNode }) {
19
20
  <main>{children}</main>
20
21
  <Footer />
21
22
  <FloatingContactWidget />
23
+ <div className="fixed bottom-6 left-6 z-40">
24
+ <ThemeToggle showLabel className="shadow-lg backdrop-blur-md" />
25
+ </div>
22
26
  </div>
23
27
  );
24
28
  }