feat(glossaire): enrich entries and refine glossary navigation
All checks were successful
SMOKE / smoke (push) Successful in 9s
CI / build-and-anchors (push) Successful in 55s
CI / build-and-anchors (pull_request) Successful in 45s

This commit is contained in:
2026-03-19 21:53:33 +01:00
parent bfa44fecda
commit d6b4eb82f4
57 changed files with 1471 additions and 429 deletions

View File

@@ -0,0 +1,223 @@
---
import SiteLayout from "../../layouts/SiteLayout.astro";
import { getCollection } from "astro:content";
const entries = await getCollection("glossaire");
const slugOf = (entry) => String(entry.id).replace(/\.(md|mdx)$/i, "");
const hrefOf = (entry) => `/glossaire/${slugOf(entry)}/`;
const collator = new Intl.Collator("fr", { sensitivity: "base", numeric: true });
const kindLabels = {
concept: "Concept",
diagnostic: "Diagnostic",
topologie: "Topologie",
verbe: "Verbe",
paradigme: "Paradigme",
doctrine: "Doctrine",
};
const domainLabels = {
transversal: "Transversal",
theorie: "Théorie",
"cas-ia": "Cas IA",
};
const levelLabels = {
fondamental: "Fondamental",
intermediaire: "Intermédiaire",
avance: "Avancé",
};
const sorted = [...entries].sort((a, b) => collator.compare(a.data.term, b.data.term));
function groupByInitial(list) {
const map = new Map();
for (const entry of list) {
const letter = (entry.data.term || "").trim().charAt(0).toUpperCase() || "#";
if (!map.has(letter)) map.set(letter, []);
map.get(letter).push(entry);
}
return [...map.entries()].sort((a, b) => collator.compare(a[0], b[0]));
}
const groupedAlpha = groupByInitial(sorted);
---
<SiteLayout title="Index complet du glossaire">
<section class="glossary-index-page">
<header class="glossary-index-page__hero">
<p class="glossary-index-page__kicker">Référentiel terminologique</p>
<h1>Index complet du glossaire</h1>
<p class="glossary-index-page__intro">
Cette page rassemble lensemble des entrées du glossaire dans un ordre alphabétique intégral.
Elle complète laccueil conceptuel du glossaire par une navigation plus encyclopédique.
</p>
</header>
<div class="glossary-index-page__topbar">
<a class="glossary-index-page__back" href="/glossaire/">← Retour à laccueil du glossaire</a>
<nav class="glossary-index-page__letters" aria-label="Lettres de lindex">
{groupedAlpha.map(([letter]) => (
<a href={`#letter-${letter}`}>{letter}</a>
))}
</nav>
</div>
<div class="glossary-index-page__groups">
{groupedAlpha.map(([letter, items]) => (
<section class="glossary-index-page__group" id={`letter-${letter}`}>
<h2>{letter}</h2>
<ul class="glossary-index-page__list">
{items.map((entry) => (
<li class="glossary-index-page__item">
<a class="glossary-index-page__term" href={hrefOf(entry)}>
{entry.data.term}
</a>
<p class="glossary-index-page__def">{entry.data.definitionShort}</p>
<p class="glossary-index-page__meta">
<span>{kindLabels[entry.data.kind] ?? entry.data.kind}</span>
<span>{domainLabels[entry.data.domain] ?? entry.data.domain}</span>
<span>{levelLabels[entry.data.level] ?? entry.data.level}</span>
</p>
</li>
))}
</ul>
</section>
))}
</div>
</section>
</SiteLayout>
<style>
.glossary-index-page{
padding: 8px 0 32px;
}
.glossary-index-page__hero{
margin-bottom: 22px;
}
.glossary-index-page__kicker{
margin: 0 0 8px;
font-size: 12px;
letter-spacing: .08em;
text-transform: uppercase;
opacity: .72;
}
.glossary-index-page__hero h1{
margin: 0 0 12px;
font-size: clamp(2.2rem, 4vw, 3rem);
line-height: 1.05;
letter-spacing: -.03em;
}
.glossary-index-page__intro{
max-width: 76ch;
margin: 0;
opacity: .92;
}
.glossary-index-page__topbar{
display: flex;
flex-direction: column;
gap: 14px;
margin: 22px 0 28px;
}
.glossary-index-page__back{
display: inline-flex;
width: fit-content;
align-items: center;
border: 1px solid rgba(127,127,127,0.28);
border-radius: 999px;
padding: 7px 14px;
text-decoration: none;
}
.glossary-index-page__letters{
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.glossary-index-page__letters a{
min-width: 34px;
text-align: center;
border: 1px solid rgba(127,127,127,0.24);
border-radius: 10px;
padding: 5px 8px;
text-decoration: none;
}
.glossary-index-page__groups{
display: flex;
flex-direction: column;
gap: 28px;
}
.glossary-index-page__group{
scroll-margin-top: calc(var(--sticky-offset) + 20px);
}
.glossary-index-page__group h2{
margin: 0 0 14px;
font-size: clamp(1.6rem, 2vw, 2rem);
line-height: 1.1;
}
.glossary-index-page__list{
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 12px;
}
.glossary-index-page__item{
border: 1px solid rgba(127,127,127,0.20);
border-radius: 16px;
padding: 14px 16px;
background: rgba(127,127,127,0.04);
}
.glossary-index-page__term{
display: inline-block;
font-weight: 800;
font-size: 1.04rem;
text-decoration: none;
margin-bottom: 6px;
}
.glossary-index-page__def{
margin: 0 0 8px;
line-height: 1.5;
opacity: .94;
}
.glossary-index-page__meta{
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0;
font-size: 12px;
opacity: .78;
}
.glossary-index-page__meta span{
border: 1px solid rgba(127,127,127,0.20);
border-radius: 999px;
padding: 2px 8px;
}
@media (prefers-color-scheme: dark){
.glossary-index-page__item{
background: rgba(255,255,255,0.04);
}
}
</style>