@deneb-ui/create-template 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,244 @@
1
+ 'use client';
2
+
3
+ import {
4
+ contentList,
5
+ contentObject,
6
+ contentText,
7
+ useSiteData,
8
+ } from '@/lib/siteDataContext';
9
+ import { pageRoute, withBasePath } from '@/lib/utils';
10
+ import {
11
+ EditableText,
12
+ EditableImage,
13
+ EditableList,
14
+ EditableCard,
15
+ EditableBox,
16
+ EditableGrid,
17
+ } from '@deneb-ui/ui';
18
+
19
+
20
+ function navigate(pageKey: string) {
21
+ window.location.href = withBasePath(pageRoute(pageKey));
22
+ }
23
+
24
+ export default function HomePage() {
25
+ const siteData = useSiteData();
26
+ const content = contentObject(siteData.content);
27
+ const home = contentObject(content.home);
28
+ const features = contentList(home.features);
29
+ const selectedPages =
30
+ siteData.requirements?.requiredPages ??
31
+ siteData.template?.structure?.pages ??
32
+ [];
33
+
34
+ return (
35
+ <div data-preview-page-key="home">
36
+ <section className="hero" data-design-section="home-hero">
37
+ <div className="hero-copy">
38
+ <EditableText
39
+ variant="eyebrow"
40
+ color="primary"
41
+ className="eyebrow"
42
+ data-preview-field-path="home.heroEyebrow"
43
+ defaultValue={contentText(home.heroEyebrow)}
44
+ />
45
+ <EditableText
46
+ variant="h1"
47
+ size="5xl"
48
+ weight="bold"
49
+ align="left"
50
+ color="heading"
51
+ data-preview-field-path="home.heroTitle"
52
+ defaultValue={contentText(home.heroTitle)}
53
+ />
54
+ <EditableText
55
+ variant="lead"
56
+ color="muted"
57
+ data-preview-field-path="home.heroSummary"
58
+ defaultValue={contentText(home.heroSummary)}
59
+ />
60
+ <div className="cta-row">
61
+ {selectedPages.includes('contact') ? (
62
+ <button
63
+ type="button"
64
+ data-target-page="contact"
65
+ className="button-primary"
66
+ onClick={() => navigate('contact')}
67
+ >
68
+ <span data-preview-field-path="home.primaryCtaLabel">
69
+ {contentText(home.primaryCtaLabel)}
70
+ </span>
71
+ </button>
72
+ ) : (
73
+ <span
74
+ data-target-page="contact"
75
+ className="button-primary unavailable"
76
+ data-preview-field-path="home.primaryCtaLabel"
77
+ >
78
+ {contentText(home.primaryCtaLabel)}
79
+ </span>
80
+ )}
81
+ {selectedPages.includes('about_us') ? (
82
+ <button
83
+ type="button"
84
+ data-target-page="about_us"
85
+ className="button-secondary"
86
+ onClick={() => navigate('about_us')}
87
+ >
88
+ <span data-preview-field-path="home.secondaryCtaLabel">
89
+ {contentText(home.secondaryCtaLabel)}
90
+ </span>
91
+ </button>
92
+ ) : (
93
+ <span
94
+ data-target-page="about_us"
95
+ className="button-secondary unavailable"
96
+ data-preview-field-path="home.secondaryCtaLabel"
97
+ >
98
+ {contentText(home.secondaryCtaLabel)}
99
+ </span>
100
+ )}
101
+ </div>
102
+ </div>
103
+ <div className="hero-fivora-wrap">
104
+ <img
105
+ className="hero-image"
106
+ src={withBasePath(
107
+ contentText(home.bannerImageUrl) || '/fivora-icon.svg',
108
+ )}
109
+ alt="Fivora"
110
+ data-preview-field-path="home.bannerImageUrl"
111
+ />
112
+ </div>
113
+ </section>
114
+
115
+ <section
116
+ className="page-section dev-guide-section"
117
+ data-design-section="home-developer-guide"
118
+ >
119
+ <div className="dev-guide-header">
120
+ <span className="dev-badge" data-preview-static="dev-guidance">
121
+ ⚡ Template Developer Quickstart
122
+ </span>
123
+ <h2 data-preview-static="dev-guidance">
124
+ Build, Test, and Package with Fivora
125
+ </h2>
126
+ <p data-preview-static="dev-guidance">
127
+ Run these commands directly in your template terminal:
128
+ </p>
129
+ </div>
130
+
131
+ <div className="dev-command-grid">
132
+ <div className="dev-cmd-card">
133
+ <div className="cmd-header">
134
+ <span className="cmd-tag" data-preview-static="dev-tag">Development</span>
135
+ <code data-preview-static="dev-command">npm run dev</code>
136
+ </div>
137
+ <p data-preview-static="dev-description">Hot-reloading local development with Next.js &amp; React 19.</p>
138
+ </div>
139
+
140
+ <div className="dev-cmd-card">
141
+ <div className="cmd-header">
142
+ <span className="cmd-tag" data-preview-static="dev-tag">Simulate</span>
143
+ <code data-preview-static="dev-command">npm run lab</code>
144
+ </div>
145
+ <p data-preview-static="dev-description">Visual Editing Lab simulating merchant field clicks &amp; edits.</p>
146
+ </div>
147
+
148
+ <div className="dev-cmd-card">
149
+ <div className="cmd-header">
150
+ <span className="cmd-tag" data-preview-static="dev-tag">Compliance</span>
151
+ <code data-preview-static="dev-command">npm run validate</code>
152
+ </div>
153
+ <p data-preview-static="dev-description">Runs fivora preflight contract tests &amp; empty states.</p>
154
+ </div>
155
+
156
+ <div className="dev-cmd-card">
157
+ <div className="cmd-header">
158
+ <span className="cmd-tag" data-preview-static="dev-tag">1-Click Upload</span>
159
+ <code data-preview-static="dev-command">npm run zip</code>
160
+ </div>
161
+ <p data-preview-static="dev-description">Automatically packages clean ZIP excluding caches &amp; junk files.</p>
162
+ </div>
163
+ </div>
164
+ </section>
165
+
166
+ <section
167
+ className="page-section"
168
+ data-design-section="home-introduction"
169
+ >
170
+ <div className="home-intro-copy">
171
+ <EditableText
172
+ variant="h2"
173
+ size="3xl"
174
+ weight="bold"
175
+ align="center"
176
+ color="heading"
177
+ data-preview-field-path="home.introTitle"
178
+ defaultValue={contentText(home.introTitle)}
179
+ />
180
+ <EditableText
181
+ variant="lead"
182
+ align="center"
183
+ color="muted"
184
+ data-preview-field-path="home.introBody"
185
+ defaultValue={contentText(home.introBody)}
186
+ />
187
+ </div>
188
+ </section>
189
+
190
+ <section
191
+ className="page-section alt"
192
+ data-design-section="home-features"
193
+ >
194
+ <div className="section-header">
195
+ <EditableText
196
+ variant="h2"
197
+ size="3xl"
198
+ weight="bold"
199
+ align="center"
200
+ color="heading"
201
+ className="section-title"
202
+ data-preview-field-path="home.featuresHeading"
203
+ defaultValue={contentText(home.featuresHeading)}
204
+ />
205
+ </div>
206
+ <EditableList
207
+ data-preview-list-path="home.features"
208
+ items={features}
209
+ className="card-grid"
210
+ itemAs={false}
211
+ >
212
+ {(rawFeature, index) => {
213
+ const feature = contentObject(rawFeature);
214
+ return (
215
+ <EditableCard
216
+ className="card"
217
+ key={index}
218
+ itemPath={`home.features[${index}]`}
219
+ data-preview-item-path={`home.features[${index}]`}
220
+ item={feature as any}
221
+ balance
222
+ minHeight="220px"
223
+ radius="16px"
224
+ >
225
+ <EditableText
226
+ variant="h3"
227
+ color="heading"
228
+ data-preview-field-path={`home.features[${index}].title`}
229
+ defaultValue={contentText(feature.title)}
230
+ />
231
+ <EditableText
232
+ variant="p"
233
+ color="muted"
234
+ data-preview-field-path={`home.features[${index}].body`}
235
+ defaultValue={contentText(feature.body)}
236
+ />
237
+ </EditableCard>
238
+ );
239
+ }}
240
+ </EditableList>
241
+ </section>
242
+ </div>
243
+ );
244
+ }
@@ -0,0 +1,51 @@
1
+ 'use client';
2
+
3
+ import { contentList, contentObject, contentText, useSiteData } from '@/lib/siteDataContext';
4
+ import { withBasePath } from '@/lib/utils';
5
+
6
+ export default function ServicesPage() {
7
+ const siteData = useSiteData();
8
+ const content = contentObject(siteData.content);
9
+ const page = contentObject(content.servicesPage);
10
+ const services = contentList(content.services);
11
+
12
+ return (
13
+ <div data-preview-page-key="services">
14
+ <section className="page-section page-heading" data-design-section="services-heading">
15
+ <h1 data-preview-field-path="servicesPage.heading">{contentText(page.heading)}</h1>
16
+ <p data-preview-field-path="servicesPage.intro">{contentText(page.intro)}</p>
17
+ </section>
18
+ <section className="page-section alt" data-design-section="services-list">
19
+ <div className="card-grid" data-preview-list-path="services">
20
+ {services.map((rawService, index) => {
21
+ const service = contentObject(rawService);
22
+ const features = contentList(service.features);
23
+ return (
24
+ <article className="card" key={contentText(service.id) || index} data-preview-item-path={`services[${index}]`}>
25
+ <img
26
+ className="card-image"
27
+ src={withBasePath(contentText(service.imageUrl) || '/placeholder.svg')}
28
+ alt=""
29
+ data-preview-field-path={`services[${index}].imageUrl`}
30
+ />
31
+ <h2 data-preview-field-path={`services[${index}].name`}>{contentText(service.name)}</h2>
32
+ <p data-preview-field-path={`services[${index}].description`}>{contentText(service.description)}</p>
33
+ <ul data-preview-list-path={`services[${index}].features`}>
34
+ {features.map((feature, featureIndex) => (
35
+ <li
36
+ key={featureIndex}
37
+ data-preview-item-path={`services[${index}].features[${featureIndex}]`}
38
+ data-preview-field-path={`services[${index}].features[${featureIndex}]`}
39
+ >
40
+ {contentText(feature)}
41
+ </li>
42
+ ))}
43
+ </ul>
44
+ </article>
45
+ );
46
+ })}
47
+ </div>
48
+ </section>
49
+ </div>
50
+ );
51
+ }
@@ -0,0 +1,22 @@
1
+ 'use client';
2
+
3
+ import type { ReactNode } from 'react';
4
+ import { usePathname } from 'next/navigation';
5
+ import { useSiteData } from '@/lib/siteDataContext';
6
+ import { Navbar, Footer, getThemeCssProperties } from '@deneb-ui/ui';
7
+
8
+ export default function SiteChrome({ children }: { children: ReactNode }) {
9
+ const siteData = useSiteData();
10
+ const pathname = usePathname();
11
+ const themeStyle = getThemeCssProperties(
12
+ siteData?.template?.structure?.theme as any,
13
+ );
14
+
15
+ return (
16
+ <div className="site-shell" style={themeStyle}>
17
+ <Navbar activeRoute={pathname} />
18
+ <main>{children}</main>
19
+ <Footer />
20
+ </div>
21
+ );
22
+ }
@@ -0,0 +1,99 @@
1
+ {
2
+ "project": { "id": "starter-demo", "title": "Fivora Starter Demo", "status": "APPROVED" },
3
+ "merchant": {
4
+ "businessName": "Fivora Store",
5
+ "description": "A modern high-converting digital storefront built on the Fivora platform."
6
+ },
7
+ "template": {
8
+ "id": "starter-template",
9
+ "name": "Fivora Starter",
10
+ "engine": "NEXT_STATIC_EXPORT",
11
+ "structure": {
12
+ "pages": ["home", "about_us", "services", "contact"],
13
+ "theme": {
14
+ "primaryColor": "#016a7e",
15
+ "secondaryColor": "#0a1931",
16
+ "accentColor": "#00adb5",
17
+ "backgroundColor": "#ffffff",
18
+ "textColor": "#0f172a",
19
+ "headingFont": "Inter",
20
+ "bodyFont": "Inter",
21
+ "baseSize": "16px",
22
+ "heroMinHeight": "72vh",
23
+ "sectionPadding": "5rem"
24
+ }
25
+ }
26
+ },
27
+ "requirements": {
28
+ "requiredPages": ["home", "about_us", "services", "contact"],
29
+ "requiredFeatures": []
30
+ },
31
+ "content": {
32
+ "common": {
33
+ "websiteTitle": "Fivora Store",
34
+ "shortDescription": "Next-generation commerce templates built for the Fivora with reusable components and strict visual editing.",
35
+ "logoUrl": "/fivora-logo.png",
36
+ "headerCtaLabel": "Contact Us",
37
+ "navLabels": {
38
+ "home": "Home",
39
+ "about_us": "About",
40
+ "services": "Services",
41
+ "contact": "Contact"
42
+ },
43
+ "footerHeading": "Build something extraordinary with Fivora.",
44
+ "copyright": "Fivora. All rights reserved."
45
+ },
46
+ "home": {
47
+ "heroEyebrow": "⚡ Fivora Template Starter",
48
+ "heroTitle": "Design Stores That Captivate",
49
+ "heroSummary": "Built with @fivora/editable-components. Hot-reload locally, simulate merchant visual editing in the Lab, validate preflight contracts, and package with 1-click.",
50
+ "bannerImageUrl": "/fivora-icon.svg",
51
+ "primaryCtaLabel": "Explore Services",
52
+ "secondaryCtaLabel": "About This Starter",
53
+ "introTitle": "Engineered for high conversion and effortless editing",
54
+ "introBody": "Every editable value comes directly from Fivora site data with auto-balancing layouts, responsive typography, and strict contract validation out of the box.",
55
+ "featuresHeading": "Why build with the Fivora Authoring Kit?",
56
+ "features": [
57
+ { "title": "Auto-Balancing Layouts", "body": "Cards, grids, and containers automatically balance and fill space seamlessly across all screen sizes." },
58
+ { "title": "Strict Visual Editing", "body": "Direct bindings enable merchants to click, edit, and preview changes without breaking template styles." },
59
+ { "title": "1-Click Clean Packaging", "body": "Built-in zip command strips heavy caches, node_modules, and git files so uploads pass instantly." }
60
+ ]
61
+ },
62
+ "about": {
63
+ "heading": "Built for the next generation of online storefronts",
64
+ "body": "The Fivora connects businesses with high-converting, beautifully crafted templates. This starter template demonstrates clean monorepo architecture, responsive typography, and auto-balancing components.",
65
+ "imageUrl": "/placeholder.svg"
66
+ },
67
+ "servicesPage": {
68
+ "heading": "Template Services & Capabilities",
69
+ "intro": "Each service card is an atomic component featuring an image, heading, description, and repeatable checklist."
70
+ },
71
+ "services": [
72
+ {
73
+ "id": "visual-editing",
74
+ "name": "Visual Editing Lab",
75
+ "description": "Simulate how merchants customize your template in real time with the built-in local development lab.",
76
+ "imageUrl": "/placeholder.svg",
77
+ "features": ["Zero-server static preview", "Field focus bridge", "Instant feedback"]
78
+ },
79
+ {
80
+ "id": "clean-packaging",
81
+ "name": "Automated Packager",
82
+ "description": "Automatically produce clean, upload-ready ZIP archives excluding junk and cache files.",
83
+ "imageUrl": "/placeholder.svg",
84
+ "features": ["Excludes node_modules", "Excludes .next and .git", "100% preflight compliant"]
85
+ }
86
+ ],
87
+ "contact": {
88
+ "heading": "Get in touch with our team",
89
+ "intro": "Have questions about building or customizing Fivora templates? Contact us today.",
90
+ "phone": "+94 11 234 5678",
91
+ "email": "developer@fivora.lk",
92
+ "address": "Colombo, Sri Lanka",
93
+ "formTitle": "Send an enquiry",
94
+ "submitLabel": "Send Message"
95
+ }
96
+ },
97
+ "media": {},
98
+ "seo": null
99
+ }
@@ -0,0 +1,55 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import {
5
+ SiteDataProvider as BaseSiteDataProvider,
6
+ useSiteData,
7
+ contentText,
8
+ contentObject,
9
+ contentList,
10
+ type SiteData,
11
+ type SiteDataProviderProps,
12
+ PREVIEW_DATA_MESSAGE,
13
+ LEGACY_PREVIEW_DATA_MESSAGE,
14
+ PREVIEW_READY_MESSAGE,
15
+ LEGACY_PREVIEW_READY_MESSAGE,
16
+ PREVIEW_FOCUS_MESSAGE,
17
+ LEGACY_PREVIEW_FOCUS_MESSAGE,
18
+ PREVIEW_FIELD_ATTRIBUTE,
19
+ } from '@deneb-ui/ui';
20
+
21
+ import initialSiteData from '@/data/site-data.json';
22
+
23
+ export function SiteDataProvider({
24
+ children,
25
+ initialSiteData: providedInitialData,
26
+ ...props
27
+ }: {
28
+ children: React.ReactNode;
29
+ initialSiteData?: SiteData;
30
+ }) {
31
+ return (
32
+ <BaseSiteDataProvider
33
+ initialSiteData={providedInitialData ?? (initialSiteData as SiteData)}
34
+ {...props}
35
+ >
36
+ {children}
37
+ </BaseSiteDataProvider>
38
+ );
39
+ }
40
+
41
+ export {
42
+ useSiteData,
43
+ contentText,
44
+ contentObject,
45
+ contentList,
46
+ PREVIEW_DATA_MESSAGE,
47
+ LEGACY_PREVIEW_DATA_MESSAGE,
48
+ PREVIEW_READY_MESSAGE,
49
+ LEGACY_PREVIEW_READY_MESSAGE,
50
+ PREVIEW_FOCUS_MESSAGE,
51
+ LEGACY_PREVIEW_FOCUS_MESSAGE,
52
+ PREVIEW_FIELD_ATTRIBUTE,
53
+ };
54
+
55
+ export type { SiteData, SiteDataProviderProps };
@@ -0,0 +1,14 @@
1
+ export function withBasePath(value?: string | null) {
2
+ const url = value?.trim() ?? '';
3
+ if (!url || /^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(url)) return url;
4
+ const basePath = (process.env.NEXT_PUBLIC_SITE_BASE_PATH ?? '').replace(
5
+ /\/$/,
6
+ '',
7
+ );
8
+ const path = url.startsWith('/') ? url : `/${url}`;
9
+ return `${basePath}${path}`;
10
+ }
11
+
12
+ export function pageRoute(pageKey: string) {
13
+ return pageKey === 'home' ? '/' : `/${pageKey}`;
14
+ }
@@ -0,0 +1,41 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": [
5
+ "dom",
6
+ "dom.iterable",
7
+ "esnext"
8
+ ],
9
+ "allowJs": true,
10
+ "skipLibCheck": true,
11
+ "strict": true,
12
+ "noEmit": true,
13
+ "esModuleInterop": true,
14
+ "module": "esnext",
15
+ "moduleResolution": "bundler",
16
+ "resolveJsonModule": true,
17
+ "isolatedModules": true,
18
+ "jsx": "preserve",
19
+ "incremental": true,
20
+ "plugins": [
21
+ {
22
+ "name": "next"
23
+ }
24
+ ],
25
+ "paths": {
26
+ "@/*": [
27
+ "./src/*"
28
+ ]
29
+ }
30
+ },
31
+ "include": [
32
+ "next-env.d.ts",
33
+ "**/*.ts",
34
+ "**/*.tsx",
35
+ ".next/types/**/*.ts",
36
+ ".next/dev/types/**/*.ts"
37
+ ],
38
+ "exclude": [
39
+ "node_modules"
40
+ ]
41
+ }