# Specialities Page — Drupal 10 Mapping Sheet

This mapping shows how each component maps to a Drupal 10 implementation target (Block, Paragraph, View, Menu, Template). It follows the pattern the Drupal team established for the homepage, cataract page, centre-cluster page, and eye-specialists page (`docs/drupal-mapping.md`, `docs/cataract-drupal-mapping.md`, `docs/centre-cluster-drupal-mapping.md`, `docs/eye-specialists-drupal-mapping.md`).

## Suggested content architecture

**Content type:** `node--landing_page` with a Paragraph field `field_sections` (bundle-restricted entity reference). The specialities page is one node of this type.

**Taxonomy vocabularies:**
- `speciality` — term fields: `name`, `slug` (auto/pathauto), `description`. Populates the category filter chips and the per-card `data-category` attribute.
- `centre_location` — term fields: `name`, `slug`, `display_order`. Used by doctor cards (shared from homepage).

**Content type: `node--treatment`** — see full field spec below. Treatments are rendered on this page via a Views display.

---

## Treatment content type — field spec

This is the most important mapping for this page. Each treatment node feeds one `04-treatment-card.html` row.

| Field name | Type | Required | Notes |
|-----------|------|----------|-------|
| `field_title` | Text (plain) | Yes | Bottom-overlay text on the card. Maps to `node--treatment` title in most setups. |
| `field_slug` | Text (plain) | Yes | URL slug for the treatment detail page; used in `href` on the card link. |
| `field_image` | Image (Media entity) | Yes | Full-bleed card image. `alt` = node title if empty. |
| `field_category` | Entity reference (term, vocabulary: `speciality`) | No | Rendered as `data-category="<slug>"` on the card `<a>`; feeds the Views category filter. |
| `field_body` | Text (long, formatted) | No | Full treatment description — used on the treatment detail page, not on this card. |
| `field_booking_url` | Link (external URL allowed) | No | Optional direct booking link; not displayed on the card in current design. |

**View mode:** `card` on `node--treatment` → `node--treatment--card.html.twig`. This single Twig file renders every treatment card consistently.

---

## Category filter as Views Exposed Form (chip variant)

The `03-category-filter.html` maps to a Views Exposed Filter on the "treatments" View, rendered as a chip list rather than a dropdown.

| Exposed filter | Views filter type | Vocabulary / field | Widget | Static HTML hook |
|---------------|------------------|--------------------|--------|-----------------|
| Category | Taxonomy term | `field_category` → `speciality` vocab | Link list (custom Twig) | `<a data-category-chip data-category="<slug>" href="?category=<slug>">` |
| All | No filter (default) | — | "All" chip, active when no `?category` param | `<a data-category-chip data-category="all" data-active="true">` |

Override `views-exposed-form.html.twig` to emit the chip `<ul>` structure from `03-category-filter.html`. Active chip detection: compare request `?category` param against each chip's slug; add `data-active="true"` and swap CSS classes accordingly in Twig.

---

## Section-by-section mapping

| # | Component | Drupal implementation target | Notes |
|---|-----------|-----------------------------|-------|
| 1 | `01-utility-bar.html` | `region--secondary.html.twig` (utility region) + menu block | Same as homepage |
| 2 | `02-main-nav.html` | `region--header.html.twig` + `menu.html.twig` + CTA button block | Same as homepage |
| 3 | `01-breadcrumb.html` | Drupal breadcrumb block (`system_breadcrumb_block`) → `breadcrumb.html.twig` override | Path-aware; standard Drupal. Trail: Home › Eye Specialities |
| 4 | `02-hero-banner.html` | Paragraph bundle `hero_banner_callback` — fields: `field_heading`, `field_subtitle`, `field_hero_image`, `field_phone_placeholder`, `field_cta_label` | Same bundle as eye-specialists, cataract, centre-cluster heroes; parameterise via field values |
| 5 | `03-category-filter.html` | `views-exposed-form.html.twig` override on the "treatments" View (chip list variant) | Expose `field_category`; render as `<ul>` of chip links; "All" = no-filter default |
| 6 | `04-treatment-card.html` | `node--treatment--card.html.twig` (view mode `card`) | Views row template; see Treatment content type spec above |
| 7 | `05-our-story.html` | Paragraph bundle `text_callout` — fields: `field_heading`, `field_body` | Same bundle as eye-specialists and centre-cluster `our-story`; fully reusable |
| 8 | `06-all-centres.html` | Paragraph bundle `region_card_grid` — header fields (`field_heading`, `field_subheading`, `field_cta_url`) + nested paragraph bundle `region_card` (per region) | Each region card: `field_image`, `field_region_name`, `field_anchor_url` |
| 9 | `07-contact-strip.html` | Paragraph bundle `contact_strip` with 3 nested items | Per item: `field_label` (text), `field_phone` or `field_url` (telephone/link) |
| 10 | `08-experts-header.html` | Paragraph bundle `text_callout` — fields: `field_heading`, `field_body` | Reuses same bundle as Our Story but with different field values and centered alignment |
| 11 | `components/06-doctor-cards.html` (shared) | Existing homepage doctor-cards implementation; no new template | Verbatim reuse — same `data-slider="doctors"` handler, same `node--doctor--card.html.twig` |
| 12 | `09-why-cfs.html` | Paragraph bundle `feature_card_grid` containing `field_cards` (entity ref → paragraph bundle `feature_card` with `field_heading`) | Same structure as eye-specialists `07-why-cfs.html`; variable card count |
| 13 | `10-faq.html` | Paragraph bundle `faq_section` with nested paragraph bundle `faq_item` (`field_question`, `field_answer`) | Same pattern as eye-specialists `08-faq.html`; content team must replace placeholder questions |
| 14 | `11-callback-form.html` | Paragraph bundle `callback_cta` — fields: `field_eyebrow`, `field_heading`, `field_background_image`. Webform reference `request_a_callback` | "Could not find" eyebrow variant; shared Webform; same paragraph bundle as eye-specialists and cataract |
| 15 | `15-footer.html` (shared) | `region--footer.html.twig` split into 3–4 blocks | Same as homepage |
| 16 | `16-sticky-bar.html` (shared) | Custom block inside `region--bottom.html.twig` | Same as homepage |

---

## Breadcrumb spec

Twig trail for this page:
```twig
{# breadcrumb.html.twig #}
<nav class="breadcrumb ..." aria-label="Breadcrumb">
  <ol ...>
    <li><a href="{{ path('<front>') }}">Home</a></li>
    <li aria-hidden="true" ...>›</li>
    <li aria-current="page" ...>Eye Specialities</li>
  </ol>
</nav>
```

No dynamic ancestors required — this is a flat second-level page.

---

## Hero banner paragraph fields

| HTML element | Paragraph field | Type | Notes |
|-------------|----------------|------|-------|
| `<h1>` text | `field_heading` | Text (plain) | Default: "Specialized Eye Care & Treatments" |
| Subtitle `<p>` | `field_subtitle` | Text (plain) | Default: "Advanced treatments to protect your vision" |
| `<img>` src | `field_hero_image` | Media (image) | Placeholder: `assets/images/specialities-family.png` |
| Phone placeholder | `field_phone_placeholder` | Text (plain) | Default: "Contact Number" |
| CTA button label | `field_cta_label` | Text (plain) | Default: "Request a Callback" |
| `+91` prefix | — | Decorative HTML | No field needed; always rendered |

Hero form posts to the shared `request_a_callback` Webform (or custom route). `+91` prefix is decorative — Webform handles full phone validation.

---

## All Centres paragraph fields

**Paragraph bundle: `region_card_grid`**

| Field | Type | Notes |
|-------|------|-------|
| `field_heading` | Text (plain) | Default: "All Centres" |
| `field_subheading` | Text (plain) | Default: "Find the Nearest Eye Care Centre for Clearer Vision." |
| `field_cta_url` | Link | Default: `/eye-hospitals-india` (centre-cluster page) |
| `field_cards` | Entity reference (paragraph[], bundle: `region_card`) | 6 cards for this page |

**Nested paragraph bundle: `region_card`**

| Field | Type | Notes |
|-------|------|-------|
| `field_image` | Media (image) | Region photo |
| `field_region_name` | Text (plain) | Displayed below the image, e.g. "Delhi" |
| `field_anchor_url` | Link | Fragment URL, e.g. `/eye-hospitals-india#delhi` |

---

## Contact strip paragraph fields

**Paragraph bundle: `contact_strip`**

| Field | Type | Notes |
|-------|------|-------|
| `field_items` | Entity reference (paragraph[], bundle: `contact_strip_item`) | 3 items for this page |

**Nested paragraph bundle: `contact_strip_item`**

| Field | Type | Notes |
|-------|------|-------|
| `field_label` | Text (plain) | Display text, e.g. "Delhi NCR: 08065423777" |
| `field_phone` | Telephone | Telephone URI, e.g. `tel:08065423777` (items 1–2) |
| `field_url` | Link | Anchor/page URL for non-phone items (item 3: International Patients) |
| `field_icon_type` | List (text) | Values: `phone` \| `globe` — controls which SVG icon to render in Twig |

---

## Our Story paragraph fields

| HTML element | Paragraph field | Type | Notes |
|-------------|----------------|------|-------|
| `<h2>` text | `field_heading` | Text (plain) | Default: "Our Story and Vision" |
| Body `<p>` | `field_body` | Text (long, formatted) | Default: CFS founding story paragraph |

Paragraph bundle: `text_callout` (shared with eye-specialists and centre-cluster).

---

## Why CFS fields

**Paragraph bundle: `feature_card_grid`**

| Field | Type | Notes |
|-------|------|-------|
| `field_cards` | Entity reference (paragraph[], bundle: `feature_card`) | 4 cards for this page |

**Nested paragraph bundle: `feature_card`**

| Field | Type | Notes |
|-------|------|-------|
| `field_heading` | Text (plain) | Card title, e.g. "Eye Care Specialists" |

Card decorative line is rendered in the Twig template, not a field.

---

## FAQ fields

**Paragraph bundle: `faq_section`**

| Field | Type | Notes |
|-------|------|-------|
| `field_items` | Entity reference (paragraph[], bundle: `faq_item`) | 6 items for this page |

**Nested paragraph bundle: `faq_item`**

| Field | Type | Notes |
|-------|------|-------|
| `field_question` | Text (plain) | Accordion button text |
| `field_answer` | Text (long, formatted) | Hidden answer panel |

---

## Callback form fields

**Paragraph bundle: `callback_cta`**

| Field | Type | Notes |
|-------|------|-------|
| `field_eyebrow` | Text (plain) | Default: "Could not find what you are looking for?" |
| `field_heading` | Text (plain) | Default: "Request a Callback" |
| `field_background_image` | Media (image) | Default: `assets/images/callback-bg.png` |
| `field_webform` | Webform reference | Shared `request_a_callback` Webform |

Webform fields: `full_name` (text, required) + `phone` (telephone, required, pattern `[0-9]{10}`). Submit handlers: email notification + CRM hook.

---

## Layout risks / notes for Drupal team

1. **Category filter chip active state must be server-driven.** The static HTML uses `data-active="true"` and CSS class differences to distinguish the active chip. In Drupal, the Twig override must compare the request's `?category` query param against each chip's taxonomy term slug to set the active class. Do not attempt client-side JS toggling — the filter reloads the page.

2. **Treatment card `data-category` must match the `?category` query param slug.** The Views Exposed Filter must populate the card's `data-category` attribute with the same slug value used in the chip href (`?category=<slug>`). If taxonomy term machine names differ from slugs, normalise in Twig using `term.path.alias` or a dedicated `field_slug` field.

3. **`<main id="treatments">` wraps only the treatment grid.** The breadcrumb, hero, category filter, and all post-grid sections are direct `<body>` children in the static HTML — semantically valid HTML5 but narrower than typical Drupal page structure. The Drupal team may choose to wrap more sections inside `<main>` when building the page template; this is safe to expand.

4. **Doctor cards section reuses the homepage implementation verbatim.** No new Drupal template work is needed for section 11 — the existing `node--doctor--card.html.twig` and the "doctors" Views page display from the eye-specialists implementation cover this entirely.

5. **Accordion JS is shared.** When the Drupal team ports FAQ to Twig, do not add per-page JS. The existing `data-faq-toggle` handler in `js/main.js` already covers this page.

6. **Contact strip phone numbers are placeholders.** `08065423777` and `08065423666` are design-time placeholder values. The real numbers should come from Drupal site configuration or the `contact_strip` paragraph fields — do not hardcode them in Twig.

---

## Required Drupal modules (suggested)

- `paragraphs` (contrib)
- `webform` (for callback form)
- `media` + `media_library`
- `pathauto` (for taxonomy term URL aliases)
- `taxonomy` (core — for `speciality` and `centre_location` vocabularies)
- `views` (core — for treatment grid and doctor cards)

## Testing checklist for Drupal theme integration

- [ ] Views "treatments" page display renders treatment cards matching `04-treatment-card.html` layout
- [ ] Category filter "All" chip shows all treatments (no exposed filter applied)
- [ ] Clicking a category chip (e.g. "Cataract") narrows the grid to matching treatment nodes
- [ ] Active chip has navy bg + white text; inactive chips have navy border + white bg
- [ ] Each treatment card's `data-category` attribute reflects the node's `field_category` term slug
- [ ] All Centres section shows 6 region cards; arrow CTA links to centre-cluster page
- [ ] Contact strip items 1–2 render as `tel:` links; item 3 renders as an anchor link
- [ ] Doctor cards slider/grid renders identically to the homepage section 06
- [ ] FAQ accordion `data-faq-toggle` click expands/collapses each answer independently
- [ ] Callback form submits correctly and sends email notification
- [ ] Mobile hamburger (`data-menu-toggle`) opens full-screen nav overlay
- [ ] Sticky bottom bar visible on mobile, chat bubble visible on desktop (not both)
- [ ] Breadcrumb shows "Home › Eye Specialities"
- [ ] Hero form `+91` phone input validates 10-digit numbers only
