From 01c5b098e4002079502c9cf73c9cd2a236e40daf Mon Sep 17 00:00:00 2001 From: antonin gallon Date: Tue, 17 Feb 2026 18:10:04 +0100 Subject: [PATCH] =?UTF-8?q?refactoring=20avec=20claude=20+=20ajout=20scrol?= =?UTF-8?q?l-margin-top=20et=20d=C3=A9saffichage=20du=20panel=20au=20click?= =?UTF-8?q?=20sur=20les=20liens=20du=20toc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 7 +++ assets/css/src/article.css | 7 ++- assets/css/src/footer.css | 12 ++--- assets/css/src/toc.css | 80 +++++++++++++++------------------- assets/js/script.js | 53 +++++++++++----------- site/plugins/helpers/index.php | 8 ---- site/plugins/toc/index.php | 47 ++++++++++++++++++++ site/snippets/cover.php | 6 +-- site/snippets/footer.php | 10 ++--- site/snippets/header.php | 15 ++----- site/snippets/nav.php | 2 +- site/snippets/panel-toc.php | 8 ++-- site/snippets/toc.php | 13 ++---- site/templates/linear.php | 2 +- 14 files changed, 149 insertions(+), 121 deletions(-) create mode 100644 .claude/settings.local.json create mode 100644 site/plugins/toc/index.php diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..1782ac3 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(git show:*)" + ] + } +} diff --git a/assets/css/src/article.css b/assets/css/src/article.css index 4b3d735..c94b0bb 100644 --- a/assets/css/src/article.css +++ b/assets/css/src/article.css @@ -30,11 +30,16 @@ article #main-content #chapo::after { article #main-content li:not(.text) { list-style-type: inherit; } - article h3 { + scroll-margin-top: calc(var(--unit--vertical) * 1); margin-top: calc(3 * var(--unit--vertical)); margin-bottom: calc(1 * var(--unit--vertical)); } +@media screen and (max-width: 640px) { + article h3 { + scroll-margin-top: calc(var(--unit--vertical) * 5); + } +} article li, article ol{ margin-left: var(--unit--horizontal); diff --git a/assets/css/src/footer.css b/assets/css/src/footer.css index 6f0f5da..d575fb6 100644 --- a/assets/css/src/footer.css +++ b/assets/css/src/footer.css @@ -20,12 +20,14 @@ border-top: 1px solid var(--color-primary); background-color: var(--color-background); } - #main-footer .open-nav-wrapper_toc{ + #main-footer .open-nav-wrapper:has([data-open-panel="toc"]) { margin-right: 50px; } } + @media screen and (min-width: 1100px) { - #main-footer .open-nav-wrapper_toc{ + /* On mobile > 1100px, le bouton sommaire n'est pas nécessaire car la TOC est visible */ + #main-footer .open-nav-wrapper:has([data-open-panel="toc"]) { display: none !important; } } @@ -52,16 +54,14 @@ @media screen and (max-width: 640px) { #main-footer .open-nav { display: flex; + justify-content: center; outline: none; font-size: var(--font-size-m); background-color: var(--color-background); color: var(--color-primary); line-height: 1; padding: calc(var(--unit--vertical) / 2) var(--unit--horizontal); - } - [data-is_toc="false"] #main-footer .open-nav { - justify-content: center; - } + } } @media screen and (min-width: 640px) { diff --git a/assets/css/src/toc.css b/assets/css/src/toc.css index a2faacd..dfae1ba 100644 --- a/assets/css/src/toc.css +++ b/assets/css/src/toc.css @@ -1,47 +1,39 @@ - -.toc{ - display: flex; - flex-direction: column; - justify-content: center; -} -.page-cover .toc{ - flex: 1; -} -@media (min-width: 1100px){ - .page-cover .toc{ - position: fixed; - width: calc(var(--body-padding) - var(--unit--horizontal) * 2) ; - left: 0; - top: 15vw; - padding-inline: var(--unit--horizontal); - padding-top: calc(var(--unit--vertical) / 2); - } -} -.page-cover .toc{ - flex: 1; -} -.panel-toc .toc{ - padding: var(--unit--vertical) var(--unit--horizontal); - -} -.toc_label{ - font-size: var(--font-size-m); - margin-bottom: calc(var(--unit--vertical) / 4); /*option 1*/ -} -.toc ul{ - display: flex; - flex-direction: column; - gap: calc(var(--unit--vertical) / 4); /*option 1*/ -} -.toc li{ - margin-left: 0; - /* text-indent: var(--unit--horizontal) hanging; */ /*option 2*/ - - /* list-style: square; */ /*option 3*/ +.toc { + display: flex; + flex-direction: column; + justify-content: center; } - -[data-is_toc="false"] .if_toc, -[data-is_toc="false"] #main-footer li.if_toc{ /*obliger d'être si précis car si non pas la priorité*/ - display: none !important; +.page-cover .toc { + flex: 1; +} + +@media (min-width: 1100px) { + .page-cover .toc { + position: fixed; + width: calc(var(--body-padding) - var(--unit--horizontal) * 2); + left: 0; + top: 15vw; + padding-inline: var(--unit--horizontal); + padding-top: calc(var(--unit--vertical) / 2); + } +} + +.panel-toc .toc { + padding: var(--unit--vertical) var(--unit--horizontal); +} + +.toc_label { + font-size: var(--font-size-m); + margin-bottom: calc(var(--unit--vertical) / 4); +} + +.toc ul { + display: flex; + flex-direction: column; + gap: calc(var(--unit--vertical) / 4); +} + +.toc li { + margin-left: 0; } diff --git a/assets/js/script.js b/assets/js/script.js index 65b8735..99c2327 100644 --- a/assets/js/script.js +++ b/assets/js/script.js @@ -129,20 +129,24 @@ function subscribe(event) { } } -const panelsNav = document.querySelectorAll(".panel"); -const panelNavText = document.querySelector(".panel-text"); -const panelNavToc = document.querySelector(".panel-toc"); +const panels = document.querySelectorAll(".panel[data-panel]"); const navOverlay = document.querySelector("#nav-overlay"); -const openNavBtns = document.querySelectorAll("button.open-nav"); -const closeNavBtns = document.querySelectorAll(".panel-close"); -function closeNav() { - panelsNav.forEach(element => { - element.classList.remove("panel--visible"); - }); + +function closeAllPanels() { + panels.forEach(panel => panel.classList.remove("panel--visible")); navOverlay.classList.remove("nav-overlay--visible"); document.body.classList.remove("no-scroll"); } +function openPanel(name) { + const panel = document.querySelector(`.panel[data-panel="${name}"]`); + if (panel) { + panel.classList.add("panel--visible"); + navOverlay.classList.add("nav-overlay--visible"); + document.body.classList.add("no-scroll"); + } +} + document.addEventListener("DOMContentLoaded", () => { ragadjust("h1, h2, h4, h5", ["all"]); window.window.scrollTo({ @@ -166,10 +170,10 @@ document.addEventListener("DOMContentLoaded", () => { window.addEventListener("keyup", (event) => { if (event.key === "Escape") { - closeNav(); + closeAllPanels(); } }); - document.querySelectorAll(".panel").forEach((panel) => { + panels.forEach((panel) => { panel.addEventListener("click", (event) => { event.stopPropagation(); }); @@ -201,25 +205,20 @@ document.addEventListener("DOMContentLoaded", () => { }); }); - openNavBtns.forEach((openNavBtn) => { - openNavBtn.addEventListener("click", (event) => { - target = event.currentTarget; - if(target.classList.contains("open-nav_text")){ - panelNavText.classList.add("panel--visible"); - }else if(target.classList.contains("open-nav_toc")){ - panelNavToc.classList.add("panel--visible"); - } - navOverlay.classList.add("nav-overlay--visible"); - document.body.classList.add("no-scroll"); + document.querySelectorAll("[data-open-panel]").forEach((btn) => { + btn.addEventListener("click", () => { + openPanel(btn.dataset.openPanel); }); }); - closeNavBtns.forEach(element => { - element.addEventListener("click", () => { - closeNav(); - }); + document.querySelectorAll(".panel-close").forEach((btn) => { + btn.addEventListener("click", closeAllPanels); }); - navOverlay.addEventListener("click", () => { - closeNav(); + + navOverlay.addEventListener("click", closeAllPanels); + + // Fermer le panel TOC quand on clique sur un lien + document.querySelectorAll(".panel-toc .toc a").forEach((link) => { + link.addEventListener("click", closeAllPanels); }); }); diff --git a/site/plugins/helpers/index.php b/site/plugins/helpers/index.php index 8726f56..3a4d755 100644 --- a/site/plugins/helpers/index.php +++ b/site/plugins/helpers/index.php @@ -12,14 +12,6 @@ function allYears ($article) { return $years; } -function addAnchors($content) { - $content = preg_replace_callback('/

(.*?)<\/h3>/', function($matches) { - $slug = Str::slug($matches[1]); - return '

' . $matches[1] . '

'; - }, $content); - return $content; -} - function setTitleFontSizeClass($title, $level = 'h1') { $length = strlen($title); diff --git a/site/plugins/toc/index.php b/site/plugins/toc/index.php new file mode 100644 index 0000000..5a6e97d --- /dev/null +++ b/site/plugins/toc/index.php @@ -0,0 +1,47 @@ + [ + /** + * Vérifie si la page doit afficher une TOC + */ + 'hasToc' => function(): bool { + if (!$this->parent()?->parent()?->is('textes')) { + return false; + } + if (!$this->bodyBlocks()?->isNotEmpty()) { + return false; + } + return (bool) preg_match('/

/', $this->bodyBlocks()->toBlocks()); + }, + + /** + * Retourne les items de la TOC + */ + 'tocItems' => function(): array { + if (!$this->bodyBlocks()?->isNotEmpty()) { + return []; + } + preg_match_all('/

(.*?)<\/h3>/', $this->bodyBlocks()->toBlocks(), $matches); + + return array_map(fn($title) => [ + 'title' => $title, + 'slug' => Str::slug($title) + ], $matches[1]); + }, + + /** + * Retourne le contenu avec les ancres ajoutées aux h3 + */ + 'bodyWithAnchors' => function(): string { + if (!$this->bodyBlocks()?->isNotEmpty()) { + return ''; + } + return preg_replace_callback( + '/

(.*?)<\/h3>/', + fn($m) => '

' . $m[1] . '

', + $this->bodyBlocks()->toBlocks() + ); + } + ] +]); diff --git a/site/snippets/cover.php b/site/snippets/cover.php index 37ed66a..fc22ac3 100644 --- a/site/snippets/cover.php +++ b/site/snippets/cover.php @@ -8,9 +8,9 @@ $isOpen ??= false; title() ?> - parent() && $page->parent()->parent()->is('textes')){ - snippet('toc', ["content" => $page->bodyBlocks()->toBlocks()]); - } ?> + hasToc()): ?> + + text()): ?>
text() ?> diff --git a/site/snippets/footer.php b/site/snippets/footer.php index 8ea5582..61b668b 100644 --- a/site/snippets/footer.php +++ b/site/snippets/footer.php @@ -2,12 +2,12 @@ is(page('lettre')) && !$page->is(page('a-propos'))): ?>