163 lines
14 KiB
Markdown
163 lines
14 KiB
Markdown
# 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-<date>-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 `<footer>`. CSS-only positioning in `_footer.scss`: `position: absolute; bottom: 100%` posed on the footer top edge. Footer raised to `z-index: 3` (cf. `_global.scss`) so the decors overlay the column bottom. `pointer-events: none`.
|
||
|
||
4. **Random page decors** (`.page-decor`) — `setupPageDecor` / `positionPageDecor`. One PNG per `.fullpage` (excluding `aside .fullpage` sidebars), tirage déterministe par colonne (index stocked on `col.dataset.pageDecorIdx`). Pool: `bird-1, bird-2, flower-1, flower-3` (flower-2 + bird-3 réservés au footer). Width by breakpoint, anchor switches to `.page-header-outside` on mobile. `flower-3` overlaps 40% inside (vs 20% default) because of thin stem.
|
||
|
||
5. **Home decors above carousel** (`.home-above-decor`, `flower-1` + `bird-1`) — `setupHomeAboveDecor`. Static (no parallax), debord `overlap` px on the carousel cards top edge, horizontal `offsetVw` from viewport edges.
|
||
|
||
6. **Home decors on carousel** (`.home-diapo-decor`, `home-diapo-left.png` + `home-diapo-right.png`) — `setupHomeDiapoDecor`. Anchored to `.slick-list` top (not `.carousel_container` to avoid catching the dots). Custom parallax shared with col-decor (same `applyColDecorParallax` siblings: `applyHomeDiapoParallax`). Width × `decorWidthScale()` (1× desktop, 1.5× tablet, 1.8× mobile).
|
||
|
||
7. **Home decors around projets block** (`.home-projet-decor`, `bird-2` + `flower-3`) — `setupHomeProjetDecor`. Anchored to `.map-projets`. `bird-2` at top-left (debord on the block left edge in desktop; `-3vw` from viewport in mobile/tablet). `flower-3` truncated by the viewport right edge (`right: -20px`), centered at 1/3 from block top. Static (no parallax).
|
||
|
||
The `decorWidthScale()` helper (mobile 1.8× / tablette 1.5× / desktop 1×) is shared by home-diapo, home-above, home-projet to keep widths visually comparable across screen sizes. Footer decors do NOT use it (pure CSS).
|
||
|
||
## Drupal configuration
|
||
|
||
- Exported config lives in `config/sync/` (and `config/tmp/`). Edits to config in the UI must be exported with `drush cex -y` and committed; conversely, after pulling config changes, run `drush cim -y` (via the vendor binary — see Drush gotcha).
|
||
- The project uses `wikimedia/composer-merge-plugin` to merge `web/profiles/drupal-starterkit-profile/composer.json` (itself a submodule from `figureslibres.io`).
|
||
- Drupal core is `^10.2`. Key contrib modules: `paragraphs`, `webform`, `panels`/`page_manager`, `geofield`+`leaflet` (project map), `smart_date`, `smart_trim` (responsible for `.more-link` rendering deep inside fields — see refonte conventions), `social_media_links`, `view_unpublished`.
|
||
|
||
## Database
|
||
|
||
- DB is auto-seeded from `${DB_IMPORTE_FILE}` (set in `.env` in the parent repo) on **first** `make up` only. To reload a dump later, copy the SQL into the mysql container and re-import manually — see "Updating manualy the mysql db" in the parent README.
|
||
- Credentials default to `root` / `erable` (DB name `erable`).
|
||
|
||
## Twig debugging
|
||
|
||
Twig theme debug is currently ON in this dev environment: every rendered region/block/field has `<!-- FILE NAME SUGGESTIONS -->` HTML comments listing candidate template names in priority order. To find which template controls a region of the page: View Source → search for the markup → read the suggestions above it. The active template is the first one that exists.
|
||
|
||
## Patterns to know
|
||
|
||
- Do not commit `web/sites/default/settings.local.php`, `salt.txt`, or the `files/` directory — they are environment-specific (copies of templates live in parent `ressources/drupal/`).
|
||
- The `php` container runs as the **host user** (USER_UID/USER_GID baked at build time) so file ownership stays clean. If you re-`make build` on a different machine, files written by the container will switch UID.
|
||
- xdebug is wired (see `Docker/php-8.1-fpm/` and the `XDEBUG_INI` mount). `host.docker.internal` resolves to the host on Linux via the `extra_hosts` mapping.
|
||
- Penpot is the design source of truth for the refonte. Frames of interest in the connected file: `1 - accueil - integration` (id `8997888b-7408-8014-8008-0cf456861e09`) for the home, and `3 - Single projet` (id `cb2f4013-441f-800a-8007-d81a04408009`) for the side-decor reference. Use `mcp__penpot__export_shape` to pull PNG/SVG references.
|