feat(glossaire): polish sticky entry flow and aside navigation
All checks were successful
SMOKE / smoke (push) Successful in 18s
CI / build-and-anchors (push) Successful in 48s
CI / build-and-anchors (pull_request) Successful in 48s

This commit is contained in:
2026-03-24 00:29:39 +01:00
parent e39a0c547d
commit 87955adf5d
18 changed files with 3639 additions and 584 deletions

View File

@@ -66,21 +66,44 @@ const paradigmesCount = paradigmes.length;
</Fragment>
<section class="theo-page" data-theo-page>
<div class="theo-hero" data-theo-hero>
<div class="theo-hero glossary-page-hero" data-theo-hero>
<p class="theo-kicker">Cartographie théorique</p>
<h1>Paradigmes et doctrines</h1>
<p class="theo-intro">
Larchicratie ne se déploie pas dans le vide. Elle sinscrit dans un
paysage intellectuel plus large où se croisent des doctrines
fondatrices de lordre et des paradigmes de régulation des collectifs.
</p>
<p class="theo-intro">
On appellera ici <strong>doctrines fondatrices</strong> les formulations
qui posent un principe premier de légitimité, de souveraineté ou dordre
politique. On appellera <strong>paradigmes régulateurs</strong> les
cadres théoriques qui décrivent des modes de tenue, de conflictualité,
dadministration, de reproduction ou de transformation des sociétés.
</p>
<div class="theo-hero-collapsible">
<div
class="theo-hero-more"
id="theo-hero-more"
data-theo-more
aria-hidden="false"
>
<p class="theo-intro">
On appellera ici <strong>doctrines fondatrices</strong> les formulations
qui posent un principe premier de légitimité, de souveraineté ou dordre
politique. On appellera <strong>paradigmes régulateurs</strong> les
cadres théoriques qui décrivent des modes de tenue, de conflictualité,
dadministration, de reproduction ou de transformation des sociétés.
</p>
</div>
<button
class="theo-hero-toggle"
id="theo-hero-toggle"
data-theo-more-toggle
type="button"
aria-controls="theo-hero-more"
aria-expanded="false"
hidden
>
lire la suite
</button>
</div>
</div>
{doctrines.length > 0 && (
@@ -227,12 +250,20 @@ const paradigmesCount = paradigmes.length;
const body = document.body;
const root = document.documentElement;
const hero = document.querySelector("[data-theo-hero]");
const follow = document.getElementById("reading-follow");
const heroMore = document.getElementById("theo-hero-more");
const heroToggle = document.getElementById("theo-hero-toggle");
if (!body || !root || !hero) return;
if (!body || !root || !hero || !follow) return;
const BODY_CLASS = "is-paradigmes-page";
const FOLLOW_ON_CLASS = "theo-follow-on";
const EXPANDED_CLASS = "theo-hero-expanded";
const mqMobile = window.matchMedia("(max-width: 860px)");
const AUTO_COLLAPSE_DELTA = 160;
let expandedAtY = null;
let lastScrollY = window.scrollY || 0;
body.classList.add(BODY_CLASS);
@@ -246,6 +277,12 @@ const paradigmesCount = paradigmes.length;
});
};
const computeFollowOn = () =>
!mqMobile.matches &&
follow.classList.contains("is-on") &&
follow.style.display !== "none" &&
follow.getAttribute("aria-hidden") !== "true";
const applyLocalStickyHeight = () => {
const h = mqMobile.matches ? 0 : heroHeight();
@@ -257,22 +294,121 @@ const paradigmesCount = paradigmes.length;
};
const syncFollowState = () => {
const follow = document.getElementById("reading-follow");
const on = computeFollowOn();
body.classList.toggle(FOLLOW_ON_CLASS, on);
return on;
};
const followOn =
!mqMobile.matches &&
!!follow &&
follow.classList.contains("is-on") &&
follow.style.display !== "none" &&
follow.getAttribute("aria-hidden") !== "true";
const collapseHero = () => {
if (!body.classList.contains(EXPANDED_CLASS)) return;
body.classList.toggle(FOLLOW_ON_CLASS, followOn);
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "true");
}
if (heroToggle) {
heroToggle.hidden = false;
heroToggle.setAttribute("aria-expanded", "false");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const expandHero = () => {
body.classList.add(EXPANDED_CLASS);
expandedAtY = window.scrollY || 0;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "true");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const syncHeroState = () => {
const followOn = computeFollowOn();
const expanded = body.classList.contains(EXPANDED_CLASS);
const collapsed = followOn && !expanded;
if (!followOn || mqMobile.matches) {
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "false");
}
return;
}
if (heroMore) {
heroMore.setAttribute("aria-hidden", collapsed ? "true" : "false");
}
if (heroToggle) {
heroToggle.hidden = !collapsed;
heroToggle.setAttribute("aria-expanded", expanded ? "true" : "false");
}
};
const maybeAutoCollapseOnScroll = () => {
if (mqMobile.matches) {
lastScrollY = window.scrollY || 0;
return;
}
if (!computeFollowOn()) {
lastScrollY = window.scrollY || 0;
return;
}
if (!body.classList.contains(EXPANDED_CLASS)) {
lastScrollY = window.scrollY || 0;
return;
}
if (expandedAtY == null) {
lastScrollY = window.scrollY || 0;
return;
}
const currentY = window.scrollY || 0;
const scrollingDown = currentY > lastScrollY;
const delta = currentY - expandedAtY;
if (scrollingDown && delta >= AUTO_COLLAPSE_DELTA) {
collapseHero();
}
lastScrollY = currentY;
};
const syncAll = () => {
stripLocalSticky();
applyLocalStickyHeight();
syncFollowState();
syncHeroState();
applyLocalStickyHeight();
};
let raf = 0;
@@ -284,13 +420,17 @@ const paradigmesCount = paradigmes.length;
});
};
const follow = document.getElementById("reading-follow");
const followObserver =
follow
? new MutationObserver(schedule)
: null;
heroToggle?.addEventListener("click", () => {
expandHero();
});
followObserver?.observe(follow, {
const onScroll = () => {
maybeAutoCollapseOnScroll();
schedule();
};
const followObserver = new MutationObserver(schedule);
followObserver.observe(follow, {
attributes: true,
attributeFilter: ["class", "style", "aria-hidden"],
subtree: false,
@@ -303,6 +443,7 @@ const paradigmesCount = paradigmes.length;
heroResizeObserver?.observe(hero);
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", schedule);
window.addEventListener("pageshow", schedule);
@@ -346,13 +487,17 @@ const paradigmesCount = paradigmes.length;
radial-gradient(900px 240px at 20% 0%, rgba(0,217,255,0.08), transparent 60%);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
display: grid;
row-gap: 14px;
transition:
margin-bottom 180ms ease,
border-radius 180ms ease;
border-radius 180ms ease,
padding 180ms ease,
row-gap 180ms ease;
}
.theo-kicker{
margin: 0 0 10px;
margin: 0;
font-size: 12px;
letter-spacing: .08em;
text-transform: uppercase;
@@ -360,23 +505,75 @@ const paradigmesCount = paradigmes.length;
}
.theo-hero h1{
margin: 0 0 14px;
margin: 0;
font-size: clamp(2.2rem, 4vw, 3.15rem);
line-height: 1.02;
letter-spacing: -.04em;
font-weight: 850;
transition: font-size 180ms ease;
}
.theo-intro{
max-width: 76ch;
margin: 0;
max-width: 72ch;
font-size: 1.04rem;
line-height: 1.55;
opacity: .94;
transition:
font-size 180ms ease,
line-height 180ms ease,
max-width 180ms ease;
}
.theo-intro + .theo-intro{
margin-top: 14px;
.theo-hero-collapsible{
display: grid;
row-gap: 6px;
}
.theo-hero-more{
display: grid;
row-gap: 14px;
max-height: 18rem;
overflow: hidden;
opacity: 1;
transition:
max-height 220ms ease,
opacity 180ms ease;
}
.theo-hero-toggle{
display: none;
align-self: flex-start;
width: fit-content;
margin: 0;
padding: 0;
border: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 11px;
line-height: 1.2;
letter-spacing: .01em;
text-transform: none;
opacity: .56;
cursor: pointer;
text-decoration: underline;
text-underline-offset: .12em;
text-decoration-thickness: 1px;
}
.theo-hero-toggle:hover{
opacity: .84;
}
.theo-hero-toggle:focus-visible{
outline: 2px solid rgba(0,217,255,0.24);
outline-offset: 4px;
border-radius: 4px;
}
.theo-hero-toggle[hidden]{
display: none !important;
}
.theo-section{
@@ -521,10 +718,33 @@ const paradigmesCount = paradigmes.length;
:global(body.is-paradigmes-page.theo-follow-on .theo-hero){
margin-bottom: 0;
padding: 12px 16px 14px;
row-gap: 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
:global(body.is-paradigmes-page.theo-follow-on .theo-hero h1){
font-size: clamp(1.9rem, 3.2vw, 2.55rem);
}
:global(body.is-paradigmes-page.theo-follow-on .theo-intro){
max-width: 68ch;
font-size: .98rem;
line-height: 1.48;
}
:global(body.is-paradigmes-page.theo-follow-on:not(.theo-hero-expanded) .theo-hero-more){
max-height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
}
:global(body.is-paradigmes-page.theo-follow-on:not(.theo-hero-expanded) .theo-hero-toggle){
display: inline-flex;
}
:global(body.is-paradigmes-page.theo-follow-on #reading-follow .reading-follow__inner){
border-top-left-radius: 0;
border-top-right-radius: 0;
@@ -548,11 +768,29 @@ const paradigmesCount = paradigmes.length;
position: static;
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
.theo-intro{
max-width: none;
}
.theo-hero-more{
max-height: none;
opacity: 1;
overflow: visible;
}
.theo-hero-toggle{
display: none !important;
}
:global(body.is-paradigmes-page.theo-follow-on .theo-hero){
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
}