Fazekit

Code

"use client";
import * as React from "react";
import { MotionConfig, useReducedMotion } from "motion/react";
import { cn } from "@/lib/utils";
import { defaultCafeData, type CafeData } from "./data";
import { Faq } from "./sections/faq";
import { Footer } from "./sections/footer";
import { Gallery } from "./sections/gallery";
import { Hero } from "./sections/hero";
import { Loyalty } from "./sections/loyalty";
import { MenuSection } from "./sections/menu";
import { Navbar } from "./sections/navbar";
import { Preorder, type PreorderRequest } from "./sections/preorder";
import { Reviews } from "./sections/reviews";
import { Specials } from "./sections/specials";
import { CB_BODY_STACK, CB_DISPLAY_STACK, scrollToId, ThemeStyle, useOpenStatus } from "./sections/ui";
import { Visit } from "./sections/visit";

export type { CafeData, PreorderRequest };
export { defaultCafeData };

export interface CafeBakeryTemplateProps {
  /** Override any top-level content group (business, menu, hours…). Missing groups fall back to the demo content. */
  data?: Partial<CafeData>;
  /** Called when a customer places a pickup order. Return a promise to keep the loading state until your API answers. */
  onPreorder?: (order: PreorderRequest) => void | Promise<void>;
  /** Called when someone joins the loyalty club with their email. */
  onJoinClub?: (email: string) => void | Promise<void>;
  className?: string;
}

/** Scope class for the brand palette — keeps the colours from leaking into the rest of your app. */
const SCOPE = "cb-theme";

export function CafeBakeryTemplate({ data, onPreorder, onJoinClub, className }: CafeBakeryTemplateProps) {
  const d = React.useMemo(() => ({ ...defaultCafeData, ...data }), [data]);
  const reduce = useReducedMotion();
  const status = useOpenStatus(d.visit.hours, d.business.timeZone);
  const toPreorder = React.useCallback(() => scrollToId("preorder", reduce), [reduce]);
  const toMenu = React.useCallback(() => scrollToId("menu", reduce), [reduce]);

  return (
    <MotionConfig reducedMotion="user">
      <ThemeStyle scope={SCOPE} theme={d.theme} />
      <div
        className={cn(SCOPE, "relative w-full bg-background font-[family-name:var(--cb-body)] text-foreground antialiased selection:bg-primary/25", className)}
        style={{ "--cb-display": CB_DISPLAY_STACK, "--cb-body": CB_BODY_STACK } as React.CSSProperties}
      >
        <Navbar business={d.business} links={d.nav} status={status} onPreorder={toPreorder} />
        <main>
          <Hero hero={d.hero} status={status} onPreorder={toPreorder} onMenu={toMenu} />
          <Specials specials={d.specials} business={d.business} status={status} />
          <MenuSection menu={d.menu} business={d.business} onPreorder={toPreorder} />
          <Preorder preorder={d.preorder} categories={d.menu.categories} hours={d.visit.hours} business={d.business} onPreorder={onPreorder} />
          <Loyalty loyalty={d.loyalty} business={d.business} onJoin={onJoinClub} />
          <Gallery gallery={d.gallery} business={d.business} />
          <Reviews reviews={d.reviews} />
          <Faq faq={d.faq} business={d.business} />
          <Visit visit={d.visit} business={d.business} status={status} />
        </main>
        <Footer footer={d.footer} business={d.business} />
      </div>
    </MotionConfig>
  );
}

More in Landing Pages

View all →