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

@@ -55,6 +55,107 @@ const { Content } = await render(entry);
const isAliasRoute = requestedSlug !== canonicalSlug;
const canonicalHref = `/glossaire/${canonicalSlug}/`;
const slugOf = (item) =>
String(item.id || "")
.trim()
.replace(/^\/+|\/+$/g, "")
.replace(/\.(md|mdx)$/i, "");
const hrefOf = (item) => `/glossaire/${slugOf(item)}/`;
const collator = new Intl.Collator("fr", { sensitivity: "base", numeric: true });
const bySlug = new Map(allEntries.map((item) => [slugOf(item), item]));
function resolveEntries(slugs = []) {
const seen = new Set();
return slugs
.map((slug) => bySlug.get(String(slug || "").trim()))
.filter(Boolean)
.filter((item) => {
const slug = slugOf(item);
if (seen.has(slug)) return false;
seen.add(slug);
return true;
})
.sort((a, b) => collator.compare(a.data.term, b.data.term));
}
const relatedEntries = resolveEntries(entry.data.related ?? []);
const opposedEntries = resolveEntries(entry.data.opposedTo ?? []);
const seeAlsoEntries = resolveEntries(entry.data.seeAlso ?? []);
const relationBlocks = [
{
title: "Concepts liés",
items: relatedEntries,
className: "is-related",
},
{
title: "En tension avec",
items: opposedEntries,
className: "is-opposed",
},
{
title: "Voir aussi",
items: seeAlsoEntries,
className: "is-see-also",
},
].filter((block) => block.items.length > 0);
const familyLabels = {
"concept-fondamental": "Concept fondamental",
scene: "Scène",
dynamique: "Dynamique",
pathologie: "Pathologie",
topologie: "Topologie",
"meta-regime": "Méta-régime",
paradigme: "Paradigme",
doctrine: "Doctrine",
verbe: "Verbe",
"dispositif-ia": "Dispositif IA",
"tension-irreductible": "Tension irréductible",
};
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 familyKey = entry.data.family ?? "";
const displayFamily =
familyLabels[familyKey] ??
kindLabels[entry.data.kind] ??
"Fiche";
const displayDomain =
domainLabels[entry.data.domain] ??
entry.data.domain;
const displayLevel =
levelLabels[entry.data.level] ??
entry.data.level;
const hasScholarlyMeta =
(entry.data.mobilizedAuthors?.length ?? 0) > 0 ||
(entry.data.comparisonTraditions?.length ?? 0) > 0;
---
<GlossaryLayout
@@ -72,23 +173,66 @@ const canonicalHref = `/glossaire/${canonicalSlug}/`;
</p>
)}
<h1>{entry.data.term}</h1>
<p><em>{entry.data.definitionShort}</em></p>
{(entry.data.mobilizedAuthors?.length > 0 || entry.data.comparisonTraditions) && (
<header class="glossary-entry-head">
<h1>{entry.data.term}</h1>
<p class="glossary-entry-dek">
<em>{entry.data.definitionShort}</em>
</p>
<div class="glossary-entry-signals" aria-label="Repères de lecture">
<span class="glossary-pill glossary-pill--family">
<strong>Famille :</strong> {displayFamily}
</span>
<span class="glossary-pill">
<strong>Domaine :</strong> {displayDomain}
</span>
<span class="glossary-pill">
<strong>Niveau :</strong> {displayLevel}
</span>
</div>
</header>
{hasScholarlyMeta && (
<div class="glossary-entry-meta">
{entry.data.mobilizedAuthors?.length > 0 && (
{(entry.data.mobilizedAuthors?.length ?? 0) > 0 && (
<p>
<strong>Auteurs mobilisés :</strong> {entry.data.mobilizedAuthors.join(" / ")}
</p>
)}
{entry.data.comparisonTraditions && (
{(entry.data.comparisonTraditions?.length ?? 0) > 0 && (
<p>
<strong>Traditions de comparaison :</strong> {entry.data.comparisonTraditions.join(" / ")}
</p>
)}
</div>
)}
<Content />
<div class="glossary-entry-body">
<Content />
</div>
{relationBlocks.length > 0 && (
<section class="glossary-relations" aria-label="Relations conceptuelles">
<h2>Relations conceptuelles</h2>
<div class="glossary-relations-grid">
{relationBlocks.map((block) => (
<section class={`glossary-relations-card ${block.className}`}>
<h3>{block.title}</h3>
<ul>
{block.items.map((item) => (
<li>
<a href={hrefOf(item)}>{item.data.term}</a>
<span> — {item.data.definitionShort}</span>
</li>
))}
</ul>
</section>
))}
</div>
</section>
)}
</GlossaryLayout>
<style>
@@ -99,10 +243,50 @@ const canonicalHref = `/glossaire/${canonicalSlug}/`;
background: rgba(127,127,127,0.05);
font-size: 14px;
line-height: 1.45;
margin-bottom: 18px;
}
.glossary-entry-meta{
margin: 0 0 16px;
.glossary-entry-head{
margin-bottom: 18px;
}
.glossary-entry-head h1{
margin-bottom: 10px;
}
.glossary-entry-dek{
margin: 0 0 14px;
font-size: 1.02rem;
line-height: 1.6;
opacity: .95;
}
.glossary-entry-signals{
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0 0 6px;
}
.glossary-pill{
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 10px;
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;
}
.glossary-pill--family{
border-color: rgba(127,127,127,0.36);
font-weight: 700;
}
.glossary-entry-meta{
margin: 0 0 18px;
padding: 10px 12px;
border: 1px solid rgba(127,127,127,0.18);
border-radius: 12px;
@@ -119,14 +303,77 @@ const canonicalHref = `/glossaire/${canonicalSlug}/`;
margin-top: 6px;
}
@media (prefers-color-scheme: dark){
.glossary-entry-meta{
background: rgba(255,255,255,0.03);
.glossary-entry-body{
margin-bottom: 28px;
}
.glossary-relations{
margin-top: 26px;
padding-top: 18px;
border-top: 1px solid rgba(127,127,127,0.18);
}
.glossary-relations h2{
margin-bottom: 14px;
}
.glossary-relations-grid{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 12px;
}
.glossary-relations-card{
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
padding: 14px 16px;
background: rgba(127,127,127,0.05);
}
.glossary-relations-card h3{
margin-top: 0;
margin-bottom: 10px;
font-size: 15px;
line-height: 1.35;
}
.glossary-relations-card ul{
margin: 0;
padding-left: 18px;
}
.glossary-relations-card li{
margin-bottom: 8px;
font-size: 14px;
line-height: 1.45;
}
.glossary-relations-card li:last-child{
margin-bottom: 0;
}
.glossary-relations-card span{
opacity: .9;
}
@media (max-width: 720px){
.glossary-entry-signals{
gap: 6px;
}
.glossary-pill{
font-size: 12px;
}
}
@media (prefers-color-scheme: dark){
.glossary-legacy-note{
.glossary-entry-meta{
background: rgba(255,255,255,0.03);
}
.glossary-legacy-note,
.glossary-pill,
.glossary-relations-card{
background: rgba(255,255,255,0.04);
}
}