Files
drupal-erable/CLAUDE.md

14 KiB
Raw Permalink Blame History

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.

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:

make maj_config     # composer install + drush updb + drush cim + drush cr + drush pag

Individual Drupal ops (also available as Make targets):

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:

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:

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):

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.jsintro.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.