refactor(glossaire): centralize glossary relation helpers
This commit is contained in:
@@ -1,258 +1,46 @@
|
||||
---
|
||||
import {
|
||||
familyOf,
|
||||
getContextualTheory,
|
||||
getDisplayDomain,
|
||||
getDisplayFamily,
|
||||
getDisplayLevel,
|
||||
getEntriesOfSameFamily,
|
||||
getFondamentaux,
|
||||
getRelationSections,
|
||||
getSameFamilyTitle,
|
||||
hrefOfGlossaryEntry,
|
||||
slugOfGlossaryEntry,
|
||||
} from "../lib/glossary";
|
||||
|
||||
const {
|
||||
currentEntry,
|
||||
allEntries = [],
|
||||
} = Astro.props;
|
||||
|
||||
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 bySlug = new Map(allEntries.map((entry) => [slugOf(entry), entry]));
|
||||
const currentSlug = slugOf(currentEntry);
|
||||
|
||||
const fondamentauxWanted = [
|
||||
"archicratie",
|
||||
"tension",
|
||||
"arcalite",
|
||||
"cratialite",
|
||||
"archicration",
|
||||
"co-viabilite",
|
||||
];
|
||||
|
||||
const fondamentaux = fondamentauxWanted
|
||||
.map((slug) => bySlug.get(slug))
|
||||
.filter(Boolean);
|
||||
|
||||
function resolveList(slugs = []) {
|
||||
return slugs
|
||||
.map((slug) => bySlug.get(String(slug || "").trim()))
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function uniqueBySlug(entries) {
|
||||
const seen = new Set();
|
||||
const out = [];
|
||||
for (const entry of entries) {
|
||||
const slug = slugOf(entry);
|
||||
if (seen.has(slug)) continue;
|
||||
seen.add(slug);
|
||||
out.push(entry);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function sortByTerm(entries = []) {
|
||||
return [...entries].sort((a, b) => collator.compare(a.data.term, b.data.term));
|
||||
}
|
||||
|
||||
function familyOf(entry) {
|
||||
return entry?.data?.family ?? "";
|
||||
}
|
||||
|
||||
function kindOf(entry) {
|
||||
return entry?.data?.kind ?? "";
|
||||
}
|
||||
|
||||
const relatedEntries = sortByTerm(
|
||||
uniqueBySlug(resolveList(currentEntry.data.related ?? []))
|
||||
);
|
||||
|
||||
const opposedEntries = sortByTerm(
|
||||
uniqueBySlug(resolveList(currentEntry.data.opposedTo ?? []))
|
||||
);
|
||||
|
||||
const seeAlsoEntries = sortByTerm(
|
||||
uniqueBySlug(resolveList(currentEntry.data.seeAlso ?? []))
|
||||
);
|
||||
|
||||
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",
|
||||
figure: "Figure",
|
||||
qualification: "Qualification",
|
||||
epistemologie: "Épistémologie",
|
||||
};
|
||||
|
||||
const kindLabels = {
|
||||
concept: "Concept",
|
||||
diagnostic: "Diagnostic",
|
||||
topologie: "Topologie",
|
||||
verbe: "Verbe",
|
||||
paradigme: "Paradigme",
|
||||
doctrine: "Doctrine",
|
||||
dispositif: "Dispositif",
|
||||
figure: "Figure",
|
||||
qualification: "Qualification",
|
||||
epistemologie: "Épistémologie",
|
||||
};
|
||||
|
||||
const domainLabels = {
|
||||
transversal: "Transversal",
|
||||
theorie: "Théorie",
|
||||
"cas-ia": "Cas IA",
|
||||
};
|
||||
|
||||
const levelLabels = {
|
||||
fondamental: "Fondamental",
|
||||
intermediaire: "Intermédiaire",
|
||||
avance: "Avancé",
|
||||
};
|
||||
|
||||
const currentSlug = slugOfGlossaryEntry(currentEntry);
|
||||
const currentFamily = familyOf(currentEntry);
|
||||
const displayFamily =
|
||||
familyLabels[currentFamily] ??
|
||||
kindLabels[currentEntry.data.kind] ??
|
||||
"Fiche";
|
||||
|
||||
const displayDomain =
|
||||
domainLabels[currentEntry.data.domain] ??
|
||||
currentEntry.data.domain;
|
||||
const fondamentaux = getFondamentaux(allEntries);
|
||||
|
||||
const displayLevel =
|
||||
levelLabels[currentEntry.data.level] ??
|
||||
currentEntry.data.level;
|
||||
const displayFamily = getDisplayFamily(currentEntry);
|
||||
const displayDomain = getDisplayDomain(currentEntry);
|
||||
const displayLevel = getDisplayLevel(currentEntry);
|
||||
|
||||
function entriesOfSameFamily(entry) {
|
||||
const family = familyOf(entry);
|
||||
const sameFamilyEntries = getEntriesOfSameFamily(currentEntry, allEntries);
|
||||
const sameFamilyTitle = getSameFamilyTitle(currentEntry);
|
||||
|
||||
if (!family) return [];
|
||||
const contextualTheory = getContextualTheory(currentEntry, allEntries);
|
||||
|
||||
if (family === "concept-fondamental") {
|
||||
return fondamentaux;
|
||||
}
|
||||
|
||||
return sortByTerm(
|
||||
allEntries.filter((item) => familyOf(item) === family)
|
||||
);
|
||||
}
|
||||
|
||||
const sameFamilyEntries = entriesOfSameFamily(currentEntry);
|
||||
|
||||
const familySectionTitles = {
|
||||
"concept-fondamental": "Noyau archicratique",
|
||||
scene: "Scènes archicratiques",
|
||||
dynamique: "Dynamiques archicratiques",
|
||||
pathologie: "Pathologies archicratiques",
|
||||
topologie: "Topologies voisines",
|
||||
"meta-regime": "Méta-régimes archicratiques",
|
||||
paradigme: "Paradigmes voisins",
|
||||
doctrine: "Doctrines fondatrices",
|
||||
verbe: "Verbes de la scène",
|
||||
"dispositif-ia": "Dispositifs IA",
|
||||
"tension-irreductible": "Tensions irréductibles",
|
||||
figure: "Figures archicratiques",
|
||||
qualification: "Qualifications archicratiques",
|
||||
epistemologie: "Outillage épistémologique",
|
||||
};
|
||||
|
||||
const sameFamilyTitle =
|
||||
familySectionTitles[currentFamily] ?? "Même famille";
|
||||
|
||||
function isTheoryEntry(entry) {
|
||||
const family = familyOf(entry);
|
||||
const kind = kindOf(entry);
|
||||
|
||||
return (
|
||||
family === "paradigme" ||
|
||||
family === "doctrine" ||
|
||||
kind === "paradigme" ||
|
||||
kind === "doctrine"
|
||||
);
|
||||
}
|
||||
|
||||
function contextualTheoryFor(entry) {
|
||||
const fromRelations = uniqueBySlug([
|
||||
...resolveList(entry.data.related ?? []),
|
||||
...resolveList(entry.data.seeAlso ?? []),
|
||||
...resolveList(entry.data.opposedTo ?? []),
|
||||
])
|
||||
.filter((item) => slugOf(item) !== currentSlug)
|
||||
.filter((item) => isTheoryEntry(item));
|
||||
|
||||
if (fromRelations.length > 0) {
|
||||
return sortByTerm(fromRelations).slice(0, 6);
|
||||
}
|
||||
|
||||
if (familyOf(entry) === "paradigme") {
|
||||
const preferred = [
|
||||
"gouvernementalite",
|
||||
"gouvernementalite-algorithmique",
|
||||
"cybernetique",
|
||||
"biopolitique",
|
||||
"domination-legale-rationnelle",
|
||||
"democratie-deliberative",
|
||||
"gouvernance-des-communs",
|
||||
"agencement-machinique",
|
||||
"pharmacologie-technique",
|
||||
"preemption-algorithmique",
|
||||
"dissensus-politique",
|
||||
"lieu-vide-du-pouvoir",
|
||||
"habitus-et-violence-symbolique",
|
||||
"theorie-de-la-resonance",
|
||||
"conatus-et-multitude",
|
||||
"configuration-et-interdependance",
|
||||
"technodiversite-et-cosmotechnie",
|
||||
"grammatisation-et-proletarisation-cognitive",
|
||||
];
|
||||
|
||||
return uniqueBySlug(
|
||||
preferred
|
||||
.filter((slug) => slug !== currentSlug)
|
||||
.map((slug) => bySlug.get(slug))
|
||||
.filter(Boolean)
|
||||
).slice(0, 8);
|
||||
}
|
||||
|
||||
if (familyOf(entry) === "doctrine") {
|
||||
const preferred = [
|
||||
"contractualisme-hobbesien",
|
||||
"droit-naturel-et-propriete",
|
||||
"volonte-generale",
|
||||
"decisionnisme-souverain",
|
||||
];
|
||||
|
||||
return uniqueBySlug(
|
||||
preferred
|
||||
.filter((slug) => slug !== currentSlug)
|
||||
.map((slug) => bySlug.get(slug))
|
||||
.filter(Boolean)
|
||||
).slice(0, 6);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
const contextualTheory = contextualTheoryFor(currentEntry);
|
||||
|
||||
const showNoyau = currentFamily !== "concept-fondamental" && fondamentaux.length > 0;
|
||||
const showNoyau =
|
||||
currentFamily !== "concept-fondamental" &&
|
||||
fondamentaux.length > 0;
|
||||
|
||||
const showSameFamily =
|
||||
sameFamilyEntries.length > 0 && currentFamily !== "concept-fondamental";
|
||||
sameFamilyEntries.length > 0 &&
|
||||
currentFamily !== "concept-fondamental";
|
||||
|
||||
const relationSections = [
|
||||
{
|
||||
title: "Concepts liés",
|
||||
items: relatedEntries,
|
||||
},
|
||||
{
|
||||
title: "En tension avec",
|
||||
items: opposedEntries,
|
||||
},
|
||||
{
|
||||
title: "Voir aussi",
|
||||
items: seeAlsoEntries,
|
||||
},
|
||||
].filter((section) => section.items.length > 0);
|
||||
const relationSections = getRelationSections(currentEntry, allEntries);
|
||||
---
|
||||
|
||||
<nav class="glossary-aside" aria-label="Navigation du glossaire">
|
||||
@@ -286,11 +74,11 @@ const relationSections = [
|
||||
<h2 class="glossary-aside__heading">Noyau archicratique</h2>
|
||||
<ul class="glossary-aside__list">
|
||||
{fondamentaux.map((entry) => {
|
||||
const active = slugOf(entry) === currentSlug;
|
||||
const active = slugOfGlossaryEntry(entry) === currentSlug;
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
href={hrefOf(entry)}
|
||||
href={hrefOfGlossaryEntry(entry)}
|
||||
aria-current={active ? "page" : undefined}
|
||||
class={active ? "is-active" : undefined}
|
||||
>
|
||||
@@ -308,11 +96,11 @@ const relationSections = [
|
||||
<h2 class="glossary-aside__heading">{sameFamilyTitle}</h2>
|
||||
<ul class="glossary-aside__list">
|
||||
{sameFamilyEntries.map((entry) => {
|
||||
const active = slugOf(entry) === currentSlug;
|
||||
const active = slugOfGlossaryEntry(entry) === currentSlug;
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
href={hrefOf(entry)}
|
||||
href={hrefOfGlossaryEntry(entry)}
|
||||
aria-current={active ? "page" : undefined}
|
||||
class={active ? "is-active" : undefined}
|
||||
>
|
||||
@@ -334,7 +122,7 @@ const relationSections = [
|
||||
<h3 class="glossary-aside__subheading">{section.title}</h3>
|
||||
<ul class="glossary-aside__list">
|
||||
{section.items.map((entry) => (
|
||||
<li><a href={hrefOf(entry)}>{entry.data.term}</a></li>
|
||||
<li><a href={hrefOfGlossaryEntry(entry)}>{entry.data.term}</a></li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
@@ -347,7 +135,7 @@ const relationSections = [
|
||||
<h2 class="glossary-aside__heading">Paysage théorique</h2>
|
||||
<ul class="glossary-aside__list">
|
||||
{contextualTheory.map((entry) => (
|
||||
<li><a href={hrefOf(entry)}>{entry.data.term}</a></li>
|
||||
<li><a href={hrefOfGlossaryEntry(entry)}>{entry.data.term}</a></li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -1,76 +1,21 @@
|
||||
---
|
||||
import {
|
||||
countGlossaryEntriesByFamily,
|
||||
countGlossaryEntriesByKind,
|
||||
getFondamentaux,
|
||||
hrefOfGlossaryEntry,
|
||||
} from "../lib/glossary";
|
||||
|
||||
const {
|
||||
allEntries = [],
|
||||
} = Astro.props;
|
||||
|
||||
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 bySlug = new Map(allEntries.map((entry) => [slugOf(entry), entry]));
|
||||
|
||||
function sortByTerm(list = []) {
|
||||
return [...list].sort((a, b) => collator.compare(a.data.term, b.data.term));
|
||||
}
|
||||
|
||||
function familyOf(entry) {
|
||||
const explicit = entry?.data?.family;
|
||||
if (explicit) return explicit;
|
||||
|
||||
const slug = slugOf(entry);
|
||||
const kind = entry?.data?.kind;
|
||||
|
||||
if (kind === "paradigme") return "paradigme";
|
||||
if (kind === "doctrine") return "doctrine";
|
||||
if (kind === "verbe") return "verbe";
|
||||
|
||||
if (slug === "scene-depreuve") return "scene";
|
||||
if (slug === "autarchicratie") return "pathologie";
|
||||
if (slug === "obliteration-archicratique") return "dynamique";
|
||||
|
||||
if (
|
||||
[
|
||||
"archicratie",
|
||||
"arcalite",
|
||||
"cratialite",
|
||||
"archicration",
|
||||
"co-viabilite",
|
||||
"tension",
|
||||
].includes(slug)
|
||||
) {
|
||||
return "concept-fondamental";
|
||||
}
|
||||
|
||||
if (slug === "archicrations-differentielles-et-formes-hybrides") {
|
||||
return "topologie";
|
||||
}
|
||||
|
||||
if (kind === "topologie" && slug.startsWith("archicrations-")) {
|
||||
return "meta-regime";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const fondamentauxWanted = [
|
||||
"archicratie",
|
||||
"arcalite",
|
||||
"cratialite",
|
||||
"archicration",
|
||||
"co-viabilite",
|
||||
"tension",
|
||||
];
|
||||
|
||||
const fondamentaux = sortByTerm(
|
||||
fondamentauxWanted
|
||||
.map((slug) => bySlug.get(slug))
|
||||
.filter(Boolean)
|
||||
);
|
||||
const fondamentaux = getFondamentaux(allEntries);
|
||||
|
||||
const totalEntries = allEntries.length;
|
||||
const paradigmesCount = allEntries.filter((entry) => entry.data.kind === "paradigme").length;
|
||||
const doctrinesCount = allEntries.filter((entry) => entry.data.kind === "doctrine").length;
|
||||
const metaRegimesCount = allEntries.filter((entry) => familyOf(entry) === "meta-regime").length;
|
||||
const paradigmesCount = countGlossaryEntriesByKind(allEntries, "paradigme");
|
||||
const doctrinesCount = countGlossaryEntriesByKind(allEntries, "doctrine");
|
||||
const metaRegimesCount = countGlossaryEntriesByFamily(allEntries, "meta-regime");
|
||||
|
||||
const portalLinks = [
|
||||
{ href: "/glossaire/concepts-fondamentaux/", label: "Concepts fondamentaux" },
|
||||
@@ -115,7 +60,7 @@ const portalLinks = [
|
||||
<h2 class="glossary-home-aside__heading">Noyau archicratique</h2>
|
||||
<ul class="glossary-home-aside__list">
|
||||
{fondamentaux.map((entry) => (
|
||||
<li><a href={hrefOf(entry)}>{entry.data.term}</a></li>
|
||||
<li><a href={hrefOfGlossaryEntry(entry)}>{entry.data.term}</a></li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
385
src/lib/glossary.ts
Normal file
385
src/lib/glossary.ts
Normal file
@@ -0,0 +1,385 @@
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
|
||||
export type GlossaryEntry = CollectionEntry<"glossaire">;
|
||||
|
||||
export const GLOSSARY_COLLATOR = new Intl.Collator("fr", {
|
||||
sensitivity: "base",
|
||||
numeric: true,
|
||||
});
|
||||
|
||||
export const FAMILY_LABELS: Record<string, string> = {
|
||||
"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",
|
||||
figure: "Figure",
|
||||
qualification: "Qualification",
|
||||
epistemologie: "Épistémologie",
|
||||
};
|
||||
|
||||
export const KIND_LABELS: Record<string, string> = {
|
||||
concept: "Concept",
|
||||
diagnostic: "Diagnostic",
|
||||
topologie: "Topologie",
|
||||
verbe: "Verbe",
|
||||
paradigme: "Paradigme",
|
||||
doctrine: "Doctrine",
|
||||
dispositif: "Dispositif",
|
||||
figure: "Figure",
|
||||
qualification: "Qualification",
|
||||
epistemologie: "Épistémologie",
|
||||
};
|
||||
|
||||
export const DOMAIN_LABELS: Record<string, string> = {
|
||||
transversal: "Transversal",
|
||||
theorie: "Théorie",
|
||||
"cas-ia": "Cas IA",
|
||||
};
|
||||
|
||||
export const LEVEL_LABELS: Record<string, string> = {
|
||||
fondamental: "Fondamental",
|
||||
intermediaire: "Intermédiaire",
|
||||
avance: "Avancé",
|
||||
};
|
||||
|
||||
export const FONDAMENTAUX_WANTED = [
|
||||
"archicratie",
|
||||
"arcalite",
|
||||
"cratialite",
|
||||
"archicration",
|
||||
"co-viabilite",
|
||||
"tension",
|
||||
] as const;
|
||||
|
||||
export const FAMILY_SECTION_TITLES: Record<string, string> = {
|
||||
"concept-fondamental": "Noyau archicratique",
|
||||
scene: "Scènes archicratiques",
|
||||
dynamique: "Dynamiques archicratiques",
|
||||
pathologie: "Pathologies archicratiques",
|
||||
topologie: "Topologies voisines",
|
||||
"meta-regime": "Méta-régimes archicratiques",
|
||||
paradigme: "Paradigmes voisins",
|
||||
doctrine: "Doctrines fondatrices",
|
||||
verbe: "Verbes de la scène",
|
||||
"dispositif-ia": "Dispositifs IA",
|
||||
"tension-irreductible": "Tensions irréductibles",
|
||||
figure: "Figures archicratiques",
|
||||
qualification: "Qualifications archicratiques",
|
||||
epistemologie: "Outillage épistémologique",
|
||||
};
|
||||
|
||||
export function normalizeGlossarySlug(value: unknown): string {
|
||||
return String(value ?? "")
|
||||
.trim()
|
||||
.replace(/^\/+|\/+$/g, "")
|
||||
.replace(/\.(md|mdx)$/i, "")
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
export function slugOfGlossaryEntry(
|
||||
entry: Pick<GlossaryEntry, "id"> | null | undefined,
|
||||
): string {
|
||||
return normalizeGlossarySlug(entry?.id ?? "");
|
||||
}
|
||||
|
||||
export function hrefOfGlossaryEntry(
|
||||
entry: Pick<GlossaryEntry, "id"> | null | undefined,
|
||||
): string {
|
||||
const slug = slugOfGlossaryEntry(entry);
|
||||
return slug ? `/glossaire/${slug}/` : "/glossaire/";
|
||||
}
|
||||
|
||||
export function buildGlossaryBySlug(
|
||||
entries: GlossaryEntry[] = [],
|
||||
): Map<string, GlossaryEntry> {
|
||||
return new Map(
|
||||
entries.map((entry) => [slugOfGlossaryEntry(entry), entry]),
|
||||
);
|
||||
}
|
||||
|
||||
export function sortGlossaryEntries(
|
||||
entries: GlossaryEntry[] = [],
|
||||
): GlossaryEntry[] {
|
||||
return [...entries].sort((a, b) =>
|
||||
GLOSSARY_COLLATOR.compare(a.data.term, b.data.term),
|
||||
);
|
||||
}
|
||||
|
||||
export function uniqueGlossaryEntries(
|
||||
entries: GlossaryEntry[] = [],
|
||||
): GlossaryEntry[] {
|
||||
const seen = new Set<string>();
|
||||
const out: GlossaryEntry[] = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
const slug = slugOfGlossaryEntry(entry);
|
||||
if (!slug || seen.has(slug)) continue;
|
||||
seen.add(slug);
|
||||
out.push(entry);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
export function resolveGlossaryEntries(
|
||||
slugs: string[] = [],
|
||||
allEntries: GlossaryEntry[] = [],
|
||||
): GlossaryEntry[] {
|
||||
const bySlug = buildGlossaryBySlug(allEntries);
|
||||
|
||||
const resolved = slugs
|
||||
.map((slug) => bySlug.get(normalizeGlossarySlug(slug)))
|
||||
.filter(Boolean) as GlossaryEntry[];
|
||||
|
||||
return sortGlossaryEntries(uniqueGlossaryEntries(resolved));
|
||||
}
|
||||
|
||||
export function rawFamilyOf(
|
||||
entry: GlossaryEntry | null | undefined,
|
||||
): string {
|
||||
return String(entry?.data?.family ?? "");
|
||||
}
|
||||
|
||||
export function kindOf(
|
||||
entry: GlossaryEntry | null | undefined,
|
||||
): string {
|
||||
return String(entry?.data?.kind ?? "");
|
||||
}
|
||||
|
||||
export function familyOf(
|
||||
entry: GlossaryEntry | null | undefined,
|
||||
): string {
|
||||
const explicit = rawFamilyOf(entry);
|
||||
if (explicit) return explicit;
|
||||
|
||||
const slug = slugOfGlossaryEntry(entry);
|
||||
const kind = kindOf(entry);
|
||||
|
||||
if (kind === "paradigme") return "paradigme";
|
||||
if (kind === "doctrine") return "doctrine";
|
||||
if (kind === "verbe") return "verbe";
|
||||
|
||||
if (slug === "scene-depreuve") return "scene";
|
||||
if (slug === "autarchicratie") return "pathologie";
|
||||
if (slug === "obliteration-archicratique") return "dynamique";
|
||||
|
||||
if (FONDAMENTAUX_WANTED.includes(slug as (typeof FONDAMENTAUX_WANTED)[number])) {
|
||||
return "concept-fondamental";
|
||||
}
|
||||
|
||||
if (slug === "archicrations-differentielles-et-formes-hybrides") {
|
||||
return "topologie";
|
||||
}
|
||||
|
||||
if (kind === "topologie" && slug.startsWith("archicrations-")) {
|
||||
return "meta-regime";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
export function getDisplayFamily(
|
||||
entry: GlossaryEntry | null | undefined,
|
||||
): string {
|
||||
const familyKey = rawFamilyOf(entry) || familyOf(entry);
|
||||
return FAMILY_LABELS[familyKey] ?? KIND_LABELS[kindOf(entry)] ?? "Fiche";
|
||||
}
|
||||
|
||||
export function getDisplayDomain(
|
||||
entry: GlossaryEntry | null | undefined,
|
||||
): string {
|
||||
const key = String(entry?.data?.domain ?? "");
|
||||
return key ? (DOMAIN_LABELS[key] ?? key) : "";
|
||||
}
|
||||
|
||||
export function getDisplayLevel(
|
||||
entry: GlossaryEntry | null | undefined,
|
||||
): string {
|
||||
const key = String(entry?.data?.level ?? "");
|
||||
return key ? (LEVEL_LABELS[key] ?? key) : "";
|
||||
}
|
||||
|
||||
export function getFondamentaux(
|
||||
entries: GlossaryEntry[] = [],
|
||||
): GlossaryEntry[] {
|
||||
const bySlug = buildGlossaryBySlug(entries);
|
||||
|
||||
return sortGlossaryEntries(
|
||||
FONDAMENTAUX_WANTED
|
||||
.map((slug) => bySlug.get(slug))
|
||||
.filter(Boolean) as GlossaryEntry[],
|
||||
);
|
||||
}
|
||||
|
||||
export function getGlossaryEntriesByFamily(
|
||||
entries: GlossaryEntry[] = [],
|
||||
familyKey: string,
|
||||
): GlossaryEntry[] {
|
||||
return sortGlossaryEntries(
|
||||
entries.filter((entry) => familyOf(entry) === familyKey),
|
||||
);
|
||||
}
|
||||
|
||||
export function countGlossaryEntriesByKind(
|
||||
entries: GlossaryEntry[] = [],
|
||||
kindKey: string,
|
||||
): number {
|
||||
return entries.filter((entry) => kindOf(entry) === kindKey).length;
|
||||
}
|
||||
|
||||
export function countGlossaryEntriesByFamily(
|
||||
entries: GlossaryEntry[] = [],
|
||||
familyKey: string,
|
||||
): number {
|
||||
return entries.filter((entry) => familyOf(entry) === familyKey).length;
|
||||
}
|
||||
|
||||
export function getEntriesOfSameFamily(
|
||||
entry: GlossaryEntry,
|
||||
allEntries: GlossaryEntry[] = [],
|
||||
): GlossaryEntry[] {
|
||||
const familyKey = familyOf(entry);
|
||||
if (!familyKey) return [];
|
||||
|
||||
if (familyKey === "concept-fondamental") {
|
||||
return getFondamentaux(allEntries);
|
||||
}
|
||||
|
||||
return getGlossaryEntriesByFamily(allEntries, familyKey);
|
||||
}
|
||||
|
||||
export function getSameFamilyTitle(
|
||||
entry: GlossaryEntry,
|
||||
): string {
|
||||
return FAMILY_SECTION_TITLES[familyOf(entry)] ?? "Même famille";
|
||||
}
|
||||
|
||||
export type GlossaryRelationBlock = {
|
||||
title: string;
|
||||
items: GlossaryEntry[];
|
||||
className: string;
|
||||
};
|
||||
|
||||
export function getRelationBlocks(
|
||||
entry: GlossaryEntry,
|
||||
allEntries: GlossaryEntry[] = [],
|
||||
): GlossaryRelationBlock[] {
|
||||
const relatedEntries = resolveGlossaryEntries(entry.data.related ?? [], allEntries);
|
||||
const opposedEntries = resolveGlossaryEntries(entry.data.opposedTo ?? [], allEntries);
|
||||
const seeAlsoEntries = resolveGlossaryEntries(entry.data.seeAlso ?? [], allEntries);
|
||||
|
||||
return [
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
export function getRelationSections(
|
||||
entry: GlossaryEntry,
|
||||
allEntries: GlossaryEntry[] = [],
|
||||
): Array<{ title: string; items: GlossaryEntry[] }> {
|
||||
return getRelationBlocks(entry, allEntries).map(({ title, items }) => ({
|
||||
title,
|
||||
items,
|
||||
}));
|
||||
}
|
||||
|
||||
function isTheoryEntry(entry: GlossaryEntry): boolean {
|
||||
const familyKey = familyOf(entry);
|
||||
const kindKey = kindOf(entry);
|
||||
|
||||
return (
|
||||
familyKey === "paradigme" ||
|
||||
familyKey === "doctrine" ||
|
||||
kindKey === "paradigme" ||
|
||||
kindKey === "doctrine"
|
||||
);
|
||||
}
|
||||
|
||||
const PREFERRED_PARADIGME_SLUGS = [
|
||||
"gouvernementalite",
|
||||
"gouvernementalite-algorithmique",
|
||||
"cybernetique",
|
||||
"biopolitique",
|
||||
"domination-legale-rationnelle",
|
||||
"democratie-deliberative",
|
||||
"gouvernance-des-communs",
|
||||
"agencement-machinique",
|
||||
"pharmacologie-technique",
|
||||
"preemption-algorithmique",
|
||||
"dissensus-politique",
|
||||
"lieu-vide-du-pouvoir",
|
||||
"habitus-et-violence-symbolique",
|
||||
"theorie-de-la-resonance",
|
||||
"conatus-et-multitude",
|
||||
"configuration-et-interdependance",
|
||||
"technodiversite-et-cosmotechnie",
|
||||
"grammatisation-et-proletarisation-cognitive",
|
||||
] as const;
|
||||
|
||||
const PREFERRED_DOCTRINE_SLUGS = [
|
||||
"contractualisme-hobbesien",
|
||||
"droit-naturel-et-propriete",
|
||||
"volonte-generale",
|
||||
"decisionnisme-souverain",
|
||||
] as const;
|
||||
|
||||
export function getContextualTheory(
|
||||
entry: GlossaryEntry,
|
||||
allEntries: GlossaryEntry[] = [],
|
||||
): GlossaryEntry[] {
|
||||
const currentSlug = slugOfGlossaryEntry(entry);
|
||||
const bySlug = buildGlossaryBySlug(allEntries);
|
||||
|
||||
const fromRelations = uniqueGlossaryEntries([
|
||||
...resolveGlossaryEntries(entry.data.related ?? [], allEntries),
|
||||
...resolveGlossaryEntries(entry.data.seeAlso ?? [], allEntries),
|
||||
...resolveGlossaryEntries(entry.data.opposedTo ?? [], allEntries),
|
||||
])
|
||||
.filter((item) => slugOfGlossaryEntry(item) !== currentSlug)
|
||||
.filter((item) => isTheoryEntry(item));
|
||||
|
||||
if (fromRelations.length > 0) {
|
||||
return sortGlossaryEntries(fromRelations).slice(0, 6);
|
||||
}
|
||||
|
||||
if (familyOf(entry) === "paradigme") {
|
||||
return uniqueGlossaryEntries(
|
||||
PREFERRED_PARADIGME_SLUGS
|
||||
.filter((slug) => slug !== currentSlug)
|
||||
.map((slug) => bySlug.get(slug))
|
||||
.filter(Boolean) as GlossaryEntry[],
|
||||
).slice(0, 8);
|
||||
}
|
||||
|
||||
if (familyOf(entry) === "doctrine") {
|
||||
return uniqueGlossaryEntries(
|
||||
PREFERRED_DOCTRINE_SLUGS
|
||||
.filter((slug) => slug !== currentSlug)
|
||||
.map((slug) => bySlug.get(slug))
|
||||
.filter(Boolean) as GlossaryEntry[],
|
||||
).slice(0, 6);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
@@ -2,6 +2,14 @@
|
||||
import GlossaryLayout from "../../layouts/GlossaryLayout.astro";
|
||||
import GlossaryAside from "../../components/GlossaryAside.astro";
|
||||
import { getCollection, render } from "astro:content";
|
||||
import {
|
||||
getDisplayDomain,
|
||||
getDisplayFamily,
|
||||
getDisplayLevel,
|
||||
getRelationBlocks,
|
||||
hrefOfGlossaryEntry,
|
||||
normalizeGlossarySlug,
|
||||
} from "../../lib/glossary";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const entries = await getCollection("glossaire");
|
||||
@@ -9,20 +17,12 @@ export async function getStaticPaths() {
|
||||
const seen = new Set();
|
||||
|
||||
for (const entry of entries) {
|
||||
const canonicalSlug = String(entry.id || "")
|
||||
.trim()
|
||||
.replace(/^\/+|\/+$/g, "")
|
||||
.replace(/\.(md|mdx)$/i, "")
|
||||
.toLowerCase();
|
||||
const canonicalSlug = normalizeGlossarySlug(entry.id);
|
||||
|
||||
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(canonicalSlug)) continue;
|
||||
|
||||
const addPath = (rawSlug) => {
|
||||
const requestedSlug = String(rawSlug || "")
|
||||
.trim()
|
||||
.replace(/^\/+|\/+$/g, "")
|
||||
.replace(/\.(md|mdx)$/i, "")
|
||||
.toLowerCase();
|
||||
const requestedSlug = normalizeGlossarySlug(rawSlug);
|
||||
|
||||
if (!requestedSlug) return;
|
||||
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(requestedSlug)) return;
|
||||
@@ -56,108 +56,11 @@ 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 relationBlocks = getRelationBlocks(entry, allEntries);
|
||||
|
||||
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).toLowerCase(), item])
|
||||
);
|
||||
|
||||
function resolveEntries(slugs = []) {
|
||||
const seen = new Set();
|
||||
|
||||
return slugs
|
||||
.map((slug) => bySlug.get(String(slug || "").trim().toLowerCase()))
|
||||
.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",
|
||||
dispositif: "Dispositif",
|
||||
figure: "Figure",
|
||||
qualification: "Qualification",
|
||||
epistemologie: "Épistémologie",
|
||||
};
|
||||
|
||||
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 = entry.data.domain
|
||||
? (domainLabels[entry.data.domain] ?? entry.data.domain)
|
||||
: "";
|
||||
|
||||
const displayLevel = entry.data.level
|
||||
? (levelLabels[entry.data.level] ?? entry.data.level)
|
||||
: "";
|
||||
const displayFamily = getDisplayFamily(entry);
|
||||
const displayDomain = getDisplayDomain(entry);
|
||||
const displayLevel = getDisplayLevel(entry);
|
||||
|
||||
const hasScholarlyMeta =
|
||||
(entry.data.mobilizedAuthors?.length ?? 0) > 0 ||
|
||||
@@ -241,7 +144,7 @@ const hasScholarlyMeta =
|
||||
<ul>
|
||||
{block.items.map((item) => (
|
||||
<li>
|
||||
<a href={hrefOf(item)}>{item.data.term}</a>
|
||||
<a href={hrefOfGlossaryEntry(item)}>{item.data.term}</a>
|
||||
<span> — {item.data.definitionShort}</span>
|
||||
</li>
|
||||
))}
|
||||
|
||||
@@ -2,74 +2,30 @@
|
||||
import GlossaryLayout from "../../layouts/GlossaryLayout.astro";
|
||||
import GlossaryHomeAside from "../../components/GlossaryHomeAside.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import {
|
||||
buildGlossaryBySlug,
|
||||
countGlossaryEntriesByKind,
|
||||
familyOf,
|
||||
getGlossaryEntriesByFamily,
|
||||
hrefOfGlossaryEntry,
|
||||
sortGlossaryEntries,
|
||||
} from "../../lib/glossary";
|
||||
|
||||
const entries = await getCollection("glossaire");
|
||||
|
||||
const slugOf = (entry) => String(entry.id).replace(/\.(md|mdx)$/i, "");
|
||||
const hrefOf = (entry) => `/glossaire/${slugOf(entry)}/`;
|
||||
const bySlug = buildGlossaryBySlug(entries);
|
||||
|
||||
const collator = new Intl.Collator("fr", { sensitivity: "base", numeric: true });
|
||||
const bySlug = new Map(entries.map((entry) => [slugOf(entry), entry]));
|
||||
|
||||
function sortByTerm(list = []) {
|
||||
return [...list].sort((a, b) => collator.compare(a.data.term, b.data.term));
|
||||
}
|
||||
|
||||
function familyOf(entry) {
|
||||
const explicit = entry?.data?.family;
|
||||
if (explicit) return explicit;
|
||||
|
||||
const slug = slugOf(entry);
|
||||
const kind = entry?.data?.kind;
|
||||
|
||||
if (kind === "paradigme") return "paradigme";
|
||||
if (kind === "doctrine") return "doctrine";
|
||||
if (kind === "verbe") return "verbe";
|
||||
|
||||
if (slug === "scene-depreuve") return "scene";
|
||||
if (slug === "autarchicratie") return "pathologie";
|
||||
if (slug === "obliteration-archicratique") return "dynamique";
|
||||
|
||||
if ([
|
||||
"archicratie",
|
||||
"arcalite",
|
||||
"cratialite",
|
||||
"archicration",
|
||||
"co-viabilite",
|
||||
"tension",
|
||||
].includes(slug)) {
|
||||
return "concept-fondamental";
|
||||
}
|
||||
|
||||
if (slug === "archicrations-differentielles-et-formes-hybrides") {
|
||||
return "topologie";
|
||||
}
|
||||
|
||||
if (kind === "topologie" && slug.startsWith("archicrations-")) {
|
||||
return "meta-regime";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const fondamentaux = sortByTerm(
|
||||
entries.filter((entry) => familyOf(entry) === "concept-fondamental")
|
||||
const fondamentaux = getGlossaryEntriesByFamily(entries, "concept-fondamental");
|
||||
const scenes = getGlossaryEntriesByFamily(entries, "scene");
|
||||
const dynamiques = sortGlossaryEntries(
|
||||
entries.filter((entry) =>
|
||||
["dynamique", "pathologie"].includes(familyOf(entry)),
|
||||
),
|
||||
);
|
||||
const metaRegimes = getGlossaryEntriesByFamily(entries, "meta-regime");
|
||||
|
||||
const scenes = sortByTerm(
|
||||
entries.filter((entry) => familyOf(entry) === "scene")
|
||||
);
|
||||
|
||||
const dynamiques = sortByTerm(
|
||||
entries.filter((entry) => ["dynamique", "pathologie"].includes(familyOf(entry)))
|
||||
);
|
||||
|
||||
const metaRegimes = sortByTerm(
|
||||
entries.filter((entry) => familyOf(entry) === "meta-regime")
|
||||
);
|
||||
|
||||
const paradigmesCount = entries.filter((entry) => entry.data.kind === "paradigme").length;
|
||||
const doctrinesCount = entries.filter((entry) => entry.data.kind === "doctrine").length;
|
||||
const paradigmesCount = countGlossaryEntriesByKind(entries, "paradigme");
|
||||
const doctrinesCount = countGlossaryEntriesByKind(entries, "doctrine");
|
||||
|
||||
const metaRegimesPreview = metaRegimes.slice(0, 6);
|
||||
|
||||
@@ -132,13 +88,13 @@ const indexCompletPageHref = "/glossaire/index-complet/";
|
||||
<div class="glossary-map__title">Forces en composition</div>
|
||||
<div class="glossary-map__roots">
|
||||
{arcalite ? (
|
||||
<a class="glossary-map__node" href={hrefOf(arcalite)}>ARCALITÉ</a>
|
||||
<a class="glossary-map__node" href={hrefOfGlossaryEntry(arcalite)}>ARCALITÉ</a>
|
||||
) : (
|
||||
<span class="glossary-map__node">ARCALITÉ</span>
|
||||
)}
|
||||
|
||||
{cratialite ? (
|
||||
<a class="glossary-map__node" href={hrefOf(cratialite)}>CRATIALITÉ</a>
|
||||
<a class="glossary-map__node" href={hrefOfGlossaryEntry(cratialite)}>CRATIALITÉ</a>
|
||||
) : (
|
||||
<span class="glossary-map__node">CRATIALITÉ</span>
|
||||
)}
|
||||
@@ -150,7 +106,7 @@ const indexCompletPageHref = "/glossaire/index-complet/";
|
||||
<div class="glossary-map__stage">
|
||||
<div class="glossary-map__title">Phénomène transversal</div>
|
||||
{tension ? (
|
||||
<a class="glossary-map__node glossary-map__node--wide" href={hrefOf(tension)}>
|
||||
<a class="glossary-map__node glossary-map__node--wide" href={hrefOfGlossaryEntry(tension)}>
|
||||
TENSION
|
||||
</a>
|
||||
) : (
|
||||
@@ -163,7 +119,7 @@ const indexCompletPageHref = "/glossaire/index-complet/";
|
||||
<div class="glossary-map__stage">
|
||||
<div class="glossary-map__title">Comparution</div>
|
||||
{sceneDepreuve ? (
|
||||
<a class="glossary-map__node glossary-map__node--wide" href={hrefOf(sceneDepreuve)}>
|
||||
<a class="glossary-map__node glossary-map__node--wide" href={hrefOfGlossaryEntry(sceneDepreuve)}>
|
||||
MISE EN SCÈNE
|
||||
</a>
|
||||
) : (
|
||||
@@ -176,7 +132,7 @@ const indexCompletPageHref = "/glossaire/index-complet/";
|
||||
<div class="glossary-map__stage">
|
||||
<div class="glossary-map__title">Opérateur régulateur</div>
|
||||
{archicration ? (
|
||||
<a class="glossary-map__node glossary-map__node--wide" href={hrefOf(archicration)}>
|
||||
<a class="glossary-map__node glossary-map__node--wide" href={hrefOfGlossaryEntry(archicration)}>
|
||||
ARCHICRATION
|
||||
</a>
|
||||
) : (
|
||||
@@ -209,7 +165,7 @@ const indexCompletPageHref = "/glossaire/index-complet/";
|
||||
|
||||
<div class="glossary-cards">
|
||||
{fondamentaux.map((entry) => (
|
||||
<a class="glossary-card" href={hrefOf(entry)}>
|
||||
<a class="glossary-card" href={hrefOfGlossaryEntry(entry)}>
|
||||
<strong>{entry.data.term}</strong>
|
||||
<span>{entry.data.definitionShort}</span>
|
||||
</a>
|
||||
@@ -265,7 +221,7 @@ const indexCompletPageHref = "/glossaire/index-complet/";
|
||||
|
||||
<div class="glossary-cards">
|
||||
{scenes.map((entry) => (
|
||||
<a class="glossary-card glossary-card--wide" href={hrefOf(entry)}>
|
||||
<a class="glossary-card glossary-card--wide" href={hrefOfGlossaryEntry(entry)}>
|
||||
<strong>{entry.data.term}</strong>
|
||||
<span>{entry.data.definitionShort}</span>
|
||||
</a>
|
||||
@@ -288,7 +244,7 @@ const indexCompletPageHref = "/glossaire/index-complet/";
|
||||
|
||||
<div class="glossary-cards">
|
||||
{dynamiques.map((entry) => (
|
||||
<a class="glossary-card" href={hrefOf(entry)}>
|
||||
<a class="glossary-card" href={hrefOfGlossaryEntry(entry)}>
|
||||
<strong>{entry.data.term}</strong>
|
||||
<span>{entry.data.definitionShort}</span>
|
||||
</a>
|
||||
@@ -316,7 +272,7 @@ const indexCompletPageHref = "/glossaire/index-complet/";
|
||||
{metaRegimesPreview.length > 0 && (
|
||||
<div class="glossary-cards">
|
||||
{metaRegimesPreview.map((entry) => (
|
||||
<a class="glossary-card" href={hrefOf(entry)}>
|
||||
<a class="glossary-card" href={hrefOfGlossaryEntry(entry)}>
|
||||
<strong>{entry.data.term}</strong>
|
||||
<span>{entry.data.definitionShort}</span>
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user