14 KiB
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 isscss/styles.scss, which importsglobal/,partials/, and per-page files (_home.scss,_projets.scss,_actualites.scss, …). Twig templates override blocks, regions, nodes and views; node templates live undertemplates/node/per content type (actualite,projet,partenaire,equipe,ressource,meetup). The single JS file isjs/erabletheme.js. Slick carousel is vendored underlibrairies/slick-1.8.1/. Rellax is also vendored underlibrairies/(powers the parallax background).web/modules/custom/erable_mod/— site-specific module (routes, blocks, controllers undersrc/, templates undertemplates/). Notable:SitesMapblock (src/Plugin/Block/SitesMap.php) renders project markers on the home map; its SVG marker template is atassets/svg/point.svgand the Twig wrapper attemplates/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: #33ffc4is the new accent;$tealis aliased to$fluo_greenso legacy$tealusages propagate automatically. Other tokens:$page_bg: #f9f9f9(site background),$text_grey: #4a4a49,$dark_green,$beige. Gradient mixinsbeige_gradient()andwhite_beige_gradient()live here too.scss/global/variables/_typography.scss— font-size scale + line-heights + weights + semantic mixins. All sizes inrem:$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-linkandfooter.fluo_linkssite-wide).
scss/global/_fonts.scss—@font-facedeclarations. 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_marginfor 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
$tealvalue, 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 likenode.html.twigorfield--body.html.twigto limit side effects. - The CTA "En savoir plus" on the home is reparented by JS (see
js/erabletheme.js—intro.appendChild(moreLink)) becausesmart_trimrenders.more-linkdeep insidearticle > 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).
-
Side frises (
.bgImg.decor-left/right) — single.decor-tileinpage.html.twigcloned by JS (setupBackgroundTiles) to filllayout-container.offsetHeight, then animated by Rellax (new Rellax('.bgImg', { wrapper: 'body' })). SCSS:_background.scss(positions in%of tile)..decor-onceimages (cut-at-top) are removed from clones. -
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 viasingleOnly: true, threshold 50%. Custom parallax (subtle upward translate, capped ±30px). Bord droit of PNG calé on bord gauche extérieur viatranslateX(-100%). Visibility responsive:_background.scss.
-
Footer ornements (
.footer-decor,bird-3.png+flower-2.png) — Twig inpage.html.twiginside<footer>. CSS-only positioning in_footer.scss:position: absolute; bottom: 100%posed on the footer top edge. Footer raised toz-index: 3(cf._global.scss) so the decors overlay the column bottom.pointer-events: none. -
Random page decors (
.page-decor) —setupPageDecor/positionPageDecor. One PNG per.fullpage(excludingaside .fullpagesidebars), tirage déterministe par colonne (index stocked oncol.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-outsideon mobile.flower-3overlaps 40% inside (vs 20% default) because of thin stem. -
Home decors above carousel (
.home-above-decor,flower-1+bird-1) —setupHomeAboveDecor. Static (no parallax), debordoverlappx on the carousel cards top edge, horizontaloffsetVwfrom viewport edges. -
Home decors on carousel (
.home-diapo-decor,home-diapo-left.png+home-diapo-right.png) —setupHomeDiapoDecor. Anchored to.slick-listtop (not.carousel_containerto avoid catching the dots). Custom parallax shared with col-decor (sameapplyColDecorParallaxsiblings:applyHomeDiapoParallax). Width ×decorWidthScale()(1× desktop, 1.5× tablet, 1.8× mobile). -
Home decors around projets block (
.home-projet-decor,bird-2+flower-3) —setupHomeProjetDecor. Anchored to.map-projets.bird-2at top-left (debord on the block left edge in desktop;-3vwfrom viewport in mobile/tablet).flower-3truncated 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/(andconfig/tmp/). Edits to config in the UI must be exported withdrush cex -yand committed; conversely, after pulling config changes, rundrush cim -y(via the vendor binary — see Drush gotcha). - The project uses
wikimedia/composer-merge-pluginto mergeweb/profiles/drupal-starterkit-profile/composer.json(itself a submodule fromfigureslibres.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-linkrendering deep inside fields — see refonte conventions),social_media_links,view_unpublished.
Database
- DB is auto-seeded from
${DB_IMPORTE_FILE}(set in.envin the parent repo) on firstmake uponly. 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 nameerable).
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 thefiles/directory — they are environment-specific (copies of templates live in parentressources/drupal/). - The
phpcontainer runs as the host user (USER_UID/USER_GID baked at build time) so file ownership stays clean. If you re-make buildon a different machine, files written by the container will switch UID. - xdebug is wired (see
Docker/php-8.1-fpm/and theXDEBUG_INImount).host.docker.internalresolves to the host on Linux via theextra_hostsmapping. - Penpot is the design source of truth for the refonte. Frames of interest in the connected file:
1 - accueil - integration(id8997888b-7408-8014-8008-0cf456861e09) for the home, and3 - Single projet(idcb2f4013-441f-800a-8007-d81a04408009) for the side-decor reference. Usemcp__penpot__export_shapeto pull PNG/SVG references.