@deneb-ui/create-template 2.0.70 → 2.0.71
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/bin/index.js +191 -7
- package/package.json +1 -1
- package/template/fivora-template.json +5 -0
- package/template/package.json +2 -2
- package/template/src/app/about_us/page.tsx +21 -7
- package/template/src/app/contact/page.tsx +110 -39
- package/template/src/app/globals.css +13 -83
- package/template/src/app/layout.tsx +7 -1
- package/template/src/components/SiteChrome.tsx +4 -0
- package/template/src/components/ThemeToggle.tsx +87 -0
- package/template/src/data/site-data.json +99 -74
- package/template/src/lib/siteDataContext.tsx +2 -0
package/bin/index.js
CHANGED
|
@@ -54,11 +54,121 @@ function copyFolderSync(src, dest) {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
const THEME_PRESETS = {
|
|
58
|
+
dual: {
|
|
59
|
+
key: 'dual',
|
|
60
|
+
name: 'Dual-Mode (Light + Dark Switcher) [Recommended]',
|
|
61
|
+
theme: {
|
|
62
|
+
primaryColor: '#016a7e',
|
|
63
|
+
secondaryColor: '#0a1931',
|
|
64
|
+
accentColor: '#00adb5',
|
|
65
|
+
backgroundColor: '#ffffff',
|
|
66
|
+
textColor: '#0f172a',
|
|
67
|
+
headingFont: 'Inter',
|
|
68
|
+
bodyFont: 'Inter',
|
|
69
|
+
baseSize: '16px',
|
|
70
|
+
heroMinHeight: '72vh',
|
|
71
|
+
sectionPadding: '5rem',
|
|
72
|
+
dark: {
|
|
73
|
+
backgroundColor: '#090d16',
|
|
74
|
+
cardBackgroundColor: '#131b2e',
|
|
75
|
+
textColor: '#f8fafc',
|
|
76
|
+
borderColor: 'rgba(255, 255, 255, 0.12)',
|
|
77
|
+
primaryColor: '#00adb5',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
light: {
|
|
82
|
+
key: 'light',
|
|
83
|
+
name: 'Modern Clean (Pure Light Commerce)',
|
|
84
|
+
theme: {
|
|
85
|
+
primaryColor: '#2563eb',
|
|
86
|
+
secondaryColor: '#1e293b',
|
|
87
|
+
accentColor: '#3b82f6',
|
|
88
|
+
backgroundColor: '#ffffff',
|
|
89
|
+
cardBackgroundColor: '#ffffff',
|
|
90
|
+
textColor: '#0f172a',
|
|
91
|
+
borderColor: '#e2e8f0',
|
|
92
|
+
headingFont: 'Inter',
|
|
93
|
+
bodyFont: 'Inter',
|
|
94
|
+
baseSize: '16px',
|
|
95
|
+
heroMinHeight: '72vh',
|
|
96
|
+
sectionPadding: '5rem',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
dark: {
|
|
100
|
+
key: 'dark',
|
|
101
|
+
name: 'Luxury Obsidian (Pure Dark Theme)',
|
|
102
|
+
theme: {
|
|
103
|
+
primaryColor: '#6366f1',
|
|
104
|
+
secondaryColor: '#0f172a',
|
|
105
|
+
accentColor: '#818cf8',
|
|
106
|
+
backgroundColor: '#090d16',
|
|
107
|
+
cardBackgroundColor: '#131b2e',
|
|
108
|
+
textColor: '#f8fafc',
|
|
109
|
+
borderColor: 'rgba(255, 255, 255, 0.12)',
|
|
110
|
+
headingFont: 'Inter',
|
|
111
|
+
bodyFont: 'Inter',
|
|
112
|
+
baseSize: '16px',
|
|
113
|
+
heroMinHeight: '72vh',
|
|
114
|
+
sectionPadding: '5rem',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
emerald: {
|
|
118
|
+
key: 'emerald',
|
|
119
|
+
name: 'Emerald Luxury (Deep Green & Gold)',
|
|
120
|
+
theme: {
|
|
121
|
+
primaryColor: '#10b981',
|
|
122
|
+
secondaryColor: '#064e3b',
|
|
123
|
+
accentColor: '#d97706',
|
|
124
|
+
backgroundColor: '#061a14',
|
|
125
|
+
cardBackgroundColor: '#0c2e24',
|
|
126
|
+
textColor: '#f0fdf4',
|
|
127
|
+
borderColor: 'rgba(16, 185, 129, 0.2)',
|
|
128
|
+
headingFont: 'Inter',
|
|
129
|
+
bodyFont: 'Inter',
|
|
130
|
+
baseSize: '16px',
|
|
131
|
+
heroMinHeight: '72vh',
|
|
132
|
+
sectionPadding: '5rem',
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
cyberpunk: {
|
|
136
|
+
key: 'cyberpunk',
|
|
137
|
+
name: 'Cyberpunk Neon (Futuristic Dark)',
|
|
138
|
+
theme: {
|
|
139
|
+
primaryColor: '#ec4899',
|
|
140
|
+
secondaryColor: '#18181b',
|
|
141
|
+
accentColor: '#06b6d4',
|
|
142
|
+
backgroundColor: '#09090b',
|
|
143
|
+
cardBackgroundColor: '#18181b',
|
|
144
|
+
textColor: '#fafafa',
|
|
145
|
+
borderColor: 'rgba(236, 72, 153, 0.3)',
|
|
146
|
+
headingFont: 'Inter',
|
|
147
|
+
bodyFont: 'Inter',
|
|
148
|
+
baseSize: '16px',
|
|
149
|
+
heroMinHeight: '72vh',
|
|
150
|
+
sectionPadding: '5rem',
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
function resolveThemePreset(input) {
|
|
156
|
+
if (!input) return THEME_PRESETS.dual;
|
|
157
|
+
const clean = input.trim().toLowerCase();
|
|
158
|
+
if (clean === '1' || clean === 'dual') return THEME_PRESETS.dual;
|
|
159
|
+
if (clean === '2' || clean === 'light') return THEME_PRESETS.light;
|
|
160
|
+
if (clean === '3' || clean === 'dark') return THEME_PRESETS.dark;
|
|
161
|
+
if (clean === '4' || clean === 'emerald') return THEME_PRESETS.emerald;
|
|
162
|
+
if (clean === '5' || clean === 'cyberpunk') return THEME_PRESETS.cyberpunk;
|
|
163
|
+
return THEME_PRESETS[clean] || THEME_PRESETS.dual;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function runScaffolding(targetInput, chosenThemeKey = 'dual') {
|
|
58
167
|
const targetPath = path.resolve(process.cwd(), targetInput.trim());
|
|
59
168
|
const folderName = path.basename(targetPath);
|
|
60
169
|
const sanitizedPkgName = folderName.toLowerCase().replace(/[^a-z0-9_-]/g, '-');
|
|
61
170
|
const templateDir = path.resolve(__dirname, '..', 'template');
|
|
171
|
+
const selectedPreset = resolveThemePreset(chosenThemeKey);
|
|
62
172
|
|
|
63
173
|
if (!fs.existsSync(templateDir)) {
|
|
64
174
|
console.error(`\n\x1b[31mError:\x1b[0m Template directory not found at ${templateDir}`);
|
|
@@ -71,6 +181,7 @@ function runScaffolding(targetInput) {
|
|
|
71
181
|
}
|
|
72
182
|
|
|
73
183
|
console.log(`\n\x1b[32mCreating DENEB template in:\x1b[0m ${targetPath}...\n`);
|
|
184
|
+
console.log(` \x1b[36m🎨 Starter Theme Style:\x1b[0m ${selectedPreset.name}`);
|
|
74
185
|
copyFolderSync(templateDir, targetPath);
|
|
75
186
|
|
|
76
187
|
// Restore .gitignore if preserved as _gitignore
|
|
@@ -91,8 +202,29 @@ function runScaffolding(targetInput) {
|
|
|
91
202
|
}
|
|
92
203
|
}
|
|
93
204
|
|
|
205
|
+
// Inject selected theme into site-data.json
|
|
206
|
+
const siteDataPath = path.join(targetPath, 'src', 'data', 'site-data.json');
|
|
207
|
+
if (fs.existsSync(siteDataPath)) {
|
|
208
|
+
try {
|
|
209
|
+
const siteData = JSON.parse(fs.readFileSync(siteDataPath, 'utf8'));
|
|
210
|
+
if (siteData.template && siteData.template.structure) {
|
|
211
|
+
siteData.template.structure.theme = {
|
|
212
|
+
...(siteData.template.structure.theme || {}),
|
|
213
|
+
...selectedPreset.theme,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
siteData.theme = {
|
|
217
|
+
...(siteData.theme || {}),
|
|
218
|
+
...selectedPreset.theme,
|
|
219
|
+
};
|
|
220
|
+
fs.writeFileSync(siteDataPath, JSON.stringify(siteData, null, 2) + '\n');
|
|
221
|
+
} catch {
|
|
222
|
+
// ignore
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
94
226
|
console.log(`\x1b[32m✔ Template structure created!\x1b[0m`);
|
|
95
|
-
console.log(` \x1b[90m- Pre-configured @deneb-ui/ui (
|
|
227
|
+
console.log(` \x1b[90m- Pre-configured @deneb-ui/ui (ThemeStyles, ThemeToggle & 28+ Editable Components)\x1b[0m`);
|
|
96
228
|
console.log(` \x1b[90m- Pre-configured @deneb-ui/cli (lab, validate, zip tools)\x1b[0m\n`);
|
|
97
229
|
|
|
98
230
|
const skipInstall = process.argv.includes('--skip-install');
|
|
@@ -135,7 +267,7 @@ function runScaffolding(targetInput) {
|
|
|
135
267
|
console.log(`\x1b[32m══════════════════════════════════════════════════════════════════════════════\x1b[0m\n`);
|
|
136
268
|
console.log(`Your storefront template is pre-configured with:`);
|
|
137
269
|
console.log(` \x1b[36m⚡ Next.js 15 App Router\x1b[0m (React 19 + Static Export support)`);
|
|
138
|
-
console.log(` \x1b[36m🎨
|
|
270
|
+
console.log(` \x1b[36m🎨 Dynamic Theming Engine\x1b[0m (ThemeStyles + ThemeToggle + Zero-FOUC)`);
|
|
139
271
|
console.log(` \x1b[36m💎 @deneb-ui/ui\x1b[0m (28+ Visual-First Editable Components)`);
|
|
140
272
|
console.log(` \x1b[36m🛠️ @deneb-ui/cli\x1b[0m (Visual Lab, Preflight Validator & Packager)`);
|
|
141
273
|
console.log(` \x1b[36m📋 Fivora Manifest\x1b[0m (Version 2 Contract Compliant)\n`);
|
|
@@ -163,8 +295,44 @@ function runScaffolding(targetInput) {
|
|
|
163
295
|
|
|
164
296
|
printBanner();
|
|
165
297
|
|
|
166
|
-
|
|
167
|
-
|
|
298
|
+
// Extract CLI flags like --theme=dark or --theme=dual
|
|
299
|
+
let cliTheme = null;
|
|
300
|
+
const themeArg = args.find((a) => a.startsWith('--theme='));
|
|
301
|
+
if (themeArg) {
|
|
302
|
+
cliTheme = themeArg.split('=')[1];
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const positionalTarget = args.find((a) => !a.startsWith('-'));
|
|
306
|
+
const isNonInteractive =
|
|
307
|
+
!process.stdin.isTTY ||
|
|
308
|
+
Boolean(process.env.CI) ||
|
|
309
|
+
args.includes('--yes') ||
|
|
310
|
+
args.includes('-y') ||
|
|
311
|
+
args.includes('--non-interactive') ||
|
|
312
|
+
args.includes('--skip-install');
|
|
313
|
+
|
|
314
|
+
if (positionalTarget && positionalTarget.trim()) {
|
|
315
|
+
if (cliTheme || isNonInteractive) {
|
|
316
|
+
runScaffolding(positionalTarget, cliTheme || 'dual');
|
|
317
|
+
} else {
|
|
318
|
+
const rl = readline.createInterface({
|
|
319
|
+
input: process.stdin,
|
|
320
|
+
output: process.stdout,
|
|
321
|
+
});
|
|
322
|
+
console.log('⚡ Template Theme Selection:\n');
|
|
323
|
+
console.log(' \x1b[36m1)\x1b[0m Dual-Mode \x1b[90m(Light + Dark Switcher pre-installed)\x1b[0m \x1b[32m[Recommended]\x1b[0m');
|
|
324
|
+
console.log(' \x1b[36m2)\x1b[0m Modern Clean \x1b[90m(Pure Light commerce)\x1b[0m');
|
|
325
|
+
console.log(' \x1b[36m3)\x1b[0m Luxury Obsidian \x1b[90m(Pure Dark theme)\x1b[0m');
|
|
326
|
+
console.log(' \x1b[36m4)\x1b[0m Emerald Luxury \x1b[90m(Deep Green & Gold)\x1b[0m');
|
|
327
|
+
console.log(' \x1b[36m5)\x1b[0m Cyberpunk Neon \x1b[90m(Futuristic Dark)\x1b[0m\n');
|
|
328
|
+
|
|
329
|
+
rl.question(' \x1b[36m?\x1b[0m \x1b[1mSelect starter theme (1-5, default 1):\x1b[0m ', (themeAns) => {
|
|
330
|
+
rl.close();
|
|
331
|
+
runScaffolding(positionalTarget, themeAns.trim() || 'dual');
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
} else if (isNonInteractive) {
|
|
335
|
+
runScaffolding('my-deneb-store', cliTheme || 'dual');
|
|
168
336
|
} else {
|
|
169
337
|
const rl = readline.createInterface({
|
|
170
338
|
input: process.stdin,
|
|
@@ -173,8 +341,24 @@ if (targetDirInput && targetDirInput.trim() && !targetDirInput.startsWith('-'))
|
|
|
173
341
|
|
|
174
342
|
console.log('⚡ Welcome to DENEB UI Template Creator!\n');
|
|
175
343
|
rl.question(' \x1b[36m?\x1b[0m \x1b[1mWhat is your template name?\x1b[0m \x1b[90m(e.g. my-store)\x1b[0m: ', (answer) => {
|
|
176
|
-
rl.close();
|
|
177
344
|
const name = answer.trim() || 'my-deneb-store';
|
|
178
|
-
|
|
345
|
+
|
|
346
|
+
if (cliTheme) {
|
|
347
|
+
rl.close();
|
|
348
|
+
runScaffolding(name, cliTheme);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
console.log('\n \x1b[36m?\x1b[0m \x1b[1mSelect starter theme style:\x1b[0m');
|
|
353
|
+
console.log(' \x1b[36m1)\x1b[0m Dual-Mode \x1b[90m(Light + Dark Switcher pre-installed)\x1b[0m \x1b[32m[Recommended]\x1b[0m');
|
|
354
|
+
console.log(' \x1b[36m2)\x1b[0m Modern Clean \x1b[90m(Pure Light commerce)\x1b[0m');
|
|
355
|
+
console.log(' \x1b[36m3)\x1b[0m Luxury Obsidian \x1b[90m(Pure Dark theme)\x1b[0m');
|
|
356
|
+
console.log(' \x1b[36m4)\x1b[0m Emerald Luxury \x1b[90m(Deep Green & Gold)\x1b[0m');
|
|
357
|
+
console.log(' \x1b[36m5)\x1b[0m Cyberpunk Neon \x1b[90m(Futuristic Dark)\x1b[0m\n');
|
|
358
|
+
|
|
359
|
+
rl.question(' \x1b[1mEnter choice (1-5, default 1):\x1b[0m ', (themeAns) => {
|
|
360
|
+
rl.close();
|
|
361
|
+
runScaffolding(name, themeAns.trim() || 'dual');
|
|
362
|
+
});
|
|
179
363
|
});
|
|
180
364
|
}
|
package/package.json
CHANGED
package/template/package.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"next": "15.5.23",
|
|
19
19
|
"react": "19.2.8",
|
|
20
20
|
"react-dom": "19.2.8",
|
|
21
|
-
"@deneb-ui/ui": "^2.0.
|
|
21
|
+
"@deneb-ui/ui": "^2.0.71"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@eslint/eslintrc": "3.3.6",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"eslint": "9.39.5",
|
|
29
29
|
"eslint-config-next": "15.5.23",
|
|
30
30
|
"typescript": "5.8.3",
|
|
31
|
-
"@deneb-ui/cli": "^2.0.
|
|
31
|
+
"@deneb-ui/cli": "^2.0.71",
|
|
32
32
|
"tailwindcss": "^3.4.17",
|
|
33
33
|
"postcss": "8.5.26",
|
|
34
34
|
"autoprefixer": "^10.4.20"
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { HeritageCollage } from '@deneb-ui/ui';
|
|
3
|
+
import { HeritageCollage, EditableText, EditableImage } from '@deneb-ui/ui';
|
|
4
4
|
import { contentObject, contentText, contentList, useSiteData } from '@/lib/siteDataContext';
|
|
5
|
-
import { withBasePath } from '@/lib/utils';
|
|
6
5
|
|
|
7
6
|
export default function AboutPage() {
|
|
8
7
|
const siteData = useSiteData();
|
|
@@ -13,14 +12,29 @@ export default function AboutPage() {
|
|
|
13
12
|
<div data-preview-page-key="about_us">
|
|
14
13
|
<section className="page-section split" data-design-section="about">
|
|
15
14
|
<div className="split-copy">
|
|
16
|
-
<
|
|
17
|
-
|
|
15
|
+
<EditableText
|
|
16
|
+
variant="h1"
|
|
17
|
+
size="4xl"
|
|
18
|
+
weight="bold"
|
|
19
|
+
color="heading"
|
|
20
|
+
className="section-title"
|
|
21
|
+
data-preview-field-path="about.heading"
|
|
22
|
+
defaultValue={contentText(about.heading)}
|
|
23
|
+
/>
|
|
24
|
+
<EditableText
|
|
25
|
+
variant="lead"
|
|
26
|
+
color="muted"
|
|
27
|
+
data-preview-field-path="about.body"
|
|
28
|
+
defaultValue={contentText(about.body)}
|
|
29
|
+
/>
|
|
18
30
|
</div>
|
|
19
|
-
<
|
|
31
|
+
<EditableImage
|
|
20
32
|
className="split-image"
|
|
21
|
-
src={
|
|
22
|
-
alt=""
|
|
33
|
+
src={contentText(about.imageUrl) || '/placeholder.svg'}
|
|
34
|
+
alt="About DENEB-UI"
|
|
23
35
|
data-preview-field-path="about.imageUrl"
|
|
36
|
+
radius="xl"
|
|
37
|
+
fit="cover"
|
|
24
38
|
/>
|
|
25
39
|
</section>
|
|
26
40
|
|
|
@@ -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 { MapLink, 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,114 @@ 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
|
-
<
|
|
53
|
-
|
|
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
|
-
<
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
+
defaultValue="Direct Information"
|
|
68
80
|
/>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
81
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem', marginTop: '0.5rem' }}>
|
|
82
|
+
{phone && (
|
|
83
|
+
<a href={`tel:${phone}`} data-preview-field-path="contact.phone">
|
|
84
|
+
{phone}
|
|
85
|
+
</a>
|
|
86
|
+
)}
|
|
87
|
+
{email && (
|
|
88
|
+
<a href={`mailto:${email}`} data-preview-field-path="contact.email">
|
|
89
|
+
{email}
|
|
90
|
+
</a>
|
|
91
|
+
)}
|
|
92
|
+
{address && (
|
|
93
|
+
<EditableText
|
|
94
|
+
variant="p"
|
|
95
|
+
color="muted"
|
|
96
|
+
data-preview-field-path="contact.address"
|
|
97
|
+
defaultValue={address}
|
|
98
|
+
/>
|
|
99
|
+
)}
|
|
100
|
+
</div>
|
|
101
|
+
<div style={{ marginTop: '1.5rem', display: 'flex', flexWrap: 'wrap', gap: '0.75rem' }}>
|
|
102
|
+
<MapLink
|
|
103
|
+
mapUrl={directionsUrl}
|
|
104
|
+
address={address}
|
|
105
|
+
label={directionsLabel}
|
|
106
|
+
labelFieldPath="contact.directionsLabel"
|
|
107
|
+
urlFieldPath="contact.directionsUrl"
|
|
108
|
+
variant="outline"
|
|
109
|
+
size="md"
|
|
110
|
+
/>
|
|
111
|
+
{whatsapp && (
|
|
112
|
+
<a
|
|
113
|
+
href={`https://wa.me/${whatsapp.replace(/[^0-9]/g, '')}`}
|
|
114
|
+
target="_blank"
|
|
115
|
+
rel="noopener noreferrer"
|
|
116
|
+
className="button-secondary"
|
|
117
|
+
>
|
|
118
|
+
<span data-preview-field-path="contact.directMessageText">
|
|
119
|
+
{directMessageText}
|
|
120
|
+
</span>
|
|
121
|
+
</a>
|
|
122
|
+
)}
|
|
123
|
+
</div>
|
|
124
|
+
</EditableBox>
|
|
125
|
+
|
|
126
|
+
<EditableBox className="card" balance radius="xl">
|
|
127
|
+
<form
|
|
128
|
+
className="contact-form"
|
|
129
|
+
onSubmit={handleSubmit}
|
|
130
|
+
data-fivora-contact-disabled
|
|
131
|
+
>
|
|
132
|
+
<EditableText
|
|
133
|
+
variant="h2"
|
|
134
|
+
size="2xl"
|
|
135
|
+
weight="bold"
|
|
136
|
+
color="heading"
|
|
137
|
+
data-preview-field-path="contact.formTitle"
|
|
138
|
+
defaultValue={contentText(contact.formTitle)}
|
|
139
|
+
/>
|
|
140
|
+
<label data-preview-static>
|
|
141
|
+
Name
|
|
142
|
+
<input type="text" name="name" autoComplete="name" required />
|
|
143
|
+
</label>
|
|
144
|
+
<label data-preview-static>
|
|
145
|
+
Email
|
|
146
|
+
<input type="email" name="email" autoComplete="email" required />
|
|
147
|
+
</label>
|
|
148
|
+
<label data-preview-static>
|
|
149
|
+
Message
|
|
150
|
+
<textarea name="message" rows={4} required />
|
|
151
|
+
</label>
|
|
152
|
+
<button type="submit" className="button-primary" style={{ marginTop: '0.5rem' }}>
|
|
153
|
+
<span data-preview-field-path="contact.submitLabel">
|
|
154
|
+
{contentText(contact.submitLabel)}
|
|
155
|
+
</span>
|
|
156
|
+
</button>
|
|
157
|
+
{status && (
|
|
158
|
+
<p role="status" aria-live="polite" style={{ marginTop: '0.75rem', fontSize: '0.9rem' }}>
|
|
159
|
+
{status}
|
|
160
|
+
</p>
|
|
161
|
+
)}
|
|
162
|
+
</form>
|
|
163
|
+
</EditableBox>
|
|
93
164
|
</section>
|
|
94
165
|
</div>
|
|
95
166
|
);
|
|
@@ -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>
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
export interface ThemeToggleProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
showLabel?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Built-in ThemeToggle Component for DENEB Storefront Templates.
|
|
12
|
+
* Toggles the `.dark` class on the root <html> element and persists preference to localStorage.
|
|
13
|
+
*/
|
|
14
|
+
export function ThemeToggle({ className = '', showLabel = false }: ThemeToggleProps) {
|
|
15
|
+
const [isDark, setIsDark] = useState(false);
|
|
16
|
+
const [mounted, setMounted] = useState(false);
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
setMounted(true);
|
|
20
|
+
const hasDarkClass = document.documentElement.classList.contains('dark');
|
|
21
|
+
const storedTheme = typeof window !== 'undefined' ? localStorage.getItem('deneb-theme') : null;
|
|
22
|
+
const prefersDark = typeof window !== 'undefined' ? window.matchMedia('(prefers-color-scheme: dark)').matches : false;
|
|
23
|
+
|
|
24
|
+
const activeDark = storedTheme ? storedTheme === 'dark' : hasDarkClass || prefersDark;
|
|
25
|
+
setIsDark(activeDark);
|
|
26
|
+
if (activeDark) {
|
|
27
|
+
document.documentElement.classList.add('dark');
|
|
28
|
+
} else {
|
|
29
|
+
document.documentElement.classList.remove('dark');
|
|
30
|
+
}
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
const toggleTheme = () => {
|
|
34
|
+
const nextDark = !isDark;
|
|
35
|
+
setIsDark(nextDark);
|
|
36
|
+
if (nextDark) {
|
|
37
|
+
document.documentElement.classList.add('dark');
|
|
38
|
+
localStorage.setItem('deneb-theme', 'dark');
|
|
39
|
+
} else {
|
|
40
|
+
document.documentElement.classList.remove('dark');
|
|
41
|
+
localStorage.setItem('deneb-theme', 'light');
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
if (!mounted) {
|
|
46
|
+
return (
|
|
47
|
+
<button
|
|
48
|
+
type="button"
|
|
49
|
+
aria-label="Toggle theme"
|
|
50
|
+
className={`w-9 h-9 rounded-lg border border-[var(--border-color,#e2e8f0)] bg-[var(--card-bg,#ffffff)] opacity-0 transition-opacity ${className}`}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<button
|
|
57
|
+
type="button"
|
|
58
|
+
onClick={toggleTheme}
|
|
59
|
+
aria-label={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
|
|
60
|
+
title={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
|
|
61
|
+
className={`inline-flex items-center justify-center gap-2 h-9 px-2.5 rounded-lg border border-[var(--border-color,rgba(0,0,0,0.1))] bg-[var(--card-bg,#ffffff)] text-[var(--text-color,#0f172a)] hover:border-[var(--color-primary,#016a7e)] hover:text-[var(--color-primary,#016a7e)] shadow-sm transition-all duration-200 cursor-pointer ${className}`}
|
|
62
|
+
>
|
|
63
|
+
{isDark ? (
|
|
64
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="w-4 h-4 text-amber-400">
|
|
65
|
+
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
|
|
66
|
+
</svg>
|
|
67
|
+
) : (
|
|
68
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="w-4 h-4 text-amber-500">
|
|
69
|
+
<circle cx="12" cy="12" r="4" />
|
|
70
|
+
<path d="M12 2v2" />
|
|
71
|
+
<path d="M12 20v2" />
|
|
72
|
+
<path d="m4.93 4.93 1.41 1.41" />
|
|
73
|
+
<path d="m17.66 17.66 1.41 1.41" />
|
|
74
|
+
<path d="M2 12h2" />
|
|
75
|
+
<path d="M20 12h2" />
|
|
76
|
+
<path d="m6.34 17.66-1.41 1.41" />
|
|
77
|
+
<path d="m19.07 4.93-1.41 1.41" />
|
|
78
|
+
</svg>
|
|
79
|
+
)}
|
|
80
|
+
{showLabel && (
|
|
81
|
+
<span className="text-xs font-medium">{isDark ? 'Dark' : 'Light'}</span>
|
|
82
|
+
)}
|
|
83
|
+
</button>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export default ThemeToggle;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"project": {
|
|
3
|
-
"id": "
|
|
4
|
-
"slug": "
|
|
5
|
-
"title": "
|
|
3
|
+
"id": "deneb-portfolio-showcase",
|
|
4
|
+
"slug": "deneb-portfolio-showcase",
|
|
5
|
+
"title": "DENEB UI — Showcase & Portfolio",
|
|
6
6
|
"status": "APPROVED"
|
|
7
7
|
},
|
|
8
8
|
"merchant": {
|
|
9
|
-
"businessName": "
|
|
10
|
-
"description": "
|
|
9
|
+
"businessName": "DENEB UI Showcase",
|
|
10
|
+
"description": "The visual-first React framework for high-converting storefronts and modern digital portfolios. Powered by DENEB-UI in collaboration with FIVORA."
|
|
11
11
|
},
|
|
12
12
|
"template": {
|
|
13
|
-
"id": "
|
|
14
|
-
"name": "
|
|
13
|
+
"id": "deneb-portfolio-template",
|
|
14
|
+
"name": "DENEB UI Portfolio Showcase",
|
|
15
15
|
"engine": "NEXT_STATIC_EXPORT",
|
|
16
16
|
"structure": {
|
|
17
17
|
"pages": [
|
|
@@ -30,7 +30,17 @@
|
|
|
30
30
|
"bodyFont": "Inter",
|
|
31
31
|
"baseSize": "16px",
|
|
32
32
|
"heroMinHeight": "72vh",
|
|
33
|
-
"sectionPadding": "5rem"
|
|
33
|
+
"sectionPadding": "5rem",
|
|
34
|
+
"borderRadius": "12px",
|
|
35
|
+
"dark": {
|
|
36
|
+
"backgroundColor": "#090d16",
|
|
37
|
+
"cardBackgroundColor": "#131b2e",
|
|
38
|
+
"textColor": "#f8fafc",
|
|
39
|
+
"borderColor": "rgba(255, 255, 255, 0.12)",
|
|
40
|
+
"primaryColor": "#00adb5",
|
|
41
|
+
"secondaryColor": "#1e293b",
|
|
42
|
+
"accentColor": "#38bdf8"
|
|
43
|
+
}
|
|
34
44
|
}
|
|
35
45
|
}
|
|
36
46
|
},
|
|
@@ -45,8 +55,8 @@
|
|
|
45
55
|
},
|
|
46
56
|
"content": {
|
|
47
57
|
"common": {
|
|
48
|
-
"websiteTitle": "
|
|
49
|
-
"shortDescription": "
|
|
58
|
+
"websiteTitle": "DENEB UI — Showcase & Portfolio",
|
|
59
|
+
"shortDescription": "The visual-first React framework for modern storefronts and digital portfolios. Powered by DENEB-UI in collaboration with FIVORA.",
|
|
50
60
|
"logoUrl": "/fivora-logo.png",
|
|
51
61
|
"headerCtaLabel": "Contact Us",
|
|
52
62
|
"navLabels": {
|
|
@@ -55,111 +65,126 @@
|
|
|
55
65
|
"services": "Services",
|
|
56
66
|
"contact": "Contact"
|
|
57
67
|
},
|
|
58
|
-
"footerHeading": "Build something extraordinary with
|
|
59
|
-
"copyright": "
|
|
68
|
+
"footerHeading": "Build something extraordinary with DENEB-UI & FIVORA.",
|
|
69
|
+
"copyright": "DENEB-UI. All rights reserved. Collaborate with FIVORA.",
|
|
60
70
|
"socialMedia": {
|
|
61
|
-
"twitter": "https://twitter.com",
|
|
62
|
-
"github": "https://github.com",
|
|
71
|
+
"twitter": "https://twitter.com/denebui",
|
|
72
|
+
"github": "https://github.com/deneb-ui",
|
|
63
73
|
"linkedin": "https://linkedin.com",
|
|
64
74
|
"instagram": "https://instagram.com"
|
|
65
75
|
}
|
|
66
76
|
},
|
|
67
77
|
"home": {
|
|
68
|
-
"heroEyebrow": "⚡
|
|
69
|
-
"heroTitle": "
|
|
70
|
-
"heroSummary": "
|
|
78
|
+
"heroEyebrow": "⚡ DENEB UI FRAMEWORK",
|
|
79
|
+
"heroTitle": "The Visual-First React Framework for High-Converting Experiences",
|
|
80
|
+
"heroSummary": "Design, build, and ship web storefronts and portfolios with 100% atomic editable components, auto-balancing layouts, and instant dual-mode aesthetics. Built in collaboration with FIVORA Cloud.",
|
|
71
81
|
"bannerImageUrl": "/fivora-icon.svg",
|
|
72
|
-
"primaryCtaLabel": "Explore
|
|
73
|
-
"secondaryCtaLabel": "About
|
|
74
|
-
"introTitle": "Engineered for
|
|
75
|
-
"introBody": "Every editable value comes directly from
|
|
76
|
-
"featuresHeading": "Why build with the
|
|
82
|
+
"primaryCtaLabel": "Explore Showcase",
|
|
83
|
+
"secondaryCtaLabel": "About DENEB-UI",
|
|
84
|
+
"introTitle": "Engineered for visual perfection and effortless editing",
|
|
85
|
+
"introBody": "Every editable value comes directly from structured site data with auto-balancing layouts, responsive typography, and strict contract validation out of the box.",
|
|
86
|
+
"featuresHeading": "Why build with the DENEB-UI Authoring Kit?",
|
|
77
87
|
"features": [
|
|
78
88
|
{
|
|
79
|
-
"title": "
|
|
80
|
-
"body": "
|
|
89
|
+
"title": "100% Atomic DENEB Components",
|
|
90
|
+
"body": "Pre-built, accessible, high-converting components with responsive design token integration and zero runtime overhead."
|
|
81
91
|
},
|
|
82
92
|
{
|
|
83
93
|
"title": "Strict Visual Editing",
|
|
84
|
-
"body": "Direct bindings enable
|
|
94
|
+
"body": "Direct bidirectional field bindings enable instant visual customization in the Lab and on the FIVORA platform without breaking styles."
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"title": "Instant Dual-Mode Aesthetics",
|
|
98
|
+
"body": "Seamless light and dark mode out-of-the-box with intelligent token contrast calculations for typography and surfaces."
|
|
85
99
|
},
|
|
86
100
|
{
|
|
87
|
-
"title": "
|
|
88
|
-
"body": "Built-in
|
|
101
|
+
"title": "FIVORA Cloud Collaboration",
|
|
102
|
+
"body": "Built-in integration for collaborative editing, marketplace publishing, and automated zero-dependency clean packaging."
|
|
89
103
|
}
|
|
90
104
|
],
|
|
91
105
|
"demoPreOrderCta": [
|
|
92
106
|
{
|
|
93
|
-
"buttonLabel": "Book a
|
|
107
|
+
"buttonLabel": "Book a Consultation",
|
|
94
108
|
"buttonUrl": "https://wa.me/94771234567"
|
|
95
109
|
}
|
|
96
110
|
],
|
|
97
|
-
"productsHeading": "Featured
|
|
98
|
-
"productsSummary": "
|
|
111
|
+
"productsHeading": "Featured Portfolio & Templates",
|
|
112
|
+
"productsSummary": "Explore high-converting storefronts, portals, and templates engineered with DENEB-UI and verified for production."
|
|
99
113
|
},
|
|
100
114
|
"about": {
|
|
101
|
-
"heading": "
|
|
102
|
-
"body": "
|
|
115
|
+
"heading": "Empowering Developers to Build Visually Editable Web Experiences",
|
|
116
|
+
"body": "DENEB UI was created by Chamika Gayashan & Induranga Kawishwara to bridge the gap between developer-grade React code and effortless visual editing. In collaboration with the FIVORA platform, we empower creators to ship ultra-fast static web applications while giving non-technical teams an intuitive live visual editor.",
|
|
103
117
|
"imageUrl": "/placeholder.svg",
|
|
104
|
-
"collageHeading": "
|
|
105
|
-
"collageDescription": "A
|
|
106
|
-
"historyHeading": "
|
|
107
|
-
"history": "We
|
|
118
|
+
"collageHeading": "The DENEB-UI Journey",
|
|
119
|
+
"collageDescription": "A visual tour of our architecture, design system engineering, and cloud deployment pipeline.",
|
|
120
|
+
"historyHeading": "Our Engineering Philosophy",
|
|
121
|
+
"history": "We believe modern web developers shouldn't have to choose between code elegance and visual customization. DENEB-UI provides atomic, contract-bound components that compile to lean Next.js static exports, backed by FIVORA Cloud for instant real-time publishing.",
|
|
108
122
|
"collageImages": [
|
|
109
123
|
{
|
|
110
|
-
"id": "
|
|
124
|
+
"id": "design-system",
|
|
111
125
|
"image": "/placeholder.svg",
|
|
112
|
-
"caption": "Design
|
|
126
|
+
"caption": "Atomic Design System"
|
|
113
127
|
},
|
|
114
128
|
{
|
|
115
|
-
"id": "
|
|
129
|
+
"id": "visual-engine",
|
|
116
130
|
"image": "/placeholder.svg",
|
|
117
|
-
"caption": "
|
|
131
|
+
"caption": "Live Visual Engine"
|
|
118
132
|
},
|
|
119
133
|
{
|
|
120
|
-
"id": "
|
|
134
|
+
"id": "cloud-publish",
|
|
121
135
|
"image": "/placeholder.svg",
|
|
122
|
-
"caption": "
|
|
136
|
+
"caption": "FIVORA Cloud Publishing"
|
|
123
137
|
}
|
|
124
138
|
]
|
|
125
139
|
},
|
|
126
140
|
"servicesPage": {
|
|
127
|
-
"heading": "
|
|
128
|
-
"intro": "
|
|
141
|
+
"heading": "Framework Solutions & Capabilities",
|
|
142
|
+
"intro": "Every capability is backed by atomic DENEB components, automated packaging, and preflight verification."
|
|
129
143
|
},
|
|
130
144
|
"services": [
|
|
131
145
|
{
|
|
132
146
|
"id": "visual-editing",
|
|
133
147
|
"name": "Visual Editing Lab",
|
|
134
|
-
"description": "Simulate how merchants customize your template in real time with the built-in local development lab.",
|
|
148
|
+
"description": "Simulate how merchants customize your template in real time with the built-in local development lab and field focus bridge.",
|
|
135
149
|
"imageUrl": "/placeholder.svg",
|
|
136
150
|
"features": [
|
|
137
151
|
"Zero-server static preview",
|
|
138
152
|
"Field focus bridge",
|
|
139
|
-
"Instant feedback"
|
|
153
|
+
"Instant visual feedback"
|
|
140
154
|
]
|
|
141
155
|
},
|
|
142
156
|
{
|
|
143
157
|
"id": "clean-packaging",
|
|
144
158
|
"name": "Automated Packager",
|
|
145
|
-
"description": "Automatically produce clean, upload-ready ZIP archives excluding junk and
|
|
159
|
+
"description": "Automatically produce clean, upload-ready ZIP archives excluding junk, build caches, and sensitive files.",
|
|
146
160
|
"imageUrl": "/placeholder.svg",
|
|
147
161
|
"features": [
|
|
148
162
|
"Excludes node_modules",
|
|
149
163
|
"Excludes .next and .git",
|
|
150
164
|
"100% preflight compliant"
|
|
151
165
|
]
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"id": "dual-mode-system",
|
|
169
|
+
"name": "Dual-Mode Theme Engine",
|
|
170
|
+
"description": "Harmonic light and dark themes generated automatically with smart contrast adjustments for high visual appeal.",
|
|
171
|
+
"imageUrl": "/placeholder.svg",
|
|
172
|
+
"features": [
|
|
173
|
+
"Auto contrast calculations",
|
|
174
|
+
"ThemeToggle component",
|
|
175
|
+
"Persistent theme storage"
|
|
176
|
+
]
|
|
152
177
|
}
|
|
153
178
|
],
|
|
154
179
|
"contact": {
|
|
155
|
-
"heading": "
|
|
156
|
-
"intro": "Have questions about
|
|
180
|
+
"heading": "Connect with the DENEB-UI Team",
|
|
181
|
+
"intro": "Have questions about DENEB-UI components or building custom storefronts with the FIVORA platform? Contact us today.",
|
|
157
182
|
"phone": "+94 11 234 5678",
|
|
158
|
-
"email": "
|
|
183
|
+
"email": "hello@deneb-ui.dev",
|
|
159
184
|
"address": "Colombo, Sri Lanka",
|
|
160
185
|
"directionsLabel": "Get Directions",
|
|
161
186
|
"directionsUrl": "https://maps.app.goo.gl/example",
|
|
162
|
-
"formTitle": "Send an
|
|
187
|
+
"formTitle": "Send an Inquiry",
|
|
163
188
|
"submitLabel": "Send Message",
|
|
164
189
|
"directMessageText": "Send us a direct message",
|
|
165
190
|
"whatsapp": "+94 77 123 4567"
|
|
@@ -167,38 +192,38 @@
|
|
|
167
192
|
"products": [
|
|
168
193
|
{
|
|
169
194
|
"id": "prod-1",
|
|
170
|
-
"name": "
|
|
171
|
-
"description": "
|
|
172
|
-
"price":
|
|
173
|
-
"compareAtPrice":
|
|
195
|
+
"name": "Aura Luxury Storefront",
|
|
196
|
+
"description": "High-converting boutique and jewelry storefront template with dark aesthetics, before/after sliders, and quick checkout.",
|
|
197
|
+
"price": 4900,
|
|
198
|
+
"compareAtPrice": 6500,
|
|
174
199
|
"currency": "LKR",
|
|
175
200
|
"imageUrl": "/placeholder.svg",
|
|
176
|
-
"category": "
|
|
177
|
-
"badge": "
|
|
201
|
+
"category": "E-Commerce",
|
|
202
|
+
"badge": "Popular",
|
|
178
203
|
"isAvailable": true
|
|
179
204
|
},
|
|
180
205
|
{
|
|
181
206
|
"id": "prod-2",
|
|
182
|
-
"name": "
|
|
183
|
-
"description": "
|
|
184
|
-
"price":
|
|
185
|
-
"compareAtPrice":
|
|
207
|
+
"name": "Apex SaaS & Analytics",
|
|
208
|
+
"description": "Clean, high-performance web template tailored for developer tools, SaaS metrics, and responsive pricing grids.",
|
|
209
|
+
"price": 6200,
|
|
210
|
+
"compareAtPrice": 7500,
|
|
186
211
|
"currency": "LKR",
|
|
187
212
|
"imageUrl": "/placeholder.svg",
|
|
188
|
-
"category": "
|
|
189
|
-
"badge": "
|
|
213
|
+
"category": "Technology",
|
|
214
|
+
"badge": "Featured",
|
|
190
215
|
"isAvailable": true
|
|
191
216
|
},
|
|
192
217
|
{
|
|
193
218
|
"id": "prod-3",
|
|
194
|
-
"name": "
|
|
195
|
-
"description": "
|
|
196
|
-
"price":
|
|
219
|
+
"name": "Zenith Artisan Portfolio",
|
|
220
|
+
"description": "Minimalist digital portfolio template featuring auto-balancing photo galleries, quote cards, and WhatsApp contact integration.",
|
|
221
|
+
"price": 3800,
|
|
197
222
|
"compareAtPrice": null,
|
|
198
223
|
"currency": "LKR",
|
|
199
224
|
"imageUrl": "/placeholder.svg",
|
|
200
|
-
"category": "
|
|
201
|
-
"badge":
|
|
225
|
+
"category": "Portfolio",
|
|
226
|
+
"badge": "New",
|
|
202
227
|
"isAvailable": true
|
|
203
228
|
}
|
|
204
229
|
]
|
|
@@ -206,16 +231,16 @@
|
|
|
206
231
|
"media": {},
|
|
207
232
|
"seo": null,
|
|
208
233
|
"siteInstance": {
|
|
209
|
-
"id": "
|
|
210
|
-
"slug": "
|
|
211
|
-
"domain": "
|
|
212
|
-
"subdomain": "
|
|
234
|
+
"id": "deneb-portfolio-showcase-instance",
|
|
235
|
+
"slug": "deneb-portfolio-showcase",
|
|
236
|
+
"domain": "deneb-showcase.fivora.site",
|
|
237
|
+
"subdomain": "deneb-showcase",
|
|
213
238
|
"customDomain": null,
|
|
214
|
-
"liveUrl": "https://
|
|
239
|
+
"liveUrl": "https://deneb-showcase.fivora.site"
|
|
215
240
|
},
|
|
216
241
|
"api": {
|
|
217
242
|
"baseUrl": "https://api.fivora.site",
|
|
218
|
-
"catalogUrl": "https://api.fivora.site/site-catalog/
|
|
243
|
+
"catalogUrl": "https://api.fivora.site/site-catalog/deneb-portfolio-showcase/live-data",
|
|
219
244
|
"contactUrl": "https://api.fivora.site/site-contact",
|
|
220
245
|
"analyticsUrl": "https://api.fivora.site/site-analytics/page-view"
|
|
221
246
|
}
|