Premium, conversion-focused agency website for BookedLoop, built with Next.js App Router + TypeScript + Tailwind CSS + Framer Motion. Designed for US small business owners (salons, clinics, barbers, home services, repair, fitness studios, tutors, etc.).
- Pages: Home, Services, Pricing, Sample Work, About, Contact
- Centralized content/config files (easy to edit later)
- No fake testimonials (sample work is clearly labeled as demo/sample/example)
- Working contact form architecture with validation + success/error states
- Google “Book a Free Audit” CTA wired to your scheduling link
- Light/Dark theme toggle
- Next.js (App Router)
- React + TypeScript
- Tailwind CSS (v4)
- Framer Motion (subtle scroll/fade/stagger animation)
- Node.js 20+ recommended
- npm (project includes a
package-lock.json)
npm install
npm run devnpm run lint
npm run build
npm run start- App routes (pages): app/
- Home:
app/page.tsx - Services:
app/services/page.tsx - Pricing:
app/pricing/page.tsx - Sample Work:
app/sample-work/page.tsx - About:
app/about/page.tsx - Contact:
app/contact/page.tsx - Contact API:
app/api/contact/route.ts
- Home:
- Reusable UI + layout: components/
- Navigation/footer:
components/SiteHeader.tsx,components/SiteFooter.tsx - Theme toggle:
components/ThemeToggle.tsx - Contact form:
components/ContactForm.tsx - Motion helpers:
components/motion.tsx,components/AnimateIn.tsx - UI primitives:
components/ui/*
- Navigation/footer:
- Content & configuration: lib/
- Site-wide config (name, CTAs, booking link, contact):
lib/site.ts - Services:
lib/content/services.ts - Pricing & featured bundle:
lib/content/pricing.ts - Sample work (explicitly labeled demo/sample/example):
lib/content/sampleWork.ts - FAQs + industries list:
lib/content/faqs.ts
- Site-wide config (name, CTAs, booking link, contact):
- Global styles (theme tokens):
app/globals.css - Static assets: public/
- Logo:
public/bookedloop.png
- Logo:
Edit site.ts:
site.name,site.tagline,site.descriptionsite.contact.email,site.contact.phonesite.booking.freeAuditUrlsite.ctas.primary.href(primary CTA used throughout the site)
Edit services.ts.
Each service is a single, clean offer and includes:
pricingLines(e.g., one-time + add-on + optional support)pricingNote(optional)includedlist (bullets)
Edit pricing.ts.
priceLinessupports multiple lines (ex: base price + add-ons + optional support)recommended: truehighlights the featured bundlepricing.notecontrols the global note about custom bundles and final pricing variability
Edit sampleWork.ts.
Everything here is intentionally labeled as:
- “Sample Project”
- “Demo Case Study”
- “Example Workflow”
Replace with real client work when you have permission and real results.
The Contact page includes a validated form with success/error states:
- ContactForm.tsx
Form submissions are handled by:
- route.ts
By default, it validates the payload and returns { ok: true }. To forward leads to a CRM / automation tool, set:
BOOKEDLOOP_CONTACT_WEBHOOK_URL=https://your-webhook-urlThis webhook will receive JSON fields like name, business name, email, phone, website, service interest, etc.
The primary CTA “Book a Free Audit” is wired to:
To change it later, update site.booking.freeAuditUrl and/or site.ctas.primary.href in site.ts.
- Theme tokens live in
app/globals.css - The toggle sets
data-theme="light|dark"on the<html>element and persists inlocalStorage - The toggle component is: ThemeToggle.tsx
From package.json:
npm run dev— local developmentnpm run build— production buildnpm run start— serve production buildnpm run lint— ESLint
This is a standard Next.js App Router project and can be deployed to Vercel or any Node-compatible hosting:
- Set environment variables (optional, only needed for lead forwarding)
- Build:
npm run build - Start:
npm run start
Hydration warnings happen when the server-rendered HTML differs from the first client render. Common causes include using window/localStorage in render logic, time-based values (Date.now()), or browser extensions modifying HTML.
If you see a hydration message, confirm client-only logic runs inside useEffect and that SSR output is stable.
Buttons detect external URLs and render a safe <a> tag that opens in a new tab. The behavior is implemented in:
- Button.tsx
- This repo intentionally avoids fake testimonials and fake results.
- “Sample Work” is explicitly labeled as demo/sample/example until you replace it with real client projects.