@cimplify/sdk 0.41.0 → 0.42.1
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/dist/cli/commands/deploy.mjs +561 -0
- package/dist/cli/commands/dev.mjs +434 -0
- package/dist/cli/commands/domains.mjs +479 -0
- package/dist/cli/commands/env.mjs +610 -0
- package/dist/cli/commands/link.mjs +325 -0
- package/dist/cli/commands/login.mjs +515 -0
- package/dist/cli/commands/logout.mjs +54 -0
- package/dist/cli/commands/logs.mjs +358 -0
- package/dist/cli/commands/projects.mjs +327 -0
- package/dist/cli/commands/rollback.mjs +477 -0
- package/dist/cli/commands/status.mjs +380 -0
- package/dist/cli/commands/unlink.mjs +58 -0
- package/dist/cli/commands/whoami.mjs +234 -0
- package/dist/dispatcher.mjs +91 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/templates/storefront-bakery/AGENTS.md +61 -10
- package/templates/storefront-bakery/app/accessibility/page.tsx +11 -0
- package/templates/storefront-bakery/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-bakery/app/account/orders/page.tsx +21 -0
- package/templates/storefront-bakery/app/account/page.tsx +22 -0
- package/templates/storefront-bakery/app/account/settings/page.tsx +21 -0
- package/templates/storefront-bakery/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-bakery/app/contact/page.tsx +54 -0
- package/templates/storefront-bakery/app/login/page.tsx +17 -0
- package/templates/storefront-bakery/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-bakery/app/returns/page.tsx +11 -0
- package/templates/storefront-bakery/app/search/page.tsx +38 -0
- package/templates/storefront-bakery/app/search/search-client.tsx +7 -0
- package/templates/storefront-bakery/app/shipping/page.tsx +16 -0
- package/templates/storefront-bakery/app/signup/page.tsx +17 -0
- package/templates/storefront-bakery/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-bakery/app/track-order/page.tsx +24 -0
- package/templates/storefront-bakery/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-bakery/components/account-iframe.tsx +13 -0
- package/templates/storefront-bakery/components/policy-page.tsx +49 -0
- package/templates/storefront-bakery/lib/brand.ts +119 -4
- package/templates/storefront-fashion/AGENTS.md +80 -26
- package/templates/storefront-fashion/app/accessibility/page.tsx +11 -0
- package/templates/storefront-fashion/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-fashion/app/account/orders/page.tsx +21 -0
- package/templates/storefront-fashion/app/account/page.tsx +22 -0
- package/templates/storefront-fashion/app/account/settings/page.tsx +21 -0
- package/templates/storefront-fashion/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-fashion/app/contact/page.tsx +54 -0
- package/templates/storefront-fashion/app/login/page.tsx +17 -0
- package/templates/storefront-fashion/app/lookbook/page.tsx +132 -0
- package/templates/storefront-fashion/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-fashion/app/returns/page.tsx +11 -0
- package/templates/storefront-fashion/app/search/page.tsx +38 -0
- package/templates/storefront-fashion/app/search/search-client.tsx +7 -0
- package/templates/storefront-fashion/app/shipping/page.tsx +16 -0
- package/templates/storefront-fashion/app/signup/page.tsx +17 -0
- package/templates/storefront-fashion/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-fashion/app/size-guide/page.tsx +155 -0
- package/templates/storefront-fashion/app/track-order/page.tsx +24 -0
- package/templates/storefront-fashion/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-fashion/components/account-iframe.tsx +13 -0
- package/templates/storefront-fashion/components/policy-page.tsx +49 -0
- package/templates/storefront-fashion/lib/brand.ts +99 -4
- package/templates/storefront-grocery/AGENTS.md +56 -11
- package/templates/storefront-grocery/app/accessibility/page.tsx +11 -0
- package/templates/storefront-grocery/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-grocery/app/account/orders/page.tsx +21 -0
- package/templates/storefront-grocery/app/account/page.tsx +22 -0
- package/templates/storefront-grocery/app/account/settings/page.tsx +21 -0
- package/templates/storefront-grocery/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-grocery/app/contact/page.tsx +54 -0
- package/templates/storefront-grocery/app/login/page.tsx +17 -0
- package/templates/storefront-grocery/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-grocery/app/returns/page.tsx +11 -0
- package/templates/storefront-grocery/app/search/page.tsx +38 -0
- package/templates/storefront-grocery/app/search/search-client.tsx +7 -0
- package/templates/storefront-grocery/app/shipping/page.tsx +16 -0
- package/templates/storefront-grocery/app/signup/page.tsx +17 -0
- package/templates/storefront-grocery/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-grocery/app/track-order/page.tsx +24 -0
- package/templates/storefront-grocery/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-grocery/components/account-iframe.tsx +13 -0
- package/templates/storefront-grocery/components/policy-page.tsx +49 -0
- package/templates/storefront-grocery/lib/brand.ts +92 -3
- package/templates/storefront-restaurant/AGENTS.md +64 -13
- package/templates/storefront-restaurant/app/accessibility/page.tsx +11 -0
- package/templates/storefront-restaurant/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-restaurant/app/account/orders/page.tsx +21 -0
- package/templates/storefront-restaurant/app/account/page.tsx +22 -0
- package/templates/storefront-restaurant/app/account/settings/page.tsx +21 -0
- package/templates/storefront-restaurant/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-restaurant/app/contact/page.tsx +54 -0
- package/templates/storefront-restaurant/app/login/page.tsx +17 -0
- package/templates/storefront-restaurant/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-restaurant/app/reservations/page.tsx +66 -0
- package/templates/storefront-restaurant/app/reservations/reservations-client.tsx +234 -0
- package/templates/storefront-restaurant/app/returns/page.tsx +11 -0
- package/templates/storefront-restaurant/app/search/page.tsx +38 -0
- package/templates/storefront-restaurant/app/search/search-client.tsx +7 -0
- package/templates/storefront-restaurant/app/shipping/page.tsx +16 -0
- package/templates/storefront-restaurant/app/signup/page.tsx +17 -0
- package/templates/storefront-restaurant/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-restaurant/app/track-order/page.tsx +24 -0
- package/templates/storefront-restaurant/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-restaurant/components/account-iframe.tsx +13 -0
- package/templates/storefront-restaurant/components/policy-page.tsx +49 -0
- package/templates/storefront-restaurant/lib/brand.ts +91 -3
- package/templates/storefront-retail/AGENTS.md +65 -24
- package/templates/storefront-retail/app/accessibility/page.tsx +11 -0
- package/templates/storefront-retail/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-retail/app/account/orders/page.tsx +21 -0
- package/templates/storefront-retail/app/account/page.tsx +22 -0
- package/templates/storefront-retail/app/account/settings/page.tsx +21 -0
- package/templates/storefront-retail/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-retail/app/contact/page.tsx +54 -0
- package/templates/storefront-retail/app/login/page.tsx +17 -0
- package/templates/storefront-retail/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-retail/app/returns/page.tsx +11 -0
- package/templates/storefront-retail/app/search/page.tsx +38 -0
- package/templates/storefront-retail/app/search/search-client.tsx +7 -0
- package/templates/storefront-retail/app/shipping/page.tsx +16 -0
- package/templates/storefront-retail/app/signup/page.tsx +17 -0
- package/templates/storefront-retail/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-retail/app/track-order/page.tsx +24 -0
- package/templates/storefront-retail/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-retail/components/account-iframe.tsx +13 -0
- package/templates/storefront-retail/components/policy-page.tsx +49 -0
- package/templates/storefront-retail/lib/brand.ts +105 -9
- package/templates/storefront-services/AGENTS.md +64 -16
- package/templates/storefront-services/app/accessibility/page.tsx +11 -0
- package/templates/storefront-services/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-services/app/account/orders/page.tsx +21 -0
- package/templates/storefront-services/app/account/page.tsx +22 -0
- package/templates/storefront-services/app/account/settings/page.tsx +21 -0
- package/templates/storefront-services/app/book/book-client.tsx +195 -0
- package/templates/storefront-services/app/book/page.tsx +65 -0
- package/templates/storefront-services/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-services/app/contact/page.tsx +54 -0
- package/templates/storefront-services/app/login/page.tsx +17 -0
- package/templates/storefront-services/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-services/app/returns/page.tsx +11 -0
- package/templates/storefront-services/app/search/page.tsx +38 -0
- package/templates/storefront-services/app/search/search-client.tsx +7 -0
- package/templates/storefront-services/app/shipping/page.tsx +16 -0
- package/templates/storefront-services/app/signup/page.tsx +17 -0
- package/templates/storefront-services/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-services/app/track-order/page.tsx +24 -0
- package/templates/storefront-services/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-services/components/account-iframe.tsx +13 -0
- package/templates/storefront-services/components/policy-page.tsx +49 -0
- package/templates/storefront-services/lib/brand.ts +93 -2
|
@@ -138,6 +138,41 @@ export interface Brand {
|
|
|
138
138
|
sections: BrandPolicySection[];
|
|
139
139
|
};
|
|
140
140
|
|
|
141
|
+
// ─── Standalone policy pages ──────────────────────────────────
|
|
142
|
+
shipping: { eyebrow: string; title: string; lastUpdated: string; sections: BrandPolicySection[] };
|
|
143
|
+
returns: { eyebrow: string; title: string; lastUpdated: string; sections: BrandPolicySection[] };
|
|
144
|
+
accessibility: { eyebrow: string; title: string; lastUpdated: string; sections: BrandPolicySection[] };
|
|
145
|
+
|
|
146
|
+
// ─── Auth + account UX copy ───────────────────────────────────
|
|
147
|
+
account: {
|
|
148
|
+
loginEyebrow: string;
|
|
149
|
+
loginTitle: string;
|
|
150
|
+
loginSubtitle: string;
|
|
151
|
+
signupEyebrow: string;
|
|
152
|
+
signupTitle: string;
|
|
153
|
+
signupSubtitle: string;
|
|
154
|
+
accountEyebrow: string;
|
|
155
|
+
accountTitle: string;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// ─── Contact form copy ────────────────────────────────────────
|
|
159
|
+
contactPage: {
|
|
160
|
+
eyebrow: string;
|
|
161
|
+
title: string;
|
|
162
|
+
body: string;
|
|
163
|
+
/** Reasons offered in the contact form's subject dropdown. */
|
|
164
|
+
reasons: string[];
|
|
165
|
+
/** Direct lines under the form (label + href, e.g. tel: / mailto:). */
|
|
166
|
+
directLines: { label: string; value: string; href: string }[];
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// ─── Track-order page copy ────────────────────────────────────
|
|
170
|
+
trackOrder: {
|
|
171
|
+
eyebrow: string;
|
|
172
|
+
title: string;
|
|
173
|
+
body: string;
|
|
174
|
+
};
|
|
175
|
+
|
|
141
176
|
footer: {
|
|
142
177
|
blurb: string;
|
|
143
178
|
sitemap: BrandSitemapSection[];
|
|
@@ -396,6 +431,74 @@ export const brand: Brand = {
|
|
|
396
431
|
],
|
|
397
432
|
},
|
|
398
433
|
|
|
434
|
+
shipping: {
|
|
435
|
+
eyebrow: "Shipping",
|
|
436
|
+
title: "Shipping & Pickup",
|
|
437
|
+
lastUpdated: "1 May 2026",
|
|
438
|
+
sections: [
|
|
439
|
+
{ heading: "Same-day Greater Accra", body: "Orders placed before 2pm are delivered the same day. Free over GH₵150; GH₵25 below." },
|
|
440
|
+
{ heading: "Outside Accra", body: "Next-day shipping by partner courier. Rates and ETA computed at checkout based on your address." },
|
|
441
|
+
{ heading: "Pickup", body: "Available 8am–8pm at our East Legon location, Tuesday through Sunday. Choose 'Pickup' at checkout — order is boxed and ready within 30 minutes of confirmation." },
|
|
442
|
+
{ heading: "Custom-cake delivery", body: "All custom cakes are hand-delivered. We coordinate the time window with you 24 hours before the event." },
|
|
443
|
+
],
|
|
444
|
+
},
|
|
445
|
+
|
|
446
|
+
returns: {
|
|
447
|
+
eyebrow: "Returns",
|
|
448
|
+
title: "Returns & Refunds",
|
|
449
|
+
lastUpdated: "1 May 2026",
|
|
450
|
+
sections: [
|
|
451
|
+
{ heading: "Baked goods", body: "We don't accept returns on baked goods for food-safety reasons. If anything is wrong with your order — quality, accuracy, or freshness — message us within 24 hours and we'll replace, refund, or credit your account. Your choice." },
|
|
452
|
+
{ heading: "Merchandise", body: "Aprons, totes, eBooks, and gift cards: 14 days, no questions asked, on unopened items." },
|
|
453
|
+
{ heading: "How to start", body: "Email hello@akuasbakery.test with your order number and what's wrong. We respond within 24 hours." },
|
|
454
|
+
],
|
|
455
|
+
},
|
|
456
|
+
|
|
457
|
+
accessibility: {
|
|
458
|
+
eyebrow: "Accessibility",
|
|
459
|
+
title: "Accessibility Statement",
|
|
460
|
+
lastUpdated: "1 May 2026",
|
|
461
|
+
sections: [
|
|
462
|
+
{ heading: "Our commitment", body: "We're committed to making this site usable by everyone, including people who use screen readers, keyboard navigation, or assistive devices. We aim for WCAG 2.1 AA compliance and test against it regularly." },
|
|
463
|
+
{ heading: "What we've done", body: { intro: "Specifically, we've:", bullets: [
|
|
464
|
+
"Maintained a minimum colour contrast of 4.5:1 on body text.",
|
|
465
|
+
"Ensured every interactive element is reachable by keyboard.",
|
|
466
|
+
"Labelled images and icons for screen-reader users.",
|
|
467
|
+
"Kept focus indicators visible at all times.",
|
|
468
|
+
] } },
|
|
469
|
+
{ heading: "Reporting issues", body: "If you encounter a barrier, email accessibility@akuasbakery.test. We respond within 5 business days." },
|
|
470
|
+
],
|
|
471
|
+
},
|
|
472
|
+
|
|
473
|
+
account: {
|
|
474
|
+
loginEyebrow: "Welcome back",
|
|
475
|
+
loginTitle: "Sign in to your account",
|
|
476
|
+
loginSubtitle: "Pick up where you left off — orders, addresses, and your subscription, all in one place.",
|
|
477
|
+
signupEyebrow: "Welcome",
|
|
478
|
+
signupTitle: "Create a baker's account",
|
|
479
|
+
signupSubtitle: "Save your favourite loaves, track orders, and get first dibs on seasonal drops.",
|
|
480
|
+
accountEyebrow: "Your account",
|
|
481
|
+
accountTitle: "Welcome back",
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
contactPage: {
|
|
485
|
+
eyebrow: "Contact",
|
|
486
|
+
title: "We'd love to hear from you.",
|
|
487
|
+
body: "Bug, idea, special request, or just hello — message us and a real human will reply within 24 hours.",
|
|
488
|
+
reasons: ["General question", "An order issue", "Custom cake enquiry", "Press / partnerships", "Wholesale", "Something else"],
|
|
489
|
+
directLines: [
|
|
490
|
+
{ label: "Email", value: "hello@akuasbakery.test", href: "mailto:hello@akuasbakery.test" },
|
|
491
|
+
{ label: "Phone", value: "+233 244 000 000", href: "tel:+233244000000" },
|
|
492
|
+
{ label: "WhatsApp", value: "+233 244 000 000", href: "https://wa.me/233244000000" },
|
|
493
|
+
],
|
|
494
|
+
},
|
|
495
|
+
|
|
496
|
+
trackOrder: {
|
|
497
|
+
eyebrow: "Track an order",
|
|
498
|
+
title: "Where's my loaf?",
|
|
499
|
+
body: "Enter your order number and the email you used at checkout. We'll show you the latest status, the rider's contact, and the live ETA.",
|
|
500
|
+
},
|
|
501
|
+
|
|
399
502
|
footer: {
|
|
400
503
|
blurb:
|
|
401
504
|
"Family-run bakery in East Legon. Sourdough, croissants, layered cakes — handcrafted since 2018, delivered across Accra.",
|
|
@@ -424,10 +527,20 @@ export const brand: Brand = {
|
|
|
424
527
|
{
|
|
425
528
|
title: "Help",
|
|
426
529
|
links: [
|
|
427
|
-
{ label: "Contact", href: "
|
|
428
|
-
{ label: "
|
|
429
|
-
{ label: "
|
|
430
|
-
{ label: "
|
|
530
|
+
{ label: "Contact", href: "/contact" },
|
|
531
|
+
{ label: "Track an order", href: "/track-order" },
|
|
532
|
+
{ label: "Shipping", href: "/shipping" },
|
|
533
|
+
{ label: "Returns", href: "/returns" },
|
|
534
|
+
{ label: "FAQ", href: "/faq" },
|
|
535
|
+
],
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
title: "Account",
|
|
539
|
+
links: [
|
|
540
|
+
{ label: "Sign in", href: "/login" },
|
|
541
|
+
{ label: "Create account", href: "/signup" },
|
|
542
|
+
{ label: "Your orders", href: "/account/orders" },
|
|
543
|
+
{ label: "Settings", href: "/account/settings" },
|
|
431
544
|
],
|
|
432
545
|
},
|
|
433
546
|
{
|
|
@@ -435,6 +548,8 @@ export const brand: Brand = {
|
|
|
435
548
|
links: [
|
|
436
549
|
{ label: "Terms of Service", href: "/terms" },
|
|
437
550
|
{ label: "Privacy Policy", href: "/privacy" },
|
|
551
|
+
{ label: "Accessibility", href: "/accessibility" },
|
|
552
|
+
{ label: "Sitemap", href: "/sitemap-page" },
|
|
438
553
|
],
|
|
439
554
|
},
|
|
440
555
|
],
|
|
@@ -4,43 +4,97 @@ If you are an AI agent (Claude, Cursor, Aider, devin, …) working on this store
|
|
|
4
4
|
|
|
5
5
|
## TL;DR for rebranding
|
|
6
6
|
|
|
7
|
-
1. **Edit `lib/brand.ts
|
|
8
|
-
2. **Edit `app/globals.css`** —
|
|
7
|
+
1. **Edit `lib/brand.ts`** — every visible string lives here.
|
|
8
|
+
2. **Edit `app/globals.css`** — `@theme { … }` for palette + radius + font references.
|
|
9
9
|
3. **Edit `.env.local`** — `NEXT_PUBLIC_CIMPLIFY_API_URL`, `NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY`, `NEXT_PUBLIC_CIMPLIFY_BUSINESS_ID`, `NEXT_PUBLIC_SITE_URL`.
|
|
10
10
|
|
|
11
11
|
## Aesthetic
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Streetwear / lookbook-led brands (Nike, Aritzia, Highsnobiety, drop culture):
|
|
14
14
|
|
|
15
|
-
- **Anton display
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
-
|
|
15
|
+
- **Anton display + Inter** — uppercase condensed display, clean body sans.
|
|
16
|
+
- **High-contrast palette** — near-black foreground on near-white background, electric primary (default coral, `oklch(0.7 0.24 30)`).
|
|
17
|
+
- **Sharp corners**: `0.125rem` — minimal rounding.
|
|
18
|
+
- **Editorial full-bleed hero** with image gradient overlay.
|
|
19
|
+
- **Block-letter header** — no logo mark, just the shortName in display type.
|
|
20
|
+
- Schema.org `@type` is `Store`.
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Page surface
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
```
|
|
25
|
+
app/
|
|
26
|
+
page.tsx Multi-section home — full-bleed editorial hero,
|
|
27
|
+
trust bar, category tiles, promo banner,
|
|
28
|
+
"Just dropped" grid, brand strip, collections,
|
|
29
|
+
studio-collective CTA, best sellers, newsletter
|
|
30
|
+
shop/page.tsx SDK <CataloguePage/> with custom hero
|
|
31
|
+
search/page.tsx Search
|
|
32
|
+
collections/[slug]/page.tsx Collection landing (drops)
|
|
33
|
+
categories/[slug]/page.tsx Category landing
|
|
34
|
+
products/[slug]/page.tsx Full product detail page (Product JSON-LD)
|
|
35
|
+
|
|
36
|
+
size-guide/page.tsx ⭐ Fashion-specific: chest/length/shoulder + waist/hip/inseam
|
|
37
|
+
tables, "how to measure" callout
|
|
38
|
+
lookbook/page.tsx ⭐ Fashion-specific: editorial multi-drop lookbook —
|
|
39
|
+
hero + 3-up tile galleries per drop, "Shop Drop X" CTAs
|
|
40
|
+
|
|
41
|
+
cart/page.tsx, checkout/page.tsx, orders/[id]/page.tsx
|
|
42
|
+
|
|
43
|
+
account/page.tsx <CimplifyAccount /> (iframe)
|
|
44
|
+
account/orders/page.tsx <CimplifyAccount section="orders" />
|
|
45
|
+
account/addresses/page.tsx <CimplifyAccount section="addresses" />
|
|
46
|
+
account/settings/page.tsx <CimplifyAccount section="settings" />
|
|
47
|
+
login/page.tsx, signup/page.tsx redirects → /account
|
|
48
|
+
|
|
49
|
+
contact/page.tsx, track-order/page.tsx
|
|
50
|
+
|
|
51
|
+
about/page.tsx, faq/page.tsx
|
|
52
|
+
shipping/page.tsx (DHL Express worldwide), returns/page.tsx (30 days),
|
|
53
|
+
accessibility/page.tsx, terms/page.tsx, privacy/page.tsx
|
|
54
|
+
|
|
55
|
+
sitemap-page/page.tsx, sitemap.ts, robots.ts, llms.txt/route.ts, opensearch.xml/route.ts
|
|
56
|
+
error.tsx, not-found.tsx
|
|
57
|
+
```
|
|
33
58
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
59
|
+
## File ↔ brand-field map
|
|
60
|
+
|
|
61
|
+
| File | Reads from `brand` |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `app/layout.tsx` | identity, contact, socials, Store JSON-LD |
|
|
64
|
+
| `app/page.tsx` | `brand.hero`, `brand.trustItems`, `brand.brandStrip`, `brand.promo`, `brand.tradeIn` (= studio-collective copy), `brand.newsletter` |
|
|
65
|
+
| `app/about/page.tsx` | `brand.about` |
|
|
66
|
+
| `app/faq/page.tsx` | `brand.faq` (sizing, drops, returns, customs) |
|
|
67
|
+
| `app/shipping/page.tsx` | `brand.shipping` (worldwide DHL, customs) |
|
|
68
|
+
| `app/returns/page.tsx` | `brand.returns` (30 days, free US/UK/EU) |
|
|
69
|
+
| `app/accessibility/page.tsx` | `brand.accessibility` |
|
|
70
|
+
| `app/terms/page.tsx`, `app/privacy/page.tsx` | `brand.terms`, `brand.privacy` |
|
|
71
|
+
| `app/contact/page.tsx` | `brand.contactPage`, `brand.contact` |
|
|
72
|
+
| `app/track-order/page.tsx` | `brand.trackOrder` |
|
|
73
|
+
| `app/account/*/page.tsx` | `brand.account` (iframe owns UI) |
|
|
74
|
+
| `app/products/[slug]/page.tsx` | `brand.name`, `brand.currency` (Product JSON-LD) |
|
|
75
|
+
| `app/size-guide/page.tsx` | currently has its size charts inlined — hoist to `brand.sizeGuide` if you want agents to edit them |
|
|
76
|
+
| `app/lookbook/page.tsx` | currently has the lookbook entries inlined (image URLs + drop names) — hoist to `brand.lookbook` for agent editing |
|
|
77
|
+
| `app/llms.txt/route.ts` | `brand.llms`, contact, currency |
|
|
78
|
+
| `components/header.tsx`, `footer.tsx` | `brand.header`, `brand.footer`, `brand.contact`, `brand.socials` |
|
|
79
|
+
| `components/promo-banner.tsx`, `trade-in-cta.tsx`, `brand-marquee.tsx`, `trust-bar.tsx`, `newsletter.tsx` | corresponding optional sections in `brand` |
|
|
80
|
+
|
|
81
|
+
## Fashion-specific notes
|
|
82
|
+
|
|
83
|
+
- **Hero is full-bleed editorial.** Replace `HERO_FALLBACK_IMAGE` in `app/page.tsx` with the merchant's drop campaign shot for maximum impact.
|
|
84
|
+
- **Drop badges and "limited run" copy** drive urgency. Keep `brand.hero.badge` and `brand.promo.badge` short and time-bounded.
|
|
85
|
+
- **`brand.tradeIn`** is repurposed as the "Studio collective" / membership programme — three-step access flow.
|
|
86
|
+
- **Product detail uses the page-driven model** (`/products/[slug]`) — fashion is a consideration purchase (sizing, fit, fabric details), not impulse.
|
|
87
|
+
- **`brandStrip.headline` is `"Stocked at"`** with editorial publication wordmarks (Vogue, Highsnobiety, etc.) — typography-led, no logo licensing required.
|
|
88
|
+
|
|
89
|
+
## Known TODOs
|
|
90
|
+
|
|
91
|
+
- `app/size-guide/page.tsx` has its size charts inlined as constants. Move them to `brand.sizeGuide` (typed) so agents can edit per-merchant size charts in one file.
|
|
92
|
+
- `app/lookbook/page.tsx` has its drop entries inlined. Move to `brand.lookbook` for agent editing — each drop becomes `{ drop, title, date, byline, hero, tiles[] }`.
|
|
93
|
+
- Contact form + newsletter fake submits.
|
|
40
94
|
|
|
41
95
|
## Mock seed
|
|
42
96
|
|
|
43
|
-
Wired to `--seed retail` (Currents Electronics catalogue
|
|
97
|
+
Wired to `--seed retail` (Currents Electronics catalogue — the closest stand-in until an apparel seed ships). Replace with apparel data in production.
|
|
44
98
|
|
|
45
99
|
## Quick start
|
|
46
100
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { brand } from "@/lib/brand";
|
|
3
|
+
import { PolicyPage } from "@/components/policy-page";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: `${brand.accessibility.title} — ${brand.name}`,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function AccessibilityPage() {
|
|
10
|
+
return <PolicyPage policy={brand.accessibility} />;
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { AccountIframe } from "@/components/account-iframe";
|
|
3
|
+
import { brand } from "@/lib/brand";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: `Addresses — ${brand.name}`,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function AddressesPage() {
|
|
10
|
+
return (
|
|
11
|
+
<article className="max-w-5xl mx-auto px-6 sm:px-8 py-12">
|
|
12
|
+
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-primary mb-2">
|
|
13
|
+
Account
|
|
14
|
+
</p>
|
|
15
|
+
<h1 className="font-serif text-[clamp(2rem,4vw,2.75rem)] font-semibold mb-8 -tracking-[0.02em]">
|
|
16
|
+
Your addresses
|
|
17
|
+
</h1>
|
|
18
|
+
<AccountIframe section="addresses" />
|
|
19
|
+
</article>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { AccountIframe } from "@/components/account-iframe";
|
|
3
|
+
import { brand } from "@/lib/brand";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: `Orders — ${brand.name}`,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function OrdersPage() {
|
|
10
|
+
return (
|
|
11
|
+
<article className="max-w-5xl mx-auto px-6 sm:px-8 py-12">
|
|
12
|
+
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-primary mb-2">
|
|
13
|
+
Account
|
|
14
|
+
</p>
|
|
15
|
+
<h1 className="font-serif text-[clamp(2rem,4vw,2.75rem)] font-semibold mb-8 -tracking-[0.02em]">
|
|
16
|
+
Your orders
|
|
17
|
+
</h1>
|
|
18
|
+
<AccountIframe section="orders" />
|
|
19
|
+
</article>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { AccountIframe } from "@/components/account-iframe";
|
|
3
|
+
import { brand } from "@/lib/brand";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: `Account — ${brand.name}`,
|
|
7
|
+
description: brand.account.signupSubtitle,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function AccountPage() {
|
|
11
|
+
return (
|
|
12
|
+
<article className="max-w-5xl mx-auto px-6 sm:px-8 py-12">
|
|
13
|
+
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-primary mb-2">
|
|
14
|
+
{brand.account.accountEyebrow}
|
|
15
|
+
</p>
|
|
16
|
+
<h1 className="font-serif text-[clamp(2rem,4vw,2.75rem)] font-semibold mb-8 -tracking-[0.02em]">
|
|
17
|
+
{brand.account.accountTitle}
|
|
18
|
+
</h1>
|
|
19
|
+
<AccountIframe />
|
|
20
|
+
</article>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { AccountIframe } from "@/components/account-iframe";
|
|
3
|
+
import { brand } from "@/lib/brand";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: `Settings — ${brand.name}`,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function SettingsPage() {
|
|
10
|
+
return (
|
|
11
|
+
<article className="max-w-5xl mx-auto px-6 sm:px-8 py-12">
|
|
12
|
+
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-primary mb-2">
|
|
13
|
+
Account
|
|
14
|
+
</p>
|
|
15
|
+
<h1 className="font-serif text-[clamp(2rem,4vw,2.75rem)] font-semibold mb-8 -tracking-[0.02em]">
|
|
16
|
+
Settings
|
|
17
|
+
</h1>
|
|
18
|
+
<AccountIframe section="settings" />
|
|
19
|
+
</article>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Local-only contact form. On submit, fakes a successful response so the
|
|
7
|
+
* template ships a usable interaction. Wire to a real handler (Server
|
|
8
|
+
* Action posting to your CRM, support inbox, or Cimplify Support API)
|
|
9
|
+
* before going to production.
|
|
10
|
+
*/
|
|
11
|
+
export function ContactForm({ reasons }: { reasons: string[] }) {
|
|
12
|
+
const [submitted, setSubmitted] = useState(false);
|
|
13
|
+
const [reason, setReason] = useState(reasons[0] ?? "");
|
|
14
|
+
|
|
15
|
+
if (submitted) {
|
|
16
|
+
return (
|
|
17
|
+
<div className="rounded-2xl border border-border bg-card p-8">
|
|
18
|
+
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-primary mb-2">
|
|
19
|
+
✓ Sent
|
|
20
|
+
</p>
|
|
21
|
+
<h2 className="font-serif text-2xl font-semibold mb-2">Thanks — we'll be in touch.</h2>
|
|
22
|
+
<p className="text-muted-foreground">
|
|
23
|
+
We respond within one business day. Check your spam folder if you don't see a
|
|
24
|
+
reply by tomorrow.
|
|
25
|
+
</p>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<form
|
|
32
|
+
onSubmit={(e) => {
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
setSubmitted(true);
|
|
35
|
+
}}
|
|
36
|
+
className="space-y-5"
|
|
37
|
+
>
|
|
38
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
39
|
+
<Field label="Your name" name="name" required />
|
|
40
|
+
<Field label="Email" name="email" type="email" required />
|
|
41
|
+
</div>
|
|
42
|
+
<div>
|
|
43
|
+
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground block mb-1.5">
|
|
44
|
+
What's it about?
|
|
45
|
+
</label>
|
|
46
|
+
<select
|
|
47
|
+
name="reason"
|
|
48
|
+
value={reason}
|
|
49
|
+
onChange={(e) => setReason(e.target.value)}
|
|
50
|
+
className="w-full px-4 py-2.5 rounded-md bg-background border border-border focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none text-sm"
|
|
51
|
+
>
|
|
52
|
+
{reasons.map((r) => (
|
|
53
|
+
<option key={r} value={r}>
|
|
54
|
+
{r}
|
|
55
|
+
</option>
|
|
56
|
+
))}
|
|
57
|
+
</select>
|
|
58
|
+
</div>
|
|
59
|
+
<Field label="Order number (optional)" name="order" />
|
|
60
|
+
<div>
|
|
61
|
+
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground block mb-1.5">
|
|
62
|
+
Message
|
|
63
|
+
</label>
|
|
64
|
+
<textarea
|
|
65
|
+
name="message"
|
|
66
|
+
required
|
|
67
|
+
rows={6}
|
|
68
|
+
className="w-full px-4 py-2.5 rounded-md bg-background border border-border focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none text-sm resize-y"
|
|
69
|
+
/>
|
|
70
|
+
</div>
|
|
71
|
+
<button
|
|
72
|
+
type="submit"
|
|
73
|
+
className="inline-flex items-center justify-center px-5 py-3 rounded-md bg-primary text-primary-foreground font-semibold text-sm hover:bg-primary/90 transition-colors"
|
|
74
|
+
>
|
|
75
|
+
Send message
|
|
76
|
+
</button>
|
|
77
|
+
</form>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function Field({
|
|
82
|
+
label,
|
|
83
|
+
name,
|
|
84
|
+
type = "text",
|
|
85
|
+
required,
|
|
86
|
+
}: {
|
|
87
|
+
label: string;
|
|
88
|
+
name: string;
|
|
89
|
+
type?: string;
|
|
90
|
+
required?: boolean;
|
|
91
|
+
}) {
|
|
92
|
+
return (
|
|
93
|
+
<div>
|
|
94
|
+
<label
|
|
95
|
+
htmlFor={name}
|
|
96
|
+
className="text-xs font-semibold uppercase tracking-wider text-muted-foreground block mb-1.5"
|
|
97
|
+
>
|
|
98
|
+
{label}
|
|
99
|
+
</label>
|
|
100
|
+
<input
|
|
101
|
+
id={name}
|
|
102
|
+
name={name}
|
|
103
|
+
type={type}
|
|
104
|
+
required={required}
|
|
105
|
+
className="w-full px-4 py-2.5 rounded-md bg-background border border-border focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none text-sm"
|
|
106
|
+
/>
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { ContactForm } from "./contact-form";
|
|
3
|
+
import { brand } from "@/lib/brand";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: `Contact — ${brand.name}`,
|
|
7
|
+
description: brand.contactPage.body,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function ContactPage() {
|
|
11
|
+
const c = brand.contactPage;
|
|
12
|
+
return (
|
|
13
|
+
<article className="max-w-5xl mx-auto px-6 sm:px-8 py-16">
|
|
14
|
+
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-primary mb-2">
|
|
15
|
+
{c.eyebrow}
|
|
16
|
+
</p>
|
|
17
|
+
<h1 className="font-serif text-[clamp(2.25rem,5vw,3.5rem)] font-semibold mb-4 -tracking-[0.02em]">
|
|
18
|
+
{c.title}
|
|
19
|
+
</h1>
|
|
20
|
+
<p className="text-lg text-muted-foreground max-w-2xl mb-12 leading-relaxed">{c.body}</p>
|
|
21
|
+
|
|
22
|
+
<div className="grid grid-cols-1 lg:grid-cols-[1.5fr_1fr] gap-10 items-start">
|
|
23
|
+
<ContactForm reasons={c.reasons} />
|
|
24
|
+
<aside className="space-y-5 lg:pl-10 lg:border-l border-border">
|
|
25
|
+
<div>
|
|
26
|
+
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-muted-foreground mb-3">
|
|
27
|
+
Direct lines
|
|
28
|
+
</p>
|
|
29
|
+
<ul className="space-y-3 list-none p-0 m-0">
|
|
30
|
+
{c.directLines.map((line) => (
|
|
31
|
+
<li key={line.label}>
|
|
32
|
+
<p className="text-xs text-muted-foreground m-0">{line.label}</p>
|
|
33
|
+
<a
|
|
34
|
+
href={line.href}
|
|
35
|
+
className="text-foreground hover:text-primary transition-colors"
|
|
36
|
+
>
|
|
37
|
+
{line.value}
|
|
38
|
+
</a>
|
|
39
|
+
</li>
|
|
40
|
+
))}
|
|
41
|
+
</ul>
|
|
42
|
+
</div>
|
|
43
|
+
<div>
|
|
44
|
+
<p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-muted-foreground mb-3">
|
|
45
|
+
Visit
|
|
46
|
+
</p>
|
|
47
|
+
<p className="text-foreground m-0">{brand.contact.address}</p>
|
|
48
|
+
<p className="text-xs text-muted-foreground mt-1">{brand.contact.hours}</p>
|
|
49
|
+
</div>
|
|
50
|
+
</aside>
|
|
51
|
+
</div>
|
|
52
|
+
</article>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { redirect } from "next/navigation";
|
|
3
|
+
import { brand } from "@/lib/brand";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: `Sign in — ${brand.name}`,
|
|
7
|
+
description: brand.account.loginSubtitle,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Cimplify Link (the iframe in `<CimplifyAccount>`) handles sign-in
|
|
12
|
+
* automatically when no session exists. We just bounce /login to /account
|
|
13
|
+
* so consumers landing here get the right UI without a duplicate form.
|
|
14
|
+
*/
|
|
15
|
+
export default function LoginPage(): never {
|
|
16
|
+
redirect("/account");
|
|
17
|
+
}
|