A modern, production-minded website for a fitness brand ("Apolo") running two centers in Puertollano, Spain: Gymapolo (strength) and Apolofit (cardio, group classes, community).
Built as a fully static site with Next.js 14 (App Router), React 18, TypeScript, TailwindCSS and Framer Motion. All content, images and credentials are placeholders/mock data — swap them for real assets before going to production.
Created by oscarxdev.
- Next.js 14 — App Router, Server Components, Metadata API, dynamic
sitemap/robots, static export (output: "export"). - React 18 + TypeScript 5 (strict).
- TailwindCSS 3 — custom brand palette (
brand,ink,accent). - Framer Motion — page and component animations.
- Lucide React — icons.
- Zod — form validation.
- clsx + tailwind-merge — conditional class handling.
Auth and data are mocked in localStorage, ready to be swapped for a real provider (NextAuth, Supabase, Firebase) and a database or CMS.
- Home — hero, benefits, featured classes, trainers, pricing, testimonials, centers and FAQ.
- Facilities — filterable gallery with lightbox.
- Classes — listing with filters + detail pages (
/clases/[slug]) and a reservation flow. - Schedule — weekly timetable.
- Pricing — plans with a feature comparison table.
- Trainers — listing + individual profile pages.
- Blog — listing with filters + article pages (
/blog/[slug]). - Contact — form (Zod-validated), per-center info and embedded Google Maps.
- Auth — login, register and password recovery (mock).
- Account area (
/cuenta/*) — profile, membership, reservations, payments, goals, notifications. - Admin panel (
/admin/*) — dashboard plus CRUD sections (classes, trainers, schedule, pricing, reservations, users, blog). - GDPR cookie system — banner + preferences modal (necessary / analytics / marketing).
- Accessibility widget — font sizing, high contrast, pause animations, underline links.
- SEO — per-page metadata, JSON-LD (
HealthClub/Article), dynamic sitemap and robots.
Requires Node 18.17+ (20 LTS recommended).
# install dependencies
npm install
# development (http://localhost:3000)
npm run dev
# production build (static export to ./out)
npm run build
npm run start
# checks
npm run lint
npm run type-check| Role | Password | |
|---|---|---|
| user | user@apolo.fit |
user123 |
| admin | admin@apolo.fit |
admin123 |
src/
├── app/ # App Router routes (home, clases, horarios, precios, entrenadores,
│ # blog, contacto, login/registro/recuperar, cuenta/*, admin/*)
│ # plus layout.tsx, sitemap.ts, robots.ts, not-found.tsx
├── components/ # layout, ui, home sections, cards, classes, gallery, schedule,
│ # pricing, blog, forms, admin, cookies, accessibility, providers
├── context/ # AuthContext, CookiesContext, AccessibilityContext
├── data/ # typed mock data (classes, trainers, pricing, blog, centers, faq…)
├── lib/ # utils.ts (cn, formatPrice, slugify), seo.ts (buildMetadata)
├── types/ # shared types
└── middleware.ts # security headers
The project is configured for static export, so it runs on any static host.
- Cloudflare Workers/Pages —
wrangler.tomlserves the./outdirectory directly. - Vercel —
npx vercel --prod. - Self-hosted —
npm run buildthen serve./outbehind a proxy (Nginx/Caddy) over HTTPS.
Set the production URL via NEXT_PUBLIC_SITE_URL (used by siteConfig in src/lib/seo.ts) so metadata, sitemap and Open Graph resolve correctly.
- Replace placeholder images, texts, addresses, phone numbers and emails with the real ones.
- Wire up real auth (NextAuth / Supabase / Firebase) and move route protection into
middleware.ts. - Connect a database (Prisma + Postgres) or a CMS (Sanity / Strapi / Payload).
- Add real payments (Stripe checkout + webhooks) and persist memberships.
- Implement real reservations with slot capacity and concurrency control.
- Load analytics conditionally, based on cookie consent.
No license specified. Ask before reusing.