Mint
Mint is a site for a dental practice: family dentists, dental clinics, orthodontists, hygienists and cosmetic or implant clinics. It is set edge to edge on a wall of fresh white tiles with mint grout, a sheen that slides across them as you scroll and bubbles of foam drifting up. On the home page a big grin runs right across the window and, as you scroll, a toothbrush with striped paste sweeps along the teeth: foam rises, the plaque goes, each tooth turns glossy white with a sparkle and the gums go a healthy pink, while a tube of toothpaste and a dental mirror float beside the headline. The visit page (and the home page) shows a map of the streets round the practice. The demo is a fictional practice, Brightwater Dental.
Mint comes in two variants, chosen when you create the site: files/Sanity (static pages, any host)
and EmDash (--cms emdash, rendered on request on Cloudflare). The pages are the
same in both.
Pages and their content
Section titled “Pages and their content”| Page | Edit it in |
|---|---|
| Home | Pages → Home page (a list of sections) |
| Treatments, team, journal, 404 | Pages → the page’s own entry |
| Prices (first visit, price list, booking, deposits and gift cards, questions) | Pages → Prices page |
| Visit (opening hours, emergencies, map, details, contact form, questions) | Pages → Visit page |
| Treatments (summary, how long, price, steps, questions, photo) | Content → Treatments |
| Team (role, qualifications, registration, languages, treatments, biography, portrait) | Content → Team |
| Journal posts | Content → Journal |
| Name, phone, address, registration statement, navigation, header button, profiles | Pages → Site settings |
| Buttons, labels, chat, emails, game texts | Content → Interface texts |
| Privacy, terms, complaints | Pages → Legal |
In headlines, words wrapped in *stars* get a swipe of fresh mint underneath and a little sparkle
that twinkles, as in “Smile like you *mean it*”.
Treatments and the team
Section titled “Treatments and the team”Each treatment has a line, a summary, how long it takes, the price as you’d show it (“£48”, “from £2,400”) with an optional note, the steps of how it goes, questions and a 3:2 photo. Its page shows who on the team does it: list the treatments by file name on each person. Team portraits are shown in round dental mirrors, so use a square photo with the face in the middle.
Prices, booking and payments
Section titled “Prices, booking and payments”The prices page holds your first visit (its steps run along a strand of floss that pulls taut as you scroll, and the home page’s “Your first visit” section shows the same steps), the price list in groups, booking a check-up with Cal.com and the deposits and gift cards you take with Stripe: each option gets a one-time Price id. Without keys, the booking shows a preview of the calendar and the payment buttons explain how to switch them on.
The map
Section titled “The map”The “Find us” map is drawn from OpenStreetMap in your
colors: streets, green spaces, water and buildings round the practice, a pin with your name, your
address and “Get directions” links to Google Maps, Apple Maps and OpenStreetMap. It is part of the
page (no embed, no cookies, nothing loaded from another site) and follows the theme and your accent.
To draw your own area, put the practice’s coordinates in map.config.json (center, and size in
metres) and run pnpm map -- fetch: it downloads the area once and writes src/data/location-map.json.
The map’s title and text are on the Visit page (and in the home page’s “Find us” section); the
attribution link stays, as OpenStreetMap’s licence asks.
Integrations
Section titled “Integrations”Everything works without keys; each feature switches on with its variables in .env.example.
| Feature | Where | Service |
|---|---|---|
| Book a check-up | Prices page, loads on click; a preview of the calendar until connected | Cal.com |
| Deposits and gift cards | Prices page (one-time Price ids) | Stripe |
| Check-up reminders | Home and journal pages, with a welcome email | Supabase |
| Contact form | Visit page; messages go to the email in Site settings | Resend |
| AI chat | On every page, answers about treatments, prices, the team and opening hours; never diagnoses | Claude |
| Search | ⌘K or the search button: treatments, team, journal, prices, visit | built in, or Algolia |
| Analytics | Every page; Google Analytics only after consent | Plausible, Umami, Google Analytics |
Sections
Section titled “Sections”The home page is built from these sections, in any order: Brush up the smile (the opening), Treatments (cards with a stripe of toothpaste squeezed across the top), Your first visit (steps along the floss), The team (portraits in dental mirrors that tilt into place), Numbers, Emergency (a gum-pink band with the phone number), Journal, Check-up reminders, Find us (the map; its streets draw themselves and the pin drops in) and Closing call. With reduced motion, the smile stands clean and sparkling and nothing moves.
Colors and brand
Section titled “Colors and brand”src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent
(deep mint: buttons, marks and the toothbrush), the second (gum pink) and the third (fresh
mint: fills, the gums’ partner and the tile grout). Buttons are darkened until their white text is
readable, the second and third are lightened until ink text on them is; a color that can’t get there
stops the build with a message. Brand also sets the fonts (headings and text) and the corners. The
site opens in the day theme even when the visitor’s system is dark; the toggle switches to the night,
deep teal tiles under a soft lamp, and the browser remembers the choice.
Languages
Section titled “Languages”Mint is ready for more languages: see Languages.
The 404 page
Section titled “The 404 page”A small game, Brush up: plaque builds up on a row of teeth; scrub it away by dragging back and forth across a tooth, or pick a tooth with the arrow keys and scrub with the space bar. Three rounds of 15 seconds, the plaque coming faster each time; the best score is kept in the visitor’s browser.
AI assistants and search engines
Section titled “AI assistants and search engines”AGENTS.mddescribes the project for coding assistants (Claude Code reads it throughCLAUDE.md, Cursor through.cursor/rules/)./llms.txtlists your pages, treatments, team and journal for AI assistants, in every language.- Pages carry JSON-LD: the practice as a
Dentist, treatments asMedicalProcedures with their price, the team asPersons, your first visit as aHowTo, questions as aFAQPage, and each journal post as aBlogPosting.
Commands
Section titled “Commands”pnpm dev # local site, editor at /keystaticpnpm build # production buildpnpm map -- fetch # draw the map round map.config.json from OpenStreetMappnpm cms sanity schema|seed # move content to Sanity (see Content → Sanity)In the EmDash variant: npm run dev, npm run deploy (Cloudflare) and npm run emdash:schema
(after changing the content model).