@cimplify/sdk 0.40.0 → 0.41.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.
Files changed (227) hide show
  1. package/dist/dispatcher.mjs +3 -2
  2. package/dist/mock/cli.mjs +30 -6
  3. package/dist/mock/library.js +30 -6
  4. package/dist/mock/library.mjs +30 -6
  5. package/dist/mock/msw.js +30 -6
  6. package/dist/mock/msw.mjs +30 -6
  7. package/dist/styles.css +1 -1
  8. package/package.json +1 -1
  9. package/templates/storefront-bakery/.env.example +5 -0
  10. package/templates/storefront-bakery/AGENTS.md +57 -0
  11. package/templates/storefront-bakery/app/about/page.tsx +21 -44
  12. package/templates/storefront-bakery/app/categories/[slug]/page.tsx +2 -1
  13. package/templates/storefront-bakery/app/collections/[slug]/page.tsx +2 -1
  14. package/templates/storefront-bakery/app/error.tsx +60 -0
  15. package/templates/storefront-bakery/app/faq/page.tsx +13 -89
  16. package/templates/storefront-bakery/app/layout.tsx +37 -2
  17. package/templates/storefront-bakery/app/llms.txt/route.ts +94 -0
  18. package/templates/storefront-bakery/app/not-found.tsx +39 -0
  19. package/templates/storefront-bakery/app/page.tsx +6 -6
  20. package/templates/storefront-bakery/app/privacy/page.tsx +24 -68
  21. package/templates/storefront-bakery/app/robots.ts +18 -0
  22. package/templates/storefront-bakery/app/shop/page.tsx +3 -2
  23. package/templates/storefront-bakery/app/sitemap.ts +62 -0
  24. package/templates/storefront-bakery/app/terms/page.tsx +24 -82
  25. package/templates/storefront-bakery/components/footer.tsx +88 -130
  26. package/templates/storefront-bakery/components/header.tsx +8 -16
  27. package/templates/storefront-bakery/lib/brand.ts +453 -0
  28. package/templates/storefront-fashion/.env.example +16 -0
  29. package/templates/storefront-fashion/AGENTS.md +52 -0
  30. package/templates/storefront-fashion/README.md +77 -0
  31. package/templates/storefront-fashion/app/about/page.tsx +41 -0
  32. package/templates/storefront-fashion/app/cart/page.tsx +9 -0
  33. package/templates/storefront-fashion/app/categories/[slug]/listing-client.tsx +19 -0
  34. package/templates/storefront-fashion/app/categories/[slug]/page.tsx +130 -0
  35. package/templates/storefront-fashion/app/checkout/page.tsx +17 -0
  36. package/templates/storefront-fashion/app/collections/[slug]/listing-client.tsx +20 -0
  37. package/templates/storefront-fashion/app/collections/[slug]/page.tsx +130 -0
  38. package/templates/storefront-fashion/app/error.tsx +61 -0
  39. package/templates/storefront-fashion/app/faq/page.tsx +46 -0
  40. package/templates/storefront-fashion/app/globals.css +46 -0
  41. package/templates/storefront-fashion/app/layout.tsx +76 -0
  42. package/templates/storefront-fashion/app/llms.txt/route.ts +94 -0
  43. package/templates/storefront-fashion/app/not-found.tsx +39 -0
  44. package/templates/storefront-fashion/app/orders/[id]/page.tsx +24 -0
  45. package/templates/storefront-fashion/app/page.tsx +183 -0
  46. package/templates/storefront-fashion/app/privacy/page.tsx +44 -0
  47. package/templates/storefront-fashion/app/products/[slug]/page.tsx +165 -0
  48. package/templates/storefront-fashion/app/products/[slug]/product-detail.tsx +71 -0
  49. package/templates/storefront-fashion/app/robots.ts +18 -0
  50. package/templates/storefront-fashion/app/shop/page.tsx +63 -0
  51. package/templates/storefront-fashion/app/shop/shop-client.tsx +32 -0
  52. package/templates/storefront-fashion/app/sitemap.ts +59 -0
  53. package/templates/storefront-fashion/app/terms/page.tsx +44 -0
  54. package/templates/storefront-fashion/components/brand-marquee.tsx +27 -0
  55. package/templates/storefront-fashion/components/cart-pill.tsx +32 -0
  56. package/templates/storefront-fashion/components/category-grid.tsx +28 -0
  57. package/templates/storefront-fashion/components/category-tiles.tsx +104 -0
  58. package/templates/storefront-fashion/components/collection-strip.tsx +45 -0
  59. package/templates/storefront-fashion/components/feature-hero.tsx +82 -0
  60. package/templates/storefront-fashion/components/footer.tsx +153 -0
  61. package/templates/storefront-fashion/components/header.tsx +43 -0
  62. package/templates/storefront-fashion/components/hero.tsx +28 -0
  63. package/templates/storefront-fashion/components/nav-link.tsx +20 -0
  64. package/templates/storefront-fashion/components/newsletter.tsx +50 -0
  65. package/templates/storefront-fashion/components/promo-banner.tsx +41 -0
  66. package/templates/storefront-fashion/components/providers.tsx +31 -0
  67. package/templates/storefront-fashion/components/section-heading.tsx +37 -0
  68. package/templates/storefront-fashion/components/store-product-card.tsx +83 -0
  69. package/templates/storefront-fashion/components/trade-in-cta.tsx +54 -0
  70. package/templates/storefront-fashion/components/trust-bar.tsx +66 -0
  71. package/templates/storefront-fashion/lib/brand.ts +421 -0
  72. package/templates/storefront-fashion/lib/cart.ts +27 -0
  73. package/templates/storefront-fashion/next.config.ts +40 -0
  74. package/templates/storefront-fashion/package.json +28 -0
  75. package/templates/storefront-fashion/postcss.config.mjs +7 -0
  76. package/templates/storefront-fashion/tsconfig.json +23 -0
  77. package/templates/storefront-grocery/.env.example +16 -0
  78. package/templates/storefront-grocery/AGENTS.md +39 -0
  79. package/templates/storefront-grocery/README.md +73 -0
  80. package/templates/storefront-grocery/app/about/page.tsx +38 -0
  81. package/templates/storefront-grocery/app/cart/page.tsx +9 -0
  82. package/templates/storefront-grocery/app/categories/[slug]/listing-client.tsx +19 -0
  83. package/templates/storefront-grocery/app/categories/[slug]/page.tsx +118 -0
  84. package/templates/storefront-grocery/app/checkout/page.tsx +17 -0
  85. package/templates/storefront-grocery/app/collections/[slug]/listing-client.tsx +20 -0
  86. package/templates/storefront-grocery/app/collections/[slug]/page.tsx +118 -0
  87. package/templates/storefront-grocery/app/error.tsx +60 -0
  88. package/templates/storefront-grocery/app/faq/page.tsx +46 -0
  89. package/templates/storefront-grocery/app/globals.css +45 -0
  90. package/templates/storefront-grocery/app/layout.tsx +75 -0
  91. package/templates/storefront-grocery/app/llms.txt/route.ts +94 -0
  92. package/templates/storefront-grocery/app/not-found.tsx +39 -0
  93. package/templates/storefront-grocery/app/orders/[id]/page.tsx +21 -0
  94. package/templates/storefront-grocery/app/page.tsx +97 -0
  95. package/templates/storefront-grocery/app/privacy/page.tsx +44 -0
  96. package/templates/storefront-grocery/app/robots.ts +18 -0
  97. package/templates/storefront-grocery/app/shop/page.tsx +31 -0
  98. package/templates/storefront-grocery/app/shop/shop-client.tsx +27 -0
  99. package/templates/storefront-grocery/app/sitemap.ts +62 -0
  100. package/templates/storefront-grocery/app/terms/page.tsx +44 -0
  101. package/templates/storefront-grocery/components/cart-pill.tsx +32 -0
  102. package/templates/storefront-grocery/components/category-grid.tsx +28 -0
  103. package/templates/storefront-grocery/components/collection-strip.tsx +45 -0
  104. package/templates/storefront-grocery/components/footer.tsx +148 -0
  105. package/templates/storefront-grocery/components/header.tsx +43 -0
  106. package/templates/storefront-grocery/components/hero.tsx +25 -0
  107. package/templates/storefront-grocery/components/nav-link.tsx +20 -0
  108. package/templates/storefront-grocery/components/providers.tsx +31 -0
  109. package/templates/storefront-grocery/components/store-product-card.tsx +83 -0
  110. package/templates/storefront-grocery/lib/brand.ts +284 -0
  111. package/templates/storefront-grocery/lib/cart.ts +27 -0
  112. package/templates/storefront-grocery/next.config.ts +40 -0
  113. package/templates/storefront-grocery/package.json +28 -0
  114. package/templates/storefront-grocery/postcss.config.mjs +7 -0
  115. package/templates/storefront-grocery/tsconfig.json +23 -0
  116. package/templates/storefront-restaurant/.env.example +16 -0
  117. package/templates/storefront-restaurant/AGENTS.md +39 -0
  118. package/templates/storefront-restaurant/README.md +73 -0
  119. package/templates/storefront-restaurant/app/about/page.tsx +38 -0
  120. package/templates/storefront-restaurant/app/cart/page.tsx +9 -0
  121. package/templates/storefront-restaurant/app/categories/[slug]/listing-client.tsx +19 -0
  122. package/templates/storefront-restaurant/app/categories/[slug]/page.tsx +118 -0
  123. package/templates/storefront-restaurant/app/checkout/page.tsx +17 -0
  124. package/templates/storefront-restaurant/app/collections/[slug]/listing-client.tsx +20 -0
  125. package/templates/storefront-restaurant/app/collections/[slug]/page.tsx +118 -0
  126. package/templates/storefront-restaurant/app/error.tsx +60 -0
  127. package/templates/storefront-restaurant/app/faq/page.tsx +46 -0
  128. package/templates/storefront-restaurant/app/globals.css +44 -0
  129. package/templates/storefront-restaurant/app/layout.tsx +80 -0
  130. package/templates/storefront-restaurant/app/llms.txt/route.ts +94 -0
  131. package/templates/storefront-restaurant/app/not-found.tsx +39 -0
  132. package/templates/storefront-restaurant/app/orders/[id]/page.tsx +21 -0
  133. package/templates/storefront-restaurant/app/page.tsx +97 -0
  134. package/templates/storefront-restaurant/app/privacy/page.tsx +44 -0
  135. package/templates/storefront-restaurant/app/robots.ts +18 -0
  136. package/templates/storefront-restaurant/app/shop/page.tsx +31 -0
  137. package/templates/storefront-restaurant/app/shop/shop-client.tsx +27 -0
  138. package/templates/storefront-restaurant/app/sitemap.ts +62 -0
  139. package/templates/storefront-restaurant/app/terms/page.tsx +44 -0
  140. package/templates/storefront-restaurant/components/cart-pill.tsx +32 -0
  141. package/templates/storefront-restaurant/components/category-grid.tsx +28 -0
  142. package/templates/storefront-restaurant/components/collection-strip.tsx +45 -0
  143. package/templates/storefront-restaurant/components/footer.tsx +148 -0
  144. package/templates/storefront-restaurant/components/header.tsx +43 -0
  145. package/templates/storefront-restaurant/components/hero.tsx +25 -0
  146. package/templates/storefront-restaurant/components/nav-link.tsx +20 -0
  147. package/templates/storefront-restaurant/components/product-modal.tsx +105 -0
  148. package/templates/storefront-restaurant/components/providers.tsx +31 -0
  149. package/templates/storefront-restaurant/components/store-product-card.tsx +83 -0
  150. package/templates/storefront-restaurant/lib/brand.ts +287 -0
  151. package/templates/storefront-restaurant/lib/cart.ts +27 -0
  152. package/templates/storefront-restaurant/next.config.ts +40 -0
  153. package/templates/storefront-restaurant/package.json +28 -0
  154. package/templates/storefront-restaurant/postcss.config.mjs +7 -0
  155. package/templates/storefront-restaurant/tsconfig.json +23 -0
  156. package/templates/storefront-retail/.env.example +5 -0
  157. package/templates/storefront-retail/AGENTS.md +64 -0
  158. package/templates/storefront-retail/app/about/page.tsx +24 -54
  159. package/templates/storefront-retail/app/categories/[slug]/page.tsx +50 -37
  160. package/templates/storefront-retail/app/collections/[slug]/page.tsx +50 -37
  161. package/templates/storefront-retail/app/error.tsx +61 -0
  162. package/templates/storefront-retail/app/faq/page.tsx +11 -92
  163. package/templates/storefront-retail/app/layout.tsx +37 -8
  164. package/templates/storefront-retail/app/llms.txt/route.ts +94 -0
  165. package/templates/storefront-retail/app/not-found.tsx +39 -0
  166. package/templates/storefront-retail/app/page.tsx +111 -26
  167. package/templates/storefront-retail/app/privacy/page.tsx +24 -81
  168. package/templates/storefront-retail/app/products/[slug]/page.tsx +165 -0
  169. package/templates/storefront-retail/app/products/[slug]/product-detail.tsx +71 -0
  170. package/templates/storefront-retail/app/robots.ts +18 -0
  171. package/templates/storefront-retail/app/shop/page.tsx +36 -3
  172. package/templates/storefront-retail/app/shop/shop-client.tsx +6 -1
  173. package/templates/storefront-retail/app/sitemap.ts +59 -0
  174. package/templates/storefront-retail/app/terms/page.tsx +24 -97
  175. package/templates/storefront-retail/components/brand-marquee.tsx +27 -0
  176. package/templates/storefront-retail/components/category-tiles.tsx +104 -0
  177. package/templates/storefront-retail/components/feature-hero.tsx +84 -0
  178. package/templates/storefront-retail/components/footer.tsx +85 -120
  179. package/templates/storefront-retail/components/header.tsx +10 -12
  180. package/templates/storefront-retail/components/newsletter.tsx +50 -0
  181. package/templates/storefront-retail/components/promo-banner.tsx +41 -0
  182. package/templates/storefront-retail/components/section-heading.tsx +37 -0
  183. package/templates/storefront-retail/components/store-product-card.tsx +7 -7
  184. package/templates/storefront-retail/components/trade-in-cta.tsx +54 -0
  185. package/templates/storefront-retail/components/trust-bar.tsx +66 -0
  186. package/templates/storefront-retail/lib/brand.ts +567 -0
  187. package/templates/storefront-services/.env.example +16 -0
  188. package/templates/storefront-services/AGENTS.md +41 -0
  189. package/templates/storefront-services/README.md +73 -0
  190. package/templates/storefront-services/app/about/page.tsx +38 -0
  191. package/templates/storefront-services/app/cart/page.tsx +9 -0
  192. package/templates/storefront-services/app/categories/[slug]/listing-client.tsx +19 -0
  193. package/templates/storefront-services/app/categories/[slug]/page.tsx +118 -0
  194. package/templates/storefront-services/app/checkout/page.tsx +17 -0
  195. package/templates/storefront-services/app/collections/[slug]/listing-client.tsx +20 -0
  196. package/templates/storefront-services/app/collections/[slug]/page.tsx +118 -0
  197. package/templates/storefront-services/app/error.tsx +60 -0
  198. package/templates/storefront-services/app/faq/page.tsx +46 -0
  199. package/templates/storefront-services/app/globals.css +45 -0
  200. package/templates/storefront-services/app/layout.tsx +80 -0
  201. package/templates/storefront-services/app/llms.txt/route.ts +94 -0
  202. package/templates/storefront-services/app/not-found.tsx +39 -0
  203. package/templates/storefront-services/app/orders/[id]/page.tsx +21 -0
  204. package/templates/storefront-services/app/page.tsx +97 -0
  205. package/templates/storefront-services/app/privacy/page.tsx +44 -0
  206. package/templates/storefront-services/app/robots.ts +18 -0
  207. package/templates/storefront-services/app/shop/page.tsx +31 -0
  208. package/templates/storefront-services/app/shop/shop-client.tsx +27 -0
  209. package/templates/storefront-services/app/sitemap.ts +62 -0
  210. package/templates/storefront-services/app/terms/page.tsx +44 -0
  211. package/templates/storefront-services/components/cart-pill.tsx +32 -0
  212. package/templates/storefront-services/components/category-grid.tsx +28 -0
  213. package/templates/storefront-services/components/collection-strip.tsx +45 -0
  214. package/templates/storefront-services/components/footer.tsx +148 -0
  215. package/templates/storefront-services/components/header.tsx +43 -0
  216. package/templates/storefront-services/components/hero.tsx +25 -0
  217. package/templates/storefront-services/components/nav-link.tsx +20 -0
  218. package/templates/storefront-services/components/product-modal.tsx +105 -0
  219. package/templates/storefront-services/components/providers.tsx +31 -0
  220. package/templates/storefront-services/components/store-product-card.tsx +83 -0
  221. package/templates/storefront-services/lib/brand.ts +303 -0
  222. package/templates/storefront-services/lib/cart.ts +27 -0
  223. package/templates/storefront-services/next.config.ts +40 -0
  224. package/templates/storefront-services/package.json +28 -0
  225. package/templates/storefront-services/postcss.config.mjs +7 -0
  226. package/templates/storefront-services/tsconfig.json +23 -0
  227. /package/templates/{storefront-retail → storefront-grocery}/components/product-modal.tsx +0 -0
@@ -2,10 +2,11 @@ import type { Metadata } from "next";
2
2
  import { cacheTag, cacheLife } from "next/cache";
3
3
  import { getServerClient, tags } from "@cimplify/sdk/server";
4
4
  import { ShopClient } from "./shop-client";
5
+ import { brand } from "@/lib/brand";
5
6
 
6
7
  export const metadata: Metadata = {
7
- title: "Shop — Akua's Bakery",
8
- description: "Browse the full catalogue: breads, pastries, cakes, drinks, merch, and more.",
8
+ title: `Shop — ${brand.name}`,
9
+ description: brand.description,
9
10
  };
10
11
 
11
12
  async function getShopData() {
@@ -0,0 +1,62 @@
1
+ import type { MetadataRoute } from "next";
2
+ import { getServerClient, type Product } from "@cimplify/sdk/server";
3
+
4
+ const SITE_URL =
5
+ process.env.NEXT_PUBLIC_SITE_URL?.trim() || "https://example.com";
6
+
7
+ const STATIC_ROUTES: { path: string; priority: number; changeFrequency: "daily" | "weekly" | "monthly" }[] = [
8
+ { path: "/", priority: 1.0, changeFrequency: "daily" },
9
+ { path: "/shop", priority: 0.9, changeFrequency: "daily" },
10
+ { path: "/about", priority: 0.5, changeFrequency: "monthly" },
11
+ { path: "/faq", priority: 0.4, changeFrequency: "monthly" },
12
+ { path: "/terms", priority: 0.2, changeFrequency: "monthly" },
13
+ { path: "/privacy", priority: 0.2, changeFrequency: "monthly" },
14
+ ];
15
+
16
+ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
17
+ const now = new Date();
18
+ const client = getServerClient();
19
+
20
+ const [productsRes, categoriesRes, collectionsRes] = await Promise.all([
21
+ client.catalogue.getProducts({ limit: 500 }),
22
+ client.catalogue.getCategories(),
23
+ client.catalogue.getCollections(),
24
+ ]);
25
+
26
+ const products = productsRes.ok ? productsRes.value.items : [];
27
+ const categories = categoriesRes.ok ? categoriesRes.value : [];
28
+ const collections = collectionsRes.ok ? collectionsRes.value : [];
29
+
30
+ const staticEntries: MetadataRoute.Sitemap = STATIC_ROUTES.map((r) => ({
31
+ url: `${SITE_URL}${r.path}`,
32
+ lastModified: now,
33
+ changeFrequency: r.changeFrequency,
34
+ priority: r.priority,
35
+ }));
36
+
37
+ // Bakery uses a URL-driven product modal (`?product=<slug>` on the home or
38
+ // shop pages). Emit those as deep-linkable URLs so search engines and LLMs
39
+ // can index each product canonically.
40
+ const productEntries: MetadataRoute.Sitemap = products.map((p: Product) => ({
41
+ url: `${SITE_URL}/shop?product=${encodeURIComponent(p.slug ?? p.id)}`,
42
+ lastModified: p.updated_at ? new Date(p.updated_at) : now,
43
+ changeFrequency: "weekly",
44
+ priority: 0.7,
45
+ }));
46
+
47
+ const categoryEntries: MetadataRoute.Sitemap = categories.map((c) => ({
48
+ url: `${SITE_URL}/categories/${c.slug}`,
49
+ lastModified: now,
50
+ changeFrequency: "weekly",
51
+ priority: 0.6,
52
+ }));
53
+
54
+ const collectionEntries: MetadataRoute.Sitemap = collections.map((c) => ({
55
+ url: `${SITE_URL}/collections/${c.slug}`,
56
+ lastModified: now,
57
+ changeFrequency: "weekly",
58
+ priority: 0.6,
59
+ }));
60
+
61
+ return [...staticEntries, ...categoryEntries, ...collectionEntries, ...productEntries];
62
+ }
@@ -1,101 +1,43 @@
1
1
  import type { Metadata } from "next";
2
+ import { brand } from "@/lib/brand";
2
3
 
3
4
  export const metadata: Metadata = {
4
- title: "Terms of Service — Akua's Bakery",
5
- description: "The rules of the road for ordering from Akua's Bakery.",
5
+ title: `Terms of Service — ${brand.name}`,
6
+ description: `The rules of the road for ordering from ${brand.name}.`,
6
7
  };
7
8
 
8
9
  export default function TermsPage() {
10
+ const t = brand.terms;
9
11
  return (
10
12
  <article className="max-w-3xl mx-auto px-8 py-16 prose prose-lg max-w-none">
11
13
  <p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-primary mb-2 not-prose">
12
- Terms of service
14
+ {t.eyebrow}
13
15
  </p>
14
16
  <h1 className="font-serif text-[clamp(2.25rem,5vw,3.5rem)] font-semibold mb-2 -tracking-[0.02em]">
15
- Terms of Service
17
+ {t.title}
16
18
  </h1>
17
19
  <p className="text-sm text-muted-foreground not-prose mb-10">
18
- Last updated: 1 May 2026
20
+ Last updated: {t.lastUpdated}
19
21
  </p>
20
22
 
21
23
  <section className="space-y-5 leading-relaxed text-foreground/90">
22
- <h2 className="font-serif text-2xl font-semibold mt-0">1. Who we are</h2>
23
- <p>
24
- Akua's Bakery (&quot;we&quot;, &quot;us&quot;) is a bakery and pâtisserie operating
25
- at 12 Independence Avenue, Accra, Ghana. By placing an order through this
26
- website, you (&quot;you&quot;, &quot;customer&quot;) agree to these terms.
27
- </p>
28
-
29
- <h2 className="font-serif text-2xl font-semibold">2. Orders and acceptance</h2>
30
- <p>
31
- Placing an order constitutes an offer to buy. We confirm acceptance by
32
- sending an order confirmation email or SMS. Until acceptance, we may
33
- decline an order — we'll refund any payment in full, immediately.
34
- </p>
35
-
36
- <h2 className="font-serif text-2xl font-semibold">3. Pricing and payment</h2>
37
- <p>
38
- Prices are in Ghana Cedis (GH₵) and include VAT where applicable.
39
- Payment is due at checkout via Mobile Money, card, or cash on delivery.
40
- We reserve the right to correct typographical pricing errors before
41
- fulfilment.
42
- </p>
43
-
44
- <h2 className="font-serif text-2xl font-semibold">4. Delivery and pickup</h2>
45
- <p>
46
- Delivery times are estimates, not guarantees. We're not liable for
47
- delays caused by weather, traffic, or events outside our control. If
48
- a rider can't reach you within 30 minutes of arrival, the order may be
49
- returned to the kitchen — please make sure your address and phone are
50
- correct.
51
- </p>
52
-
53
- <h2 className="font-serif text-2xl font-semibold">5. Custom cakes</h2>
54
- <p>
55
- Custom cake orders require a 50% deposit at booking and the balance
56
- before pickup or dispatch. Cancellations more than 72 hours before the
57
- event date receive a full refund of the deposit; within 72 hours,
58
- the deposit is non-refundable.
59
- </p>
60
-
61
- <h2 className="font-serif text-2xl font-semibold">6. Allergens</h2>
62
- <p>
63
- Our kitchen handles wheat, dairy, eggs, and tree nuts. We can't
64
- guarantee freedom from cross-contamination. Customers with severe
65
- allergies order at their own risk.
66
- </p>
67
-
68
- <h2 className="font-serif text-2xl font-semibold">7. Returns</h2>
69
- <p>
70
- Baked goods are non-returnable for food-safety reasons. If something
71
- is wrong with your order, contact us within 24 hours of delivery and
72
- we'll replace it, refund it, or credit your account — your choice.
73
- </p>
74
-
75
- <h2 className="font-serif text-2xl font-semibold">8. Liability</h2>
76
- <p>
77
- To the maximum extent permitted by Ghanaian law, our liability for any
78
- claim arising from this website or your order is limited to the value
79
- of the order. We're not liable for indirect or consequential losses.
80
- </p>
81
-
82
- <h2 className="font-serif text-2xl font-semibold">9. Governing law</h2>
83
- <p>
84
- These terms are governed by the laws of Ghana. Disputes will be
85
- resolved in the courts of Greater Accra.
86
- </p>
87
-
88
- <h2 className="font-serif text-2xl font-semibold">10. Contact</h2>
89
- <p>
90
- Questions? Email{" "}
91
- <a
92
- href="mailto:hello@akuasbakery.test"
93
- className="text-primary font-semibold hover:underline"
94
- >
95
- hello@akuasbakery.test
96
- </a>
97
- .
98
- </p>
24
+ {t.sections.map((s) => (
25
+ <div key={s.heading}>
26
+ <h2 className="font-serif text-2xl font-semibold mt-0">{s.heading}</h2>
27
+ {typeof s.body === "string" ? (
28
+ <p>{s.body}</p>
29
+ ) : (
30
+ <>
31
+ <p>{s.body.intro}</p>
32
+ <ul className="list-disc pl-6 space-y-2">
33
+ {s.body.bullets.map((b) => (
34
+ <li key={b}>{b}</li>
35
+ ))}
36
+ </ul>
37
+ </>
38
+ )}
39
+ </div>
40
+ ))}
99
41
  </section>
100
42
  </article>
101
43
  );
@@ -1,127 +1,84 @@
1
1
  import Link from "next/link";
2
+ import { brand } from "@/lib/brand";
2
3
 
3
- const SOCIALS: { label: string; href: string; svg: React.ReactNode }[] = [
4
- {
5
- label: "Instagram",
6
- href: "https://instagram.com/akuasbakery",
7
- svg: (
8
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden className="w-5 h-5">
9
- <rect x="3" y="3" width="18" height="18" rx="5" />
10
- <circle cx="12" cy="12" r="4" />
11
- <circle cx="17.5" cy="6.5" r="0.75" fill="currentColor" />
12
- </svg>
13
- ),
14
- },
15
- {
16
- label: "TikTok",
17
- href: "https://tiktok.com/@akuasbakery",
18
- svg: (
19
- <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
20
- <path d="M16 3v3.5a4.5 4.5 0 0 0 4.5 4.5V14a7.5 7.5 0 0 1-4.5-1.5V16a5 5 0 1 1-5-5v3a2 2 0 1 0 2 2V3z" />
21
- </svg>
22
- ),
23
- },
24
- {
25
- label: "X",
26
- href: "https://x.com/akuasbakery",
27
- svg: (
28
- <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
29
- <path d="M18 2h3l-7.5 8.6L22 22h-6.6l-5-6.5L4 22H1l8-9.2L1.4 2H8l4.6 6 5.4-6z" />
30
- </svg>
31
- ),
32
- },
33
- {
34
- label: "Facebook",
35
- href: "https://facebook.com/akuasbakery",
36
- svg: (
37
- <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
38
- <path d="M14 9V7a1 1 0 0 1 1-1h2V3h-3a4 4 0 0 0-4 4v2H8v3h2v9h3v-9h2.5l.5-3H13z" />
39
- </svg>
40
- ),
41
- },
42
- {
43
- label: "WhatsApp",
44
- href: "https://wa.me/233244000000",
45
- svg: (
46
- <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
47
- <path d="M12 2a10 10 0 0 0-8.6 15l-1.4 5 5.2-1.4A10 10 0 1 0 12 2zm5 14.2c-.2.6-1.2 1.2-1.7 1.2-.5.1-1.1.1-1.7-.1-.4-.1-.9-.3-1.5-.6a8.4 8.4 0 0 1-3.7-3.4c-.7-1-1-1.8-1-2.5 0-.7.4-1.1.6-1.3.2-.2.4-.2.5-.2h.4c.1 0 .3 0 .4.3l.6 1.4c.1.2 0 .3 0 .4l-.3.4-.3.3c-.1.1-.2.2-.1.4.2.4.7 1.1 1.4 1.8.9.8 1.7 1.1 1.9 1.2.2.1.3.1.5-.1l.6-.7c.2-.2.3-.2.5-.1l1.4.7c.2.1.3.2.4.3.1.2.1.6 0 1z" />
48
- </svg>
49
- ),
50
- },
51
- ];
4
+ const ICONS: Record<string, React.ReactNode> = {
5
+ instagram: (
6
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden className="w-5 h-5">
7
+ <rect x="3" y="3" width="18" height="18" rx="5" />
8
+ <circle cx="12" cy="12" r="4" />
9
+ <circle cx="17.5" cy="6.5" r="0.75" fill="currentColor" />
10
+ </svg>
11
+ ),
12
+ x: (
13
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
14
+ <path d="M18 2h3l-7.5 8.6L22 22h-6.6l-5-6.5L4 22H1l8-9.2L1.4 2H8l4.6 6 5.4-6z" />
15
+ </svg>
16
+ ),
17
+ tiktok: (
18
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
19
+ <path d="M16 3v3.5a4.5 4.5 0 0 0 4.5 4.5V14a7.5 7.5 0 0 1-4.5-1.5V16a5 5 0 1 1-5-5v3a2 2 0 1 0 2 2V3z" />
20
+ </svg>
21
+ ),
22
+ facebook: (
23
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
24
+ <path d="M14 9V7a1 1 0 0 1 1-1h2V3h-3a4 4 0 0 0-4 4v2H8v3h2v9h3v-9h2.5l.5-3H13z" />
25
+ </svg>
26
+ ),
27
+ youtube: (
28
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
29
+ <path d="M22.5 6.5a2.6 2.6 0 0 0-1.8-1.8C19 4.2 12 4.2 12 4.2s-7 0-8.7.5A2.6 2.6 0 0 0 1.5 6.5C1 8.2 1 12 1 12s0 3.8.5 5.5a2.6 2.6 0 0 0 1.8 1.8C5 19.8 12 19.8 12 19.8s7 0 8.7-.5a2.6 2.6 0 0 0 1.8-1.8c.5-1.7.5-5.5.5-5.5s0-3.8-.5-5.5zM10 15.5v-7l6 3.5-6 3.5z" />
30
+ </svg>
31
+ ),
32
+ linkedin: (
33
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
34
+ <path d="M4 4h4v16H4zM6 2.5a2 2 0 1 0 0 4 2 2 0 0 0 0-4zM10 8h4v2.5h.1c.6-1.1 2-2.5 4-2.5 4 0 4.9 2.6 4.9 6V20h-4v-5c0-1.5-.5-3-2.3-3-1.7 0-2.5 1.3-2.5 3v5h-4z" />
35
+ </svg>
36
+ ),
37
+ whatsapp: (
38
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
39
+ <path d="M12 2a10 10 0 0 0-8.6 15l-1.4 5 5.2-1.4A10 10 0 1 0 12 2zm5 14.2c-.2.6-1.2 1.2-1.7 1.2-.5.1-1.1.1-1.7-.1-.4-.1-.9-.3-1.5-.6a8.4 8.4 0 0 1-3.7-3.4c-.7-1-1-1.8-1-2.5 0-.7.4-1.1.6-1.3.2-.2.4-.2.5-.2h.4c.1 0 .3 0 .4.3l.6 1.4c.1.2 0 .3 0 .4l-.3.4-.3.3c-.1.1-.2.2-.1.4.2.4.7 1.1 1.4 1.8.9.8 1.7 1.1 1.9 1.2.2.1.3.1.5-.1l.6-.7c.2-.2.3-.2.5-.1l1.4.7c.2.1.3.2.4.3.1.2.1.6 0 1z" />
40
+ </svg>
41
+ ),
42
+ };
52
43
 
53
- const SITEMAP: { title: string; links: { label: string; href: string }[] }[] = [
54
- {
55
- title: "Shop",
56
- links: [
57
- { label: "All products", href: "/shop" },
58
- { label: "Breads", href: "/categories/breads" },
59
- { label: "Pastries", href: "/categories/pastries" },
60
- { label: "Cakes", href: "/categories/cakes" },
61
- { label: "Drinks", href: "/categories/drinks" },
62
- { label: "Merch & More", href: "/categories/merch" },
63
- { label: "Classes & Stays", href: "/categories/classes" },
64
- ],
65
- },
66
- {
67
- title: "Bakery",
68
- links: [
69
- { label: "Our story", href: "/about" },
70
- { label: "FAQ", href: "/faq" },
71
- { label: "Visit us", href: "/about#visit" },
72
- { label: "Wholesale", href: "/categories/merch" },
73
- ],
74
- },
75
- {
76
- title: "Help",
77
- links: [
78
- { label: "Contact", href: "mailto:hello@akuasbakery.test" },
79
- { label: "Custom cakes", href: "/faq#custom-cakes--celebrations" },
80
- { label: "Allergens", href: "/faq#allergens--ingredients" },
81
- { label: "Delivery", href: "/faq#ordering--delivery" },
82
- ],
83
- },
84
- {
85
- title: "Legal",
86
- links: [
87
- { label: "Terms of Service", href: "/terms" },
88
- { label: "Privacy Policy", href: "/privacy" },
89
- ],
90
- },
91
- ];
44
+ const FALLBACK_ICON = (
45
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden className="w-5 h-5">
46
+ <circle cx="12" cy="12" r="9" />
47
+ </svg>
48
+ );
92
49
 
93
50
  export async function Footer() {
94
51
  "use cache";
95
52
  const year = new Date().getFullYear();
96
53
  return (
97
- <footer className="mt-16 border-t border-border bg-card text-sm">
98
- <div className="max-w-7xl mx-auto px-8 pt-12 pb-8">
54
+ <footer className="mt-12 px-8 py-10 text-xs text-muted-foreground border-t border-border bg-card">
55
+ <div className="max-w-7xl mx-auto">
99
56
  <div className="grid gap-10 md:grid-cols-[1.4fr_repeat(4,1fr)]">
100
57
  <div>
101
- <p className="font-serif text-2xl text-foreground m-0 mb-2">Akua&apos;s Bakery</p>
102
- <p className="text-muted-foreground leading-relaxed mb-4 max-w-sm">
103
- Family-run bakery in East Legon. Sourdough, croissants, layered
104
- cakes — handcrafted since 2018, delivered across Accra.
105
- </p>
106
- <address className="not-italic text-muted-foreground space-y-1">
107
- <p className="m-0">12 Independence Ave, Accra</p>
58
+ <p className="font-serif text-2xl text-foreground m-0 mb-2">{brand.name}</p>
59
+ <p className="leading-relaxed mb-4 max-w-sm">{brand.footer.blurb}</p>
60
+ <address className="not-italic space-y-1">
61
+ <p className="m-0">{brand.contact.address}</p>
108
62
  <p className="m-0">
109
- <a href="tel:+233244000000" className="hover:text-foreground transition-colors">
110
- +233 244 000 000
63
+ <a
64
+ href={`tel:${brand.contact.phoneTel}`}
65
+ className="hover:text-foreground transition-colors"
66
+ >
67
+ {brand.contact.phone}
111
68
  </a>
112
69
  </p>
113
70
  <p className="m-0">
114
71
  <a
115
- href="mailto:hello@akuasbakery.test"
72
+ href={`mailto:${brand.contact.email}`}
116
73
  className="hover:text-foreground transition-colors"
117
74
  >
118
- hello@akuasbakery.test
75
+ {brand.contact.email}
119
76
  </a>
120
77
  </p>
121
- <p className="m-0 text-xs">Tue–Sun · 8am–8pm · closed Mondays</p>
78
+ <p className="m-0">{brand.contact.hours}</p>
122
79
  </address>
123
80
  <div className="flex items-center gap-3 mt-5">
124
- {SOCIALS.map((s) => (
81
+ {brand.socials.map((s) => (
125
82
  <a
126
83
  key={s.label}
127
84
  href={s.href}
@@ -130,12 +87,12 @@ export async function Footer() {
130
87
  rel="noopener noreferrer"
131
88
  className="inline-flex items-center justify-center w-9 h-9 rounded-full border border-border text-muted-foreground hover:text-foreground hover:border-foreground transition-colors"
132
89
  >
133
- {s.svg}
90
+ {(s.icon && ICONS[s.icon]) ?? FALLBACK_ICON}
134
91
  </a>
135
92
  ))}
136
93
  </div>
137
94
  </div>
138
- {SITEMAP.map((section) => (
95
+ {brand.footer.sitemap.map((section) => (
139
96
  <nav key={section.title} aria-labelledby={`footer-${section.title}`}>
140
97
  <p
141
98
  id={`footer-${section.title}`}
@@ -148,7 +105,7 @@ export async function Footer() {
148
105
  <li key={link.label}>
149
106
  <Link
150
107
  href={link.href}
151
- className="text-muted-foreground hover:text-foreground transition-colors"
108
+ className="hover:text-foreground transition-colors"
152
109
  >
153
110
  {link.label}
154
111
  </Link>
@@ -158,31 +115,32 @@ export async function Footer() {
158
115
  </nav>
159
116
  ))}
160
117
  </div>
161
-
162
- <div className="mt-12 pt-6 border-t border-border flex flex-col sm:flex-row items-center justify-between gap-3 text-xs text-muted-foreground">
163
- <p className="m-0">© {year} Akua&apos;s Bakery. All rights reserved.</p>
164
- <p className="m-0 inline-flex items-center gap-1.5">
165
- <span className="text-muted-foreground/80">Powered by</span>
166
- <a
167
- href="https://app.cimplify.io"
168
- target="_blank"
169
- rel="noopener noreferrer"
170
- aria-label="Cimplify"
171
- className="inline-flex items-center gap-1 font-serif text-foreground hover:text-primary transition-colors"
172
- >
173
- <span className="font-semibold tracking-tight">Cimplify</span>
174
- <svg
175
- viewBox="0 0 12 12"
176
- aria-hidden
177
- className="w-3 h-3 opacity-70"
178
- fill="none"
179
- stroke="currentColor"
180
- strokeWidth="1.5"
118
+ <div className="mt-12 pt-6 border-t border-border flex flex-col sm:flex-row items-center justify-between gap-3">
119
+ <p className="m-0">© {year} {brand.name}. All rights reserved.</p>
120
+ {brand.footer.poweredBy && (
121
+ <p className="m-0 inline-flex items-center gap-1.5">
122
+ <span className="text-muted-foreground/80">Powered by</span>
123
+ <a
124
+ href={brand.footer.poweredBy.href}
125
+ target="_blank"
126
+ rel="noopener noreferrer"
127
+ aria-label={brand.footer.poweredBy.label}
128
+ className="inline-flex items-center gap-1 font-serif text-foreground hover:text-primary transition-colors"
181
129
  >
182
- <path d="M3 9L9 3M9 3H4M9 3v5" strokeLinecap="round" strokeLinejoin="round" />
183
- </svg>
184
- </a>
185
- </p>
130
+ <span className="font-semibold tracking-tight">{brand.footer.poweredBy.label}</span>
131
+ <svg
132
+ viewBox="0 0 12 12"
133
+ aria-hidden
134
+ className="w-3 h-3 opacity-70"
135
+ fill="none"
136
+ stroke="currentColor"
137
+ strokeWidth="1.5"
138
+ >
139
+ <path d="M3 9L9 3M9 3H4M9 3v5" strokeLinecap="round" strokeLinejoin="round" />
140
+ </svg>
141
+ </a>
142
+ </p>
143
+ )}
186
144
  </div>
187
145
  </div>
188
146
  </footer>
@@ -2,8 +2,7 @@ import Link from "next/link";
2
2
  import { Suspense } from "react";
3
3
  import { NavLink } from "./nav-link";
4
4
  import { CartPill, CartPillSkeleton } from "./cart-pill";
5
-
6
- const TAGLINE = "ACCRA · SINCE 2018";
5
+ import { brand } from "@/lib/brand";
7
6
 
8
7
  /**
9
8
  * Server-rendered header chrome. Brand mark + nav layout streams from the
@@ -15,25 +14,18 @@ export function Header() {
15
14
  <header className="sticky top-0 z-30 flex items-center justify-between px-8 py-4 border-b border-border bg-background/90 backdrop-blur-md">
16
15
  <Link href="/" className="flex items-baseline gap-2">
17
16
  <span className="font-serif text-[22px] font-semibold -tracking-[0.02em]">
18
- Akua&apos;s Bakery
17
+ {brand.shortName}
19
18
  </span>
20
19
  <span className="text-[11px] font-medium uppercase tracking-[0.12em] text-muted-foreground">
21
- {TAGLINE}
20
+ {brand.microTag}
22
21
  </span>
23
22
  </Link>
24
23
  <nav className="flex items-center gap-6">
25
- <Suspense fallback={<NavLinkFallback>Home</NavLinkFallback>}>
26
- <NavLink href="/">Home</NavLink>
27
- </Suspense>
28
- <Suspense fallback={<NavLinkFallback>Shop</NavLinkFallback>}>
29
- <NavLink href="/shop">Shop</NavLink>
30
- </Suspense>
31
- <Suspense fallback={<NavLinkFallback>About</NavLinkFallback>}>
32
- <NavLink href="/about">About</NavLink>
33
- </Suspense>
34
- <Suspense fallback={<NavLinkFallback>FAQ</NavLinkFallback>}>
35
- <NavLink href="/faq">FAQ</NavLink>
36
- </Suspense>
24
+ {brand.header.nav.map((link) => (
25
+ <Suspense key={link.href} fallback={<NavLinkFallback>{link.label}</NavLinkFallback>}>
26
+ <NavLink href={link.href}>{link.label}</NavLink>
27
+ </Suspense>
28
+ ))}
37
29
  <Suspense fallback={<CartPillSkeleton />}>
38
30
  <CartPill />
39
31
  </Suspense>