Synchronise les contenus glossaire et ajoute les scripts de conversion DOCX/MDX
All checks were successful
SMOKE / smoke (push) Successful in 4s
CI / build-and-anchors (push) Successful in 37s
CI / build-and-anchors (pull_request) Successful in 34s

This commit is contained in:
2026-04-23 12:04:31 +02:00
parent fa46971e76
commit 5b427d5602
34 changed files with 6781 additions and 1084 deletions

View File

@@ -22,43 +22,58 @@ const entries = [...await getCollection(collection)].sort((a, b) => {
const bt = String(b.data.title ?? b.data.term ?? slugOf(b));
return collator.compare(at, bt);
});
const tocId = `toc-global-${collection}-${String(basePath).replace(/[^\w-]+/g, "-")}`;
---
<nav class="toc-global" aria-label={label}>
<div class="toc-global__head">
<div class="toc-global__title">{label}</div>
</div>
<nav
class="toc-global"
aria-label={label}
data-toc-global
data-toc-key={`global:${collection}:${basePath}`}
>
<button
class="toc-global__head toc-global__toggle"
type="button"
aria-expanded="true"
aria-controls={tocId}
>
<span class="toc-global__title">{label}</span>
<span class="toc-global__chevron" aria-hidden="true">▾</span>
</button>
<ol class="toc-global__list">
{entries.map((e) => {
const slug = slugOf(e);
const active = slug === currentSlug;
<div class="toc-global__body-clip" id={tocId}>
<div class="toc-global__body">
<ol class="toc-global__list">
{entries.map((e) => {
const slug = slugOf(e);
const active = slug === currentSlug;
return (
<li class={`toc-item ${active ? "is-active" : ""}`}>
<a class="toc-link" href={hrefOf(e)} aria-current={active ? "page" : undefined}>
<span class="toc-link__row">
{active ? (
<span class="toc-active-indicator" aria-hidden="true">👉</span>
) : (
<span class="toc-active-spacer" aria-hidden="true"></span>
)}
return (
<li class={`toc-item ${active ? "is-active" : ""}`}>
<a class="toc-link" href={hrefOf(e)} aria-current={active ? "page" : undefined}>
<span class="toc-link__row">
<span class={`toc-active-mark ${active ? "is-on" : ""}`} aria-hidden="true">
<span class="toc-active-mark__dot"></span>
</span>
<span class="toc-link__title">{e.data.title}</span>
<span class="toc-link__title">{e.data.title}</span>
{active && (
<span class="toc-badge" aria-label="Chapitre en cours">
En cours
{active && (
<span class="toc-badge" aria-label="Chapitre en cours">
En cours
</span>
)}
</span>
)}
</span>
{active && <span class="toc-underline" aria-hidden="true"></span>}
</a>
</li>
);
})}
</ol>
{active && <span class="toc-underline" aria-hidden="true"></span>}
</a>
</li>
);
})}
</ol>
</div>
</div>
</nav>
<style>
@@ -69,7 +84,22 @@ const entries = [...await getCollection(collection)].sort((a, b) => {
background: rgba(127,127,127,0.06);
}
.toc-global__toggle{
width: 100%;
appearance: none;
border: 0;
background: transparent;
color: inherit;
text-align: left;
padding: 0;
cursor: pointer;
}
.toc-global__head{
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px dashed rgba(127,127,127,0.25);
@@ -82,11 +112,36 @@ const entries = [...await getCollection(collection)].sort((a, b) => {
opacity: .88;
}
.toc-global__chevron{
font-size: 12px;
opacity: .7;
transition: transform 180ms ease;
}
.toc-global__body-clip{
display: grid;
grid-template-rows: 1fr;
transition:
grid-template-rows 220ms ease,
opacity 160ms ease,
margin-top 220ms ease;
}
.toc-global__body{
min-height: 0;
overflow: hidden;
}
.toc-global__list{
list-style: none;
margin: 0;
padding: 0;
max-height: 44vh;
overflow: auto;
padding-right: 8px;
scrollbar-gutter: stable;
}
.toc-global__list li::marker{ content: ""; }
.toc-item{ margin: 6px 0; }
@@ -112,13 +167,33 @@ const entries = [...await getCollection(collection)].sort((a, b) => {
align-items: center;
}
.toc-active-indicator{
font-size: 14px;
line-height: 1;
.toc-active-mark{
width: 14px;
height: 14px;
display: inline-grid;
place-items: center;
border-radius: 999px;
border: 1px solid transparent;
opacity: .55;
}
.toc-active-spacer{
width: 14px;
.toc-active-mark__dot{
width: 5px;
height: 5px;
border-radius: 999px;
background: currentColor;
opacity: .65;
}
.toc-active-mark.is-on{
border-color: rgba(127,127,127,0.34);
opacity: 1;
}
.toc-active-mark.is-on .toc-active-mark__dot{
width: 6px;
height: 6px;
opacity: 1;
}
.toc-link__title{
@@ -156,11 +231,66 @@ const entries = [...await getCollection(collection)].sort((a, b) => {
border-radius: 999px;
}
.toc-global__list{
max-height: 44vh;
overflow: auto;
padding-right: 8px;
scrollbar-gutter: stable;
@media (max-width: 980px){
.toc-global{
padding: 10px 12px;
border-radius: 14px;
}
.toc-global__head{
margin-bottom: 0;
padding-bottom: 0;
border-bottom: 0;
min-height: 28px;
}
.toc-global__title{
font-size: 13px;
}
.toc-global__body-clip{
margin-top: 10px;
}
.toc-global.is-collapsed .toc-global__body-clip{
grid-template-rows: 0fr;
opacity: 0;
margin-top: 0;
}
.toc-global__body{
min-height: 0;
overflow: hidden;
transition: opacity 180ms ease;
}
.toc-global.is-collapsed .toc-global__body{
opacity: 0;
}
.toc-global.is-collapsed .toc-global__chevron{
transform: rotate(-90deg);
}
.toc-link{
padding: 7px 9px;
border-radius: 12px;
}
.toc-link__title{
font-size: 12.5px;
line-height: 1.22;
}
.toc-badge{
font-size: 10px;
padding: 2px 7px;
}
.toc-global__list{
max-height: min(42vh, 360px);
padding-right: 4px;
}
}
@media (prefers-color-scheme: dark){
@@ -168,12 +298,88 @@ const entries = [...await getCollection(collection)].sort((a, b) => {
.toc-link:hover{ background: rgba(255,255,255,0.06); }
.toc-item.is-active .toc-link{ background: rgba(255,255,255,0.06); }
.toc-badge{ background: rgba(255,255,255,0.06); }
.toc-active-mark.is-on{ border-color: rgba(255,255,255,0.22); }
}
</style>
<script is:inline>
(() => {
const active = document.querySelector(".toc-global .toc-item.is-active");
if (active) active.scrollIntoView({ block: "nearest" });
function init() {
document.querySelectorAll("[data-toc-global]").forEach((nav) => {
if (nav.dataset.tocReady === "1") return;
nav.dataset.tocReady = "1";
const toggle = nav.querySelector(".toc-global__toggle");
const bodyClip = nav.querySelector(".toc-global__body-clip");
const active = nav.querySelector(".toc-item.is-active");
const mq = window.matchMedia("(max-width: 980px)");
const key = `archicratie:${nav.dataset.tocKey || "toc-global"}`;
if (!toggle || !bodyClip) return;
const read = () => {
try {
const v = localStorage.getItem(key);
if (v === "open") return true;
if (v === "closed") return false;
} catch {}
return null;
};
const write = (open) => {
try { localStorage.setItem(key, open ? "open" : "closed"); } catch {}
};
const setOpen = (open, { persist = true } = {}) => {
const isMobile = mq.matches;
nav.classList.toggle("is-collapsed", isMobile && !open);
toggle.setAttribute("aria-expanded", open ? "true" : "false");
if (persist && isMobile) write(open);
};
const initState = () => {
if (!mq.matches) {
setOpen(true, { persist: false });
if (active) active.scrollIntoView({ block: "nearest" });
return;
}
const stored = read();
const open = stored == null ? false : stored;
setOpen(open, { persist: false });
if (open && active) active.scrollIntoView({ block: "nearest" });
};
toggle.addEventListener("click", () => {
const open = toggle.getAttribute("aria-expanded") !== "true";
setOpen(open);
if (open && active) active.scrollIntoView({ block: "nearest" });
if (open) {
window.dispatchEvent(new CustomEvent("archicratie:tocGlobalOpen"));
}
});
window.addEventListener("archicratie:tocLocalOpen", () => {
if (!mq.matches) return;
setOpen(false);
});
if (mq.addEventListener) {
mq.addEventListener("change", initState);
} else if (mq.addListener) {
mq.addListener(initState);
}
initState();
});
}
if (document.readyState === "loading") {
window.addEventListener("DOMContentLoaded", init, { once: true });
} else {
init();
}
})();
</script>

View File

@@ -49,85 +49,114 @@ const portalLinks = getGlossaryPortalLinks();
</div>
</div>
<section class="glossary-aside__block">
<h2 class="glossary-aside__heading">Portails</h2>
<ul class="glossary-aside__list">
{portalLinks.map((item) => (
<li><a href={item.href}>{item.label}</a></li>
))}
</ul>
</section>
<details class="glossary-aside__block glossary-aside__disclosure" open>
<summary class="glossary-aside__summary">
<span class="glossary-aside__heading">Portails</span>
<span class="glossary-aside__chevron" aria-hidden="true">▾</span>
</summary>
<div class="glossary-aside__panel">
<ul class="glossary-aside__list">
{portalLinks.map((item) => (
<li><a href={item.href}>{item.label}</a></li>
))}
</ul>
</div>
</details>
{showNoyau && (
<section class="glossary-aside__block">
<h2 class="glossary-aside__heading">Noyau archicratique</h2>
<ul class="glossary-aside__list">
{fondamentaux.map((entry) => {
const active = slugOfGlossaryEntry(entry) === currentSlug;
return (
<li>
<a
href={hrefOfGlossaryEntry(entry)}
aria-current={active ? "page" : undefined}
class={active ? "is-active" : undefined}
>
{entry.data.term}
</a>
</li>
);
})}
</ul>
</section>
<details class="glossary-aside__block glossary-aside__disclosure" open>
<summary class="glossary-aside__summary">
<span class="glossary-aside__heading">Noyau archicratique</span>
<span class="glossary-aside__chevron" aria-hidden="true">▾</span>
</summary>
<div class="glossary-aside__panel">
<ul class="glossary-aside__list">
{fondamentaux.map((entry) => {
const active = slugOfGlossaryEntry(entry) === currentSlug;
return (
<li>
<a
href={hrefOfGlossaryEntry(entry)}
aria-current={active ? "page" : undefined}
class={active ? "is-active" : undefined}
>
{entry.data.term}
</a>
</li>
);
})}
</ul>
</div>
</details>
)}
{showSameFamily && (
<section class="glossary-aside__block">
<h2 class="glossary-aside__heading">{sameFamilyTitle}</h2>
<ul class="glossary-aside__list">
{sameFamilyEntries.map((entry) => {
const active = slugOfGlossaryEntry(entry) === currentSlug;
return (
<li>
<a
href={hrefOfGlossaryEntry(entry)}
aria-current={active ? "page" : undefined}
class={active ? "is-active" : undefined}
>
{entry.data.term}
</a>
</li>
);
})}
</ul>
</section>
<details class="glossary-aside__block glossary-aside__disclosure" open>
<summary class="glossary-aside__summary">
<span class="glossary-aside__heading">{sameFamilyTitle}</span>
<span class="glossary-aside__chevron" aria-hidden="true">▾</span>
</summary>
<div class="glossary-aside__panel">
<ul class="glossary-aside__list">
{sameFamilyEntries.map((entry) => {
const active = slugOfGlossaryEntry(entry) === currentSlug;
return (
<li>
<a
href={hrefOfGlossaryEntry(entry)}
aria-current={active ? "page" : undefined}
class={active ? "is-active" : undefined}
>
{entry.data.term}
</a>
</li>
);
})}
</ul>
</div>
</details>
)}
{relationSections.length > 0 && (
<section class="glossary-aside__block">
<h2 class="glossary-aside__heading">Autour de cette fiche</h2>
<details class="glossary-aside__block glossary-aside__disclosure" open>
<summary class="glossary-aside__summary">
<span class="glossary-aside__heading">Autour de cette fiche</span>
<span class="glossary-aside__chevron" aria-hidden="true">▾</span>
</summary>
{relationSections.map((section) => (
<>
<h3 class="glossary-aside__subheading">{section.title}</h3>
<ul class="glossary-aside__list">
{section.items.map((entry) => (
<li><a href={hrefOfGlossaryEntry(entry)}>{entry.data.term}</a></li>
))}
</ul>
</>
))}
</section>
<div class="glossary-aside__panel">
{relationSections.map((section) => (
<>
<h3 class="glossary-aside__subheading">{section.title}</h3>
<ul class="glossary-aside__list">
{section.items.map((entry) => (
<li><a href={hrefOfGlossaryEntry(entry)}>{entry.data.term}</a></li>
))}
</ul>
</>
))}
</div>
</details>
)}
{contextualTheory.length > 0 && (
<section class="glossary-aside__block">
<h2 class="glossary-aside__heading">Paysage théorique</h2>
<ul class="glossary-aside__list">
{contextualTheory.map((entry) => (
<li><a href={hrefOfGlossaryEntry(entry)}>{entry.data.term}</a></li>
))}
</ul>
</section>
<details class="glossary-aside__block glossary-aside__disclosure" open>
<summary class="glossary-aside__summary">
<span class="glossary-aside__heading">Paysage théorique</span>
<span class="glossary-aside__chevron" aria-hidden="true">▾</span>
</summary>
<div class="glossary-aside__panel">
<ul class="glossary-aside__list">
{contextualTheory.map((entry) => (
<li><a href={hrefOfGlossaryEntry(entry)}>{entry.data.term}</a></li>
))}
</ul>
</div>
</details>
)}
</nav>
@@ -136,6 +165,7 @@ const portalLinks = getGlossaryPortalLinks();
display: flex;
flex-direction: column;
gap: 14px;
min-width: 0;
}
.glossary-aside__block{
@@ -143,6 +173,7 @@ const portalLinks = getGlossaryPortalLinks();
border-radius: 16px;
padding: 14px;
background: rgba(127,127,127,0.05);
min-width: 0;
}
.glossary-aside__block--intro{
@@ -160,10 +191,10 @@ const portalLinks = getGlossaryPortalLinks();
}
.glossary-aside__title{
font-size: 16px;
font-weight: 800;
letter-spacing: .2px;
line-height: 1.3;
font-size: 18px;
font-weight: 850;
letter-spacing: .1px;
line-height: 1.22;
}
.glossary-aside__pills{
@@ -183,6 +214,7 @@ const portalLinks = getGlossaryPortalLinks();
font-size: 13px;
line-height: 1.35;
opacity: .92;
min-width: 0;
}
.glossary-aside__pill--family{
@@ -190,12 +222,54 @@ const portalLinks = getGlossaryPortalLinks();
font-weight: 800;
}
.glossary-aside__disclosure{
padding: 0;
overflow: hidden;
}
.glossary-aside__summary{
list-style: none;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 14px;
cursor: pointer;
user-select: none;
}
.glossary-aside__summary::-webkit-details-marker{
display: none;
}
.glossary-aside__summary:hover{
background: rgba(127,127,127,0.035);
}
.glossary-aside__heading{
margin: 0 0 11px;
margin: 0;
font-size: 16px;
font-weight: 850;
line-height: 1.28;
opacity: .97;
}
.glossary-aside__chevron{
flex: 0 0 auto;
font-size: 14px;
font-weight: 800;
line-height: 1.35;
opacity: .94;
line-height: 1;
opacity: .72;
transform: rotate(0deg);
transition: transform 160ms ease, opacity 160ms ease;
}
.glossary-aside__disclosure[open] .glossary-aside__chevron{
transform: rotate(180deg);
opacity: .96;
}
.glossary-aside__panel{
padding: 0 14px 14px;
}
.glossary-aside__subheading{
@@ -222,16 +296,210 @@ const portalLinks = getGlossaryPortalLinks();
text-decoration: none;
font-size: 14px;
line-height: 1.4;
word-break: break-word;
}
.glossary-aside__list a.is-active{
font-weight: 800;
}
@media (max-width: 860px){
.glossary-aside{
gap: 10px;
}
.glossary-aside__block{
border-radius: 14px;
}
.glossary-aside__block--intro{
padding: 12px;
}
.glossary-aside__back{
margin-bottom: 8px;
font-size: 13px;
line-height: 1.28;
}
.glossary-aside__title{
font-size: 19px;
line-height: 1.18;
}
.glossary-aside__pills{
gap: 6px;
margin-top: 8px;
}
.glossary-aside__pill{
padding: 4px 9px;
font-size: 12px;
line-height: 1.26;
}
.glossary-aside__summary{
padding: 12px;
}
.glossary-aside__heading{
font-size: 17px;
line-height: 1.2;
}
.glossary-aside__panel{
padding: 0 12px 12px;
}
.glossary-aside__subheading{
margin: 10px 0 6px;
font-size: 11.5px;
line-height: 1.26;
}
.glossary-aside__list li{
margin: 5px 0;
}
.glossary-aside__list a{
font-size: 14px;
line-height: 1.34;
}
.glossary-aside__disclosure:not([open]) .glossary-aside__panel{
display: none;
}
}
@media (max-width: 860px){
.glossary-aside__disclosure{
background: rgba(127,127,127,0.045);
}
.glossary-aside__disclosure[open] .glossary-aside__summary{
border-bottom: 1px solid rgba(127,127,127,0.12);
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.glossary-aside{
gap: 8px;
}
.glossary-aside__block{
border-radius: 12px;
}
.glossary-aside__block--intro{
padding: 10px 11px;
}
.glossary-aside__back{
margin-bottom: 6px;
font-size: 12px;
line-height: 1.2;
}
.glossary-aside__title{
font-size: 16px;
line-height: 1.14;
}
.glossary-aside__pills{
gap: 5px;
margin-top: 7px;
}
.glossary-aside__pill{
padding: 3px 8px;
font-size: 11px;
line-height: 1.2;
}
.glossary-aside__summary{
padding: 10px 11px;
}
.glossary-aside__heading{
font-size: 15px;
line-height: 1.16;
}
.glossary-aside__panel{
padding: 0 11px 10px;
}
.glossary-aside__subheading{
margin: 8px 0 5px;
font-size: 11px;
line-height: 1.18;
}
.glossary-aside__list li{
margin: 4px 0;
}
.glossary-aside__list a{
font-size: 13px;
line-height: 1.28;
}
}
@media (min-width: 861px){
.glossary-aside__summary{
cursor: default;
}
.glossary-aside__chevron{
display: none;
}
}
@media (prefers-color-scheme: dark){
.glossary-aside__block,
.glossary-aside__pill{
background: rgba(255,255,255,0.04);
}
.glossary-aside__summary:hover{
background: rgba(255,255,255,0.03);
}
}
</style>
</style>
<script is:inline>
(() => {
const syncMobileDisclosure = () => {
const mobile = window.matchMedia("(max-width: 860px)").matches;
const smallLandscape = window.matchMedia(
"(orientation: landscape) and (max-width: 920px) and (max-height: 520px)"
).matches;
const compact = mobile || smallLandscape;
document
.querySelectorAll(".glossary-aside__disclosure")
.forEach((el, index) => {
if (!(el instanceof HTMLDetailsElement)) return;
if (compact) {
if (!el.dataset.mobileInit) {
el.open = index === 0;
el.dataset.mobileInit = "true";
}
} else {
el.open = true;
}
});
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", syncMobileDisclosure, { once: true });
} else {
syncMobileDisclosure();
}
window.addEventListener("resize", syncMobileDisclosure);
window.addEventListener("pageshow", syncMobileDisclosure);
})();
</script>

View File

@@ -32,16 +32,16 @@ const {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 12px;
margin-top: 14px;
margin-top: 12px;
}
.glossary-card{
display: flex;
flex-direction: column;
gap: 8px;
padding: 14px 16px;
gap: 7px;
padding: 13px 14px;
border: 1px solid var(--glossary-border);
border-radius: 18px;
border-radius: 16px;
background: var(--glossary-bg-soft);
text-decoration: none;
transition: transform 120ms ease, background 120ms ease, border-color 120ms ease;
@@ -60,17 +60,44 @@ const {
.glossary-card strong{
color: var(--glossary-accent);
font-size: 1.04rem;
line-height: 1.28;
font-size: 1.02rem;
line-height: 1.24;
}
.glossary-card span{
color: inherit;
font-size: 1rem;
line-height: 1.5;
font-size: .98rem;
line-height: 1.46;
opacity: .94;
}
@media (max-width: 760px){
.glossary-cards{
grid-template-columns: 1fr;
gap: 10px;
margin-top: 10px;
}
.glossary-card{
gap: 6px;
padding: 12px 12px;
border-radius: 14px;
}
.glossary-card strong{
font-size: .98rem;
}
.glossary-card span{
font-size: .94rem;
line-height: 1.42;
}
.glossary-card--wide{
grid-column: auto;
}
}
@media (prefers-color-scheme: dark){
.glossary-card{
background: rgba(255,255,255,0.04);

View File

@@ -75,9 +75,9 @@ const hasScholarlyMeta =
position: sticky;
top: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px));
z-index: 11;
margin: 0 0 24px;
margin: 0 0 22px;
border: 1px solid rgba(127,127,127,0.18);
border-radius: 28px;
border-radius: 24px;
background:
linear-gradient(180deg, rgba(0,0,0,0.60), rgba(0,0,0,0.92)),
radial-gradient(900px 240px at 20% 0%, rgba(0,217,255,0.08), transparent 60%);
@@ -97,7 +97,7 @@ const hasScholarlyMeta =
calc(var(--entry-hero-pad-top, 18px) - 2px);
transition: padding 180ms ease;
}
.glossary-entry-head h1{
margin: 0;
font-size: var(--entry-hero-h1-size, clamp(2.2rem, 4vw, 3.15rem));
@@ -129,12 +129,17 @@ const hasScholarlyMeta =
max-width 180ms ease,
font-size 180ms ease,
line-height 180ms ease;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
overflow: hidden;
}
.glossary-entry-signals{
display: flex;
flex-wrap: wrap;
gap: 8px;
gap: 7px;
margin: 0;
transition: gap 180ms ease;
}
@@ -142,13 +147,13 @@ const hasScholarlyMeta =
.glossary-pill{
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 10px;
gap: 5px;
padding: 5px 9px;
border: 1px solid rgba(127,127,127,0.24);
border-radius: 999px;
background: rgba(127,127,127,0.05);
font-size: 13px;
line-height: 1.35;
font-size: 12.5px;
line-height: 1.28;
transition:
padding 180ms ease,
font-size 180ms ease,
@@ -179,42 +184,67 @@ const hasScholarlyMeta =
.glossary-entry-meta p{
margin: 0;
font-size: 14px;
line-height: 1.5;
font-size: 13.5px;
line-height: 1.45;
}
.glossary-entry-meta p + p{
margin-top: 6px;
}
@media (max-width: 720px){
@media (max-width: 860px){
.glossary-entry-head{
position: static;
border-radius: 18px;
margin-bottom: 16px;
}
.glossary-entry-head__title{
padding: 12px 12px 10px;
}
.glossary-entry-summary{
gap: 9px;
padding: 10px 12px 12px;
}
.glossary-entry-dek{
max-width: none;
-webkit-line-clamp: 3;
}
.glossary-entry-signals{
gap: 6px;
}
.glossary-pill{
font-size: 12px;
padding: 4px 8px;
}
}
@media (max-width: 860px){
@media (max-width: 520px){
.glossary-entry-head{
position: static;
border-radius: 22px;
margin-bottom: 20px;
border-radius: 16px;
margin-bottom: 14px;
}
.glossary-entry-head__title{
padding: 14px 14px 12px;
padding: 10px 10px 9px;
}
.glossary-entry-summary{
gap: 12px;
padding: 14px;
gap: 8px;
padding: 9px 10px 10px;
}
.glossary-entry-dek{
max-width: none;
-webkit-line-clamp: 2;
}
.glossary-pill{
font-size: 11.5px;
padding: 3px 7px;
}
}

View File

@@ -6,6 +6,9 @@
const hero = document.querySelector("[data-ge-hero]");
const follow = document.getElementById("reading-follow");
const mqMobile = window.matchMedia("(max-width: 860px)");
const mqSmallLandscape = window.matchMedia(
"(orientation: landscape) and (max-width: 920px) and (max-height: 520px)"
);
if (!body || !root || !hero || !follow) return;
@@ -18,11 +21,26 @@
body.classList.add(BODY_CLASS);
const isCompactViewport = () =>
mqMobile.matches || mqSmallLandscape.matches;
const heroHeight = () =>
Math.max(0, Math.round(hero.getBoundingClientRect().height || 0));
const neutralizeGlobalFollowIfCompact = () => {
if (!isCompactViewport()) {
follow.style.display = "";
return;
}
follow.classList.remove("is-on");
follow.setAttribute("aria-hidden", "true");
follow.style.display = "none";
root.style.setProperty("--followbar-h", "0px");
};
const computeFollowOn = () =>
!mqMobile.matches &&
!isCompactViewport() &&
follow.classList.contains("is-on") &&
follow.style.display !== "none" &&
follow.getAttribute("aria-hidden") !== "true";
@@ -39,7 +57,7 @@
};
const applyLocalStickyHeight = () => {
const h = mqMobile.matches ? 0 : heroHeight();
const h = isCompactViewport() ? 0 : heroHeight();
if (h === lastHeight) return;
lastHeight = h;
@@ -58,6 +76,7 @@
};
const syncAll = () => {
neutralizeGlobalFollowIfCompact();
stripLocalSticky();
syncFollowState();
applyLocalStickyHeight();
@@ -98,6 +117,12 @@
mqMobile.addListener(schedule);
}
if (mqSmallLandscape.addEventListener) {
mqSmallLandscape.addEventListener("change", schedule);
} else if (mqSmallLandscape.addListener) {
mqSmallLandscape.addListener(schedule);
}
schedule();
};
@@ -114,37 +139,47 @@
z-index: 10;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-signals){
gap: 6px;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-head){
margin-bottom: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
box-shadow: 0 8px 20px rgba(0,0,0,0.10);
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-head h1){
letter-spacing: -.03em;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-summary){
gap: 10px;
padding-top: 12px;
padding-bottom: 10px;
gap: 8px;
padding-top: 10px;
padding-bottom: 8px;
border-top-color: rgba(127,127,127,0.10);
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-dek){
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
-webkit-line-clamp: 1;
overflow: hidden;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-signals){
gap: 5px;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-pill){
padding: 4px 8px;
font-size: 12px;
gap: 4px;
padding: 3px 7px;
font-size: 11px;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-meta){
padding: 0;
border-color: transparent;
max-height: 0;
opacity: 0;
overflow: hidden;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on #reading-follow){
@@ -177,9 +212,78 @@
}
@media (max-width: 860px){
:global(body.is-glossary-entry-page #reading-follow),
:global(body.is-glossary-entry-page #reading-follow .reading-follow__inner){
display: none !important;
opacity: 0 !important;
pointer-events: none !important;
visibility: hidden !important;
}
:global(body.is-glossary-entry-page){
--followbar-h: 0px !important;
--sticky-offset-px: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px)) !important;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-head){
margin-bottom: 20px;
border-radius: 22px;
margin-bottom: 18px;
border-radius: 20px;
box-shadow: none;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-summary){
gap: 6px;
padding-top: 8px;
padding-bottom: 8px;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-dek){
display: none;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-signals){
gap: 5px;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-pill){
padding: 3px 6px;
font-size: 10.5px;
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
:global(body.is-glossary-entry-page #reading-follow),
:global(body.is-glossary-entry-page #reading-follow .reading-follow__inner){
display: none !important;
opacity: 0 !important;
pointer-events: none !important;
visibility: hidden !important;
}
:global(body.is-glossary-entry-page){
--followbar-h: 0px !important;
--sticky-offset-px: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px)) !important;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-head){
margin-bottom: 14px;
border-radius: 16px;
box-shadow: none;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-summary){
gap: 5px;
padding-top: 6px;
padding-bottom: 6px;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-dek){
display: none;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-pill){
padding: 2px 6px;
font-size: 10px;
}
}
</style>

View File

@@ -37,24 +37,36 @@ const {
</div>
</div>
<section class="glossary-home-aside__block">
<h2 class="glossary-home-aside__heading">Parcours du glossaire</h2>
<ul class="glossary-home-aside__list">
{portalLinks.map((item) => (
<li><a href={item.href}>{item.label}</a></li>
))}
</ul>
</section>
<details class="glossary-home-aside__block glossary-home-aside__disclosure" open>
<summary class="glossary-home-aside__summary">
<span class="glossary-home-aside__heading">Parcours du glossaire</span>
<span class="glossary-home-aside__chevron" aria-hidden="true">▾</span>
</summary>
{fondamentaux.length > 0 && (
<section class="glossary-home-aside__block">
<h2 class="glossary-home-aside__heading">Noyau archicratique</h2>
<div class="glossary-home-aside__panel">
<ul class="glossary-home-aside__list">
{fondamentaux.map((entry) => (
<li><a href={hrefOfGlossaryEntry(entry)}>{entry.data.term}</a></li>
{portalLinks.map((item) => (
<li><a href={item.href}>{item.label}</a></li>
))}
</ul>
</section>
</div>
</details>
{fondamentaux.length > 0 && (
<details class="glossary-home-aside__block glossary-home-aside__disclosure" open>
<summary class="glossary-home-aside__summary">
<span class="glossary-home-aside__heading">Noyau archicratique</span>
<span class="glossary-home-aside__chevron" aria-hidden="true">▾</span>
</summary>
<div class="glossary-home-aside__panel">
<ul class="glossary-home-aside__list">
{fondamentaux.map((entry) => (
<li><a href={hrefOfGlossaryEntry(entry)}>{entry.data.term}</a></li>
))}
</ul>
</div>
</details>
)}
</nav>
@@ -63,6 +75,7 @@ const {
display: flex;
flex-direction: column;
gap: 14px;
min-width: 0;
}
.glossary-home-aside__block{
@@ -70,6 +83,7 @@ const {
border-radius: 16px;
padding: 14px;
background: rgba(127,127,127,0.05);
min-width: 0;
}
.glossary-home-aside__block--intro{
@@ -78,10 +92,10 @@ const {
}
.glossary-home-aside__title{
font-size: 16px;
font-weight: 800;
letter-spacing: .2px;
line-height: 1.3;
font-size: 18px;
font-weight: 850;
letter-spacing: .1px;
line-height: 1.22;
}
.glossary-home-aside__meta{
@@ -108,14 +122,57 @@ const {
font-size: 13px;
line-height: 1.35;
opacity: .92;
min-width: 0;
}
.glossary-home-aside__disclosure{
padding: 0;
overflow: hidden;
}
.glossary-home-aside__summary{
list-style: none;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 14px;
cursor: pointer;
user-select: none;
}
.glossary-home-aside__summary::-webkit-details-marker{
display: none;
}
.glossary-home-aside__summary:hover{
background: rgba(127,127,127,0.035);
}
.glossary-home-aside__heading{
margin: 0 0 11px;
margin: 0;
font-size: 16px;
font-weight: 850;
line-height: 1.28;
opacity: .97;
}
.glossary-home-aside__chevron{
flex: 0 0 auto;
font-size: 14px;
font-weight: 800;
line-height: 1.35;
opacity: .94;
line-height: 1;
opacity: .72;
transform: rotate(0deg);
transition: transform 160ms ease, opacity 160ms ease;
}
.glossary-home-aside__disclosure[open] .glossary-home-aside__chevron{
transform: rotate(180deg);
opacity: .96;
}
.glossary-home-aside__panel{
padding: 0 14px 14px;
}
.glossary-home-aside__list{
@@ -131,7 +188,148 @@ const {
.glossary-home-aside__list a{
text-decoration: none;
font-size: 14px;
line-height: 1.4;
line-height: 1.42;
word-break: break-word;
}
@media (max-width: 860px){
.glossary-home-aside{
gap: 10px;
}
.glossary-home-aside__block{
border-radius: 14px;
}
.glossary-home-aside__block--intro{
padding: 12px;
}
.glossary-home-aside__title{
font-size: 19px;
line-height: 1.18;
}
.glossary-home-aside__meta{
margin-top: 6px;
font-size: 12px;
line-height: 1.32;
}
.glossary-home-aside__pills{
gap: 6px;
margin-top: 9px;
}
.glossary-home-aside__pill{
padding: 4px 9px;
font-size: 12px;
line-height: 1.28;
}
.glossary-home-aside__summary{
padding: 12px;
}
.glossary-home-aside__heading{
font-size: 17px;
line-height: 1.2;
}
.glossary-home-aside__panel{
padding: 0 12px 12px;
}
.glossary-home-aside__list li{
margin: 5px 0;
}
.glossary-home-aside__list a{
font-size: 14px;
line-height: 1.34;
}
.glossary-home-aside__disclosure:not([open]) .glossary-home-aside__panel{
display: none;
}
}
@media (max-width: 860px){
.glossary-home-aside__disclosure{
background: rgba(127,127,127,0.045);
}
.glossary-home-aside__disclosure[open] .glossary-home-aside__summary{
border-bottom: 1px solid rgba(127,127,127,0.12);
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.glossary-home-aside{
gap: 8px;
}
.glossary-home-aside__block{
border-radius: 12px;
}
.glossary-home-aside__block--intro{
padding: 10px 11px;
}
.glossary-home-aside__title{
font-size: 16px;
line-height: 1.14;
}
.glossary-home-aside__meta{
font-size: 11px;
line-height: 1.26;
margin-top: 5px;
}
.glossary-home-aside__pills{
gap: 5px;
margin-top: 8px;
}
.glossary-home-aside__pill{
padding: 3px 8px;
font-size: 11px;
line-height: 1.2;
}
.glossary-home-aside__summary{
padding: 10px 11px;
}
.glossary-home-aside__heading{
font-size: 15px;
line-height: 1.16;
}
.glossary-home-aside__panel{
padding: 0 11px 10px;
}
.glossary-home-aside__list li{
margin: 4px 0;
}
.glossary-home-aside__list a{
font-size: 13px;
line-height: 1.28;
}
}
@media (min-width: 861px){
.glossary-home-aside__summary{
cursor: default;
}
.glossary-home-aside__chevron{
display: none;
}
}
@media (prefers-color-scheme: dark){
@@ -139,5 +337,46 @@ const {
.glossary-home-aside__pill{
background: rgba(255,255,255,0.04);
}
.glossary-home-aside__summary:hover{
background: rgba(255,255,255,0.03);
}
}
</style>
</style>
<script is:inline>
(() => {
const syncMobileDisclosure = () => {
const mobile = window.matchMedia("(max-width: 860px)").matches;
const smallLandscape = window.matchMedia(
"(orientation: landscape) and (max-width: 920px) and (max-height: 520px)"
).matches;
const compact = mobile || smallLandscape;
document
.querySelectorAll(".glossary-home-aside__disclosure")
.forEach((el, index) => {
if (!(el instanceof HTMLDetailsElement)) return;
if (compact) {
if (!el.dataset.mobileInit) {
el.open = index === 0;
el.dataset.mobileInit = "true";
}
} else {
el.open = true;
}
});
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", syncMobileDisclosure, { once: true });
} else {
syncMobileDisclosure();
}
window.addEventListener("resize", syncMobileDisclosure);
window.addEventListener("pageshow", syncMobileDisclosure);
})();
</script>

View File

@@ -15,7 +15,28 @@ const {
<header class="glossary-hero" id="glossary-hero">
<p class="glossary-kicker">{kicker}</p>
<h1>{title}</h1>
<p class="glossary-intro">{intro}</p>
<div class="glossary-hero__collapsible">
<p
class="glossary-intro"
id="glossary-hero-intro"
aria-hidden="false"
>
{intro}
</p>
<button
class="glossary-hero__toggle"
id="glossary-hero-toggle"
type="button"
aria-controls="glossary-hero-intro"
aria-expanded="false"
hidden
>
lire la suite
</button>
</div>
<h2
class="glossary-hero-follow"
id="glossary-hero-follow"
@@ -36,6 +57,8 @@ const {
linear-gradient(180deg, rgba(0,0,0,0.60), rgba(0,0,0,0.90)),
radial-gradient(900px 240px at 20% 0%, rgba(0,217,255,0.08), transparent 60%);
transition:
padding 220ms cubic-bezier(.22,.8,.22,1),
border-radius 220ms cubic-bezier(.22,.8,.22,1),
background 300ms cubic-bezier(.22,.8,.22,1),
border-color 300ms cubic-bezier(.22,.8,.22,1),
box-shadow 300ms cubic-bezier(.22,.8,.22,1);
@@ -43,6 +66,8 @@ const {
-webkit-backdrop-filter: blur(10px);
display: grid;
row-gap: 12px;
min-width: 0;
overflow: clip;
}
.glossary-kicker{
@@ -59,6 +84,16 @@ const {
line-height: 1.02;
letter-spacing: -.04em;
font-weight: 850;
transition:
font-size 220ms cubic-bezier(.22,.8,.22,1),
line-height 220ms cubic-bezier(.22,.8,.22,1);
min-width: 0;
}
.glossary-hero__collapsible{
display: grid;
row-gap: 6px;
min-width: 0;
}
.glossary-intro{
@@ -67,13 +102,58 @@ const {
font-size: 1.05rem;
line-height: 1.55;
opacity: .94;
min-width: 0;
transition:
font-size 220ms cubic-bezier(.22,.8,.22,1),
line-height 220ms cubic-bezier(.22,.8,.22,1),
max-height 220ms cubic-bezier(.22,.8,.22,1),
opacity 180ms ease;
}
.glossary-hero__toggle{
display: inline-flex;
align-items: center;
justify-content: center;
width: fit-content;
min-height: 30px;
padding: 3px 0;
border: 0;
border-radius: 0;
background: transparent;
color: inherit;
font-size: 12px;
line-height: 1.2;
letter-spacing: .01em;
opacity: .72;
cursor: pointer;
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 2px;
transition:
opacity 120ms ease,
transform 120ms ease;
}
.glossary-hero__toggle:hover{
opacity: .92;
transform: translateY(-1px);
}
.glossary-hero__toggle:focus-visible{
outline: 2px solid rgba(0,217,255,0.24);
outline-offset: 4px;
border-radius: 4px;
}
.glossary-hero__toggle[hidden]{
display: none !important;
}
.glossary-hero-follow{
margin: 2px 0 0;
min-height: var(--glossary-follow-height);
display: flex;
align-items: flex-end;
display: block;
max-width: min(100%, 22ch);
opacity: 0;
transform: translateY(10px) scale(.985);
filter: blur(6px);
@@ -86,6 +166,7 @@ const {
overflow: hidden;
text-overflow: ellipsis;
will-change: opacity, transform, filter;
min-width: 0;
}
.glossary-hero-follow.is-visible{
@@ -94,10 +175,190 @@ const {
filter: blur(0);
}
:global(body.glossary-home-follow-on) .glossary-hero{
padding: 12px 14px 14px;
border-bottom-left-radius: 18px;
border-bottom-right-radius: 18px;
}
:global(body.glossary-home-follow-on) .glossary-hero h1{
font-size: clamp(1.7rem, 3.2vw, 2.2rem);
line-height: 1.02;
}
:global(body.glossary-home-follow-on:not(.glossary-home-hero-expanded)) .glossary-intro{
font-size: .94rem;
line-height: 1.34;
max-height: 2.7em;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
:global(body.glossary-home-follow-on:not(.glossary-home-hero-expanded)) .glossary-hero__toggle{
display: inline-flex;
}
@media (max-width: 760px){
.glossary-hero{
top: calc(var(--glossary-sticky-top) - 2px);
padding: 12px 14px 16px;
border-radius: 22px;
row-gap: 10px;
}
.glossary-hero h1{
font-size: clamp(1.9rem, 8vw, 2.45rem);
line-height: 1.02;
letter-spacing: -.03em;
}
.glossary-hero__collapsible{
row-gap: 7px;
}
.glossary-intro{
max-width: 100%;
width: 100%;
font-size: .98rem;
line-height: 1.44;
}
:global(body.glossary-home-follow-on) .glossary-hero{
padding: 10px 13px 12px;
border-radius: 18px;
}
:global(body.glossary-home-follow-on) .glossary-hero h1{
font-size: clamp(1.45rem, 6vw, 1.8rem);
}
:global(body.glossary-home-follow-on:not(.glossary-home-hero-expanded)) .glossary-intro{
max-width: 100%;
width: 100%;
font-size: .86rem;
line-height: 1.24;
max-height: 2.48em;
-webkit-line-clamp: 2;
opacity: .9;
}
.glossary-hero__toggle{
min-height: 28px;
font-size: 11.5px;
}
.glossary-hero-follow{
max-width: min(100%, 24ch);
}
}
@media (max-width: 520px){
.glossary-hero{
padding: 11px 12px 14px;
border-radius: 20px;
}
.glossary-intro{
max-width: 100%;
width: 100%;
font-size: .94rem;
line-height: 1.4;
}
:global(body.glossary-home-follow-on) .glossary-hero{
padding: 9px 11px 11px;
}
:global(body.glossary-home-follow-on:not(.glossary-home-hero-expanded)) .glossary-intro{
max-width: 100%;
width: 100%;
font-size: .84rem;
line-height: 1.22;
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.glossary-hero{
padding: 10px 12px 12px;
border-radius: 16px;
row-gap: 8px;
}
.glossary-kicker{
font-size: 10px;
letter-spacing: .1em;
}
.glossary-hero h1{
font-size: clamp(1.35rem, 4vw, 1.8rem);
line-height: 1;
}
.glossary-intro{
font-size: .84rem;
line-height: 1.24;
}
:global(body.glossary-home-follow-on) .glossary-hero{
padding: 9px 11px 10px;
border-radius: 16px;
}
:global(body.glossary-home-follow-on) .glossary-hero h1{
font-size: clamp(1.1rem, 3vw, 1.35rem);
}
:global(body.glossary-home-follow-on:not(.glossary-home-hero-expanded)) .glossary-intro{
font-size: .8rem;
line-height: 1.18;
max-height: 2.36em;
-webkit-line-clamp: 2;
opacity: .88;
}
.glossary-hero__toggle{
min-height: 24px;
font-size: 11px;
}
.glossary-hero-follow{
max-width: min(100%, 26ch);
}
}
@media (max-width: 860px){
.glossary-hero{
position: static !important;
top: auto !important;
z-index: auto !important;
margin-bottom: 18px !important;
}
.glossary-hero-follow{
display: none !important;
min-height: 0 !important;
opacity: 0 !important;
transform: none !important;
filter: none !important;
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.glossary-hero{
position: static !important;
top: auto !important;
z-index: auto !important;
margin-bottom: 14px !important;
}
.glossary-hero-follow{
display: none !important;
min-height: 0 !important;
opacity: 0 !important;
transform: none !important;
filter: none !important;
}
}
</style>

View File

@@ -43,22 +43,22 @@ const showCta = Boolean(ctaHref && ctaLabel);
<style>
.glossary-section{
margin-top: 42px;
scroll-margin-top: calc(var(--glossary-sticky-top) + 190px);
margin-top: 34px;
scroll-margin-top: calc(var(--glossary-sticky-top) + 150px);
}
.glossary-section__head{
display: flex;
justify-content: space-between;
align-items: start;
gap: 16px;
gap: 14px;
flex-wrap: wrap;
margin-bottom: 14px;
margin-bottom: 12px;
}
.glossary-section h2{
margin: 0;
font-size: clamp(2rem, 3vw, 2.55rem);
font-size: clamp(1.8rem, 3vw, 2.55rem);
line-height: 1.06;
letter-spacing: -.03em;
font-weight: 800;
@@ -67,23 +67,23 @@ const showCta = Boolean(ctaHref && ctaLabel);
.glossary-intro{
margin: 0;
max-width: 72ch;
font-size: 1.05rem;
line-height: 1.55;
font-size: 1rem;
line-height: 1.52;
opacity: .94;
}
.glossary-section__head .glossary-intro{
margin-top: 10px;
margin-top: 8px;
}
.glossary-cta{
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 40px;
min-height: 38px;
border: 1px solid var(--glossary-border-strong);
border-radius: 999px;
padding: 7px 14px;
padding: 6px 13px;
color: var(--glossary-accent);
text-decoration: none;
white-space: nowrap;
@@ -97,13 +97,37 @@ const showCta = Boolean(ctaHref && ctaLabel);
}
@media (max-width: 760px){
.glossary-section{
margin-top: 24px;
scroll-margin-top: calc(var(--glossary-sticky-top) + 110px);
}
.glossary-section__head{
flex-direction: column;
align-items: stretch;
gap: 10px;
margin-bottom: 10px;
}
.glossary-section h2{
font-size: clamp(1.45rem, 6vw, 1.95rem);
line-height: 1.05;
}
.glossary-intro{
font-size: .95rem;
line-height: 1.42;
}
.glossary-section__head .glossary-intro{
margin-top: 6px;
}
.glossary-cta{
width: fit-content;
min-height: 35px;
padding: 5px 12px;
font-size: .95rem;
}
}
</style>

View File

@@ -65,37 +65,39 @@ const {
.glossary-portal-aside__block{
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
padding: 12px;
padding: 14px;
background: rgba(127,127,127,0.05);
}
.glossary-portal-aside__back{
display: inline-block;
margin-bottom: 8px;
font-size: 13px;
margin-bottom: 10px;
font-size: 14px;
font-weight: 700;
line-height: 1.35;
text-decoration: none;
}
.glossary-portal-aside__title{
font-size: 14px;
font-size: 16px;
font-weight: 800;
letter-spacing: .2px;
line-height: 1.25;
line-height: 1.3;
}
.glossary-portal-aside__meta{
margin-top: 8px;
font-size: 12px;
line-height: 1.35;
opacity: .78;
font-size: 13px;
line-height: 1.4;
opacity: .8;
}
.glossary-portal-aside__heading{
margin: 0 0 10px;
font-size: 13px;
margin: 0 0 11px;
font-size: 14px;
font-weight: 800;
opacity: .9;
line-height: 1.35;
opacity: .94;
}
.glossary-portal-aside__list{
@@ -105,13 +107,108 @@ const {
}
.glossary-portal-aside__list li{
margin: 6px 0;
margin: 7px 0;
}
.glossary-portal-aside__list a{
text-decoration: none;
font-size: 13px;
line-height: 1.3;
font-size: 14px;
line-height: 1.4;
}
@media (max-width: 980px){
.glossary-portal-aside{
gap: 12px;
}
.glossary-portal-aside__block{
padding: 12px;
border-radius: 14px;
}
}
@media (max-width: 760px){
.glossary-portal-aside{
gap: 10px;
}
.glossary-portal-aside__block{
padding: 11px 12px;
border-radius: 14px;
}
.glossary-portal-aside__back{
margin-bottom: 8px;
font-size: 13px;
}
.glossary-portal-aside__title{
font-size: 15px;
line-height: 1.22;
}
.glossary-portal-aside__meta{
margin-top: 6px;
font-size: 12px;
line-height: 1.32;
}
.glossary-portal-aside__heading{
margin-bottom: 8px;
font-size: 13px;
line-height: 1.22;
}
.glossary-portal-aside__list li{
margin: 5px 0;
}
.glossary-portal-aside__list a{
font-size: 12.5px;
line-height: 1.3;
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.glossary-portal-aside{
gap: 8px;
}
.glossary-portal-aside__block{
padding: 9px 10px;
border-radius: 12px;
}
.glossary-portal-aside__back{
margin-bottom: 6px;
font-size: 12px;
}
.glossary-portal-aside__title{
font-size: 14px;
line-height: 1.18;
}
.glossary-portal-aside__meta{
margin-top: 4px;
font-size: 11px;
line-height: 1.24;
}
.glossary-portal-aside__heading{
margin-bottom: 6px;
font-size: 12px;
line-height: 1.18;
}
.glossary-portal-aside__list li{
margin: 4px 0;
}
.glossary-portal-aside__list a{
font-size: 11.5px;
line-height: 1.22;
}
}
@media (prefers-color-scheme: dark){

View File

@@ -24,64 +24,44 @@ const {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
min-height: 40px;
padding: 0 14px;
border: 1px solid rgba(0,217,255,0.24);
padding: 7px 14px;
border: 1px solid rgba(127,127,127,0.24);
border-radius: 999px;
background:
linear-gradient(180deg, rgba(0,217,255,0.10), rgba(0,217,255,0.04)),
rgba(127,127,127,0.06);
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.05),
0 0 0 1px rgba(0,217,255,0.04);
background: rgba(127,127,127,0.05);
text-decoration: none;
font-size: 12px;
font-weight: 800;
letter-spacing: .01em;
white-space: nowrap;
line-height: 1.2;
transition:
transform 120ms ease,
background 120ms ease,
border-color 120ms ease,
box-shadow 120ms ease;
border-color 120ms ease;
}
.glossary-portal-cta:hover{
transform: translateY(-1px);
border-color: rgba(0,217,255,0.34);
background:
linear-gradient(180deg, rgba(0,217,255,0.14), rgba(0,217,255,0.06)),
rgba(127,127,127,0.08);
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.06),
0 0 0 1px rgba(0,217,255,0.08),
0 10px 28px rgba(0,0,0,0.18);
background: rgba(127,127,127,0.08);
border-color: rgba(0,217,255,0.18);
text-decoration: none;
}
.glossary-portal-cta:focus-visible{
outline: 2px solid rgba(0,217,255,0.28);
outline-offset: 4px;
outline-offset: 3px;
}
@media (max-width: 720px){
@media (max-width: 760px){
.glossary-portal-cta{
width: 100%;
min-height: 36px;
padding: 6px 12px;
font-size: 12px;
}
}
@media (prefers-color-scheme: dark){
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.glossary-portal-cta{
background:
linear-gradient(180deg, rgba(0,217,255,0.12), rgba(0,217,255,0.05)),
rgba(255,255,255,0.04);
}
.glossary-portal-cta:hover{
background:
linear-gradient(180deg, rgba(0,217,255,0.16), rgba(0,217,255,0.07)),
rgba(255,255,255,0.06);
min-height: 32px;
padding: 5px 10px;
font-size: 11px;
}
}
</style>

View File

@@ -36,17 +36,17 @@ const {
.glossary-portals{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 14px;
margin-top: 14px;
gap: 12px;
margin-top: 12px;
}
.glossary-portal-card{
display: flex;
flex-direction: column;
gap: 8px;
padding: 16px 18px;
gap: 7px;
padding: 14px 15px;
border: 1px solid var(--glossary-border);
border-radius: 18px;
border-radius: 16px;
background: var(--glossary-bg-soft);
text-decoration: none;
transition: transform 120ms ease, background 120ms ease, border-color 120ms ease;
@@ -61,24 +61,51 @@ const {
.glossary-portal-card strong{
color: var(--glossary-accent);
font-size: 1.08rem;
line-height: 1.28;
font-size: 1.04rem;
line-height: 1.24;
}
.glossary-portal-card span{
color: inherit;
font-size: 1rem;
line-height: 1.5;
font-size: .98rem;
line-height: 1.46;
opacity: .94;
}
.glossary-portal-card small{
color: var(--glossary-accent);
font-size: .94rem;
line-height: 1.35;
font-size: .9rem;
line-height: 1.28;
opacity: .9;
}
@media (max-width: 760px){
.glossary-portals{
grid-template-columns: 1fr;
gap: 10px;
margin-top: 10px;
}
.glossary-portal-card{
padding: 12px 12px;
border-radius: 14px;
gap: 6px;
}
.glossary-portal-card strong{
font-size: .98rem;
}
.glossary-portal-card span{
font-size: .94rem;
line-height: 1.42;
}
.glossary-portal-card small{
font-size: .85rem;
}
}
@media (prefers-color-scheme: dark){
.glossary-portal-card{
background: rgba(255,255,255,0.04);

View File

@@ -16,8 +16,8 @@ const {
title,
intro,
moreParagraphs = [],
introMaxWidth = "72ch",
followIntroMaxWidth = "68ch",
introMaxWidth = "70ch",
followIntroMaxWidth = "62ch",
moreMaxHeight = "18rem",
} = Astro.props;
---
@@ -25,12 +25,13 @@ const {
<div
class="glossary-portal-hero glossary-page-hero"
data-glossary-portal-hero
style={`--portal-hero-intro-max-w:${introMaxWidth}; --portal-hero-follow-intro-max-w:${followIntroMaxWidth}; --portal-hero-more-max-h:${moreMaxHeight};`}
style={`--portal-hero-intro-max-w:${introMaxWidth}; --portal-hero-follow-intro-max-w:${followIntroMaxWidth}; --portal-hero-secondary-max-h:${moreMaxHeight};`}
>
<p class="glossary-portal-hero__kicker">{kicker}</p>
<h1>{title}</h1>
<p class="glossary-portal-hero__intro">
<p class="glossary-portal-hero__intro glossary-portal-hero__intro--lead">
{intro}
</p>
@@ -43,7 +44,9 @@ const {
aria-hidden="false"
>
{moreParagraphs.map((paragraph) => (
<p class="glossary-portal-hero__intro">{paragraph}</p>
<p class="glossary-portal-hero__intro glossary-portal-hero__intro--more">
{paragraph}
</p>
))}
</div>
@@ -65,93 +68,121 @@ const {
<style>
.glossary-portal-hero{
position: sticky;
top: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px));
z-index: 11;
margin: 0 0 24px;
padding: 18px 18px 20px;
top: var(--glossary-sticky-top);
z-index: 12;
margin-bottom: var(--portal-hero-margin-bottom, 28px);
padding:
var(--portal-hero-pad-top, 20px)
var(--portal-hero-pad-x, 18px)
var(--portal-hero-pad-bottom, 22px);
border: 1px solid rgba(127,127,127,0.18);
border-radius: 28px;
background:
linear-gradient(180deg, rgba(0,0,0,0.60), rgba(0,0,0,0.92)),
radial-gradient(900px 240px at 20% 0%, rgba(0,217,255,0.08), transparent 60%);
radial-gradient(980px 260px at 18% 0%, rgba(0,217,255,0.08), transparent 60%);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
display: grid;
row-gap: 14px;
row-gap: var(--portal-hero-gap, 16px);
min-width: 0;
overflow: hidden;
transition:
margin-bottom 180ms ease,
border-radius 180ms ease,
padding 180ms ease,
row-gap 180ms ease;
background 280ms cubic-bezier(.22,.8,.22,1),
border-color 220ms cubic-bezier(.22,.8,.22,1),
box-shadow 220ms cubic-bezier(.22,.8,.22,1),
border-radius 220ms ease,
padding 220ms ease,
row-gap 220ms ease,
margin-bottom 220ms ease;
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.02),
0 10px 26px rgba(0,0,0,0.08);
}
.glossary-portal-hero__kicker{
margin: 0;
font-size: 12px;
letter-spacing: .08em;
font-size: var(--portal-kicker-size, 12px);
line-height: var(--portal-kicker-lh, 1.2);
letter-spacing: var(--portal-kicker-spacing, .14em);
text-transform: uppercase;
opacity: .72;
font-weight: 650;
opacity: .74;
}
.glossary-portal-hero h1{
margin: 0;
font-size: clamp(2.2rem, 4vw, 3.15rem);
line-height: 1.02;
letter-spacing: -.04em;
font-size: var(--portal-hero-h1-size, clamp(3rem, 4.8vw, 4.15rem));
line-height: var(--portal-hero-h1-lh, .98);
letter-spacing: var(--portal-hero-h1-spacing, -.045em);
font-weight: 850;
transition: font-size 180ms ease;
text-wrap: balance;
transition:
font-size 180ms ease,
line-height 180ms ease,
letter-spacing 180ms ease;
}
.glossary-portal-hero__intro{
margin: 0;
max-width: var(--portal-hero-intro-max-w);
font-size: 1.04rem;
line-height: 1.55;
opacity: .94;
max-width: var(--portal-hero-intro-max-w, 70ch);
font-size: var(--portal-hero-intro-size, 1.06rem);
line-height: var(--portal-hero-intro-lh, 1.6);
text-wrap: pretty;
transition:
font-size 180ms ease,
line-height 180ms ease,
max-width 180ms ease;
max-width 180ms ease,
opacity 180ms ease;
}
.glossary-portal-hero__intro--lead{ opacity: .95; }
.glossary-portal-hero__intro--more{ opacity: .89; }
.glossary-portal-hero__collapsible{
display: grid;
row-gap: 6px;
row-gap: 8px;
min-width: 0;
}
.glossary-portal-hero__more{
display: grid;
row-gap: 14px;
max-height: var(--portal-hero-more-max-h);
gap: 12px;
max-height: var(--portal-hero-secondary-max-h, 20em);
overflow: hidden;
opacity: 1;
opacity: var(--portal-hero-secondary-opacity, .92);
min-width: 0;
transition:
max-height 220ms ease,
opacity 180ms ease;
}
.glossary-portal-hero__toggle{
display: none;
align-self: flex-start;
display: inline-flex;
align-items: center;
justify-content: center;
width: fit-content;
margin: 0;
padding: 0;
min-height: 34px;
padding: 5px 0;
border: 0;
border-radius: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 11px;
font-size: 12.5px;
line-height: 1.2;
letter-spacing: .01em;
opacity: .56;
opacity: .72;
cursor: pointer;
text-decoration: underline;
text-underline-offset: .12em;
text-decoration-thickness: 1px;
text-underline-offset: 2px;
transition:
opacity 120ms ease,
transform 120ms ease;
}
.glossary-portal-hero__toggle:hover{
opacity: .84;
opacity: .92;
transform: translateY(-1px);
}
.glossary-portal-hero__toggle:focus-visible{
@@ -164,27 +195,66 @@ const {
display: none !important;
}
@media (max-width: 860px){
@media (max-width: 980px){
.glossary-portal-hero{
position: static;
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
border-radius: 24px;
}
.glossary-portal-hero__intro{
max-width: none;
.glossary-portal-hero h1{
text-wrap: pretty;
}
.glossary-portal-hero__more{
max-height: none;
opacity: 1;
overflow: visible;
gap: 10px;
}
}
@media (max-width: 860px){
.glossary-portal-hero{
position: static !important;
top: auto !important;
z-index: auto !important;
margin-bottom: 18px !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
}
.glossary-portal-hero__toggle{
display: none !important;
.glossary-portal-hero h1,
.glossary-portal-hero__intro,
.glossary-portal-hero__more,
.glossary-portal-hero__collapsible{
min-width: 0 !important;
max-width: 100% !important;
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.glossary-portal-hero{
position: static !important;
top: auto !important;
z-index: auto !important;
margin-bottom: 14px !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
border-radius: 16px !important;
}
.glossary-portal-hero h1,
.glossary-portal-hero__intro,
.glossary-portal-hero__more,
.glossary-portal-hero__collapsible{
min-width: 0 !important;
max-width: 100% !important;
}
}
@media (prefers-color-scheme: dark){
.glossary-portal-hero{
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.02),
0 14px 34px rgba(0,0,0,0.16);
}
}
</style>

View File

@@ -38,59 +38,90 @@ const {
<style>
.glossary-portal-panel{
display: grid;
gap: 12px;
gap: 10px;
}
.glossary-portal-panel--surface{
padding: 18px 18px 16px;
padding:
var(--portal-panel-pad-y, 16px)
var(--portal-panel-pad-x, 16px);
border: 1px solid var(--glossary-border, rgba(127,127,127,0.18));
border-radius: 18px;
border-radius: var(--portal-panel-radius, 18px);
background:
linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01)),
var(--glossary-bg-soft, rgba(127,127,127,0.035));
}
.glossary-portal-panel__head{
display: flex;
align-items: baseline;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
gap: 10px;
flex-wrap: wrap;
}
.glossary-portal-panel__head h3{
margin: 0;
font-size: 15px;
line-height: 1.3;
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 36px);
font-size: var(--portal-local-h3-size, clamp(1.35rem, 2vw, 1.7rem));
line-height: var(--portal-local-h3-lh, 1.15);
letter-spacing: -.02em;
}
.glossary-portal-panel__count{
display: inline-flex;
align-items: center;
min-height: 24px;
padding: 0 10px;
border: 1px solid rgba(127,127,127,0.22);
min-height: 26px;
padding: 0 9px;
border: 1px solid rgba(127,127,127,0.20);
border-radius: 999px;
font-size: 12px;
background: rgba(127,127,127,0.04);
font-size: 11.5px;
line-height: 1.2;
opacity: .78;
opacity: .8;
white-space: nowrap;
}
.glossary-portal-panel__intro{
max-width: 78ch;
margin: 0;
font-size: 14px;
line-height: 1.5;
opacity: .9;
font-size: var(--portal-card-text-size, 14px);
line-height: var(--portal-card-text-lh, 1.45);
opacity: .92;
}
@media (max-width: 760px){
.glossary-portal-panel{
gap: 8px;
}
.glossary-portal-panel__head{
gap: 8px;
}
.glossary-portal-panel__count{
min-height: 23px;
padding: 0 8px;
font-size: 10.5px;
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.glossary-portal-panel{
gap: 6px;
}
.glossary-portal-panel__head{
gap: 6px;
}
.glossary-portal-panel__count{
min-height: 21px;
padding: 0 7px;
font-size: 10px;
}
}
@media (prefers-color-scheme: dark){
.glossary-portal-panel--surface{
background:
linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01)),
rgba(255,255,255,0.04);
background: rgba(255,255,255,0.04);
}
}
</style>

View File

@@ -31,37 +31,113 @@ const {
<style>
.glossary-portal-section{
margin-top: 34px;
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
margin-top: 30px;
}
.glossary-portal-section h2{
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
margin: 0;
font-size: clamp(1.8rem, 3vw, 2.35rem);
line-height: 1.05;
letter-spacing: -.03em;
font-weight: 800;
}
.glossary-portal-section__head{
display: flex;
align-items: baseline;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 10px;
position: static;
}
.glossary-portal-section__count{
font-size: 13px;
opacity: .72;
display: inline-flex;
align-items: center;
min-height: 28px;
padding: 0 10px;
border: 1px solid rgba(127,127,127,0.20);
border-radius: 999px;
background: rgba(127,127,127,0.04);
font-size: 12px;
line-height: 1.2;
opacity: .8;
white-space: nowrap;
}
.glossary-portal-section__intro{
max-width: 78ch;
margin: 0;
opacity: .92;
max-width: 76ch;
font-size: var(--portal-body-size, 1rem);
line-height: var(--portal-body-lh, 1.55);
opacity: .94;
}
.glossary-portal-section--final{
margin-top: 42px;
margin-top: 34px;
}
@media (max-width: 980px){
.glossary-portal-section{
margin-top: 24px;
}
.glossary-portal-section h2{
font-size: clamp(1.6rem, 4.4vw, 2rem);
line-height: 1.04;
}
}
@media (max-width: 760px){
.glossary-portal-section{
margin-top: 20px;
}
.glossary-portal-section__head{
gap: 8px;
margin-bottom: 8px;
}
.glossary-portal-section h2{
font-size: clamp(1.34rem, 6.5vw, 1.72rem);
line-height: 1.04;
letter-spacing: -.022em;
}
.glossary-portal-section__count{
min-height: 24px;
padding: 0 8px;
font-size: 11px;
}
.glossary-portal-section--final{
margin-top: 24px;
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.glossary-portal-section{
margin-top: 16px;
}
.glossary-portal-section__head{
gap: 6px;
margin-bottom: 6px;
}
.glossary-portal-section h2{
font-size: clamp(1.12rem, 4.2vw, 1.34rem);
line-height: 1.02;
}
.glossary-portal-section__count{
min-height: 22px;
padding: 0 7px;
font-size: 10px;
}
.glossary-portal-section--final{
margin-top: 18px;
}
}
</style>

View File

@@ -34,16 +34,24 @@ const {
const BODY_CLASS = "is-glossary-portal-page";
const FOLLOW_ON_CLASS = "glossary-portal-follow-on";
const EXPANDED_CLASS = "glossary-portal-hero-expanded";
const CONDENSED_CLASS = "glossary-portal-hero-condensed";
const mqMobile = window.matchMedia(`(max-width: ${mobileBreakpoint}px)`);
const mqSmallLandscape = window.matchMedia(
"(orientation: landscape) and (max-width: 920px) and (max-height: 520px)"
);
let expandedAtY = null;
let lastScrollY = window.scrollY || 0;
let raf = 0;
let lastFollowOn = null;
let lastCondensed = null;
let lastHeroHeight = -1;
body.classList.add(BODY_CLASS);
const heroHeight = () =>
Math.max(0, Math.round(hero.getBoundingClientRect().height || 0));
const isCompactViewport = () =>
mqMobile.matches || mqSmallLandscape.matches;
const stripLocalSticky = () => {
document.querySelectorAll(sectionHeadSelector).forEach((el) => {
@@ -52,14 +60,53 @@ const {
});
};
const readStickyTop = () => {
const raw = getComputedStyle(document.documentElement)
.getPropertyValue("--glossary-sticky-top")
.trim();
const n = Number.parseFloat(raw);
return Number.isFinite(n) ? n : 64;
};
const computeFollowOn = () =>
!mqMobile.matches &&
!isCompactViewport() &&
follow.classList.contains("is-on") &&
follow.style.display !== "none" &&
follow.getAttribute("aria-hidden") !== "true";
const computeCondensed = () => {
if (isCompactViewport()) return false;
const heroRect = hero.getBoundingClientRect();
const stickyTop = readStickyTop();
return heroRect.top <= stickyTop + 2;
};
const measureHeroHeight = () =>
Math.max(0, Math.round(hero.getBoundingClientRect().height || 0));
const PIN_EPS = 3;
const isHeroPinned = () => {
if (isCompactViewport()) return false;
const rect = hero.getBoundingClientRect();
const stickyTop = readStickyTop();
const cs = getComputedStyle(hero);
if (cs.position !== "sticky") return false;
const pinnedOnRail = Math.abs(rect.top - stickyTop) <= PIN_EPS;
const stillVisible = rect.bottom > stickyTop + 24;
return pinnedOnRail && stillVisible;
};
const applyLocalStickyHeight = () => {
const h = mqMobile.matches ? 0 : heroHeight();
const h = isHeroPinned() ? measureHeroHeight() : 0;
if (h === lastHeroHeight) return;
lastHeroHeight = h;
if (typeof window.__archiSetLocalStickyHeight === "function") {
window.__archiSetLocalStickyHeight(h);
@@ -70,10 +117,26 @@ const {
const syncFollowState = () => {
const on = computeFollowOn();
body.classList.toggle(FOLLOW_ON_CLASS, on);
if (on !== lastFollowOn) {
lastFollowOn = on;
body.classList.toggle(FOLLOW_ON_CLASS, on);
}
return on;
};
const syncCondensedState = () => {
const condensed = computeCondensed();
if (condensed !== lastCondensed) {
lastCondensed = condensed;
body.classList.toggle(CONDENSED_CLASS, condensed);
}
return condensed;
};
const collapseHero = () => {
if (!body.classList.contains(EXPANDED_CLASS)) return;
@@ -116,12 +179,11 @@ const {
schedule();
};
const syncHeroState = () => {
const followOn = computeFollowOn();
const syncHeroState = (condensed) => {
const expanded = body.classList.contains(EXPANDED_CLASS);
const collapsed = followOn && !expanded;
const collapsed = condensed && !expanded;
if (!followOn || mqMobile.matches) {
if (isCompactViewport() || !condensed) {
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
@@ -148,12 +210,7 @@ const {
};
const maybeAutoCollapseOnScroll = () => {
if (mqMobile.matches) {
lastScrollY = window.scrollY || 0;
return;
}
if (!computeFollowOn()) {
if (isCompactViewport()) {
lastScrollY = window.scrollY || 0;
return;
}
@@ -181,16 +238,59 @@ const {
const syncAll = () => {
stripLocalSticky();
syncFollowState();
syncHeroState();
applyLocalStickyHeight();
if (isCompactViewport()) {
body.classList.remove(FOLLOW_ON_CLASS);
body.classList.remove(CONDENSED_CLASS);
body.classList.remove(EXPANDED_CLASS);
lastFollowOn = false;
lastCondensed = false;
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "false");
}
requestAnimationFrame(() => {
applyLocalStickyHeight();
try {
window.__archiUpdateFollow?.();
} catch {}
});
return;
}
const condensed = syncCondensedState();
syncHeroState(condensed);
requestAnimationFrame(() => {
applyLocalStickyHeight();
syncFollowState();
try {
window.__archiUpdateFollow?.();
} catch {}
});
requestAnimationFrame(() => {
applyLocalStickyHeight();
try {
window.__archiUpdateFollow?.();
} catch {}
});
};
const schedule = () => {
if (raf) return;
raf = requestAnimationFrame(() => {
raf = 0;
requestAnimationFrame(syncAll);
syncAll();
});
};
@@ -229,6 +329,12 @@ const {
mqMobile.addListener(schedule);
}
if (mqSmallLandscape.addEventListener) {
mqSmallLandscape.addEventListener("change", schedule);
} else if (mqSmallLandscape.addListener) {
mqSmallLandscape.addListener(schedule);
}
schedule();
};
@@ -245,40 +351,63 @@ const {
z-index: 10;
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on .glossary-portal-hero){
margin-bottom: 0;
padding: 12px 16px 14px;
row-gap: 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
/* Le hero se condense dès quil devient sticky */
:global(body.is-glossary-portal-page.glossary-portal-hero-condensed .glossary-portal-hero){
padding:
var(--portal-hero-pad-top-condensed, 14px)
var(--portal-hero-pad-x-condensed, 16px)
var(--portal-hero-pad-bottom-condensed, 16px);
row-gap: var(--portal-hero-gap-condensed, 10px);
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.02),
0 8px 20px rgba(0,0,0,0.12);
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on .glossary-portal-hero h1){
font-size: clamp(1.9rem, 3.2vw, 2.55rem);
:global(body.is-glossary-portal-page.glossary-portal-hero-condensed .glossary-portal-hero h1){
font-size: var(--portal-hero-h1-size-condensed, clamp(2.05rem, 3.15vw, 2.7rem));
line-height: var(--portal-hero-h1-lh-condensed, 1);
letter-spacing: var(--portal-hero-h1-spacing-condensed, -.04em);
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on .glossary-portal-hero__intro){
max-width: var(--portal-hero-follow-intro-max-w, 68ch);
font-size: .98rem;
line-height: 1.48;
:global(body.is-glossary-portal-page.glossary-portal-hero-condensed .glossary-portal-hero__intro){
max-width: var(--portal-hero-follow-intro-max-w, 62ch);
font-size: var(--portal-hero-intro-size-condensed, .98rem);
line-height: var(--portal-hero-intro-lh-condensed, 1.46);
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on:not(.glossary-portal-hero-expanded) .glossary-portal-hero__more){
:global(body.is-glossary-portal-page.glossary-portal-hero-condensed .glossary-portal-hero__kicker){
opacity: .68;
}
/* Le more se replie dès létat condensé */
:global(body.is-glossary-portal-page.glossary-portal-hero-condensed:not(.glossary-portal-hero-expanded) .glossary-portal-hero__more){
max-height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on:not(.glossary-portal-hero-expanded) .glossary-portal-hero__toggle){
:global(body.is-glossary-portal-page.glossary-portal-hero-condensed:not(.glossary-portal-hero-expanded) .glossary-portal-hero__toggle){
display: inline-flex;
}
/* Laccolage hero + follow narrive que quand le follow est actif */
:global(body.is-glossary-portal-page.glossary-portal-hero-condensed.glossary-portal-follow-on .glossary-portal-hero){
margin-bottom: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on #reading-follow .reading-follow__inner){
margin-top: -1px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on #reading-follow .rf-h2){
letter-spacing: -.02em;
}
:global(body.is-glossary-portal-page .glossary-portal-section__head.is-sticky),
:global(body.is-glossary-portal-page .glossary-portal-section__head[data-sticky-active="true"]){
position: static !important;
@@ -291,4 +420,68 @@ const {
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
@media (max-width: 860px){
:global(body.is-glossary-portal-page #reading-follow),
:global(body.is-glossary-portal-page #reading-follow .reading-follow__inner){
display: none !important;
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
:global(body.is-glossary-portal-page){
--followbar-h: 0px !important;
--sticky-offset-px: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px)) !important;
}
:global(body.is-glossary-portal-page .glossary-portal-hero){
margin-bottom: var(--portal-hero-margin-bottom, 18px);
border-radius: 20px !important;
box-shadow: none !important;
}
:global(body.is-glossary-portal-page .glossary-portal-hero__more){
max-height: none !important;
opacity: 1 !important;
overflow: visible !important;
pointer-events: auto !important;
}
:global(body.is-glossary-portal-page .glossary-portal-hero__toggle){
display: none !important;
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
:global(body.is-glossary-portal-page #reading-follow),
:global(body.is-glossary-portal-page #reading-follow .reading-follow__inner){
display: none !important;
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
:global(body.is-glossary-portal-page){
--followbar-h: 0px !important;
--sticky-offset-px: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px)) !important;
}
:global(body.is-glossary-portal-page .glossary-portal-hero){
margin-bottom: var(--portal-hero-margin-bottom, 12px);
border-radius: 16px !important;
box-shadow: none !important;
}
:global(body.is-glossary-portal-page .glossary-portal-hero__more){
max-height: none !important;
opacity: 1 !important;
overflow: visible !important;
pointer-events: auto !important;
}
:global(body.is-glossary-portal-page .glossary-portal-hero__toggle){
display: none !important;
}
}
</style>

View File

@@ -36,44 +36,45 @@ const relationsHeadingId = "relations-conceptuelles";
<style>
.glossary-relations{
margin-top: 26px;
padding-top: 18px;
margin-top: 22px;
padding-top: 14px;
border-top: 1px solid rgba(127,127,127,0.18);
}
.glossary-relations h2{
margin-bottom: 14px;
margin: 0 0 12px;
font-size: clamp(1.35rem, 3vw, 1.8rem);
line-height: 1.08;
}
.glossary-relations-grid{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 12px;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 10px;
}
.glossary-relations-card{
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
padding: 14px 16px;
border: 1px solid rgba(127,127,127,0.20);
border-radius: 14px;
padding: 12px 13px;
background: rgba(127,127,127,0.05);
}
.glossary-relations-card h3{
margin-top: 0;
margin-bottom: 10px;
font-size: 15px;
line-height: 1.35;
margin: 0 0 8px;
font-size: 14px;
line-height: 1.3;
}
.glossary-relations-card ul{
margin: 0;
padding-left: 18px;
padding-left: 16px;
}
.glossary-relations-card li{
margin-bottom: 8px;
font-size: 14px;
line-height: 1.45;
margin-bottom: 7px;
font-size: 13.5px;
line-height: 1.42;
}
.glossary-relations-card li:last-child{
@@ -81,7 +82,39 @@ const relationsHeadingId = "relations-conceptuelles";
}
.glossary-relations-card span{
opacity: .9;
opacity: .88;
}
@media (max-width: 760px){
.glossary-relations{
margin-top: 18px;
padding-top: 12px;
}
.glossary-relations h2{
margin-bottom: 10px;
font-size: 1.3rem;
}
.glossary-relations-grid{
grid-template-columns: 1fr;
gap: 8px;
}
.glossary-relations-card{
padding: 11px 11px;
border-radius: 13px;
}
.glossary-relations-card h3{
font-size: 13px;
margin-bottom: 7px;
}
.glossary-relations-card li{
font-size: 13px;
line-height: 1.38;
}
}
@media (prefers-color-scheme: dark){

View File

@@ -68,7 +68,6 @@ const { initialLevel = 1 } = Astro.props;
} catch {}
}
// init : storage > initialLevel
let start = clampLevel(initialLevel);
try {
const stored = localStorage.getItem(KEY);
@@ -77,13 +76,11 @@ const { initialLevel = 1 } = Astro.props;
applyLevel(start, { persist: false });
// clicks
wrap.addEventListener("click", (ev) => {
const btn = ev.target?.closest?.("button[data-level]");
if (!btn) return;
ev.preventDefault();
// ✅ crucial : on capture la position AVANT le reflow lié au changement de niveau
captureBeforeLevelSwitch();
applyLevel(btn.dataset.level);
});
@@ -95,6 +92,8 @@ const { initialLevel = 1 } = Astro.props;
display: inline-flex;
gap: 8px;
align-items: center;
flex-wrap: wrap;
max-width: 100%;
}
.level-btn{
@@ -106,6 +105,7 @@ const { initialLevel = 1 } = Astro.props;
cursor: pointer;
user-select: none;
transition: filter .12s ease, transform .12s ease, background .12s ease, border-color .12s ease;
white-space: nowrap;
}
.level-btn:hover{
@@ -125,4 +125,21 @@ const { initialLevel = 1 } = Astro.props;
.level-btn:active{
transform: translateY(1px);
}
</style>
@media (max-width: 980px){
.level-toggle{
gap: 6px;
}
.level-btn{
padding: 5px 9px;
font-size: 12px;
}
}
@media (max-width: 760px){
.level-toggle{
display: none;
}
}
</style>

View File

@@ -3,49 +3,122 @@ const { headings } = Astro.props;
// H2/H3 seulement
const items = (headings || []).filter((h) => h.depth >= 2 && h.depth <= 3);
const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
---
{items.length > 0 && (
<nav class="toc-local" aria-label="Dans ce chapitre">
<div class="toc-local__title">Dans ce chapitre</div>
<nav class="toc-local" aria-label="Dans ce chapitre" data-toc-local>
<button
class="toc-local__head toc-local__toggle"
type="button"
aria-expanded="true"
aria-controls={tocId}
>
<span class="toc-local__title">Dans ce chapitre</span>
<span class="toc-local__chevron" aria-hidden="true">▾</span>
</button>
<ol class="toc-local__list">
{items.map((h) => (
<li
class={`toc-local__item d${h.depth}`}
data-toc-item
data-depth={h.depth}
data-id={h.slug}
>
<a href={`#${h.slug}`} data-toc-link data-slug={h.slug}>
{h.text}
</a>
</li>
))}
</ol>
<div class="toc-local__body-clip" id={tocId}>
<div class="toc-local__body">
<ol class="toc-local__list">
{items.map((h) => (
<li
class={`toc-local__item d${h.depth}`}
data-toc-item
data-depth={h.depth}
data-id={h.slug}
>
<a href={`#${h.slug}`} data-toc-link data-slug={h.slug}>
<span class="toc-local__mark" aria-hidden="true"></span>
<span class="toc-local__text">{h.text}</span>
</a>
</li>
))}
</ol>
</div>
</div>
</nav>
)}
<script is:inline>
(() => {
function init() {
const toc = document.querySelector(".toc-local");
if (!toc) return;
const toc = document.querySelector(".toc-local[data-toc-local]");
if (!toc || toc.dataset.tocReady === "1") return;
toc.dataset.tocReady = "1";
const toggle = toc.querySelector(".toc-local__toggle");
const bodyClip = toc.querySelector(".toc-local__body-clip");
const mq = window.matchMedia("(max-width: 980px)");
const KEY = `archicratie:toc-local:${window.location.pathname}`;
if (!toggle || !bodyClip) return;
const readState = () => {
try {
const v = localStorage.getItem(KEY);
if (v === "open") return true;
if (v === "closed") return false;
} catch {}
return null;
};
const writeState = (open) => {
try { localStorage.setItem(KEY, open ? "open" : "closed"); } catch {}
};
const setOpen = (open, { persist = true, emit = true } = {}) => {
const isMobile = mq.matches;
toc.classList.toggle("is-collapsed", isMobile && !open);
toggle.setAttribute("aria-expanded", open ? "true" : "false");
if (persist && isMobile) writeState(open);
if (emit && open && isMobile) {
window.dispatchEvent(new CustomEvent("archicratie:tocLocalOpen"));
}
};
const initAccordion = () => {
if (!mq.matches) {
setOpen(true, { persist: false, emit: false });
return;
}
const stored = readState();
setOpen(stored == null ? true : stored, { persist: false, emit: false });
};
toggle.addEventListener("click", () => {
const next = toggle.getAttribute("aria-expanded") !== "true";
setOpen(next);
});
if (mq.addEventListener) {
mq.addEventListener("change", initAccordion);
} else if (mq.addListener) {
mq.addListener(initAccordion);
}
const itemEls = Array.from(toc.querySelectorAll("[data-toc-item]"));
if (!itemEls.length) return;
if (!itemEls.length) {
initAccordion();
return;
}
const ordered = itemEls
.map((li) => {
const a = li.querySelector("a[data-toc-link]");
const id = li.getAttribute("data-id") || a?.dataset.slug || "";
const depth = Number(li.getAttribute("data-depth") || "0");
const el = id ? document.getElementById(id) : null; // span.details-anchor OU h3[id]
const el = id ? document.getElementById(id) : null;
return (a && id && el) ? { id, depth, li, a, el } : null;
})
.filter(Boolean);
if (!ordered.length) return;
if (!ordered.length) {
initAccordion();
return;
}
const clear = () => {
for (const t of ordered) {
@@ -55,14 +128,29 @@ const items = (headings || []).filter((h) => h.depth >= 2 && h.depth <= 3);
};
const openDetailsIfNeeded = (el) => {
const d = el?.closest?.("details");
if (d && !d.open) d.open = true;
try {
if (!el) return;
let d = el.closest?.("details") || null;
if (!d && el.classList?.contains("details-anchor")) {
const n = el.nextElementSibling;
if (n && n.tagName === "DETAILS") d = n;
}
if (!d) {
const s = el.closest?.("summary");
if (s && s.parentElement && s.parentElement.tagName === "DETAILS") d = s.parentElement;
}
if (d && d.tagName === "DETAILS" && !d.open) d.open = true;
} catch {}
};
let current = "";
const setCurrent = (id) => {
if (!id || id === current) return;
const setCurrent = (id, { autoOpen = true } = {}) => {
if (!id) return;
const t = ordered.find((x) => x.id === id);
if (!t) return;
@@ -74,17 +162,21 @@ const items = (headings || []).filter((h) => h.depth >= 2 && h.depth <= 3);
t.a.setAttribute("aria-current", "true");
t.li.classList.add("is-current");
// ✅ IMPORTANT: plus de scrollIntoView ici
// sinon ça scroll l'aside pendant le scroll du reading => TOC global “disparaît”.
if (mq.matches && autoOpen && toc.classList.contains("is-collapsed")) {
setOpen(true);
}
window.dispatchEvent(
new CustomEvent("archicratie:tocLocalActive", { detail: { id } })
);
};
const computeActive = () => {
const visible = ordered.filter((t) => {
const d = t.el.closest?.("details");
if (d && !d.open) {
// Si l'élément est dans <summary>, il reste visible même details fermé
const inSummary = !!t.el.closest?.("summary");
if (!inSummary) return false;
if (!inSummary && !t.el.classList?.contains("details-anchor")) return false;
}
return true;
});
@@ -102,7 +194,7 @@ const items = (headings || []).filter((h) => h.depth >= 2 && h.depth <= 3);
}
if (!best) best = visible[0];
setCurrent(best.id);
if (best && best.id !== current) setCurrent(best.id, { autoOpen: true });
};
let ticking = false;
@@ -117,11 +209,14 @@ const items = (headings || []).filter((h) => h.depth >= 2 && h.depth <= 3);
const syncFromHash = () => {
const id = (location.hash || "").slice(1);
if (!id) { computeActive(); return; }
if (!id) {
computeActive();
return;
}
const el = document.getElementById(id);
if (el) openDetailsIfNeeded(el);
setCurrent(id);
setCurrent(id, { autoOpen: true });
};
toc.addEventListener("click", (ev) => {
@@ -133,13 +228,14 @@ const items = (headings || []).filter((h) => h.depth >= 2 && h.depth <= 3);
const el = document.getElementById(id);
if (el) openDetailsIfNeeded(el);
setCurrent(id);
setCurrent(id, { autoOpen: true });
});
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", onScroll);
window.addEventListener("hashchange", syncFromHash);
initAccordion();
syncFromHash();
onScroll();
}
@@ -153,30 +249,183 @@ const items = (headings || []).filter((h) => h.depth >= 2 && h.depth <= 3);
</script>
<style>
.toc-local{margin-top:12px;border:1px solid rgba(127,127,127,.25);border-radius:16px;padding:12px}
.toc-local__title{font-size:13px;opacity:.85;margin-bottom:8px}
.toc-local__list{list-style:none;margin:0;padding:0}
.toc-local__item::marker{content:""}
.toc-local__item{margin:6px 0}
.toc-local__item.d3{margin-left:12px;opacity:.9}
.toc-local__item.is-current > a{
font-weight: 750;
text-decoration: underline;
.toc-local{
margin-top: 12px;
border: 1px solid rgba(127,127,127,.25);
border-radius: 16px;
padding: 12px;
background: rgba(127,127,127,0.03);
}
.toc-local a{
display:inline-block;
max-width:100%;
text-decoration:none;
.toc-local__toggle{
width: 100%;
appearance: none;
border: 0;
background: transparent;
color: inherit;
text-align: left;
padding: 0;
cursor: pointer;
}
.toc-local a:hover{ text-decoration: underline; }
.toc-local__head{
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-bottom: 8px;
}
.toc-local__title{
font-size: 13px;
opacity: .85;
}
.toc-local__chevron{
font-size: 12px;
opacity: .72;
transition: transform 180ms ease;
}
.toc-local__body-clip{
display: grid;
grid-template-rows: 1fr;
transition:
grid-template-rows 220ms ease,
opacity 160ms ease,
margin-top 220ms ease;
}
.toc-local__body{
min-height: 0;
overflow: hidden;
}
.toc-local__list{
list-style: none;
margin: 0;
padding: 0;
max-height: 44vh;
overflow: auto;
padding-right: 8px;
scrollbar-gutter: stable;
}
</style>
.toc-local__item::marker{ content:""; }
.toc-local__item{ margin: 6px 0; }
.toc-local__item.d3{
margin-left: 14px;
opacity: .94;
}
.toc-local a{
display: grid;
grid-template-columns: auto 1fr;
gap: 8px;
align-items: start;
max-width: 100%;
text-decoration: none;
}
.toc-local a:hover{
text-decoration: none;
}
.toc-local__mark{
width: 10px;
height: 10px;
margin-top: .36em;
border-radius: 999px;
border: 1px solid rgba(127,127,127,.34);
background: transparent;
opacity: .68;
}
.toc-local__text{
line-height: 1.28;
}
.toc-local__item.is-current > a{
font-weight: 760;
}
.toc-local__item.is-current > a .toc-local__mark{
background: currentColor;
border-color: currentColor;
box-shadow: 0 0 0 3px rgba(127,127,127,.10);
opacity: 1;
}
@media (max-width: 980px){
.toc-local{
padding: 10px 12px;
border-radius: 14px;
}
.toc-local__head{
margin-bottom: 0;
min-height: 28px;
}
.toc-local__body-clip{
margin-top: 10px;
}
.toc-local.is-collapsed .toc-local__body-clip{
grid-template-rows: 0fr;
opacity: 0;
margin-top: 0;
}
.toc-local__body{
min-height: 0;
overflow: hidden;
transition: opacity 180ms ease;
}
.toc-local.is-collapsed .toc-local__body{
opacity: 0;
}
.toc-local.is-collapsed .toc-local__chevron{
transform: rotate(-90deg);
}
.toc-local__title{
font-size: 13px;
}
.toc-local__list{
max-height: min(42vh, 360px);
padding-right: 4px;
}
.toc-local__item{
margin: 5px 0;
}
.toc-local__item.d2 > a .toc-local__text{
font-size: 12.9px;
line-height: 1.24;
font-weight: 680;
}
.toc-local__item.d3{
margin-left: 12px;
}
.toc-local__item.d3 > a .toc-local__text{
font-size: 12.1px;
line-height: 1.22;
opacity: .95;
}
.toc-local__item.d3 > a .toc-local__mark{
width: 8px;
height: 8px;
margin-top: .42em;
opacity: .55;
}
}
</style>