尚未收集儲存庫資訊。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
VOLT Padel & Squash Club — open-source Opencals booking template with an in-page court booking grid (courts × time, custom duration) and a coach-led training flow. Next.js 15 + React 19 + Tailwind.
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗A production-ready booking website for padel & squash clubs. Built with Next.js 15, Tailwind CSS v4, and the Opencals Storefront SDK.
A dark, technical club aesthetic — near-black surfaces, electric-orange accent, and a monospace display face — for a multi-club network: a club-first, full-screen court booking page (a live hall map of every court, or a courts × time grid) for rentals, and a classic coach-led training flow for lessons and group classes. Full storefront included — courts, trainings, coaches, checkout, customer accounts — wired up out of the box. MIT licensed: clone it, rebrand it, ship it.
Sign up at app.opencals.com and create a Dev Store. When prompted for a dataset, choose the VOLT Padel & Squash preset — this seeds your store with four clubs (Madrid, Barcelona, Valencia, Málaga), their padel doubles, padel singles and squash courts, coaches, training classes and add-ons, so your template looks exactly like the demo.
Go to your User Account Settings in the Opencals dashboard and generate a private storefront key (spk_). The template calls the API from its server, so the key stays secret, and it forwards each visitor's IP (nextBuyerIp in lib/opencals.ts) so visitors get their own rate limits. If your server has fixed outgoing IPs you can restrict the key to them; on Vercel, leave the list empty. A public key (sfk_) also works, but then all visitors share your server's limits.
During deployment, Vercel will ask you to set environment variables:
| Variable | Value |
|---|---|
OPENCALS_API_KEY | Your private storefront key (starts with spk_) |
AUTH_SECRET | Any random string — used for session encryption |
That's it. Once deployed, you'll have the same fully functional booking site as the live demo.
A full-bleed, cinematic homepage with an "Our clubs" section (one card per club, straight into its courts), a two-mode intro (rent a court vs. train with a coach), sports with live court counts, a coaches teaser and a facility gallery, all driven by your Opencals data.
The centerpiece, full screen. Players don't look for a court in four cities at once, so /book starts from one club: the one in the link, the one this browser remembers, or the nearest one ("Near me" uses the club coordinates from your store). New visitors pick from photo cards that show each club's soonest free court. The club's page then has two views over the same live data:
Pick a day (14 days ahead, sold-out days struck through), a sport (only the club's sports show) and a game length. Everything is in the URL (/book?club=volt-madrid&sport=padel&date=…&length=90&time=19:30&view=grid), so links to a club, a day or a time just work.
Fast by design. The page makes one request per club: /api/clubs/[id]/availability reads each court's free ranges for the whole booking window once (merged availability), caches each court for 60 seconds on the server, and the browser computes the map, the grid, the pulse and every "free from" locally. Switching day, length, sport or view never calls the API. A booking, cancel or reschedule invalidates the cached courts at once.
siteConfig.clubs.presentation, matched by location slug or city.padel-courts, squash-courts). Give each court allowCustomDuration with a 30-minute base and a 2-hour maximum. Each court is its own resource, so booking one court leaves the others free.Court 7 · Singles is a singles court (narrow tile, 2 players); anything else is doubles (4 players). Court numbers come from the title too.siteConfig.sports maps a court collection (and a training collection) to a label and colour. Add pickleball by adding an entry and its collections; a club only shows the sports it has courts for./training and /coaches filter by club and default to the remembered one.Lessons and classes per club. Browse the training catalog by club, sport, level (Starter → Advanced) and format (individual vs. group), then book: pick the level, club and coach (or "Any coach"), a day and a start. Group classes show live "N left" places and you can book more than one.
maxAttendees: 1) — an independent, exclusively-booked unit each.maxAttendees > 1), which drives the "spots left" display.Bookings read naturally either way: "Padel · Court 3 · 1h 30m" for a rental, "Padel Group Class · Intermediate · Coach Marta" for a class.
One checkout for courts and training, built like a match sheet: numbered steps that fold up as you go, with a sticky match card (court from above, day, time, length, who's on court, running total, hold timer).
/thank-you opens on the club photo ("Game on, Sam! / VOLT Madrid") with the match ticket: the court from above with a spot per player (doubles, singles or squash), day, time, length, players, booking reference, kit and a live countdown. Then add-to-calendar (.ics), directions, send-to-crew, your crew, "Before you play", "Getting there" (address, hours, map link), the free-cancellation line and "Same time next week?". Guests see it too, from a snapshot of the flow.
Passwordless sign-in by default: players enter their email and receive a 6-digit login code (password sign-in stays available as a fallback). My games shows a stats strip (games played, hours on court, your club, clubs played), the next game as a full ticket, upcoming games and trainings, the players you play with, and past games with Book again. Each game can invite more players by email, change time or cancel; orders and details are one tab away.
Review every post-booking state without a store at /preview/index (fixture clubs and games; on in development, or set VOLT_PREVIEW=1).
One-time email links from Opencals (view/reschedule/cancel booking, leave feedback, verify email, reset password) all resolve through the /link/[token] route, which signs the customer in and redirects them to the right place.
Set your Storefront Base URL. For emailed links to point back to this app, set Storefront Base URL in your Opencals dashboard (Settings → API) to your deployed URL (e.g.
https://your-domain.com). Opencals builds every customer link as{storefrontBaseUrl}/link/{token}.
The homepage hero is a full-bleed background with a looping video (public/videos/hero.mp4) over a still image. To use the still only, set heroVideoSrc to null in app/page.tsx.
Fully responsive. The hall map reflows its courts to the screen and the grid scrolls horizontally on phones with a sticky court-name column; the training flow is a card-stack that feels native on mobile and expands to two columns on desktop.
Per-page metadata, Open Graph cards, SportsActivityLocation structured data, robots.txt, and sitemap.xml — configured out of the box.
| Category | Technology |
|---|---|
| Framework | Next.js 15 (App Router) |
| Styling | Tailwind CSS v4 |
| Animations | Framer Motion |
| Forms | react-hook-form + Zod |
| Payments | Stripe Elements |
| Auth | NextAuth.js v5 |
| Dates | moment-timezone |
| API | Opencals Storefront SDK (v0.3.14) |
git clone https://github.com/letsopencals/template-volt.git
cd template-volt
npm install
cp .env.example .env
Edit .env with your values:
OPENCALS_API_KEY=spk_your_key_here
AUTH_SECRET=change_me_to_a_random_string
npm run dev
Open http://localhost:3000.
All club-specific copy is centralized in lib/site-config.ts:
Edit this single file to rebrand the entire template. The bookable data (courts, trainings, coaches, prices, availability) comes from your Opencals store.
Design tokens live in app/globals.css as Tailwind v4 @theme properties. Token names are intentionally stable, so components keep working when you change the values:
@theme {
--color-bg: #0A0A0A; /* near-black page background */
--color-surface: #141414; /* cards / panels */
--color-ink: #FAFAFA; /* primary text */
--color-primary: #FF4A1C; /* electric-orange accent */
--font-display: 'JetBrains Mono', ui-monospace, monospace;
--font-body: 'Space Grotesk', system-ui, sans-serif;
}
Tip: keep the accent aligned with your store's storefront primary color so the deployed site matches your Opencals settings.
Drop hero, sport, gallery, coach and club images into public/images/{hero,sports,gallery,coaches,about}/ (and the hero video at public/videos/hero.mp4). See public/images/PLACEHOLDERS.md for filenames and recommended dimensions. Court, training and coach photos in the live booking flow come from your Opencals store, not this folder.
app/your-page/page.tsxlayout.tsx with metadatanavLinks in components/layout/header.tsxapp/
page.tsx # Homepage
book/page.tsx # Club-first court booking (hall map | grid)
training/page.tsx # Training catalog (filter by club / sport / level / format)
booking/[slug]/page.tsx # Training booking (the game flow)
thank-you/page.tsx # Match-ticket confirmation
preview/[screen]/ # Fixture previews of confirmation + account states
coaches/ # Meet the coaches
about/ # About page
contact/ # Contact form + info
account/ # Customer dashboard
auth/ # Sign in, sign up, password reset
link/[token]/ # One-time email link resolver
api/ # API routes proxy SDK calls server-side
clubs/[locationId]/availability # One club's court availability (cached per court)
components/
layout/{header,footer}.tsx # Site chrome
home/ # Hero, modes, sports, training levels, coaches, gallery, ...
book/ # Club chooser, club hero, hall map, toolbar
booking/ # Court grid, duration popover, Stripe Elements
game/ # Game flow (steps + match card), confirmation, account
account/ # Customer dashboard components
ui/ # Shared primitives (button, input, ...)
contexts/ # cart, location, timezone, settings
hooks/ # use-home-club, use-club-availability, use-club-grid, use-game-booking, use-game-checkout, ...
lib/ # club (catalogue + availability maths), game (appointment → game), availability-server, server-data,
# site-config, opencals (SDK), auth (NextAuth), schemas, format, utils
| Variable | Required | Description |
|---|---|---|
OPENCALS_API_KEY | Yes | Private storefront key (spk_) from your Opencals dashboard |
AUTH_SECRET | Yes | Random string for NextAuth session encryption |
OPENCALS_API_URL | No | Override API base URL (defaults to production) |
NEXT_PUBLIC_BASE_URL | No | Public site URL (for sitemap) |
VOLT_PREVIEW | No | 1 serves /preview/[screen] in production (always on in development) |
VOLT is one of the open-source booking templates built on the Opencals Storefront SDK. Same backend, different design and vertical:
See all templates and the Storefront API at opencals.com/developers.
Prefer to let an AI agent do the heavy lifting? Install the Opencals Agent Skills in Claude Code, Cursor, Codex or Gemini CLI:
opencals-build-booking-site — scaffold, wire and deploy a template like this oneopencals-storefront-api — ground-truth reference for the Opencals API & SDKDocs: opencals.com/docs → AI Agents.
MIT