Skip to content

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

Static marketing site for Citrus Dental (a dental clinic in Varthur/Whitefield, Bengaluru), built with VitePress. Content pages are Markdown; interactive bits (signup/booking forms, appointment date-time picker, carousel) are Vue components loaded into the default VitePress theme.

Commands

  • npm run docs:dev — start local dev server
  • npm run docs:build — build static site to .vitepress/dist
  • npm run docs:preview — preview the production build locally
  • No test suite, linter, or CI config exists in this repo.
  • Node version is pinned via .nvmrc (23.5.0).

Architecture

Content = Markdown, interactivity = Vue components. Each top-level .md file (index.md, book.md, register.md, contact.md, faq.md, pricing.md, team.md, services/*.md) is a VitePress page. Pages that need interactivity import components from components/ directly inside a <script setup> block and use them in the page body (see book.md and register.md).

Site config (.vitepress/config.mts) is the source of truth for nav, sidebar, and SEO/social metadata:

  • services array at the top defines the full service list once, and is reused both for the nav/sidebar items and for generating the JSON-LD hasOfferCatalog in the structured-data script — keep new services in sync with actual files under services/.
  • A large inline JSON-LD MedicalClinic schema block carries business info (address, hours, ratings, socials, staff). Update this when real-world business details change (this file has seen several such commits — hours, staff, etc.).
  • transformHead generates per-page canonical URL and OG/Twitter meta from pageData.
  • GA and Meta Pixel tracking scripts are injected directly in head.
  • Theme customization lives in .vitepress/theme/index.ts (extends DefaultTheme) and .vitepress/theme/style.css.

Form flow (components/SignupForm.vue) is the shared component behind both book.md (appointment booking) and register.md (patient registration):

  • Gates the form behind Google Sign-In (components/GoogleSignIn.vue, using Google Identity Services and a hardcoded OAuth client ID) — the actual form fields only render after isSignedIn is true.
  • Collects base fields (name, phone, age, gender) plus an intent discriminator ("appointment" vs "registration") and any extra formData passed in via slot/prop from the parent page.
  • Pages inject page-specific fields (e.g. TabbedAppointmentPicker in book.md, area/source Multiselects in register.md) via the default slot, which receives formData as a slot prop so extra fields merge into the same submitted object.
  • Submits via fetch to ${VITE_API_URL}/signup (env var — backend is external/out of repo) with intent distinguishing appointment vs. registration server-side.
  • Phone validation is a simple Indian mobile regex (/^[6-9]\d{9}$/).

components/TabbedAppointmentPicker.vue is a custom modal date+time picker (wraps @vuepic/vue-datepicker for the date tab, hand-rolled 30-min time-slot grid for the time tab), constrained to a 14-day window, Sundays disabled, and slots less than 30 minutes from now disabled. Emits an ISO string via v-model.

components/Carousel.vue wraps vue3-carousel, used for reviews/testimonials elsewhere in the pages.

All Vue components are used via VitePress's Vue-in-Markdown support (<script setup> + component tags directly in .md files) rather than a separate SPA — there is no router or global state store.

Last updated: