From 0d5e9dac19fd7e223f778ce74b37a706b1d63b6b Mon Sep 17 00:00:00 2001 From: Pontoporeia Date: Sat, 20 Jun 2026 13:29:36 +0200 Subject: [PATCH] fix: make sticky TOC work for full scroll height and fix heading anchor links --- TODO.md | 10 ++++----- app/public/assets/css/apropos.css | 24 +++++++++++++-------- app/public/assets/css/components/header.css | 3 +++ app/src/Controllers/CharteController.php | 1 + app/src/Controllers/LicenceController.php | 1 + 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/TODO.md b/TODO.md index b4613c1..810fd95 100644 --- a/TODO.md +++ b/TODO.md @@ -1,22 +1,22 @@ # TODO -> Last updated: 2026-06-19 -> Context: Analyse OverType editors on /admin/contenus-edit.php: concurrency safety, save reliability, content truncation bugs +> Last updated: 2026-06-20 +> Context: Fix sticky TOC going out of view + heading anchor links not working on charte/licence/apropos pages ## In Progress -- [ ] #overtype-analysis Analyse and fix OverType editor reliability on contenus-edit.php ## Pending +- [ ] #overtype-analysis Analyse and fix OverType editor reliability on contenus-edit.php - [x] #tfe-optional-formats Make TFE file optional when format is Site web (1), Performance (4) or Installation (6) — fixed incorrect format IDs [3→1,4,6] + added client-side JS toggle for TFE required/asterisk. Note d'intention remains required. 🎯 `(fichiers-fragment.php, file-upload-filepond.js)` ✓ - [x] #typography-weight-300 Set search placeholder + apropos/charte/licence

content to BBBDMSans weight 300 `(search.css, apropos.css)` ✓ - [x] #toc-parts-uppercase Hardcode "PARTIES" uppercase + black bottom border on TOC label `(about.php, charte.php, licence.php, apropos.css)` ✓ - [x] #apropos-overflow Prevent #apropos-intro and content-section children from overflowing `(apropos.css)` ✓ -- [x] #toc-navigation Fix TOC links not navigating to headings — enable `heading_permalink` extension in CommonMark with `id_prefix: ''`, `insert: 'before'`, `aria_hidden: true` + register extension on environment; use CommonMark's SlugNormalizer in extractToc; hide permalink anchors with CSS; add `min-width: 0` to `.content` to prevent grid overflow `(CharteController.php, LicenceController.php, MarkdownHelper.php, apropos.css)` ✓ +- [x] #toc-navigation Fix TOC links not navigating to headings — added `apply_id_to_heading: true` to CommonMark config so IDs land on headings not hidden elements; added scroll-margin-top to headings; unstuck main from flex container so sticky TOC works for full page height `(CharteController.php, LicenceController.php, apropos.css)` ✓ - [x] #apropos-toc-style Fix TOC "Parties" label: Ductus font + lowercase, remove border-left from links, match global link style; rename .apropos-content → section.content, .apropos-section → .content-section, remove .prose wrapper `(apropos.css, about.php, charte.php, licence.php)` ✓ -- [ ] #apropos-toc-confirm Visually confirm charte + licence TOC layout renders correctly in browser (dup after #apropos-toc-style) +- [x] #apropos-toc-confirm Fixed sticky TOC: removed `flex: 1; min-height: 0` on main for apropos-body so the sticky container is full content height; added `max-height` + `overflow-y: auto` to TOC for long lists `(apropos.css)` ✓ - [ ] #aria-test-manual Test WCAG changes with VoiceOver and NVDA on full add/edit/partage form flows - [ ] #nojs-upload-test Test end-to-end: submit partage form with JS disabled, verify files arrive via `$_FILES` - [ ] #csp-media-iframe-deploy Deploy nginx config fix to server, test PDF iframe on /tfe?id=221 diff --git a/app/public/assets/css/apropos.css b/app/public/assets/css/apropos.css index c695414..777cb5e 100644 --- a/app/public/assets/css/apropos.css +++ b/app/public/assets/css/apropos.css @@ -3,15 +3,14 @@ Root class: .page-content ============================================================ */ -/* Override body overflow:hidden — these pages use the viewport scrollbar - so that anchor navigation (#fragment) works natively. */ -.apropos-body { - overflow: auto; -} +/* Keep the base flex layout (no html/body overrides) — + main scrolls internally so the body gradient stays at viewport bottom. */ .page-content { flex: 1; min-height: 0; + overflow-y: auto; + overflow-x: hidden; scroll-behavior: smooth; padding: var(--space-xl) var(--space-l) var(--space-2xl); display: grid; @@ -21,7 +20,7 @@ } /* ------------------------------------------------------------------ */ -/* Left — sticky table of contents */ +/* Left — sticky table of contents */ /* ------------------------------------------------------------------ */ .apropos-toc { @@ -173,7 +172,7 @@ word-break: normal; font-family: "Courier New", Courier, monospace; font-size: 0.88em; - background: var(--bg-tertiary); + background: color-mix(in srgb, var(--bg-tertiary) 50%, transparent); padding: 0.5em 0.75em; border-radius: var(--radius); white-space: pre-wrap; @@ -198,7 +197,7 @@ .page-content > .content-section:last-child { border-bottom: none; margin-bottom: 0; - padding-bottom: 0; + padding-bottom: var(--space-xl); } /* ------------------------------------------------------------------ */ @@ -214,7 +213,13 @@ line-height: 1.1; } -/* Hide CommonMark heading permalink anchors (needed only for their id attr) */ +/* Scroll margin so anchor links account for the sticky header */ +.content :where(h1, h2, h3), +.content-section :where(h1, h2, h3) { + scroll-margin-top: var(--space-l); +} + +/* Hide CommonMark heading permalink anchors (id now lives on the heading itself) */ .heading-permalink { display: none; } @@ -324,6 +329,7 @@ .page-content { grid-template-columns: 1fr; gap: var(--space-l); + padding: var(--space-m) var(--space-s) var(--space-xl); } .apropos-toc { diff --git a/app/public/assets/css/components/header.css b/app/public/assets/css/components/header.css index b9801ec..f082813 100644 --- a/app/public/assets/css/components/header.css +++ b/app/public/assets/css/components/header.css @@ -56,6 +56,9 @@ header nav ul a:hover { header nav ul a[aria-current="page"] { color: var(--accent-primary); + text-shadow: + 0 0 4px white, + 0 0 8px white; border-radius: 0; border-bottom: 2px solid currentColor; padding-bottom: 1px; diff --git a/app/src/Controllers/CharteController.php b/app/src/Controllers/CharteController.php index 6068e26..3583d7b 100644 --- a/app/src/Controllers/CharteController.php +++ b/app/src/Controllers/CharteController.php @@ -31,6 +31,7 @@ class CharteController $converter = new CommonMarkConverter([ 'html_input' => 'strip', 'heading_permalink' => [ + 'apply_id_to_heading' => true, 'id_prefix' => '', 'insert' => 'before', 'aria_hidden' => true, diff --git a/app/src/Controllers/LicenceController.php b/app/src/Controllers/LicenceController.php index 79e164c..a6854e1 100644 --- a/app/src/Controllers/LicenceController.php +++ b/app/src/Controllers/LicenceController.php @@ -31,6 +31,7 @@ class LicenceController $converter = new CommonMarkConverter([ 'html_input' => 'strip', 'heading_permalink' => [ + 'apply_id_to_heading' => true, 'id_prefix' => '', 'insert' => 'before', 'aria_hidden' => true,