@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
@@ -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: `Create an account — ${brand.name}`,
7
+ description: brand.account.signupSubtitle,
8
+ };
9
+
10
+ /**
11
+ * Cimplify Link handles sign-up inside the `<CimplifyAccount>` iframe.
12
+ * We bounce /signup to /account; the iframe shows the create-account UI
13
+ * for visitors with no session.
14
+ */
15
+ export default function SignupPage(): never {
16
+ redirect("/account");
17
+ }
@@ -0,0 +1,167 @@
1
+ import type { Metadata } from "next";
2
+ import Link from "next/link";
3
+ import { cacheTag, cacheLife } from "next/cache";
4
+ import { getServerClient, tags, type Product } from "@cimplify/sdk/server";
5
+ import { brand } from "@/lib/brand";
6
+
7
+ export const metadata: Metadata = {
8
+ title: `Sitemap — ${brand.name}`,
9
+ description: "A human-readable index of every page on this site.",
10
+ };
11
+
12
+ interface SitemapData {
13
+ products: { slug: string; name: string }[];
14
+ categories: { slug: string; name: string }[];
15
+ collections: { slug: string; name: string }[];
16
+ }
17
+
18
+ async function getSitemap(): Promise<SitemapData> {
19
+ "use cache";
20
+ cacheTag(tags.products(), tags.categories(), tags.collections());
21
+ cacheLife("hours");
22
+
23
+ const client = getServerClient();
24
+ const [pRes, cRes, colRes] = await Promise.all([
25
+ client.catalogue.getProducts({ limit: 500 }),
26
+ client.catalogue.getCategories(),
27
+ client.catalogue.getCollections(),
28
+ ]);
29
+ return {
30
+ products: (pRes.ok ? pRes.value.items : []).map((p: Product) => ({
31
+ slug: p.slug ?? p.id,
32
+ name: p.name,
33
+ })),
34
+ categories: (cRes.ok ? cRes.value : []).map((c) => ({ slug: c.slug, name: c.name })),
35
+ collections: (colRes.ok ? colRes.value : []).map((c) => ({ slug: c.slug, name: c.name })),
36
+ };
37
+ }
38
+
39
+ const STATIC_LINKS: { title: string; links: { href: string; label: string }[] }[] = [
40
+ {
41
+ title: "Browse",
42
+ links: [
43
+ { href: "/", label: "Home" },
44
+ { href: "/shop", label: "Shop" },
45
+ { href: "/search", label: "Search" },
46
+ ],
47
+ },
48
+ {
49
+ title: "Account",
50
+ links: [
51
+ { href: "/account", label: "Account" },
52
+ { href: "/account/orders", label: "Orders" },
53
+ { href: "/account/addresses", label: "Addresses" },
54
+ { href: "/account/settings", label: "Settings" },
55
+ { href: "/login", label: "Sign in" },
56
+ { href: "/signup", label: "Create account" },
57
+ { href: "/track-order", label: "Track an order" },
58
+ { href: "/cart", label: "Cart" },
59
+ { href: "/checkout", label: "Checkout" },
60
+ ],
61
+ },
62
+ {
63
+ title: "About",
64
+ links: [
65
+ { href: "/about", label: "About" },
66
+ { href: "/faq", label: "FAQ" },
67
+ { href: "/contact", label: "Contact" },
68
+ ],
69
+ },
70
+ {
71
+ title: "Policies",
72
+ links: [
73
+ { href: "/shipping", label: "Shipping" },
74
+ { href: "/returns", label: "Returns" },
75
+ { href: "/accessibility", label: "Accessibility" },
76
+ { href: "/terms", label: "Terms of Service" },
77
+ { href: "/privacy", label: "Privacy Policy" },
78
+ ],
79
+ },
80
+ {
81
+ title: "Machine-readable",
82
+ links: [
83
+ { href: "/sitemap.xml", label: "sitemap.xml (search engines)" },
84
+ { href: "/llms.txt", label: "llms.txt (LLM agents)" },
85
+ { href: "/robots.txt", label: "robots.txt" },
86
+ { href: "/opensearch.xml", label: "opensearch.xml (browser search)" },
87
+ ],
88
+ },
89
+ ];
90
+
91
+ export default async function SitemapHtmlPage() {
92
+ const { products, categories, collections } = await getSitemap();
93
+
94
+ return (
95
+ <article className="max-w-5xl mx-auto px-6 sm:px-8 py-16">
96
+ <p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-primary mb-2">
97
+ Sitemap
98
+ </p>
99
+ <h1 className="text-[clamp(2rem,4vw,2.75rem)] font-semibold mb-2 -tracking-[0.02em]">
100
+ Every page, in one place.
101
+ </h1>
102
+ <p className="text-muted-foreground mb-12">
103
+ For search engines, see <Link href="/sitemap.xml" className="text-primary hover:underline">/sitemap.xml</Link>.
104
+ For LLM agents, see <Link href="/llms.txt" className="text-primary hover:underline">/llms.txt</Link>.
105
+ </p>
106
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
107
+ {STATIC_LINKS.map((s) => (
108
+ <Section key={s.title} title={s.title}>
109
+ {s.links.map((l) => (
110
+ <li key={l.href}>
111
+ <Link href={l.href} className="hover:text-primary transition-colors">
112
+ {l.label}
113
+ </Link>
114
+ </li>
115
+ ))}
116
+ </Section>
117
+ ))}
118
+ {categories.length > 0 && (
119
+ <Section title="Categories">
120
+ {categories.map((c) => (
121
+ <li key={c.slug}>
122
+ <Link href={`/categories/${c.slug}`} className="hover:text-primary transition-colors">
123
+ {c.name}
124
+ </Link>
125
+ </li>
126
+ ))}
127
+ </Section>
128
+ )}
129
+ {collections.length > 0 && (
130
+ <Section title="Collections">
131
+ {collections.map((c) => (
132
+ <li key={c.slug}>
133
+ <Link href={`/collections/${c.slug}`} className="hover:text-primary transition-colors">
134
+ {c.name}
135
+ </Link>
136
+ </li>
137
+ ))}
138
+ </Section>
139
+ )}
140
+ {products.length > 0 && (
141
+ <Section title={`Products (${products.length})`}>
142
+ {products.map((p) => (
143
+ <li key={p.slug}>
144
+ <Link href={`/shop?product=${encodeURIComponent(p.slug)}`} className="hover:text-primary transition-colors">
145
+ {p.name}
146
+ </Link>
147
+ </li>
148
+ ))}
149
+ </Section>
150
+ )}
151
+ </div>
152
+ </article>
153
+ );
154
+ }
155
+
156
+ function Section({ title, children }: { title: string; children: React.ReactNode }) {
157
+ return (
158
+ <div>
159
+ <p className="font-semibold text-[12px] uppercase tracking-[0.12em] text-foreground mb-3">
160
+ {title}
161
+ </p>
162
+ <ul className="space-y-2 m-0 p-0 list-none text-sm text-muted-foreground">
163
+ {children}
164
+ </ul>
165
+ </div>
166
+ );
167
+ }
@@ -0,0 +1,24 @@
1
+ import type { Metadata } from "next";
2
+ import { TrackOrderForm } from "./track-order-form";
3
+ import { brand } from "@/lib/brand";
4
+
5
+ export const metadata: Metadata = {
6
+ title: `Track an order — ${brand.name}`,
7
+ description: brand.trackOrder.body,
8
+ };
9
+
10
+ export default function TrackOrderPage() {
11
+ const t = brand.trackOrder;
12
+ return (
13
+ <article className="max-w-2xl 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
+ {t.eyebrow}
16
+ </p>
17
+ <h1 className="font-serif text-[clamp(2rem,5vw,3rem)] font-semibold mb-4 -tracking-[0.02em]">
18
+ {t.title}
19
+ </h1>
20
+ <p className="text-muted-foreground leading-relaxed mb-8">{t.body}</p>
21
+ <TrackOrderForm />
22
+ </article>
23
+ );
24
+ }
@@ -0,0 +1,69 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { useRouter } from "next/navigation";
5
+
6
+ /**
7
+ * Guest order tracker. Routes /orders/<id> with the entered id; the
8
+ * post-checkout confirmation page already lives at /orders/[id] so this
9
+ * just sends the visitor there. Replace the redirect with a real lookup
10
+ * (e.g. Cimplify orders API + email-match guard) for production.
11
+ */
12
+ export function TrackOrderForm() {
13
+ const router = useRouter();
14
+ const [orderId, setOrderId] = useState("");
15
+ const [email, setEmail] = useState("");
16
+
17
+ return (
18
+ <form
19
+ onSubmit={(e) => {
20
+ e.preventDefault();
21
+ if (!orderId.trim()) return;
22
+ router.push(`/orders/${encodeURIComponent(orderId.trim())}`);
23
+ }}
24
+ className="space-y-4 rounded-2xl border border-border bg-card p-6"
25
+ >
26
+ <div>
27
+ <label
28
+ htmlFor="orderId"
29
+ className="text-xs font-semibold uppercase tracking-wider text-muted-foreground block mb-1.5"
30
+ >
31
+ Order number
32
+ </label>
33
+ <input
34
+ id="orderId"
35
+ name="orderId"
36
+ required
37
+ value={orderId}
38
+ onChange={(e) => setOrderId(e.target.value)}
39
+ placeholder="ord_abc123…"
40
+ className="w-full px-4 py-3 rounded-md bg-background border border-border focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none text-sm"
41
+ />
42
+ </div>
43
+ <div>
44
+ <label
45
+ htmlFor="email"
46
+ className="text-xs font-semibold uppercase tracking-wider text-muted-foreground block mb-1.5"
47
+ >
48
+ Order email
49
+ </label>
50
+ <input
51
+ id="email"
52
+ name="email"
53
+ type="email"
54
+ required
55
+ value={email}
56
+ onChange={(e) => setEmail(e.target.value)}
57
+ placeholder="you@email.com"
58
+ className="w-full px-4 py-3 rounded-md bg-background border border-border focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none text-sm"
59
+ />
60
+ </div>
61
+ <button
62
+ type="submit"
63
+ className="w-full 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"
64
+ >
65
+ Track order
66
+ </button>
67
+ </form>
68
+ );
69
+ }
@@ -0,0 +1,13 @@
1
+ "use client";
2
+
3
+ import { CimplifyAccount } from "@cimplify/sdk/react";
4
+
5
+ /**
6
+ * Cimplify Account portal — iframe-mounted UI hosted by Cimplify Link.
7
+ * Handles sign-in, sign-up, OTP, addresses, payment methods, sessions,
8
+ * and order history. The iframe owns auth state; we just choose which
9
+ * `section` to land on.
10
+ */
11
+ export function AccountIframe({ section }: { section?: string }) {
12
+ return <CimplifyAccount section={section} />;
13
+ }
@@ -0,0 +1,49 @@
1
+ import type { BrandPolicySection } from "@/lib/brand";
2
+
3
+ interface PolicyShape {
4
+ eyebrow: string;
5
+ title: string;
6
+ lastUpdated?: string;
7
+ sections: BrandPolicySection[];
8
+ }
9
+
10
+ /**
11
+ * Shared layout for shipping / returns / accessibility / terms / privacy.
12
+ * Reads a `{ eyebrow, title, lastUpdated, sections[] }` block from brand.
13
+ */
14
+ export function PolicyPage({ policy }: { policy: PolicyShape }) {
15
+ return (
16
+ <article className="max-w-3xl mx-auto px-8 py-16 prose prose-lg max-w-none">
17
+ <p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-primary mb-2 not-prose">
18
+ {policy.eyebrow}
19
+ </p>
20
+ <h1 className="text-[clamp(2.25rem,5vw,3.5rem)] font-semibold mb-2 -tracking-[0.02em]">
21
+ {policy.title}
22
+ </h1>
23
+ {policy.lastUpdated && (
24
+ <p className="text-sm text-muted-foreground not-prose mb-10">
25
+ Last updated: {policy.lastUpdated}
26
+ </p>
27
+ )}
28
+ <section className="space-y-5 leading-relaxed text-foreground/90">
29
+ {policy.sections.map((s) => (
30
+ <div key={s.heading}>
31
+ <h2 className="text-2xl font-semibold mt-0">{s.heading}</h2>
32
+ {typeof s.body === "string" ? (
33
+ <p>{s.body}</p>
34
+ ) : (
35
+ <>
36
+ <p>{s.body.intro}</p>
37
+ <ul className="list-disc pl-6 space-y-2">
38
+ {s.body.bullets.map((b) => (
39
+ <li key={b}>{b}</li>
40
+ ))}
41
+ </ul>
42
+ </>
43
+ )}
44
+ </div>
45
+ ))}
46
+ </section>
47
+ </article>
48
+ );
49
+ }
@@ -58,6 +58,20 @@ export interface Brand {
58
58
  };
59
59
  terms: { eyebrow: string; title: string; lastUpdated: string; sections: BrandPolicySection[] };
60
60
  privacy: { eyebrow: string; title: string; lastUpdated: string; sections: BrandPolicySection[] };
61
+ shipping: { eyebrow: string; title: string; lastUpdated: string; sections: BrandPolicySection[] };
62
+ returns: { eyebrow: string; title: string; lastUpdated: string; sections: BrandPolicySection[] };
63
+ accessibility: { eyebrow: string; title: string; lastUpdated: string; sections: BrandPolicySection[] };
64
+ account: {
65
+ loginEyebrow: string; loginTitle: string; loginSubtitle: string;
66
+ signupEyebrow: string; signupTitle: string; signupSubtitle: string;
67
+ accountEyebrow: string; accountTitle: string;
68
+ };
69
+ contactPage: {
70
+ eyebrow: string; title: string; body: string;
71
+ reasons: string[];
72
+ directLines: { label: string; value: string; href: string }[];
73
+ };
74
+ trackOrder: { eyebrow: string; title: string; body: string };
61
75
  footer: {
62
76
  blurb: string; sitemap: BrandSitemapSection[];
63
77
  poweredBy?: { label: string; href: string };
@@ -232,6 +246,68 @@ export const brand: Brand = {
232
246
  ],
233
247
  },
234
248
 
249
+ shipping: {
250
+ eyebrow: "Delivery",
251
+ title: "Delivery & Pickup",
252
+ lastUpdated: "1 May 2026",
253
+ sections: [
254
+ { heading: "Greater Accra", body: "Same-day, 12pm–9pm Tue–Sun. Free over GH₵250; GH₵35 below. Typical 60-minute window from order." },
255
+ { heading: "Pickup", body: "Skip the queue: order ahead, pick a window, walk in. Free." },
256
+ { heading: "Catering & private events", body: "Off-site catering (12+ people) requires 5 days' notice. Email events@mamaskitchen.test." },
257
+ ],
258
+ },
259
+
260
+ returns: {
261
+ eyebrow: "Refunds",
262
+ title: "Refunds & Quality",
263
+ lastUpdated: "1 May 2026",
264
+ sections: [
265
+ { heading: "Quality guarantee", body: "If anything is wrong with your order — wrong dish, cold, off — message us within 2 hours and we'll replace, refund, or credit." },
266
+ { heading: "Reservation cancellations", body: "Free up to 4 hours before. Within 4 hours, parties of 6+ are charged GH₵60/cover for no-shows." },
267
+ { heading: "Custom event deposits", body: "Refundable up to 7 days before the event. Within 7 days, deposits are non-refundable." },
268
+ ],
269
+ },
270
+
271
+ accessibility: {
272
+ eyebrow: "Accessibility",
273
+ title: "Accessibility Statement",
274
+ lastUpdated: "1 May 2026",
275
+ sections: [
276
+ { heading: "In the dining room", body: "Step-free entrance, accessible bathroom, and a flat path from the curb. Service dogs welcome. We can move tables in advance — let us know at booking." },
277
+ { heading: "Online", body: "We aim for WCAG 2.1 AA on the website and test it on every release." },
278
+ { heading: "Reporting issues", body: "Email accessibility@mamaskitchen.test or call ahead — we respond within a business day." },
279
+ ],
280
+ },
281
+
282
+ account: {
283
+ loginEyebrow: "Welcome back",
284
+ loginTitle: "Sign in to Mama's",
285
+ loginSubtitle: "Pick up where you left off — orders, reservations, and your favourites.",
286
+ signupEyebrow: "Welcome",
287
+ signupTitle: "Create an account",
288
+ signupSubtitle: "Reorder in one tap, hold tables faster, and get first-look at the long-table evenings.",
289
+ accountEyebrow: "Your account",
290
+ accountTitle: "Welcome back",
291
+ },
292
+
293
+ contactPage: {
294
+ eyebrow: "Contact",
295
+ title: "Talk to the kitchen.",
296
+ body: "Reservation question, dietary need, private event — message us and we'll reply within a business day.",
297
+ reasons: ["Reservation question", "An order issue", "Dietary / allergens", "Private event", "Press / partnerships", "Something else"],
298
+ directLines: [
299
+ { label: "Email", value: "hello@mamaskitchen.test", href: "mailto:hello@mamaskitchen.test" },
300
+ { label: "Phone", value: "+233 244 200 100", href: "tel:+233244200100" },
301
+ { label: "WhatsApp", value: "+233 244 200 100", href: "https://wa.me/233244200100" },
302
+ ],
303
+ },
304
+
305
+ trackOrder: {
306
+ eyebrow: "Track an order",
307
+ title: "Where's my order?",
308
+ body: "Enter your order number and the email used at checkout. We'll show the kitchen status, the rider, and the live ETA.",
309
+ },
310
+
235
311
  footer: {
236
312
  blurb:
237
313
  "West African plates, prepared by our matriarchs, served family-style in East Legon. Dine in, take out, deliver.",
@@ -258,10 +334,20 @@ export const brand: Brand = {
258
334
  {
259
335
  title: "Help",
260
336
  links: [
261
- { label: "Contact", href: "mailto:hello@mamaskitchen.test" },
337
+ { label: "Contact", href: "/contact" },
338
+ { label: "Track an order", href: "/track-order" },
339
+ { label: "Delivery", href: "/shipping" },
340
+ { label: "Refunds", href: "/returns" },
262
341
  { label: "FAQ", href: "/faq" },
263
- { label: "Allergens", href: "/faq" },
264
- { label: "Delivery", href: "/faq" },
342
+ ],
343
+ },
344
+ {
345
+ title: "Account",
346
+ links: [
347
+ { label: "Sign in", href: "/login" },
348
+ { label: "Create account", href: "/signup" },
349
+ { label: "Your orders", href: "/account/orders" },
350
+ { label: "Settings", href: "/account/settings" },
265
351
  ],
266
352
  },
267
353
  {
@@ -269,6 +355,8 @@ export const brand: Brand = {
269
355
  links: [
270
356
  { label: "Terms of Service", href: "/terms" },
271
357
  { label: "Privacy Policy", href: "/privacy" },
358
+ { label: "Accessibility", href: "/accessibility" },
359
+ { label: "Sitemap", href: "/sitemap-page" },
272
360
  ],
273
361
  },
274
362
  ],
@@ -4,39 +4,75 @@ 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
- To rebrand this storefront end-to-end as a different merchant:
7
+ 1. **Edit `lib/brand.ts`** — every visible string lives here.
8
+ 2. **Edit `app/globals.css`** — `@theme { … }` block for palette + radius + font references.
9
+ 3. **Edit `.env.local`** — `NEXT_PUBLIC_CIMPLIFY_API_URL`, `NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY`, `NEXT_PUBLIC_CIMPLIFY_BUSINESS_ID`, `NEXT_PUBLIC_SITE_URL`.
8
10
 
9
- 1. **Edit `lib/brand.ts`.** Every visible string reads from this file. Replace each field with the merchant's actual content.
10
- 2. **Edit `app/globals.css`** — the `@theme { … }` block holds the design tokens (palette, radius, font references). Tweak to match the merchant's brand.
11
- 3. **Edit `.env.local`** — set `NEXT_PUBLIC_CIMPLIFY_API_URL`, `NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY`, `NEXT_PUBLIC_CIMPLIFY_BUSINESS_ID`, `NEXT_PUBLIC_SITE_URL`.
11
+ ## Aesthetic
12
12
 
13
- That is the entire rebrand. Do not modify any `.tsx` file in `app/` or `components/` for content changes — they are design-only and read from `brand`.
13
+ - **Inter + JetBrains Mono** — clean modern sans, mono-spaced labels for spec-feel.
14
+ - **Cool navy + electric blue**: dark foreground, electric primary.
15
+ - **Sharp corners**: `0.5rem` — modern retail.
16
+ - **Section heroes** in dark with mono-spaced eyebrow labels.
14
17
 
15
- ## Rules
18
+ ## Page surface
16
19
 
17
- - ✅ All content edits → `lib/brand.ts`
18
- - ✅ All design-token edits → `app/globals.css` `@theme` block
19
- - ✅ Server Components stay cached via `'use cache'` + `cacheTag(tags.X())` + `cacheLife("hours")`
20
- - ✅ Client islands (header active link, cart pill, product card link) live behind `<Suspense>`
21
- - ❌ Don't hardcode strings. If a string isn't in `brand`, add a new field to the `Brand` interface.
22
- - ❌ Don't disable `cacheComponents: true` in `next.config.ts`.
23
- - ❌ Don't use `unstable_cache` — Next 16 uses the `'use cache'` directive.
20
+ ```
21
+ app/
22
+ page.tsx Multi-section home — split hero, trust bar, category tiles,
23
+ promo banner, "Just dropped" grid, brand strip, collections,
24
+ trade-in CTA, best sellers, newsletter
25
+ shop/page.tsx SDK <CataloguePage/> with custom hero
26
+ search/page.tsx Search (SDK <SearchPage/>)
27
+ collections/[slug]/page.tsx Collection landing
28
+ categories/[slug]/page.tsx Category landing
29
+ products/[slug]/page.tsx Full product detail page (Product JSON-LD)
30
+
31
+ cart/page.tsx SDK <CartPage/>
32
+ checkout/page.tsx SDK <CheckoutPage/>
33
+ orders/[id]/page.tsx Post-checkout confirmation
34
+
35
+ account/page.tsx <CimplifyAccount /> (iframe)
36
+ account/orders/page.tsx <CimplifyAccount section="orders" />
37
+ account/addresses/page.tsx <CimplifyAccount section="addresses" />
38
+ account/settings/page.tsx <CimplifyAccount section="settings" />
39
+ login/page.tsx, signup/page.tsx redirects → /account
40
+
41
+ contact/page.tsx Branded contact form
42
+ track-order/page.tsx Guest lookup → /orders/[id]
43
+
44
+ about/page.tsx, faq/page.tsx Brand pages
45
+ shipping/page.tsx, returns/page.tsx, accessibility/page.tsx Standalone policies
46
+ terms/page.tsx, privacy/page.tsx
47
+
48
+ sitemap-page/page.tsx HTML sitemap
49
+ sitemap.ts, robots.ts XML sitemap, robots.txt
50
+ llms.txt/route.ts LLM-friendly site index
51
+ opensearch.xml/route.ts Browser search description
52
+ error.tsx, not-found.tsx Global boundaries
53
+ ```
24
54
 
25
- ## File map (what reads from where)
55
+ ## File ↔ brand-field map
26
56
 
27
57
  | File | Reads from `brand` |
28
58
  |---|---|
29
- | `app/layout.tsx` | metadata, OpenGraph, Organization JSON-LD |
59
+ | `app/layout.tsx` | identity, contact, socials, schemaType (Store JSON-LD) |
30
60
  | `app/page.tsx` | `brand.hero`, `brand.trustItems`, `brand.brandStrip`, `brand.promo`, `brand.tradeIn`, `brand.newsletter` |
31
61
  | `app/about/page.tsx` | `brand.about` |
32
62
  | `app/faq/page.tsx` | `brand.faq` |
33
63
  | `app/terms/page.tsx` | `brand.terms` |
34
64
  | `app/privacy/page.tsx` | `brand.privacy` |
35
- | `app/products/[slug]/page.tsx` | `brand.name`, `brand.currency` (Product JSON-LD) |
65
+ | `app/shipping/page.tsx` | `brand.shipping` (warranty + returns + same-day delivery copy) |
66
+ | `app/returns/page.tsx` | `brand.returns` |
67
+ | `app/accessibility/page.tsx` | `brand.accessibility` |
68
+ | `app/contact/page.tsx` | `brand.contactPage`, `brand.contact` |
69
+ | `app/track-order/page.tsx` | `brand.trackOrder` |
70
+ | `app/account/*/page.tsx` | `brand.account` (Cimplify Link iframe owns the UI) |
71
+ | `app/products/[slug]/page.tsx` | `brand.name`, `brand.currency` (Product JSON-LD: brand, offer, availability) |
36
72
  | `app/llms.txt/route.ts` | `brand.llms`, contact, currency |
37
- | `app/not-found.tsx` | `brand.name` (page title) |
73
+ | `app/opensearch.xml/route.ts` | `brand.shortName`, `brand.name` |
38
74
  | `components/header.tsx` | `brand.shortName`, `brand.microTag`, `brand.header.nav` |
39
- | `components/footer.tsx` | `brand.footer`, contact, socials |
75
+ | `components/footer.tsx` | `brand.footer`, `brand.contact`, `brand.socials` |
40
76
  | `components/promo-banner.tsx` | `brand.promo` (renders nothing if absent) |
41
77
  | `components/trade-in-cta.tsx` | `brand.tradeIn` (renders nothing if absent) |
42
78
  | `components/brand-marquee.tsx` | `brand.brandStrip` |
@@ -45,20 +81,25 @@ That is the entire rebrand. Do not modify any `.tsx` file in `app/` or `componen
45
81
 
46
82
  ## Retail-specific notes
47
83
 
48
- - Product detail is a **full `/products/[slug]` page** with image gallery, customizer, related products rail, and Product JSON-LD. This fits consideration-purchase electronics UX (specs, reviews, warranty). Do not replace with a modal.
49
- - Schema.org type is `Store`. Change in `lib/brand.ts` (`schemaType`) for a different industry.
50
- - Optional sections render conditionally: `brand.promo`, `brand.tradeIn`, `brand.trustItems`, `brand.brandStrip` — set to `undefined` to hide.
51
- - `app/page.tsx` uses Unsplash fallback hero image (`HERO_FALLBACK_IMAGE`) — replace with your own asset URL.
84
+ - Product detail is a **full `/products/[slug]` page** with image gallery, customizer, related products rail, and Product JSON-LD. Consideration purchases (phones, laptops, headphones) need real estate. Don't replace with a modal.
85
+ - Schema.org `@type` is `Store`.
86
+ - Optional sections render conditionally: set `brand.promo`, `brand.tradeIn`, `brand.trustItems`, or `brand.brandStrip` to `undefined` to hide them.
87
+ - `app/page.tsx` uses an Unsplash fallback hero (`HERO_FALLBACK_IMAGE`) — replace with the merchant's own product photography.
88
+
89
+ ## Known TODOs
90
+
91
+ - Contact form + newsletter signup currently fake their submit. Wire `client.support.sendMessage(...)` for contact and a real list provider for newsletter.
92
+ - Trust-bar / brand-marquee imagery / wordmarks are placeholders — swap for the merchant's real partners.
52
93
 
53
94
  ## Mock seed
54
95
 
55
- Wired to `--seed retail` (Currents Electronics) via `package.json` `dev:mock`. To preview another seed, change the flag or run `bunx @cimplify/sdk --seed services` directly and update `NEXT_PUBLIC_CIMPLIFY_BUSINESS_ID` in `.env.local`.
96
+ Wired to `--seed retail` (Currents Electronics). Edit `dev:mock` in `package.json` to preview another seed.
56
97
 
57
98
  ## Quick start
58
99
 
59
100
  ```bash
60
101
  bun install
61
- bun dev # boots mock + Next dev server
102
+ bun dev
62
103
  ```
63
104
 
64
105
  Open <http://localhost:3000>.
@@ -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
+ }