@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.
Files changed (148) hide show
  1. package/dist/cli/commands/deploy.mjs +561 -0
  2. package/dist/cli/commands/dev.mjs +434 -0
  3. package/dist/cli/commands/domains.mjs +479 -0
  4. package/dist/cli/commands/env.mjs +610 -0
  5. package/dist/cli/commands/link.mjs +325 -0
  6. package/dist/cli/commands/login.mjs +515 -0
  7. package/dist/cli/commands/logout.mjs +54 -0
  8. package/dist/cli/commands/logs.mjs +358 -0
  9. package/dist/cli/commands/projects.mjs +327 -0
  10. package/dist/cli/commands/rollback.mjs +477 -0
  11. package/dist/cli/commands/status.mjs +380 -0
  12. package/dist/cli/commands/unlink.mjs +58 -0
  13. package/dist/cli/commands/whoami.mjs +234 -0
  14. package/dist/dispatcher.mjs +91 -0
  15. package/dist/styles.css +1 -1
  16. package/package.json +1 -1
  17. package/templates/storefront-bakery/AGENTS.md +61 -10
  18. package/templates/storefront-bakery/app/accessibility/page.tsx +11 -0
  19. package/templates/storefront-bakery/app/account/addresses/page.tsx +21 -0
  20. package/templates/storefront-bakery/app/account/orders/page.tsx +21 -0
  21. package/templates/storefront-bakery/app/account/page.tsx +22 -0
  22. package/templates/storefront-bakery/app/account/settings/page.tsx +21 -0
  23. package/templates/storefront-bakery/app/contact/contact-form.tsx +109 -0
  24. package/templates/storefront-bakery/app/contact/page.tsx +54 -0
  25. package/templates/storefront-bakery/app/login/page.tsx +17 -0
  26. package/templates/storefront-bakery/app/opensearch.xml/route.ts +37 -0
  27. package/templates/storefront-bakery/app/returns/page.tsx +11 -0
  28. package/templates/storefront-bakery/app/search/page.tsx +38 -0
  29. package/templates/storefront-bakery/app/search/search-client.tsx +7 -0
  30. package/templates/storefront-bakery/app/shipping/page.tsx +16 -0
  31. package/templates/storefront-bakery/app/signup/page.tsx +17 -0
  32. package/templates/storefront-bakery/app/sitemap-page/page.tsx +167 -0
  33. package/templates/storefront-bakery/app/track-order/page.tsx +24 -0
  34. package/templates/storefront-bakery/app/track-order/track-order-form.tsx +69 -0
  35. package/templates/storefront-bakery/components/account-iframe.tsx +13 -0
  36. package/templates/storefront-bakery/components/policy-page.tsx +49 -0
  37. package/templates/storefront-bakery/lib/brand.ts +119 -4
  38. package/templates/storefront-fashion/AGENTS.md +80 -26
  39. package/templates/storefront-fashion/app/accessibility/page.tsx +11 -0
  40. package/templates/storefront-fashion/app/account/addresses/page.tsx +21 -0
  41. package/templates/storefront-fashion/app/account/orders/page.tsx +21 -0
  42. package/templates/storefront-fashion/app/account/page.tsx +22 -0
  43. package/templates/storefront-fashion/app/account/settings/page.tsx +21 -0
  44. package/templates/storefront-fashion/app/contact/contact-form.tsx +109 -0
  45. package/templates/storefront-fashion/app/contact/page.tsx +54 -0
  46. package/templates/storefront-fashion/app/login/page.tsx +17 -0
  47. package/templates/storefront-fashion/app/lookbook/page.tsx +132 -0
  48. package/templates/storefront-fashion/app/opensearch.xml/route.ts +37 -0
  49. package/templates/storefront-fashion/app/returns/page.tsx +11 -0
  50. package/templates/storefront-fashion/app/search/page.tsx +38 -0
  51. package/templates/storefront-fashion/app/search/search-client.tsx +7 -0
  52. package/templates/storefront-fashion/app/shipping/page.tsx +16 -0
  53. package/templates/storefront-fashion/app/signup/page.tsx +17 -0
  54. package/templates/storefront-fashion/app/sitemap-page/page.tsx +167 -0
  55. package/templates/storefront-fashion/app/size-guide/page.tsx +155 -0
  56. package/templates/storefront-fashion/app/track-order/page.tsx +24 -0
  57. package/templates/storefront-fashion/app/track-order/track-order-form.tsx +69 -0
  58. package/templates/storefront-fashion/components/account-iframe.tsx +13 -0
  59. package/templates/storefront-fashion/components/policy-page.tsx +49 -0
  60. package/templates/storefront-fashion/lib/brand.ts +99 -4
  61. package/templates/storefront-grocery/AGENTS.md +56 -11
  62. package/templates/storefront-grocery/app/accessibility/page.tsx +11 -0
  63. package/templates/storefront-grocery/app/account/addresses/page.tsx +21 -0
  64. package/templates/storefront-grocery/app/account/orders/page.tsx +21 -0
  65. package/templates/storefront-grocery/app/account/page.tsx +22 -0
  66. package/templates/storefront-grocery/app/account/settings/page.tsx +21 -0
  67. package/templates/storefront-grocery/app/contact/contact-form.tsx +109 -0
  68. package/templates/storefront-grocery/app/contact/page.tsx +54 -0
  69. package/templates/storefront-grocery/app/login/page.tsx +17 -0
  70. package/templates/storefront-grocery/app/opensearch.xml/route.ts +37 -0
  71. package/templates/storefront-grocery/app/returns/page.tsx +11 -0
  72. package/templates/storefront-grocery/app/search/page.tsx +38 -0
  73. package/templates/storefront-grocery/app/search/search-client.tsx +7 -0
  74. package/templates/storefront-grocery/app/shipping/page.tsx +16 -0
  75. package/templates/storefront-grocery/app/signup/page.tsx +17 -0
  76. package/templates/storefront-grocery/app/sitemap-page/page.tsx +167 -0
  77. package/templates/storefront-grocery/app/track-order/page.tsx +24 -0
  78. package/templates/storefront-grocery/app/track-order/track-order-form.tsx +69 -0
  79. package/templates/storefront-grocery/components/account-iframe.tsx +13 -0
  80. package/templates/storefront-grocery/components/policy-page.tsx +49 -0
  81. package/templates/storefront-grocery/lib/brand.ts +92 -3
  82. package/templates/storefront-restaurant/AGENTS.md +64 -13
  83. package/templates/storefront-restaurant/app/accessibility/page.tsx +11 -0
  84. package/templates/storefront-restaurant/app/account/addresses/page.tsx +21 -0
  85. package/templates/storefront-restaurant/app/account/orders/page.tsx +21 -0
  86. package/templates/storefront-restaurant/app/account/page.tsx +22 -0
  87. package/templates/storefront-restaurant/app/account/settings/page.tsx +21 -0
  88. package/templates/storefront-restaurant/app/contact/contact-form.tsx +109 -0
  89. package/templates/storefront-restaurant/app/contact/page.tsx +54 -0
  90. package/templates/storefront-restaurant/app/login/page.tsx +17 -0
  91. package/templates/storefront-restaurant/app/opensearch.xml/route.ts +37 -0
  92. package/templates/storefront-restaurant/app/reservations/page.tsx +66 -0
  93. package/templates/storefront-restaurant/app/reservations/reservations-client.tsx +234 -0
  94. package/templates/storefront-restaurant/app/returns/page.tsx +11 -0
  95. package/templates/storefront-restaurant/app/search/page.tsx +38 -0
  96. package/templates/storefront-restaurant/app/search/search-client.tsx +7 -0
  97. package/templates/storefront-restaurant/app/shipping/page.tsx +16 -0
  98. package/templates/storefront-restaurant/app/signup/page.tsx +17 -0
  99. package/templates/storefront-restaurant/app/sitemap-page/page.tsx +167 -0
  100. package/templates/storefront-restaurant/app/track-order/page.tsx +24 -0
  101. package/templates/storefront-restaurant/app/track-order/track-order-form.tsx +69 -0
  102. package/templates/storefront-restaurant/components/account-iframe.tsx +13 -0
  103. package/templates/storefront-restaurant/components/policy-page.tsx +49 -0
  104. package/templates/storefront-restaurant/lib/brand.ts +91 -3
  105. package/templates/storefront-retail/AGENTS.md +65 -24
  106. package/templates/storefront-retail/app/accessibility/page.tsx +11 -0
  107. package/templates/storefront-retail/app/account/addresses/page.tsx +21 -0
  108. package/templates/storefront-retail/app/account/orders/page.tsx +21 -0
  109. package/templates/storefront-retail/app/account/page.tsx +22 -0
  110. package/templates/storefront-retail/app/account/settings/page.tsx +21 -0
  111. package/templates/storefront-retail/app/contact/contact-form.tsx +109 -0
  112. package/templates/storefront-retail/app/contact/page.tsx +54 -0
  113. package/templates/storefront-retail/app/login/page.tsx +17 -0
  114. package/templates/storefront-retail/app/opensearch.xml/route.ts +37 -0
  115. package/templates/storefront-retail/app/returns/page.tsx +11 -0
  116. package/templates/storefront-retail/app/search/page.tsx +38 -0
  117. package/templates/storefront-retail/app/search/search-client.tsx +7 -0
  118. package/templates/storefront-retail/app/shipping/page.tsx +16 -0
  119. package/templates/storefront-retail/app/signup/page.tsx +17 -0
  120. package/templates/storefront-retail/app/sitemap-page/page.tsx +167 -0
  121. package/templates/storefront-retail/app/track-order/page.tsx +24 -0
  122. package/templates/storefront-retail/app/track-order/track-order-form.tsx +69 -0
  123. package/templates/storefront-retail/components/account-iframe.tsx +13 -0
  124. package/templates/storefront-retail/components/policy-page.tsx +49 -0
  125. package/templates/storefront-retail/lib/brand.ts +105 -9
  126. package/templates/storefront-services/AGENTS.md +64 -16
  127. package/templates/storefront-services/app/accessibility/page.tsx +11 -0
  128. package/templates/storefront-services/app/account/addresses/page.tsx +21 -0
  129. package/templates/storefront-services/app/account/orders/page.tsx +21 -0
  130. package/templates/storefront-services/app/account/page.tsx +22 -0
  131. package/templates/storefront-services/app/account/settings/page.tsx +21 -0
  132. package/templates/storefront-services/app/book/book-client.tsx +195 -0
  133. package/templates/storefront-services/app/book/page.tsx +65 -0
  134. package/templates/storefront-services/app/contact/contact-form.tsx +109 -0
  135. package/templates/storefront-services/app/contact/page.tsx +54 -0
  136. package/templates/storefront-services/app/login/page.tsx +17 -0
  137. package/templates/storefront-services/app/opensearch.xml/route.ts +37 -0
  138. package/templates/storefront-services/app/returns/page.tsx +11 -0
  139. package/templates/storefront-services/app/search/page.tsx +38 -0
  140. package/templates/storefront-services/app/search/search-client.tsx +7 -0
  141. package/templates/storefront-services/app/shipping/page.tsx +16 -0
  142. package/templates/storefront-services/app/signup/page.tsx +17 -0
  143. package/templates/storefront-services/app/sitemap-page/page.tsx +167 -0
  144. package/templates/storefront-services/app/track-order/page.tsx +24 -0
  145. package/templates/storefront-services/app/track-order/track-order-form.tsx +69 -0
  146. package/templates/storefront-services/components/account-iframe.tsx +13 -0
  147. package/templates/storefront-services/components/policy-page.tsx +49 -0
  148. 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: "mailto:hello@akuasbakery.test" },
428
- { label: "Custom cakes", href: "/faq" },
429
- { label: "Allergens", href: "/faq" },
430
- { label: "Delivery", href: "/faq" },
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`.** Every visible string reads from this file.
8
- 2. **Edit `app/globals.css`** — the `@theme { … }` block holds the design tokens (palette, radius, font references). High-contrast neutrals + electric primary by default.
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
- This template is built for streetwear / capsule fashion / lookbook-led brands (Nike, Aritzia, Highsnobiety, drop culture). Key design moves:
13
+ Streetwear / lookbook-led brands (Nike, Aritzia, Highsnobiety, drop culture):
14
14
 
15
- - **Anton display typography** for hero + section titles (uppercase, condensed, heavy).
16
- - **Inter** for body and UI.
17
- - **High-contrast palette**: near-black foreground on near-white background, with one electric primary (default: `oklch(0.7 0.24 30)` — coral-orange).
18
- - **Sharp corners**: `--radius: 0.125rem` — minimal rounding, near-square inputs and buttons.
19
- - **Editorial full-bleed hero** with image gradient overlay (see `components/feature-hero.tsx`).
20
- - **Block-letter header** — no logo mark, just the shortName in display type with a microTag.
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
- ## Industry-specific copy patterns
22
+ ## Page surface
23
23
 
24
- The bundled brand presets:
25
- - `brand.hero.badge` is a "drop counter" (e.g. `"Drop 04 · Live now"`).
26
- - `brand.tradeIn` is repurposed as a "Studio collective" / membership programme.
27
- - `brand.brandStrip.headline` is `"Stocked at"` with editorial publication wordmarks (Vogue, Highsnobiety, etc.).
28
- - `brand.faq` covers sizing, drops/restocks, returns, customs.
29
-
30
- Replace these freely. The components render conditionally — set any optional block to `undefined` to hide it.
31
-
32
- ## Rules
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
- - ✅ All content edits → `lib/brand.ts`
35
- - ✅ All design-token edits → `app/globals.css` `@theme` block
36
- - ✅ Server Components stay cached via `'use cache'` + `cacheTag(tags.X())` + `cacheLife("hours")`
37
- - ✅ Client islands behind `<Suspense>`
38
- - ❌ Don't hardcode strings.
39
- - ❌ Don't disable `cacheComponents: true`.
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). Replace with apparel data in production. To preview a different seed, edit `dev:mock` in `package.json`.
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
+ }