# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Repository layout This directory (`src/`) is a **git submodule** of the parent `docker-erable` repo. It holds the Drupal 10 application; the parent repo holds the Docker environment (`Docker/`, `docker-compose.yml`, `Makefile`, `ressources/db.sql`). - `src/` (this repo, `drupal-erable.git`) — Drupal codebase, custom theme & modules, exported config. - `../` (parent repo, `docker-erable.git`) — Docker setup, DB seed, Makefile commands. Branches: `master` (dev), `stage` (preprod), `prod` (prod). A `refonte-graphique` branch is currently active for the ongoing visual redesign — **all work happens there**, not on `master`. `git push origin master` from `src/` will appear up-to-date even after committing on `refonte-graphique`; push the branch by name. The parent repo references the submodule under its own branch set (`master`, `prod`). After pulling parent changes, run `git submodule update --recursive --checkout`. ## Commands All commands are run **from the parent directory** (`docker-erable/`), never directly from `src/`. Never use `docker-compose` directly — always go through the Makefile. ```sh make build # first-time build (uses host UID/GID via build args — do not skip) make up # start the stack (php, nginx, mysql, redis, phpmyadmin) make down # stop make logs # follow logs make ps # status make exec_php # shell into the PHP container (where drush lives) make exec_mysql # shell into the MySQL container make dump_db # dump erable DB to ressources/erable--local.sql ``` After pulling code changes that affect Drupal config/schema: ```sh make maj_config # composer install + drush updb + drush cim + drush cr + drush pag ``` Individual Drupal ops (also available as Make targets): ```sh make composer_install # composer install --no-dev in the php container make updb # drush updb -y make cim # drush config-import -y make cr # drush cr (cache rebuild) make pag # drush pag all for nodes & taxonomy terms ``` For ad-hoc drush use, `make exec_php` then run `drush ...` from `/var/www/erable/`. ### Drush gotcha (Make targets broken) The Make targets that wrap drush (`cr`, `cim`, `updb`, `crd`, `pag`, and the composite `maj_config`) are currently broken because the container's global `drush` is the Drush Launcher, which errors out against Drush 12+ (`Drush Launcher is not compatible with Drush 12+`). Until the parent `Makefile` is fixed, call the vendor binary directly: ```sh docker exec erable-php-1 /var/www/erable/vendor/bin/drush cr docker exec erable-php-1 /var/www/erable/vendor/bin/drush cim -y docker exec erable-php-1 /var/www/erable/vendor/bin/drush updb -y ``` Inside an `exec_php` shell, use `vendor/bin/drush` (or `./vendor/bin/drush` from `/var/www/erable/`) — not the bare `drush`. ### When to run drush cr **Every Twig template edit must be followed by a cache rebuild**, otherwise Drupal keeps serving the previously rendered markup. This applies to anything under `web/themes/erabletheme/templates/` and any custom module template (e.g. `web/modules/custom/erable_mod/templates/`). SCSS/CSS changes do NOT require `drush cr` (the CSS file is served as-is by Drupal). Run: ```sh docker exec erable-php-1 /var/www/erable/vendor/bin/drush cr ``` after every `.twig` edit, then hard-reload the browser. Site URL (via reverse proxy on the host): `http://dev.erable.fr` (container exposed on `:8980`). phpMyAdmin on `http://dev.phpmyadmin.erable.fr` (`:8981`). See parent `README.md` for the nginx/apache vhost snippets. ## Theme build The custom theme is `web/themes/erabletheme/`. SCSS is compiled to CSS via **Dart Sass** (`sass` package, not `node-sass`): ```sh cd web/themes/erabletheme npm install # first time only npm run sass # runs: sass --watch --no-source-map scss/styles.scss:css/styles.css ``` The compiled `css/styles.css` is what Drupal serves (see `erabletheme.libraries.yml`). The watch must be running while editing SCSS, or styles won't update. If `npm run sass` ever appears to output into `scss/` itself, the script has been mis-set — the entry must be the `IN:OUT` form `scss/styles.scss:css/styles.css`, not two positional args. Compile failures surface in the rendered page as garbage in `body::before { content: "..." }` (the Sass watcher injects the error there). To see them from a script: `curl -s http://dev.erable.fr | grep -A2 'body::before'`. ## Custom code - **`web/themes/erabletheme/`** — base theme: `stark`. SCSS entry is `scss/styles.scss`, which imports `global/`, `partials/`, and per-page files (`_home.scss`, `_projets.scss`, `_actualites.scss`, …). Twig templates override blocks, regions, nodes and views; node templates live under `templates/node/` per content type (`actualite`, `projet`, `partenaire`, `equipe`, `ressource`, `meetup`). The single JS file is `js/erabletheme.js`. Slick carousel is vendored under `librairies/slick-1.8.1/`. Rellax is also vendored under `librairies/` (powers the parallax background). - **`web/modules/custom/erable_mod/`** — site-specific module (routes, blocks, controllers under `src/`, templates under `templates/`). Notable: `SitesMap` block (`src/Plugin/Block/SitesMap.php`) renders project markers on the home map; its SVG marker template is at `assets/svg/point.svg` and the Twig wrapper at `templates/svg-mapsites.html.twig`. - **`web/modules/custom/loginregisterblock/`** — combined login + register block. ## Theme design system (post-refonte) The redesign on `refonte-graphique` introduces a token-driven design system. **All typography sizes are in `rem`**, never `px` (one exception: deliberate "magic numbers" tied to a slick-carousel structural quirk in `_carousel.scss`, commented as such). ### Tokens (single source of truth) - `scss/global/variables/_colors.scss` — brand colors. `$fluo_green: #33ffc4` is the new accent; `$teal` is aliased to `$fluo_green` so legacy `$teal` usages propagate automatically. Other tokens: `$page_bg: #f9f9f9` (site background), `$text_grey: #4a4a49`, `$dark_green`, `$beige`. Gradient mixins `beige_gradient()` and `white_beige_gradient()` live here too. - `scss/global/variables/_typography.scss` — font-size scale + line-heights + weights + semantic mixins. All sizes in `rem`: - `$fs_xs: 0.8125rem` (≈13px), `$fs_sm: 0.9375rem` (≈15px), `$fs_md: 1.0625rem` (≈17px), `$fs_lg: 1.375rem` (≈22px), `$fs_xl: 2.25rem` (≈36px), `$fs_2xl: 3.5625rem` (≈57px). - Mixins (**use these, do not hardcode font properties**): `main_title()`, `sous_titre()`, `sous_titre_alt()` (intermediate Vogun 22→36px), `main_text_content()`, `meta_text()`, `cta_text()`, `fluo_button()` (the universal CTA — propagates to `.more-link` and `footer.fluo_links` site-wide). - `scss/global/_fonts.scss` — `@font-face` declarations. **Vogun** (titles/CTA, `fonts/Vogun/Vogun-Regular.woff2`) and **Marianne** (body) are the only typefaces. Barlow has been removed. - `scss/global/variables/_layout.scss` — breakpoints: `$breakpoint_tablet: 760px`, `$breakpoint_desktop: 1080px`, `$breakpoint_desktop_large: 1600px`. Plus `$x_margin` for horizontal page padding. ### Responsive philosophy Mobile-first via `vw` for proportional sizing + `max-width` (or aspect ratios) to cap on large screens. Avoid hard `px` breakpoints in component sizing — use the breakpoint variables for layout shifts only. ### Refonte branch conventions - This is a redesign branch, so **replace** legacy code rather than stacking new styles on top. Removing the old `$teal` value, renaming Barlow out, deleting unused SVGs (e.g. `feuille.svg`) is the norm here. - Semantic mixin names (`main_title`, `sous_titre`) are kept even when their visual content is overhauled — this preserves call-sites across all per-page SCSS files. - It's OK to edit Twig block templates (e.g. `block--views-block--home-blocks-block-1.html.twig`, `block--sitesmap-block.html.twig`) when restructuring layouts. Avoid editing core templates like `node.html.twig` or `field--body.html.twig` to limit side effects. - The CTA "En savoir plus" on the home is reparented by JS (see `js/erabletheme.js` — `intro.appendChild(moreLink)`) because `smart_trim` renders `.more-link` deep inside `article > div`. This is intentional and lets the separator stop at text-end instead of button-end. ### Décors parallax v2 All decor systems are JS-driven (injection + positioning + parallax where applicable). Common entry points live in `Drupal.behaviors.erabletheme.attach` inside `erabletheme.js`; positions recompute on `window.load`, `window.resize` (debounced 200ms). Body scroll is on `body` (not `html`) — see `_global.scss` (`body { overflow: scroll }`, `html { overflow: hidden }`). Rellax's `wrapper: 'body'` and the custom parallax scroll listener both depend on this. Assets live in `assets/new-bg-shapes/` (frises, mid-left, home-diapo) and `assets/drawings/` (oiseaux, fleurs ponctuels). 1. **Side frises** (`.bgImg.decor-left/right`) — single `.decor-tile` in `page.html.twig` cloned by JS (`setupBackgroundTiles`) to fill `layout-container.offsetHeight`, then animated by Rellax (`new Rellax('.bgImg', { wrapper: 'body' })`). SCSS: `_background.scss` (positions in `%` of tile). `.decor-once` images (cut-at-top) are removed from clones. 2. **Mid-left column decors** (`.col-decor`, `mid-left-1.png` + `mid-left-2.png`) — `setupColDecor` / `positionColDecor` / `applyColDecorParallax`. Two cibles: - `.fullpage:not(.large-container)` (internal pages): stack of up to 2 PNG at the bottom-left outer edge of the column. Sizes + gaps proportional to colH, min/max clamped. Display thresholds: 50% colH for both, 30% for one. - `.map-projets` (home "projets" block): single PNG via `singleOnly: true`, threshold 50%. Custom parallax (subtle upward translate, capped ±30px). Bord droit of PNG calé on bord gauche extérieur via `translateX(-100%)`. Visibility responsive: `_background.scss`. 3. **Footer ornements** (`.footer-decor`, `bird-3.png` + `flower-2.png`) — Twig in `page.html.twig` inside `