Fazekit

Code

"use client";
import * as React from "react";
import { MotionConfig, useReducedMotion } from "motion/react";
import { cn } from "@/lib/utils";
import { defaultGymData, type GymClass, type GymData, type Plan } from "./data";
import { Calculator } from "./sections/calculator";
import { AppPromo, Footer, Location, Stories } from "./sections/closing";
import { Hero, Marquee } from "./sections/hero";
import { Navbar } from "./sections/navbar";
import { Coaches, Membership } from "./sections/people";
import { Timetable } from "./sections/timetable";
import { scrollToId, useMoney } from "./sections/ui";

export type { GymData, GymClass, Plan };
export { defaultGymData };

export interface GymTemplateProps {
  /** Override any top-level content group (brand, classes, coaches, plans…). Missing groups fall back to the demo content. */
  data?: Partial<GymData>;
  /** Called when a class is booked (`true`) or cancelled (`false`). */
  onBookClass?: (gymClass: GymClass, booked: boolean) => void;
  /** Called when a membership plan CTA is pressed. */
  onSelectPlan?: (plan: Plan, billing: "monthly" | "annual") => void;
  /** Called when someone requests a free day pass. */
  onDayPass?: (email: string) => void;
  className?: string;
}

/**
 * Forge Athletics — an energetic, dark-first fitness club landing page.
 * Kinetic hero, crossing marquee, filterable weekly timetable with booking, coaches, membership toggle,
 * BMI/calorie calculator, transformation charts, app promo, location with day-pass form and a footer.
 */
export function GymTemplate({ data, onBookClass, onSelectPlan, onDayPass, className }: GymTemplateProps) {
  const d: GymData = React.useMemo(() => ({ ...defaultGymData, ...data }), [data]);
  const reduce = useReducedMotion();
  const money = useMoney(d.brand.currency);
  const toPlans = React.useCallback(() => scrollToId("membership", reduce), [reduce]);

  return (
    <MotionConfig reducedMotion="user">
      <div className={cn("relative w-full bg-background text-foreground antialiased selection:bg-[#c8ff2e] selection:text-zinc-950", className)}>
        <Navbar name={d.brand.name} links={d.nav} onJoin={toPlans} />
        <main>
          <Hero hero={d.hero} onJoin={toPlans} onTimetable={() => scrollToId("classes", reduce)} />
          <Marquee words={d.marquee} />
          <Timetable data={d} onBookClass={onBookClass} />
          <Coaches coaches={d.coaches} />
          <Membership plans={d.plans} money={money} onJoin={(p, b) => onSelectPlan?.(p, b)} />
          <Calculator />
          <Stories stories={d.stories} />
          <AppPromo app={d.app} />
          <Location location={d.location} brand={d.brand} onJoin={onDayPass} />
        </main>
        <Footer footer={d.footer} brand={d.brand} />
      </div>
    </MotionConfig>
  );
}

More in Landing Pages

View all →