refactoring avec claude + ajout scroll-margin-top et désaffichage du panel au click sur les liens du toc
This commit is contained in:
parent
d51fc592ed
commit
01c5b098e4
14 changed files with 149 additions and 121 deletions
7
.claude/settings.local.json
Normal file
7
.claude/settings.local.json
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(git show:*)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -30,11 +30,16 @@ article #main-content #chapo::after {
|
||||||
article #main-content li:not(.text) {
|
article #main-content li:not(.text) {
|
||||||
list-style-type: inherit;
|
list-style-type: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
article h3 {
|
article h3 {
|
||||||
|
scroll-margin-top: calc(var(--unit--vertical) * 1);
|
||||||
margin-top: calc(3 * var(--unit--vertical));
|
margin-top: calc(3 * var(--unit--vertical));
|
||||||
margin-bottom: calc(1 * 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{
|
article li, article ol{
|
||||||
margin-left: var(--unit--horizontal);
|
margin-left: var(--unit--horizontal);
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,14 @@
|
||||||
border-top: 1px solid var(--color-primary);
|
border-top: 1px solid var(--color-primary);
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
}
|
}
|
||||||
#main-footer .open-nav-wrapper_toc{
|
#main-footer .open-nav-wrapper:has([data-open-panel="toc"]) {
|
||||||
margin-right: 50px;
|
margin-right: 50px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1100px) {
|
@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;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,16 +54,14 @@
|
||||||
@media screen and (max-width: 640px) {
|
@media screen and (max-width: 640px) {
|
||||||
#main-footer .open-nav {
|
#main-footer .open-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
outline: none;
|
outline: none;
|
||||||
font-size: var(--font-size-m);
|
font-size: var(--font-size-m);
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
padding: calc(var(--unit--vertical) / 2) var(--unit--horizontal);
|
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) {
|
@media screen and (min-width: 640px) {
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,39 @@
|
||||||
|
.toc {
|
||||||
.toc{
|
display: flex;
|
||||||
display: flex;
|
flex-direction: column;
|
||||||
flex-direction: column;
|
justify-content: center;
|
||||||
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*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-cover .toc {
|
||||||
[data-is_toc="false"] .if_toc,
|
flex: 1;
|
||||||
[data-is_toc="false"] #main-footer li.if_toc{ /*obliger d'être si précis car si non pas la priorité*/
|
}
|
||||||
display: none !important;
|
|
||||||
|
@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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,20 +129,24 @@ function subscribe(event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const panelsNav = document.querySelectorAll(".panel");
|
const panels = document.querySelectorAll(".panel[data-panel]");
|
||||||
const panelNavText = document.querySelector(".panel-text");
|
|
||||||
const panelNavToc = document.querySelector(".panel-toc");
|
|
||||||
const navOverlay = document.querySelector("#nav-overlay");
|
const navOverlay = document.querySelector("#nav-overlay");
|
||||||
const openNavBtns = document.querySelectorAll("button.open-nav");
|
|
||||||
const closeNavBtns = document.querySelectorAll(".panel-close");
|
function closeAllPanels() {
|
||||||
function closeNav() {
|
panels.forEach(panel => panel.classList.remove("panel--visible"));
|
||||||
panelsNav.forEach(element => {
|
|
||||||
element.classList.remove("panel--visible");
|
|
||||||
});
|
|
||||||
navOverlay.classList.remove("nav-overlay--visible");
|
navOverlay.classList.remove("nav-overlay--visible");
|
||||||
document.body.classList.remove("no-scroll");
|
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", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
ragadjust("h1, h2, h4, h5", ["all"]);
|
ragadjust("h1, h2, h4, h5", ["all"]);
|
||||||
window.window.scrollTo({
|
window.window.scrollTo({
|
||||||
|
|
@ -166,10 +170,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
||||||
window.addEventListener("keyup", (event) => {
|
window.addEventListener("keyup", (event) => {
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
closeNav();
|
closeAllPanels();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
document.querySelectorAll(".panel").forEach((panel) => {
|
panels.forEach((panel) => {
|
||||||
panel.addEventListener("click", (event) => {
|
panel.addEventListener("click", (event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
@ -201,25 +205,20 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
openNavBtns.forEach((openNavBtn) => {
|
document.querySelectorAll("[data-open-panel]").forEach((btn) => {
|
||||||
openNavBtn.addEventListener("click", (event) => {
|
btn.addEventListener("click", () => {
|
||||||
target = event.currentTarget;
|
openPanel(btn.dataset.openPanel);
|
||||||
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");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
closeNavBtns.forEach(element => {
|
document.querySelectorAll(".panel-close").forEach((btn) => {
|
||||||
element.addEventListener("click", () => {
|
btn.addEventListener("click", closeAllPanels);
|
||||||
closeNav();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,6 @@ function allYears ($article) {
|
||||||
return $years;
|
return $years;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAnchors($content) {
|
|
||||||
$content = preg_replace_callback('/<h3>(.*?)<\/h3>/', function($matches) {
|
|
||||||
$slug = Str::slug($matches[1]);
|
|
||||||
return '<h3 id="' . $slug . '">' . $matches[1] . '</h3>';
|
|
||||||
}, $content);
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setTitleFontSizeClass($title, $level = 'h1')
|
function setTitleFontSizeClass($title, $level = 'h1')
|
||||||
{
|
{
|
||||||
$length = strlen($title);
|
$length = strlen($title);
|
||||||
|
|
|
||||||
47
site/plugins/toc/index.php
Normal file
47
site/plugins/toc/index.php
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
Kirby::plugin('actuel-inactuel/toc', [
|
||||||
|
'pageMethods' => [
|
||||||
|
/**
|
||||||
|
* 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('/<h3>/', $this->bodyBlocks()->toBlocks());
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne les items de la TOC
|
||||||
|
*/
|
||||||
|
'tocItems' => function(): array {
|
||||||
|
if (!$this->bodyBlocks()?->isNotEmpty()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
preg_match_all('/<h3>(.*?)<\/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>(.*?)<\/h3>/',
|
||||||
|
fn($m) => '<h3 id="' . Str::slug($m[1]) . '">' . $m[1] . '</h3>',
|
||||||
|
$this->bodyBlocks()->toBlocks()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
@ -8,9 +8,9 @@ $isOpen ??= false;
|
||||||
<?= $slots->title() ?>
|
<?= $slots->title() ?>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<?php if ($page->parent() && $page->parent()->parent()->is('textes')){
|
<?php if ($page->hasToc()): ?>
|
||||||
snippet('toc', ["content" => $page->bodyBlocks()->toBlocks()]);
|
<?php snippet('toc') ?>
|
||||||
} ?>
|
<?php endif ?>
|
||||||
<?php if ($slots->text()): ?>
|
<?php if ($slots->text()): ?>
|
||||||
<div class="text-wrapper">
|
<div class="text-wrapper">
|
||||||
<?= $slots->text() ?>
|
<?= $slots->text() ?>
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
<?php if (!$page->is(page('lettre')) && !$page->is(page('a-propos'))): ?>
|
<?php if (!$page->is(page('lettre')) && !$page->is(page('a-propos'))): ?>
|
||||||
<footer id="main-footer">
|
<footer id="main-footer">
|
||||||
<ul id="links">
|
<ul id="links">
|
||||||
<li class="open-nav-wrapper open-nav-wrapper_text hidden">
|
<li class="open-nav-wrapper hidden">
|
||||||
<button class="plus open-nav open-nav_text" title="chercher parmi les textes">textes</button>
|
<button class="plus open-nav" data-open-panel="text" title="chercher parmi les textes">textes</button>
|
||||||
</li>
|
</li>
|
||||||
<?php if ($page->parent() && $page->parent()->parent()->is('textes')): ?>
|
<?php if ($page->hasToc()): ?>
|
||||||
<li class="open-nav-wrapper open-nav-wrapper_toc hidden if_toc">
|
<li class="open-nav-wrapper hidden">
|
||||||
<button class="plus open-nav open-nav_toc" title="ouvrir le sommaire">sommaire</button>
|
<button class="plus open-nav" data-open-panel="toc" title="ouvrir le sommaire">sommaire</button>
|
||||||
</li>
|
</li>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<li>
|
<li>
|
||||||
|
|
|
||||||
|
|
@ -84,13 +84,7 @@ $entryTopPos ??= 20;
|
||||||
|
|
||||||
<body
|
<body
|
||||||
class="background-grid <?= e($page->fullWidth() == 'true', 'full-width') ?>"
|
class="background-grid <?= e($page->fullWidth() == 'true', 'full-width') ?>"
|
||||||
data-is_toc="<?php
|
data-has-toc="<?= $page->hasToc() ? 'true' : 'false' ?>"
|
||||||
if ($page->bodyBlocks() && $page->bodyBlocks()->isNotEmpty() && preg_match('/<h3>(.*?)<\/h3>/', $page->bodyBlocks())){
|
|
||||||
echo "true";
|
|
||||||
}else{
|
|
||||||
echo "false";
|
|
||||||
}
|
|
||||||
?>"
|
|
||||||
data-template="<?= $page->template() ?>">
|
data-template="<?= $page->template() ?>">
|
||||||
<button class="theme-toggler" data-theme-toggler>
|
<button class="theme-toggler" data-theme-toggler>
|
||||||
<span class="theme-toggler-icon"></span>
|
<span class="theme-toggler-icon"></span>
|
||||||
|
|
@ -107,8 +101,7 @@ $entryTopPos ??= 20;
|
||||||
</a>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
<?php snippet('nav') ?>
|
<?php snippet('nav') ?>
|
||||||
<?php if ($page->parent() && $page->parent()->parent()->is('textes')){
|
<?php if ($page->hasToc()): ?>
|
||||||
snippet('panel-toc');
|
<?php snippet('panel-toc') ?>
|
||||||
}
|
<?php endif ?>
|
||||||
?>
|
|
||||||
<div id="nav-overlay"></div>
|
<div id="nav-overlay"></div>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<nav class="panel panel-text" x-data="{search: ''}">
|
<nav class="panel panel-text" data-panel="text" x-data="{search: ''}">
|
||||||
<header>
|
<header>
|
||||||
<p class="sort-btns">
|
<p class="sort-btns">
|
||||||
<button class="sort-btn sort-btn--years active">années</span></button>
|
<button class="sort-btn sort-btn--years active">années</span></button>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
<div class="panel panel-toc" x-data="{search: ''}">
|
<div class="panel panel-toc" data-panel="toc">
|
||||||
<?php
|
<?php snippet('toc') ?>
|
||||||
snippet('toc', ["content" => $page->bodyBlocks()->toBlocks()]);
|
|
||||||
?>
|
|
||||||
<button class="less panel-close">sommaire</button>
|
<button class="less panel-close">sommaire</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,8 @@
|
||||||
<nav class="toc">
|
<nav class="toc">
|
||||||
<div class="light toc_label if_toc">Sommaire</div>
|
<div class="light toc_label">Sommaire</div>
|
||||||
<ul>
|
<ul>
|
||||||
<?php
|
<?php foreach ($page->tocItems() as $item): ?>
|
||||||
preg_match_all('/<h3>(.*?)<\/h3>/', $content, $titres);
|
<li><a href="#<?= $item['slug'] ?>"><?= $item['title'] ?></a></li>
|
||||||
foreach ($titres[1] as $index => $titre) {
|
<?php endforeach ?>
|
||||||
$slug = Str::slug($titre);
|
|
||||||
echo '<li><a href="#' . $slug . '">' . $titre . '</a></li>';
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
<?php if ($page->isHtmlMode()->isTrue()): ?>
|
<?php if ($page->isHtmlMode()->isTrue()): ?>
|
||||||
<?= $page->htmlBody()->kt() ?>
|
<?= $page->htmlBody()->kt() ?>
|
||||||
<?php elseif ($page->bodyBlocks()->isNotEmpty()): ?>
|
<?php elseif ($page->bodyBlocks()->isNotEmpty()): ?>
|
||||||
<?= addAnchors($page->bodyBlocks()->toBlocks()) ?>
|
<?= $page->bodyWithAnchors() ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?= $page->body() ?>
|
<?= $page->body() ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue