Who is it for?
-
- {giftingCategories.map((c, i) => (
-
-
-
-
- {c.name}
-
-
-
- ))}
+
+
+ Gifts, price by price
+
+
+
+
diff --git a/src/components/ContactForm.tsx b/src/components/ContactForm.tsx
new file mode 100644
index 0000000..63ed5fa
--- /dev/null
+++ b/src/components/ContactForm.tsx
@@ -0,0 +1,257 @@
+import { useState, type FormEvent, type ReactNode } from "react";
+import { submitEnquiry, type EnquiryResult } from "@/data/enquiry";
+
+/**
+ * Editorial form used in two places:
+ * variant="contact" — the Contact Us page
+ * variant="bespoke" — bulk gifting / bespoke gifting enquiries
+ */
+
+const CONTACT_TOPICS = [
+ "General enquiry",
+ "My order",
+ "Feedback",
+ "Press & collaborations",
+];
+
+const BESPOKE_TYPES = [
+ "Corporate & bulk gifting",
+ "Weddings & celebrations",
+ "Brand collaboration",
+ "Events & experiences",
+ "Custom packaging",
+];
+
+const BUDGETS = [
+ "Under ₹25,000",
+ "₹25,000 – ₹1,00,000",
+ "₹1,00,000 – ₹5,00,000",
+ "Above ₹5,00,000",
+];
+
+const inputClass =
+ "mt-2 w-full border-b border-ink-900/20 bg-transparent pb-3 pt-1 text-[1.05rem] font-light text-ink-900 outline-none transition-colors duration-300 placeholder:text-ink-500/40 focus:border-orange-500";
+
+function Field({
+ label,
+ error,
+ children,
+ className = "",
+}: {
+ label: string;
+ error?: string;
+ children: ReactNode;
+ className?: string;
+}) {
+ return (
+
+ {label}
+ {children}
+ {error && {error} }
+
+ );
+}
+
+export default function ContactForm({ variant }: { variant: "contact" | "bespoke" }) {
+ const bespoke = variant === "bespoke";
+ const [pending, setPending] = useState(false);
+ const [errors, setErrors] = useState
>({});
+ const [done, setDone] = useState(false);
+
+ async function onSubmit(event: FormEvent) {
+ event.preventDefault();
+ const form = event.currentTarget;
+ const f = new FormData(form);
+ const get = (k: string) => String(f.get(k) ?? "").trim();
+
+ setPending(true);
+ setErrors({});
+ let result: EnquiryResult;
+ try {
+ result = await submitEnquiry({
+ data: {
+ form: variant,
+ name: get("name"),
+ email: get("email"),
+ phone: get("phone"),
+ company: get("company"),
+ topic: bespoke ? undefined : get("topic"),
+ enquiryType: bespoke ? get("enquiryType") : undefined,
+ quantity: get("quantity"),
+ budget: get("budget"),
+ date: get("date"),
+ message: get("message"),
+ website: get("website"),
+ },
+ });
+ } catch {
+ result = { ok: false, errors: { form: "Something went wrong — please try again, or call the atelier." } };
+ }
+ setPending(false);
+
+ if (result.ok) {
+ form.reset();
+ setDone(true);
+ } else {
+ setErrors(result.errors);
+ }
+ }
+
+ if (done) {
+ return (
+
+
Thank you
+
+ Your {bespoke ? "enquiry" : "note"} has reached the atelier — we reply
+ within one working day.
+
+
setDone(false)}
+ className="link-quiet eyebrow mt-8 text-ink-700 hover:text-orange-500"
+ >
+ Send another
+
+
+ );
+ }
+
+ return (
+
+ );
+}
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
index 083b0d5..e4cd887 100644
--- a/src/components/Footer.tsx
+++ b/src/components/Footer.tsx
@@ -39,6 +39,7 @@ const EXPLORE = [
{ label: "Bespoke", href: "/bespoke" },
{ label: "Our World", href: "/our-world" },
{ label: "The Journal", href: "/journal" },
+ { label: "Contact", href: "/contact" },
];
const POLICIES = [
diff --git a/src/components/GiftingTabs.tsx b/src/components/GiftingTabs.tsx
new file mode 100644
index 0000000..1c3d92d
--- /dev/null
+++ b/src/components/GiftingTabs.tsx
@@ -0,0 +1,184 @@
+import { useState } from "react";
+import { Link } from "@tanstack/react-router";
+import Reveal from "@/components/Reveal";
+import ProductCard from "@/components/ProductCard";
+import { giftingTabs, seasonal, type GiftingTab } from "@/data/catalog";
+
+/**
+ * "Who is it for?" — tabs ordered price-wise, from Signature (entry)
+ * to Bespoke Gifting (made to order).
+ */
+
+function TabCta({ tab }: { tab: GiftingTab }) {
+ if (!tab.cta) return null;
+ const { label, url, external } = tab.cta;
+ if (external) {
+ return (
+
+ {label}
+
+ );
+ }
+ const [to, hash] = url.split("#");
+ return (
+
+ {label}
+
+ );
+}
+
+function EnquiryPanel({ tab }: { tab: GiftingTab }) {
+ return (
+
+
+
{tab.note}
+
+ {tab.title}
+
+
{tab.blurb}
+
+ {[
+ "Custom packaging & personalisation",
+ "Volume pricing for teams & events",
+ "Composed and delivered to order",
+ ].map((line) => (
+
+ —
+ {line}
+
+ ))}
+
+
+
+
+ {tab.name.split(" ")[0]}
+
+
+ );
+}
+
+function SeasonalPanel() {
+ return (
+
+ );
+}
+
+export default function GiftingTabs() {
+ const [active, setActive] = useState(0);
+ const tab = giftingTabs[active];
+
+ return (
+
+ {/* tab bar */}
+
+
+ {giftingTabs.map((t, i) => (
+ setActive(i)}
+ className={`shrink-0 rounded-full border px-5 py-2.5 text-[0.8rem] tracking-wide transition-all duration-400 ${
+ active === i
+ ? "border-bean-900 bg-bean-900 text-ivory-50"
+ : "border-ink-900/15 text-ink-700 hover:border-orange-500 hover:bg-orange-500 hover:text-ivory-50"
+ }`}
+ >
+ {t.name}
+
+ ))}
+
+
+
+ {/* active tab panel */}
+
+
+
+ {tab.note}
+
+ {tab.title}
+
+ {tab.blurb}
+
+ {tab.cta && (
+
+
+
+ )}
+
+
+
+ {tab.mode === "products" && tab.products && (
+
+ {tab.products.map((p, i) => (
+
+
+
+ ))}
+
+ )}
+ {tab.mode === "seasonal" && (
+
+
+
+ )}
+ {tab.mode === "enquiry" && (
+
+
+
+ )}
+
+
+ {tab.cta && (
+
+
+
+ )}
+
+
+ );
+}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index ad95956..ff744d5 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -10,6 +10,7 @@ const NAV_LEFT = [
const NAV_RIGHT = [
{ label: "Our World", to: "/our-world" },
{ label: "Bespoke", to: "/bespoke" },
+ { label: "Contact", to: "/contact" },
];
const ANNOUNCE_H = 32;
diff --git a/src/components/IndexShowcase.tsx b/src/components/IndexShowcase.tsx
index 35e5612..7647412 100644
--- a/src/components/IndexShowcase.tsx
+++ b/src/components/IndexShowcase.tsx
@@ -1,4 +1,4 @@
-import { useState } from "react";
+import { useEffect, useState } from "react";
import Reveal from "@/components/Reveal";
import type { Collection } from "@/data/catalog";
@@ -8,12 +8,36 @@ type Props = {
id?: string;
};
+const SLIDE_MS = 3200;
+
/**
- * Editorial index: rows on the left, a sticky image panel on the right
- * that crossfades to the hovered row's photograph. No floating popups.
+ * Editorial index: rows on the left, a sticky panel on the right that
+ * crossfades to the hovered row's photographs — each collection rendered
+ * as a three-image carousel. No floating popups.
*/
export default function IndexShowcase({ items, id }: Props) {
const [active, setActive] = useState(0);
+ const [slide, setSlide] = useState(0);
+
+ const images = items[active]?.images ?? [];
+
+ // a new collection always opens on its first photograph
+ useEffect(() => {
+ setSlide(0);
+ }, [active]);
+
+ // gentle auto-advance while the collection is in view
+ useEffect(() => {
+ if (images.length < 2) return;
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
+ const t = window.setInterval(
+ () => setSlide((s) => (s + 1) % images.length),
+ SLIDE_MS,
+ );
+ return () => window.clearInterval(t);
+ }, [images.length]);
+
+ const current = images.length ? slide % images.length : 0;
return (
@@ -60,28 +84,53 @@ export default function IndexShowcase({ items, id }: Props) {
))}
- {/* sticky crossfading panel */}
+ {/* sticky crossfading carousel */}
- {items.map((item, i) => (
+ {images.map((src, i) => (
))}
+ {images.length > 1 && (
+
+ {images.map((_, i) => (
+ setSlide(i)}
+ aria-label={`Photo ${i + 1} of ${images.length}`}
+ aria-pressed={current === i}
+ className={`h-1.5 rounded-full transition-all duration-500 ${
+ current === i
+ ? "w-7 bg-ivory-50"
+ : "w-1.5 bg-ivory-50/55 hover:bg-ivory-50/80"
+ }`}
+ />
+ ))}
+
+ )}
+
+
+
+ {items[active]?.name} — {items[active]?.blurb}
+
+ {images.length > 1 && (
+
+ {String(current + 1).padStart(2, "0")} / {String(images.length).padStart(2, "0")}
+
+ )}
-
- {items[active]?.name} — {items[active]?.blurb}
-
diff --git a/src/data/catalog.ts b/src/data/catalog.ts
index 1da567e..a40de74 100644
--- a/src/data/catalog.ts
+++ b/src/data/catalog.ts
@@ -18,7 +18,10 @@ export type Product = {
export type Collection = {
name: string;
blurb: string;
+ /** primary still — used for thumbnails */
image: string;
+ /** carousel stills shown in the showcase panel (3 per collection) */
+ images: string[];
url: string;
};
@@ -74,42 +77,49 @@ export const collections: Collection[] = [
name: "Bars",
blurb: "Single-origin tablets, 45% to 85%",
image: "/products/01-dark85-60gm.jpg",
+ images: ["/products/01-dark85-60gm.jpg", "/products/02-dark60-60gm.jpg", "/products/img-5469.jpg"],
url: `${SHOP}/collections/bars`,
},
{
name: "Barks",
blurb: "Crackled slabs of nuts, fruit & crunch",
image: "/products/01-almondbark60.jpg",
- url: `${SHOP}/collections/barks`,
+ images: ["/products/01-almondbark60.jpg", "/products/02-almondbark45.jpg", "/products/20-almondpralinebark.jpg"],
+ url: `${SHOP}/collections/bark`,
},
{
name: "Pralines",
blurb: "Hand-piped ganache, boxed like jewels",
image: "/products/mozi-27.jpg",
+ images: ["/products/mozi-27.jpg", "/products/irw05205.jpg", "/products/14-mozimopralinepanetela-9c9a80d8-e4fc-4c4b-9c56-ca7f42b57847.jpg"],
url: `${SHOP}/collections/pralines`,
},
{
name: "Spreads",
blurb: "Stone-ground, silky, single origin",
image: "/products/02-pistachiospread60.jpg",
+ images: ["/products/02-pistachiospread60.jpg", "/products/03-hazelnutspread45.jpg", "/products/mozi-23.jpg"],
url: `${SHOP}/collections/spreads`,
},
{
name: "Dragees",
blurb: "Roasted nuts under a thin chocolate shell",
image: "/products/04-almonddragees60.jpg",
+ images: ["/products/04-almonddragees60.jpg", "/products/02-hazelnutdragees45.jpg", "/products/03-pistachiodragees.jpg"],
url: `${SHOP}/collections/dragees`,
},
{
name: "Tuilles & Rocks",
blurb: "Lace-thin wafers, orangettes & slivers",
image: "/products/01-milk45-tuilles-100gm.jpg",
+ images: ["/products/01-milk45-tuilles-100gm.jpg", "/products/02-whitechocolatetuilles-100gm.jpg", "/products/01-almondsliversrocks-100gm.jpg"],
url: `${SHOP}/collections/tuilles`,
},
{
name: "Gifting",
blurb: "Hampers composed for every celebration",
image: "/products/mozi20.jpg",
+ images: ["/products/mozi20.jpg", "/products/mozi-33.jpg", "/products/mozi4.jpg"],
url: `${SHOP}/collections/gift-collection`,
},
];
@@ -121,36 +131,42 @@ export const signatures: Collection[] = [
name: "The Signature Box",
blurb: "Our most-loved assortment, composed by hand",
image: "/products/mozi-33.jpg",
+ images: ["/products/mozi-33.jpg", "/products/mozi-25.jpg", "/products/mozi-17.jpg"],
url: `${SHOP}/collections/gift-collection`,
},
{
name: "The Praline Collection",
blurb: "Ganache jewels, piped and finished by hand",
image: "/products/mozi-27.jpg",
+ images: ["/products/mozi-27.jpg", "/products/irw05205.jpg", "/products/panetela.jpg"],
url: `${SHOP}/collections/pralines`,
},
{
name: "The Dark Collection",
blurb: "Single-origin darkness, 60% to 85%",
image: "/products/01-dark85-60gm.jpg",
+ images: ["/products/01-dark85-60gm.jpg", "/products/02-dark60-60gm.jpg", "/products/03-dark45-60gm.jpg"],
url: `${SHOP}/collections/bars`,
},
{
name: "The Festive Collection",
blurb: "Limited editions for the season's light",
image: "/products/mozi-30.jpg",
+ images: ["/products/mozi-30.jpg", "/products/mozi31.jpg", "/products/mozi18.jpg"],
url: `${SHOP}/collections/all`,
},
{
name: "The Chocolate Bar",
blurb: "The bean itself, pressed into 60 grams",
image: "/products/02-dark60-60gm.jpg",
+ images: ["/products/02-dark60-60gm.jpg", "/products/01-nuttybarmilk-100gm.jpg", "/products/img-5469.jpg"],
url: `${SHOP}/collections/bars`,
},
{
name: "The Mozimo Gifts",
blurb: "Hampers that say more than words",
image: "/products/mozi20.jpg",
+ images: ["/products/mozi20.jpg", "/products/mozi19.jpg", "/products/mozi16.jpg"],
url: `${SHOP}/collections/gift-collection`,
},
];
@@ -196,6 +212,105 @@ export const giftingCategories = [
{ name: "Weddings", image: "/products/panetela.jpg" },
];
+/* ── Gifting tabs — price-wise, as shoppable tiers ──────────── */
+
+export type GiftingTab = {
+ id: string;
+ name: string;
+ /** price positioning line, shown above the tab's title */
+ note: string;
+ title: string;
+ blurb: string;
+ mode: "products" | "seasonal" | "enquiry";
+ products?: Product[];
+ cta?: { label: string; url: string; external?: boolean };
+};
+
+export const giftingTabs: GiftingTab[] = [
+ {
+ id: "signature",
+ name: "Signature",
+ note: "From ₹265",
+ title: "Small gestures, remembered.",
+ blurb: "Thoughtful everyday gifting — a bar, a little box, a note of chocolate that says enough.",
+ mode: "products",
+ products: [
+ product("Dark Chocolate Bar 85%", 265, "01-dark85-60gm.jpg", "mozimo-dark-chocolate-bar-85", { weight: "60 g", tag: "Signature" }),
+ product("9 Pralines Box", 990, "mozi-27.jpg", "9-pralines-box", { tag: "Hand-piped" }),
+ product("Bars Box", 1050, "mozi14.jpg", "bars-box"),
+ ],
+ cta: { label: "View all Signature gifts", url: `${SHOP}/collections/gift-collection`, external: true },
+ },
+ {
+ id: "best-sellers",
+ name: "Best Sellers",
+ note: "From ₹825",
+ title: "The boxes they ask for by name.",
+ blurb: "The spreads, dragees and bars our regulars return for — gifting that never misses.",
+ mode: "products",
+ products: [
+ product("Pistachio Spread 60%", 825, "02-pistachiospread60.jpg", "pistachio-spread-60"),
+ product("Almond Dragees 60%", 900, "04-almonddragees60.jpg", "mozimo-almond-dragees-60"),
+ product("Kunafa Chocolate Bar", 1600, "mozi-23.jpg", "kunafa-chocolate-bar", { tag: "New" }),
+ product("Spreads Box", 1650, "mozi16.jpg", "spreads-box"),
+ ],
+ cta: { label: "Shop Best Sellers", url: `${SHOP}/collections/best-sellers`, external: true },
+ },
+ {
+ id: "exquisite",
+ name: "Exquisite",
+ note: "From ₹2,400",
+ title: "Celebrations, elevated.",
+ blurb: "The Carnival boxes — layered, abundant and composed for the moments in between.",
+ mode: "products",
+ products: [
+ product("Carnival Celebration · S", 2400, "mozi20.jpg", "mozimo-carnival-celebration-s"),
+ product("Carnival Celebration · M", 3000, "mozi19.jpg", "mozimo-carnival-celebration-m"),
+ ],
+ cta: { label: "View the full collection", url: `${SHOP}/collections/gift-collection`, external: true },
+ },
+ {
+ id: "premium",
+ name: "Premium",
+ note: "From ₹3,900",
+ title: "Generosity, composed.",
+ blurb: "Our grandest hampers — the ones that arrive before you speak and say everything after.",
+ mode: "products",
+ products: [
+ product("Carnival Celebration · L", 3900, "mozi18.jpg", "mozimo-carnival-celebration-l"),
+ product("Celestial (S)", 4500, "mozi-33.jpg", "mozimo-celestial-s", { tag: "Grande" }),
+ ],
+ cta: { label: "View the full collection", url: `${SHOP}/collections/gift-collection`, external: true },
+ },
+ {
+ id: "seasonal",
+ name: "Seasonal",
+ note: "Limited editions",
+ title: "Chocolate for the calendar.",
+ blurb: "Diwali to Valentine's — editions composed for the season's light, here only while it lasts.",
+ mode: "seasonal",
+ cta: { label: "Shop the Seasonal Edit", url: `${SHOP}/collections/gift-collection`, external: true },
+ },
+ {
+ id: "corporate",
+ name: "Corporate & Bulk",
+ note: "At scale",
+ title: "Gratitude at scale.",
+ blurb: "Branded hampers, volume pricing and door-step delivery for teams, clients and occasions of every size.",
+ mode: "enquiry",
+ cta: { label: "Start a corporate enquiry", url: "/bespoke#enquiry", external: false },
+ },
+ {
+ id: "bespoke",
+ name: "Bespoke Gifting",
+ note: "Made to order",
+ title: "Composed around your moment.",
+ blurb: "Custom selections, packaging and personalisation — designed with our chocolatiers from the first conversation.",
+ mode: "enquiry",
+ cta: { label: "Begin a bespoke commission", url: "/bespoke#enquiry", external: false },
+ },
+];
+
/* ── The Seasonal Edit ──────────────────────────────────────── */
export const seasonal = [
diff --git a/src/data/enquiry.ts b/src/data/enquiry.ts
new file mode 100644
index 0000000..21e3701
--- /dev/null
+++ b/src/data/enquiry.ts
@@ -0,0 +1,97 @@
+import { createServerFn } from "@tanstack/react-start";
+
+/**
+ * Shared receiver for the Contact Us form and the Bulk / Bespoke gifting
+ * enquiry form. Validates on the server, then delivers the enquiry:
+ *
+ * 1. CONTACT_WEBHOOK_URL (if set) — POSTs the enquiry as JSON, so any
+ * automation (Zapier, n8n, email service) can pick it up;
+ * 2. otherwise — appends one JSON line to ./contact-submissions.jsonl
+ * (best effort; skipped silently on read-only filesystems).
+ *
+ * Every enquiry is also logged to the process console.
+ */
+
+export type EnquiryForm = "contact" | "bespoke";
+
+export type EnquiryPayload = {
+ form: EnquiryForm;
+ name: string;
+ email: string;
+ phone?: string;
+ company?: string;
+ /** contact variant: General enquiry · My order · Feedback · Press & collaborations */
+ topic?: string;
+ /** bespoke variant: Corporate & bulk gifting · Weddings · Brand collaboration · Events · Custom packaging */
+ enquiryType?: string;
+ quantity?: string;
+ budget?: string;
+ date?: string;
+ message: string;
+ /** honeypot — real users never fill this */
+ website?: string;
+};
+
+export type EnquiryResult =
+ | { ok: true }
+ | { ok: false; errors: Record };
+
+const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+
+const str = (v: unknown) => (typeof v === "string" ? v.trim() : "");
+
+export const submitEnquiry = createServerFn({ method: "POST" })
+ .validator((input: unknown) => input as EnquiryPayload)
+ .handler(async ({ data }): Promise => {
+ // honeypot: act successful, deliver nothing
+ if (str(data?.website)) return { ok: true };
+
+ const errors: Record = {};
+ const name = str(data?.name);
+ const email = str(data?.email);
+ const message = str(data?.message);
+
+ if (name.length < 2) errors.name = "Please tell us your name.";
+ if (!EMAIL_RE.test(email)) errors.email = "Please enter a valid email.";
+ if (message.length < 10) errors.message = "A sentence or two helps us help you.";
+ if (Object.keys(errors).length) return { ok: false, errors };
+
+ const record = {
+ receivedAt: new Date().toISOString(),
+ form: data.form === "bespoke" ? "bespoke" : "contact",
+ name,
+ email,
+ phone: str(data?.phone),
+ company: str(data?.company),
+ topic: str(data?.topic) || str(data?.enquiryType),
+ quantity: str(data?.quantity),
+ budget: str(data?.budget),
+ date: str(data?.date),
+ message,
+ };
+
+ console.log("[mozimo enquiry]", JSON.stringify(record));
+
+ const webhook = process.env.CONTACT_WEBHOOK_URL;
+ if (webhook) {
+ try {
+ const res = await fetch(webhook, {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify(record),
+ });
+ if (!res.ok) console.error("[mozimo enquiry] webhook responded", res.status);
+ } catch (error) {
+ console.error("[mozimo enquiry] webhook failed", error);
+ }
+ } else {
+ try {
+ const { appendFile } = await import("node:fs/promises");
+ await appendFile("contact-submissions.jsonl", JSON.stringify(record) + "\n", "utf8");
+ } catch {
+ // read-only filesystem — the console log above is the record
+ }
+ }
+
+ return { ok: true };
+ });
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index f52a1a2..529d4c2 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -13,6 +13,7 @@ import { Route as IndexRouteImport } from './app/index'
import { Route as AboutRouteImport } from './app/about'
import { Route as BespokeRouteImport } from './app/bespoke'
import { Route as ChocolateRouteImport } from './app/chocolate'
+import { Route as ContactRouteImport } from './app/contact'
import { Route as ExperiencesRouteImport } from './app/experiences'
import { Route as GiftingRouteImport } from './app/gifting'
import { Route as OurWorldRouteImport } from './app/our-world'
@@ -39,6 +40,11 @@ const ChocolateRoute = ChocolateRouteImport.update({
path: '/chocolate',
getParentRoute: () => rootRouteImport,
} as any)
+const ContactRoute = ContactRouteImport.update({
+ id: '/contact',
+ path: '/contact',
+ getParentRoute: () => rootRouteImport,
+} as any)
const ExperiencesRoute = ExperiencesRouteImport.update({
id: '/experiences',
path: '/experiences',
@@ -70,6 +76,7 @@ export interface FileRoutesByFullPath {
'/about': typeof AboutRoute
'/bespoke': typeof BespokeRoute
'/chocolate': typeof ChocolateRoute
+ '/contact': typeof ContactRoute
'/experiences': typeof ExperiencesRoute
'/gifting': typeof GiftingRoute
'/our-world': typeof OurWorldRoute
@@ -81,6 +88,7 @@ export interface FileRoutesByTo {
'/about': typeof AboutRoute
'/bespoke': typeof BespokeRoute
'/chocolate': typeof ChocolateRoute
+ '/contact': typeof ContactRoute
'/experiences': typeof ExperiencesRoute
'/gifting': typeof GiftingRoute
'/our-world': typeof OurWorldRoute
@@ -93,6 +101,7 @@ export interface FileRoutesById {
'/about': typeof AboutRoute
'/bespoke': typeof BespokeRoute
'/chocolate': typeof ChocolateRoute
+ '/contact': typeof ContactRoute
'/experiences': typeof ExperiencesRoute
'/gifting': typeof GiftingRoute
'/our-world': typeof OurWorldRoute
@@ -106,6 +115,7 @@ export interface FileRouteTypes {
| '/about'
| '/bespoke'
| '/chocolate'
+ | '/contact'
| '/experiences'
| '/gifting'
| '/our-world'
@@ -117,6 +127,7 @@ export interface FileRouteTypes {
| '/about'
| '/bespoke'
| '/chocolate'
+ | '/contact'
| '/experiences'
| '/gifting'
| '/our-world'
@@ -128,6 +139,7 @@ export interface FileRouteTypes {
| '/about'
| '/bespoke'
| '/chocolate'
+ | '/contact'
| '/experiences'
| '/gifting'
| '/our-world'
@@ -140,6 +152,7 @@ export interface RootRouteChildren {
AboutRoute: typeof AboutRoute
BespokeRoute: typeof BespokeRoute
ChocolateRoute: typeof ChocolateRoute
+ ContactRoute: typeof ContactRoute
ExperiencesRoute: typeof ExperiencesRoute
GiftingRoute: typeof GiftingRoute
OurWorldRoute: typeof OurWorldRoute
@@ -177,6 +190,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ChocolateRouteImport
parentRoute: typeof rootRouteImport
}
+ '/contact': {
+ id: '/contact'
+ path: '/contact'
+ fullPath: '/contact'
+ preLoaderRoute: typeof ContactRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/experiences': {
id: '/experiences'
path: '/experiences'
@@ -220,6 +240,7 @@ const rootRouteChildren: RootRouteChildren = {
AboutRoute: AboutRoute,
BespokeRoute: BespokeRoute,
ChocolateRoute: ChocolateRoute,
+ ContactRoute: ContactRoute,
ExperiencesRoute: ExperiencesRoute,
GiftingRoute: GiftingRoute,
OurWorldRoute: OurWorldRoute,