feat(ui): harmoniser navigation pages d’entrée et recherche
All checks were successful
SMOKE / smoke (push) Successful in 6s
CI / build-and-anchors (push) Successful in 44s
CI / build-and-anchors (pull_request) Successful in 36s

This commit is contained in:
2026-04-25 01:31:14 +02:00
parent 8605b7198f
commit 64e56e8abc
10 changed files with 835 additions and 254 deletions

View File

@@ -28,6 +28,7 @@ const tocId = `toc-global-${collection}-${String(basePath).replace(/[^\w-]+/g, "
<nav
class="toc-global"
data-mobile-default="closed"
aria-label={label}
data-toc-global
data-toc-key={`global:${collection}:${basePath}`}
@@ -35,14 +36,14 @@ const tocId = `toc-global-${collection}-${String(basePath).replace(/[^\w-]+/g, "
<button
class="toc-global__head toc-global__toggle"
type="button"
aria-expanded="true"
aria-expanded="false"
aria-controls={tocId}
>
<span class="toc-global__title">{label}</span>
<span class="toc-global__chevron" aria-hidden="true">▾</span>
</button>
<div class="toc-global__body-clip" id={tocId}>
<div class="toc-global__body-clip" id={tocId} hidden>
<div class="toc-global__body">
<ol class="toc-global__list">
{entries.map((e) => {
@@ -291,6 +292,10 @@ const tocId = `toc-global-${collection}-${String(basePath).replace(/[^\w-]+/g, "
max-height: min(42vh, 360px);
padding-right: 4px;
}
.toc-global__body-clip[hidden]{
display: none !important;
}
}
@media (prefers-color-scheme: dark){
@@ -332,9 +337,16 @@ const tocId = `toc-global-${collection}-${String(basePath).replace(/[^\w-]+/g, "
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 effectiveOpen = isMobile ? open : true;
nav.classList.toggle("is-collapsed", isMobile && !effectiveOpen);
toggle.setAttribute("aria-expanded", effectiveOpen ? "true" : "false");
if (bodyClip) {
bodyClip.hidden = isMobile && !effectiveOpen;
}
if (persist && isMobile) write(effectiveOpen);
};
const initState = () => {

View File

@@ -7,18 +7,18 @@ const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
---
{items.length > 0 && (
<nav class="toc-local" aria-label="Dans ce chapitre" data-toc-local>
<nav class="toc-local" aria-label="Dans ce chapitre" data-toc-local data-mobile-default="closed">
<button
class="toc-local__head toc-local__toggle"
type="button"
aria-expanded="true"
aria-expanded="false"
aria-controls={tocId}
>
<span class="toc-local__title">Dans ce chapitre</span>
<span class="toc-local__chevron" aria-hidden="true">▾</span>
</button>
<div class="toc-local__body-clip" id={tocId}>
<div class="toc-local__body-clip" id={tocId} hidden>
<div class="toc-local__body">
<ol class="toc-local__list">
{items.map((h) => (
@@ -69,12 +69,18 @@ const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
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");
const effectiveOpen = isMobile ? open : true;
if (persist && isMobile) writeState(open);
toc.classList.toggle("is-collapsed", isMobile && !effectiveOpen);
toggle.setAttribute("aria-expanded", effectiveOpen ? "true" : "false");
if (emit && open && isMobile) {
if (bodyClip) {
bodyClip.hidden = isMobile && !effectiveOpen;
}
if (persist && isMobile) writeState(effectiveOpen);
if (emit && effectiveOpen && isMobile) {
window.dispatchEvent(new CustomEvent("archicratie:tocLocalOpen"));
}
};
@@ -85,7 +91,7 @@ const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
return;
}
const stored = readState();
setOpen(stored == null ? true : stored, { persist: false, emit: false });
setOpen(stored == null ? false : stored, { persist: false, emit: false });
};
toggle.addEventListener("click", () => {
@@ -162,7 +168,8 @@ const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
t.a.setAttribute("aria-current", "true");
t.li.classList.add("is-current");
if (mq.matches && autoOpen && toc.classList.contains("is-collapsed")) {
// Sur mobile/tablette, le suivi actif ne doit pas rouvrir automatiquement la TOC.
if (!mq.matches && autoOpen && toc.classList.contains("is-collapsed")) {
setOpen(true);
}
@@ -216,7 +223,7 @@ const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
const el = document.getElementById(id);
if (el) openDetailsIfNeeded(el);
setCurrent(id, { autoOpen: true });
setCurrent(id, { autoOpen: false });
};
toc.addEventListener("click", (ev) => {
@@ -427,5 +434,9 @@ const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
margin-top: .42em;
opacity: .55;
}
.toc-local__body-clip[hidden]{
display: none !important;
}
}
</style>

View File

@@ -1,17 +1,15 @@
<nav class="site-nav" aria-label="Navigation principale">
<a href="/">Accueil</a>
<span aria-hidden="true"> · </span>
<a href="/">Accueil</a>
<span aria-hidden="true"> · </span>
<a href="/archicrat-ia/">Essai-thèse — ArchiCraT-IA</a>
<span aria-hidden="true"> · </span>
<a href="/archicrat-ia/">Essai-thèse</a>
<span aria-hidden="true"> · </span>
<a href="/cas-ia/">Cas pratique — Gouvernance IA</a>
<span aria-hidden="true"> · </span>
<a href="/cas-ia/">Cas IA</a>
<span aria-hidden="true"> · </span>
<a href="/glossaire/">Glossaire</a>
<span aria-hidden="true"> · </span>
<a href="/recherche/">Recherche</a>
<a href="/glossaire/">Glossaire</a>
<span aria-hidden="true"> · </span>
<a href="/recherche/">Recherche</a>
</nav>

View File

@@ -184,7 +184,8 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
.catch(() => Boolean(__DEV__));
}
})();
</script>
</script>
</head>
<body
@@ -665,6 +666,40 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
}
}
@media (orientation: landscape) and (min-width: 981px) and (max-width: 1220px) and (pointer: coarse){
.page{
padding-left: 10px;
padding-right: 10px;
}
.page-shell{
--aside-w: 300px;
--gap: 14px;
max-width: calc(100vw - 20px) !important;
grid-template-columns: minmax(260px, var(--aside-w)) minmax(0, 1fr) !important;
}
.reading{
max-width: none !important;
width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
}
:global(.reading p[id^="p-"]){
padding-right: 108px;
}
:global(.para-tools){
right: 0;
}
:global(.para-tools-actions){
flex-wrap: wrap;
justify-content: flex-end;
}
}
@media (prefers-color-scheme: dark){
:global(body[data-edition-key="glossaire"][data-sticky-mode="glossary-portal"] #reading-follow .reading-follow__inner){
background: rgba(0,0,0,.6);
@@ -957,7 +992,7 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
}
}
.mobile-para-menu{
.mobile-para-menu{
position: fixed;
inset: auto 10px 10px 10px;
z-index: 120;
@@ -1009,7 +1044,7 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
transform: translateY(1px);
}
.mobile-para-menu{
.mobile-para-menu{
touch-action: manipulation;
}
@@ -1082,6 +1117,7 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
const docEditionKey = document.body?.dataset?.editionKey || "";
const docStickyMode = String(document.body?.dataset?.stickyMode || "default");
const isGlossaryEdition = docEditionKey === "glossaire";
const isIntroEdition = docEditionKey === "commencer";
const hasLocalGlossaryFollow =
isGlossaryEdition && Boolean(document.getElementById("glossary-hero-follow"));
@@ -1501,45 +1537,45 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
}
function updateResumeButton() {
const btn = document.getElementById("resume-btn");
if (!btn) return;
const btn = document.getElementById("resume-btn");
if (!btn) return;
const current = getResumeBookmark();
const current = getResumeBookmark();
btn.hidden = false;
btn.setAttribute("href", "#");
btn.hidden = false;
btn.setAttribute("href", "#");
if (!current) {
delete btn.dataset.resumeAnchor;
delete btn.dataset.resumePath;
delete btn.dataset.resumeKind;
btn.setAttribute("aria-disabled", "true");
btn.classList.add("is-disabled");
btn.title = "Aucun marque-page explicite enregistré";
return;
if (!current) {
delete btn.dataset.resumeAnchor;
delete btn.dataset.resumePath;
delete btn.dataset.resumeKind;
btn.setAttribute("aria-disabled", "true");
btn.classList.add("is-disabled");
btn.title = "Aucun marque-page explicite enregistré";
return;
}
btn.dataset.resumeAnchor = current.anchor;
btn.dataset.resumePath = current.path || "";
btn.dataset.resumeKind = current.kind || "explicit-bookmark";
btn.setAttribute("aria-disabled", "false");
btn.classList.remove("is-disabled");
btn.title = `Reprendre : ${current.anchor}`;
if (!__resumeClickBound) {
__resumeClickBound = true;
btn.addEventListener("click", (ev) => {
ev.preventDefault();
ev.stopPropagation();
if (btn.getAttribute("aria-disabled") === "true") return;
performResume();
}, { passive: false });
}
}
btn.dataset.resumeAnchor = current.anchor;
btn.dataset.resumePath = current.path || "";
btn.dataset.resumeKind = current.kind || "explicit-bookmark";
btn.setAttribute("aria-disabled", "false");
btn.classList.remove("is-disabled");
btn.title = `Reprendre : ${current.anchor}`;
if (!__resumeClickBound) {
__resumeClickBound = true;
btn.addEventListener("click", (ev) => {
ev.preventDefault();
ev.stopPropagation();
if (btn.getAttribute("aria-disabled") === "true") return;
performResume();
}, { passive: false });
}
}
window.__archiUpdateResumeButton = updateResumeButton;
if (window.location.search.includes("body=")) {
@@ -1858,7 +1894,7 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
}
safe("para-tools", () => {
if (isGlossaryEdition) return;
if (isGlossaryEdition || isIntroEdition) return;
for (const p of parasAll) {
if (p.querySelector(".para-tools")) continue;
@@ -1961,7 +1997,7 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
});
safe("mobile-para-tools", () => {
if (isGlossaryEdition) return;
if (isGlossaryEdition || isIntroEdition) return;
if (!reading) return;
const isMobileLike = () =>
@@ -1985,8 +2021,12 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
let menuOpen = false;
let touchLongPressActive = false;
const LONG_PRESS_DELAY = 460;
const LONG_PRESS_MOVE_TOLERANCE = 18;
const LONG_PRESS_DELAY = 520;
const isTabletLike = () =>
window.matchMedia("(pointer: coarse)").matches &&
Math.min(window.innerWidth, window.innerHeight) >= 700;
const getMoveTolerance = () => isTabletLike() ? 42 : 22;
function isInteractiveTarget(node) {
const el = node?.closest?.(
@@ -2029,7 +2069,12 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
function movedTooFar(x, y) {
const dx = Math.abs(Number(x || 0) - pressStartX);
const dy = Math.abs(Number(y || 0) - pressStartY);
return dx > LONG_PRESS_MOVE_TOLERANCE || dy > LONG_PRESS_MOVE_TOLERANCE;
const tol = getMoveTolerance();
// iPad/tablette : on tolère mieux la dérive verticale naturelle du doigt.
if (isTabletLike()) return dx > tol || dy > (tol * 1.65);
return dx > tol || dy > tol;
}
function closeMenu() {
@@ -2118,13 +2163,10 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
}
}
function handlePressEnd() {
cancelLongPress();
}
function handlePressEnd() {
clearPressTimer();
pressPointerId = null;
touchLongPressActive = false;
}
reading.addEventListener("pointerdown", handlePressStart, { passive: true });
@@ -2162,15 +2204,17 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
cancelLongPress();
}, { passive: true });
window.addEventListener("scroll", () => {
clearPressTimer();
if (menuOpen) closeMenu();
}, { passive: true });
function handleScrollDuringMobileMenu() {
// Tant que le timer long-press est en cours, ne pas l'annuler brutalement
// sur tablette : iPadOS peut produire un micro-scroll fantôme.
if (pressTimer && isTabletLike()) return;
document.addEventListener("scroll", () => {
clearPressTimer();
if (menuOpen) closeMenu();
}, { passive: true, capture: true });
}
window.addEventListener("scroll", handleScrollDuringMobileMenu, { passive: true });
document.addEventListener("scroll", handleScrollDuringMobileMenu, { passive: true, capture: true });
document.addEventListener("click", (ev) => {
const p = ev.target?.closest?.('.reading p[id^="p-"]');
@@ -2559,6 +2603,14 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
nav.classList.toggle("is-collapsed", !open);
toggle.setAttribute("aria-expanded", open ? "true" : "false");
const bodyClip =
nav.querySelector(".toc-global__body-clip") ||
nav.querySelector(".toc-local__body-clip");
if (bodyClip) {
bodyClip.hidden = !open;
}
const key = nav.dataset.tocKey
? `archicratie:${nav.dataset.tocKey || ""}`
: nav.classList.contains("toc-local")
@@ -2580,9 +2632,16 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
}
function syncAutoCollapse() {
const shouldOpen = nearTopZone();
// Sur mobile/tablette, les TOC restent fermées par défaut.
// Elles ne souvrent que par action explicite utilisateur.
if (mqCompact.matches) {
setTocOpen(tocGlobal, false, false);
setTocOpen(tocLocal, false, false);
return;
}
// En desktop comme en mobile : TOC ouverts en haut, repliés dès quon quitte le haut.
// Desktop : comportement historique conservé.
const shouldOpen = nearTopZone();
setTocOpen(tocGlobal, shouldOpen, false);
setTocOpen(tocLocal, shouldOpen, false);
}
@@ -2607,45 +2666,12 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
schedule();
});
safe("mobile-toc-collapse", () => {
const isMobile = () => window.innerWidth <= 760;
const bindToggle = (rootSel, headSel) => {
document.querySelectorAll(rootSel).forEach((box) => {
const head = box.querySelector(headSel);
if (!head) return;
if (!box.hasAttribute("data-mobile-collapsible-bound")) {
box.setAttribute("data-mobile-collapsible-bound", "1");
if (isMobile()) box.classList.remove("is-open");
else box.classList.add("is-open");
head.addEventListener("click", () => {
if (!isMobile()) return;
box.classList.toggle("is-open");
});
}
});
};
const syncOpenState = () => {
document
.querySelectorAll(".toc-global, .toc-local")
.forEach((box) => {
if (isMobile()) box.classList.remove("is-open");
else box.classList.add("is-open");
});
};
bindToggle(".toc-global", ".toc-global__head");
bindToggle(".toc-local", ".toc-local__head");
bindToggle(".toc-global", "[data-toc-global-head]");
bindToggle(".toc-local", "[data-toc-local-head]");
syncOpenState();
window.addEventListener("resize", syncOpenState, { passive: true });
});
/*
* TOC accordions are owned by EditionToc.astro / LocalToc.astro.
* Keep only the top-zone auto-collapse below; the previous legacy
* mobile-toc-collapse binder toggled an unused .is-open state and
* added duplicate click listeners on the same headers.
*/
safe("reading-follow", () => {
if (!reading || !followEl) return;

View File

@@ -7,15 +7,62 @@ entries.sort((a, b) => (a.data.order ?? 9999) - (b.data.order ?? 9999));
---
<SiteLayout title="Essai-thèse — ArchiCraT-IA">
<h1>Essai-thèse — ArchiCraT-IA</h1>
<section class="landing landing-home">
<header class="landing-hero">
<p class="landing-kicker">Corpus principal</p>
<h1>Essai-thèse — ArchiCraT-IA</h1>
<p class="landing-lead">
Fondements, histoire, philosophie du pouvoir, tensions et régulations
archicratiques.
</p>
</header>
<ul>
{entries.map((e) => (
<li>
<a href={`/archicrat-ia/${String(e.id).replace(/\.(md|mdx)$/i, "")}/`}>
{e.data.title}
</a>
</li>
))}
</ul>
<section class="edition-note" aria-labelledby="note-lecteur-title">
<p class="landing-kicker">Note au lecteur</p>
<h2 id="note-lecteur-title">Statut du travail</h2>
<p>
Le texte que vous vous apprêtez à lire ne constitue pas une théorie close
ni un système achevé. Il sagit dun travail de longue élaboration, ayant
progressivement pris la forme dune hypothèse structurée : celle dune
méta-grammaire des régulations collectives, désignée ici sous le nom
darchicratie.
</p>
<p>
Cette proposition vise à offrir un cadre transversal pour penser les formes
de constitution, de régulation et dévolution des collectifs humains, en
particulier dans des contextes marqués par la complexification des dispositifs,
lopacification des décisions et la transformation des scènes de conflictualité.
</p>
<p>
Elle doit donc être lue comme une architecture conceptuelle déjà cohérente
dans ses lignes de force, mais encore ouverte à la discussion, à la critique,
à lapprofondissement et à la mise à lépreuve.
</p>
<p>
Ce texte est proposé non comme un énoncé définitif, mais comme une hypothèse
à éprouver : un chantier ouvert dont la viabilité dépendra aussi de sa
capacité à être interrogé, corrigé et repris.
</p>
</section>
<section class="landing-section">
<div class="landing-section__head">
<p class="landing-kicker">Index de lœuvre</p>
<h2>Parcours de lecture</h2>
</div>
<div class="landing-grid">
{entries.map((e) => (
<a class="landing-card" href={`/archicrat-ia/${String(e.id).replace(/\.(md|mdx)$/i, "")}/`}>
<strong>{e.data.title}</strong>
<small>Lire ce texte →</small>
</a>
))}
</div>
</section>
</section>
</SiteLayout>

View File

@@ -7,15 +7,68 @@ entries.sort((a, b) => (a.data.order ?? 9999) - (b.data.order ?? 9999));
---
<SiteLayout title="Cas pratique — Gouvernance des systèmes IA">
<h1>Cas pratique — Gouvernance des systèmes IA</h1>
<section class="landing landing-home">
<!-- HERO -->
<header class="landing-hero">
<p class="landing-kicker">Cas pratique</p>
<ul>
{entries.map((e) => (
<li>
<a href={`/cas-ia/${String(e.id).replace(/\.(md|mdx)$/i, "")}/`}>
{e.data.title}
</a>
</li>
))}
</ul>
<h1>Gouvernance des systèmes IA</h1>
<p class="landing-lead">
Une mise à lépreuve du paradigme archicratique à travers les systèmes
contemporains dintelligence artificielle.
</p>
</header>
<!-- NOTE AU LECTEUR -->
<section class="edition-note" aria-labelledby="note-cas-title">
<p class="landing-kicker">Note au lecteur</p>
<h2 id="note-cas-title">Statut du cas pratique</h2>
<p>
Ce cas pratique ne constitue pas une application stabilisée du paradigme
archicratique, mais un terrain dexpérimentation destiné à en éprouver
la portée, les limites et les conditions dopérabilité.
</p>
<p>
Les systèmes dintelligence artificielle offrent un environnement
particulièrement exigeant : complexité technique, opacité croissante,
enchevêtrement dacteurs, transformations rapides des cadres de régulation.
</p>
<p>
Lanalyse proposée doit donc être lue comme une série dépreuves
— détectabilité, topologie, archéogenèse, morphologie, historicité,
co-viabilité — visant à faire apparaître les architectures effectives
qui organisent ces systèmes.
</p>
<p>
Ce travail na pas vocation à clore lanalyse, mais à ouvrir un espace
dinvestigation : il sagit moins de fournir des réponses définitives
que de rendre visibles les tensions et les structures qui appellent
régulation.
</p>
</section>
<!-- INDEX -->
<section class="landing-section">
<div class="landing-section__head">
<p class="landing-kicker">Index du cas</p>
<h2>Parcours danalyse</h2>
</div>
<div class="landing-grid">
{entries.map((e) => (
<a class="landing-card" href={`/cas-ia/${String(e.id).replace(/\.(md|mdx)$/i, "")}/`}>
<strong>{e.data.title}</strong>
<small>Lire ce chapitre →</small>
</a>
))}
</div>
</section>
</section>
</SiteLayout>

View File

@@ -4,7 +4,7 @@ import DocumentDePresentation from "../../content/commencer/document-de-presenta
---
<EditionLayout
title="Document de présentation"
title="Entrevoir lArchicratie"
editionLabel="Document dentrée"
editionKey="commencer"
statusLabel="Présentation"
@@ -12,7 +12,20 @@ import DocumentDePresentation from "../../content/commencer/document-de-presenta
level={1}
version="0.1.0"
>
<h1>Document de présentation</h1>
<h1 class="commencer-title">Entrevoir lArchicratie...</h1>
<DocumentDePresentation />
<nav class="landing-actions presentation-next" aria-label="Suite de lecture">
<a class="landing-btn landing-btn--primary" href="/archicrat-ia/">
Plonger dans lessai-thèse — ArchiCraT-IA
</a>
<a class="landing-btn" href="/glossaire/">
Explorer son glossaire
</a>
<a class="landing-btn" href="/cas-ia/">
Entrer dans le cas pratique — Gouvernance IA
</a>
</nav>
</EditionLayout>

View File

@@ -3,55 +3,70 @@ import SiteLayout from "../layouts/SiteLayout.astro";
---
<SiteLayout title="Archicratie — Édition web">
<section class="landing landing-home" aria-labelledby="home-title">
<header class="landing-hero">
<p class="landing-kicker">Édition web expérimentale</p>
<h1>Archicratie</h1>
<h1 id="home-title">Archicratie</h1>
<p>
Ce site présente le noyau conceptuel du paradigme archicratique :
une théorie des architectures de régulation qui rendent possible la co-viabilité
des sociétés complexes.
</p>
<p class="landing-lead">
Une recherche indépendante sur les architectures de régulation qui rendent
possible la co-viabilité des sociétés complexes.
</p>
<hr />
<div class="landing-actions" aria-label="Entrées principales">
<a class="landing-btn landing-btn--primary" href="/commencer/">
Entrevoir larchicratie
</a>
<a class="landing-btn" href="/glossaire/">
Explorer son glossaire
</a>
</div>
</header>
<h2>Document dentrée</h2>
<section class="landing-section" aria-labelledby="home-paths-title">
<div class="landing-section__head">
<p class="landing-kicker">Parcours</p>
<h2 id="home-paths-title">Accès principaux</h2>
</div>
<p>
Le document suivant propose une première entrée dans le paradigme archicratique.
</p>
<div class="landing-grid">
<a class="landing-card" href="/archicrat-ia/">
<strong>Essai-thèse — ArchiCraT-IA</strong>
<span>
Le corpus principal : fondements, histoire, philosophie du pouvoir,
tensions et régulations archicratiques.
</span>
<small>Lire ArchiCraT-IA →</small>
</a>
<p>
👉 <a href="/commencer/">Lire le document de présentation</a>
</p>
<a class="landing-card" href="/cas-ia/">
<strong>Cas pratique — Gouvernance IA</strong>
<span>
Une mise à lépreuve contemporaine du paradigme à travers la
gouvernance des systèmes dintelligence artificielle.
</span>
<small>Explorer le cas pratique →</small>
</a>
<hr />
<h2>Accès principaux</h2>
<ul>
<li>
<a href="/archicrat-ia/">
Essai-thèse — ArchiCraT-IA
</a>
</li>
<li>
<a href="/cas-ia/">
Cas pratique — Gouvernance des systèmes IA
</a>
</li>
<li>
<a href="/glossaire/">
Glossaire archicratique
</a>
</li>
<li>
<a href="/recherche/">
Recherche dans les textes
</a>
</li>
</ul>
<a class="landing-card" href="/glossaire/">
<strong>Glossaire</strong>
<span>
La cartographie conceptuelle du système : notions, scènes,
dynamiques, tensions et méta-régimes.
</span>
<small>Entrer dans le glossaire →</small>
</a>
<a class="landing-card" href="/recherche/">
<strong>Recherche</strong>
<span>
Rechercher un terme, une notion ou un passage dans les textes de
lédition web.
</span>
<small>Lancer une recherche →</small>
</a>
</div>
</section>
</section>
</SiteLayout>

View File

@@ -1,41 +1,51 @@
---
import SiteLayout from "../../layouts/SiteLayout.astro";
---
<SiteLayout title="Recherche">
<h1>Recherche</h1>
<p>Recherche plein texte (statique) dans les pages “édition-livre”.</p>
<section class="search-page" aria-labelledby="search-title">
<header class="landing-hero search-hero">
<p class="landing-kicker">Exploration transversale</p>
<h1 id="search-title">Recherche</h1>
<p class="landing-lead">
Rechercher un terme, une notion ou un passage dans les textes de lédition web.
</p>
</header>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:12px 0 18px;">
<label>
<span style="display:block;font-size:12px;opacity:0.85;">Terme</span>
<input id="q" type="search" placeholder="Ex: archicratie, régulation, inertie…" style="padding:8px 10px;min-width:280px;">
</label>
<section class="landing-section search-panel" aria-label="Formulaire de recherche">
<div class="search-controls">
<label class="search-field search-field--main">
<span>Terme</span>
<input id="q" type="search" autocomplete="off" placeholder="Ex. archicratie, régulation, inertie…" />
</label>
<label>
<span style="display:block;font-size:12px;opacity:0.85;">Édition</span>
<select id="edition" style="padding:8px 10px;">
<option value="">Toutes</option>
<option value="archicratie">Archicratie</option>
<option value="traite">Traité</option>
<option value="ia">Cas IA</option>
<option value="glossaire">Glossaire</option>
<option value="atlas">Atlas</option>
</select>
</label>
<label class="search-field">
<span>Édition</span>
<select id="edition">
<option value="">Toutes</option>
<option value="archicrat-ia">Essai-thèse</option>
<option value="cas-ia">Cas IA</option>
<option value="glossaire">Glossaire</option>
<option value="commencer">Commencer</option>
</select>
</label>
<label>
<span style="display:block;font-size:12px;opacity:0.85;">Niveau</span>
<select id="level" style="padding:8px 10px;">
<option value="">Tous</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</label>
</div>
<label class="search-field">
<span>Niveau</span>
<select id="level">
<option value="">Tous</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</label>
</div>
<div id="status" style="margin:10px 0;opacity:0.9;"></div>
<ol id="results" style="padding-left:18px;"></ol>
<p id="status" class="search-status" aria-live="polite"></p>
<ol id="results" class="search-results"></ol>
</section>
</section>
<script is:inline>
(() => {
@@ -52,10 +62,10 @@ import SiteLayout from "../../layouts/SiteLayout.astro";
pfPromise = (async () => {
try {
const pagefind = await import("/pagefind/pagefind.js");
// init facultatif, mais accélère si on clique dans linput
await pagefind.init?.();
return pagefind;
} catch {
} catch (e) {
console.error("[Recherche] Pagefind init failed:", e);
return null;
}
})();
@@ -69,25 +79,26 @@ import SiteLayout from "../../layouts/SiteLayout.astro";
return Object.keys(filters).length ? filters : null;
}
function clearResults() {
results.innerHTML = "";
}
function setStatus(msg) {
status.textContent = msg;
}
function clearResults() {
results.innerHTML = "";
}
async function runSearch() {
const term = q.value.trim();
if (!term) {
setStatus("Tape un terme pour chercher.");
setStatus("Tape un terme pour lancer une recherche.");
clearResults();
return;
}
const pagefind = await getPagefind();
if (!pagefind) {
setStatus("Index de recherche indisponible. Fais `npm run build` puis `npm run preview`.");
setStatus("Index de recherche indisponible. Lance `npm run build` puis `npm run preview`.");
clearResults();
return;
}
@@ -96,49 +107,56 @@ import SiteLayout from "../../layouts/SiteLayout.astro";
const filters = currentFilters();
if (filters) opts.filters = filters;
setStatus("Recherche…");
setStatus("Recherche en cours…");
const search = await pagefind.debouncedSearch(term, opts, 250);
if (search === null) return;
const items = await Promise.all(search.results.slice(0, 20).map(r => r.data()));
setStatus(`${items.length} résultat(s) (sur ${search.results.length}).`);
const items = await Promise.all(search.results.slice(0, 24).map((r) => r.data()));
clearResults();
if (!items.length) {
setStatus("Aucun résultat pour cette recherche.");
return;
}
setStatus(`${items.length} résultat(s) affiché(s) sur ${search.results.length}.`);
results.innerHTML = "";
for (const item of items) {
const li = document.createElement("li");
li.style.marginBottom = "12px";
li.className = "search-result";
const a = document.createElement("a");
a.className = "search-result__title";
a.href = item.url;
a.textContent = item.meta?.title || item.url;
const meta = document.createElement("div");
meta.style.fontSize = "12px";
meta.style.opacity = "0.85";
const edv = item.meta?.edition ? `édition: ${item.meta.edition}` : "";
const lv = item.meta?.level ? `niveau: ${item.meta.level}` : "";
const v = item.meta?.version ? `v${item.meta.version}` : "";
meta.textContent = [edv, lv, v].filter(Boolean).join(" · ");
meta.className = "search-result__meta";
const ex = document.createElement("div");
ex.style.marginTop = "6px";
ex.innerHTML = item.excerpt || "";
const edition = item.meta?.edition ? `édition : ${item.meta.edition}` : "";
const level = item.meta?.level ? `niveau : ${item.meta.level}` : "";
const version = item.meta?.version ? `v${item.meta.version}` : "";
meta.textContent = [edition, level, version].filter(Boolean).join(" · ");
const excerpt = document.createElement("div");
excerpt.className = "search-result__excerpt";
excerpt.innerHTML = item.excerpt || "";
li.appendChild(a);
if (meta.textContent) li.appendChild(meta);
li.appendChild(ex);
li.appendChild(excerpt);
results.appendChild(li);
}
}
// Précharge quand focus => UX meilleure
q.addEventListener("focus", () => { getPagefind(); });
q.addEventListener("input", runSearch);
ed.addEventListener("change", runSearch);
lv.addEventListener("change", runSearch);
setStatus("Tape un terme pour chercher.");
setStatus("Tape un terme pour lancer une recherche.");
})();
</script>
</SiteLayout>
</SiteLayout>

View File

@@ -65,20 +65,94 @@ a:hover { text-decoration: underline; }
header{
position: sticky;
top: 0;
z-index: 50;
z-index: 1000;
isolation: isolate;
background: rgba(255,255,255,.92);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
background: rgba(0,0,0,.82);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-bottom: 1px solid rgba(127,127,127,0.35);
padding: 12px 16px;
border-bottom: 1px solid rgba(127,127,127,0.28);
padding: 10px 16px;
}
@media (prefers-color-scheme: light){
header{
background: rgba(255,255,255,.90);
}
}
@media (prefers-color-scheme: dark){
header{ background: rgba(0,0,0,.72); }
}
.site-nav { font-size: 14px; opacity: 0.9; }
.site-nav{
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
font-size: 13px;
line-height: 1.2;
}
.site-nav span[aria-hidden="true"]{
display: none;
}
.site-nav a{
display: inline-flex;
align-items: center;
min-height: 30px;
padding: 5px 10px;
border: 1px solid transparent;
border-radius: 999px;
color: #00d9ff;
font-weight: 700;
text-decoration: none;
opacity: .94;
transition:
transform 120ms var(--ease-out),
background 120ms var(--ease-out),
border-color 120ms var(--ease-out),
opacity 120ms var(--ease-out);
}
.site-nav a:hover{
transform: translateY(-1px);
background: rgba(0,217,255,.08);
border-color: rgba(0,217,255,.22);
opacity: 1;
text-decoration: none;
}
.site-nav a:active{
transform: translateY(0);
}
@media (max-width: 760px){
.site-nav{
gap: 5px;
font-size: 12px;
}
.site-nav a{
min-height: 28px;
padding: 4px 8px;
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.site-nav{
gap: 4px;
font-size: 11px;
}
.site-nav a{
min-height: 24px;
padding: 3px 7px;
}
}
main { padding: 0; }
.reading {
@@ -90,12 +164,10 @@ main { padding: 0; }
letter-spacing: 0.005em;
}
.reading h1 {
line-height: 1.2;
margin: 0 0 10px;
/* polish */
letter-spacing: -0.01em;
.reading > h1{
font-size: clamp(1.8rem, 3.5vw, 2.6rem);
line-height: 1.15;
letter-spacing: -0.02em;
}
.reading p { margin: 0 0 12px; }
@@ -626,4 +698,320 @@ html{ scroll-behavior: smooth; }
.glossary-alpha-group h3{
margin-bottom: 8px;
}
/* ==========================
Landing pages
========================== */
.reading:has(> .landing){
max-width: min(1180px, calc(100vw - 32px));
padding: 0;
}
.landing{
display: grid;
gap: clamp(18px, 3vw, 30px);
width: 100%;
padding: 14px 0 10px;
}
.landing-hero,
.landing-section,
.edition-note{
position: relative;
z-index: 0;
overflow: hidden;
border: 1px solid rgba(127,127,127,0.22);
border-radius: 24px;
background:
radial-gradient(circle at 12% 0%, rgba(0,217,255,0.12), transparent 36%),
rgba(127,127,127,0.045);
}
.landing-hero{
padding: clamp(24px, 4vw, 46px);
}
.landing-kicker{
margin: 0 0 8px;
color: #00d9ff;
font-size: .78rem;
line-height: 1.2;
font-weight: 850;
letter-spacing: .08em;
text-transform: uppercase;
}
.landing-hero h1{
margin: 0;
font-size: clamp(2.45rem, 7vw, 5.4rem);
line-height: .95;
letter-spacing: -.055em;
text-shadow: 0 0 34px rgba(0,217,255,.10);
}
.landing-lead{
max-width: 66ch;
margin: 18px 0 0;
font-size: clamp(1.02rem, 2vw, 1.28rem);
line-height: 1.55;
opacity: .94;
text-wrap: pretty;
}
.landing-actions{
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 24px;
}
.landing-btn{
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 38px;
padding: 7px 14px;
border: 1px solid rgba(127,127,127,0.38);
border-radius: 999px;
background: rgba(127,127,127,0.06);
font-weight: 850;
text-decoration: none;
transition:
transform 120ms var(--ease-out),
background 120ms var(--ease-out),
border-color 120ms var(--ease-out);
}
.landing-btn:hover{
transform: translateY(-1px);
background: rgba(127,127,127,0.11);
text-decoration: none;
}
.landing-btn--primary{
border-color: rgba(0,217,255,0.42);
background: rgba(0,217,255,0.10);
color: #00d9ff;
}
.landing-section,
.edition-note{
padding: clamp(18px, 3vw, 28px);
}
.landing-section__head,
.edition-note .landing-kicker{
margin-bottom: 14px;
}
.landing-section h2,
.edition-note h2{
margin: 0;
font-size: clamp(1.45rem, 3vw, 2.25rem);
line-height: 1.05;
letter-spacing: -.035em;
}
.edition-note p:not(.landing-kicker){
max-width: 78ch;
margin: 14px 0 0;
line-height: 1.62;
opacity: .93;
text-wrap: pretty;
}
.landing-grid{
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.landing-card{
display: grid;
gap: 8px;
min-width: 0;
padding: 16px;
border: 1px solid rgba(127,127,127,0.22);
border-radius: 18px;
background: rgba(127,127,127,0.045);
text-decoration: none;
transition:
transform 120ms var(--ease-out),
background 120ms var(--ease-out),
border-color 120ms var(--ease-out);
}
.landing-card:hover{
transform: translateY(-1px);
background: rgba(127,127,127,0.075);
border-color: rgba(0,217,255,0.24);
text-decoration: none;
}
.landing-card strong{
color: #00d9ff;
font-size: 1.05rem;
line-height: 1.22;
}
.landing-card span{
color: inherit;
line-height: 1.5;
opacity: .92;
}
.landing-card small{
color: #00d9ff;
font-weight: 800;
opacity: .92;
}
.presentation-next{
margin-top: 42px;
padding-top: 24px;
border-top: 1px solid rgba(127,127,127,0.25);
}
body[data-edition-key="commencer"] .commencer-title{
font-size: clamp(2.6rem, 6vw, 4.8rem);
line-height: .98;
letter-spacing: -.055em;
margin: 18px 0 28px;
text-shadow: 0 0 34px rgba(0,217,255,.10);
}
body[data-edition-key="commencer"] .reading h2{
margin-top: 34px;
padding-top: 18px;
border-top: 1px solid rgba(127,127,127,.18);
font-size: clamp(1.35rem, 2.3vw, 1.85rem);
letter-spacing: -.025em;
}
body[data-edition-key="commencer"] .reading h2:first-of-type{
margin-top: 0;
padding-top: 0;
border-top: 0;
}
@media (max-width: 760px){
.reading:has(> .landing){
max-width: none;
width: auto;
margin: 0;
padding: 0 12px;
}
.landing{
gap: 18px;
padding-top: 8px;
}
.landing-hero,
.landing-section,
.edition-note{
border-radius: 18px;
}
.landing-hero,
.landing-section,
.edition-note{
padding: 18px 16px;
}
.landing-hero h1{
font-size: clamp(2.15rem, 13vw, 3.25rem);
}
.landing-lead{
font-size: .98rem;
line-height: 1.42;
}
.landing-grid{
grid-template-columns: 1fr;
}
.landing-card{
padding: 14px;
border-radius: 15px;
}
.edition-note p:not(.landing-kicker){
line-height: 1.52;
}
}
@media (max-width: 460px){
.landing-actions{
display: grid;
}
.landing-btn{
width: 100%;
box-sizing: border-box;
}
}
@media (orientation: landscape) and (max-width: 920px) and (max-height: 520px){
.reading:has(> .landing){
max-width: none;
width: auto;
margin: 0;
padding: 0 10px;
}
.landing{
gap: 14px;
padding-top: 6px;
}
.landing-hero,
.landing-section,
.edition-note{
padding: 14px 16px;
border-radius: 16px;
}
.landing-hero h1{
font-size: clamp(2.2rem, 6vw, 4.6rem);
}
.landing-lead{
margin-top: 12px;
font-size: .94rem;
line-height: 1.38;
}
.landing-actions{
margin-top: 16px;
}
.edition-note p:not(.landing-kicker){
margin-top: 10px;
line-height: 1.45;
}
}
.search-hero h1{
font-size: clamp(1.9rem, 4.5vw, 2.8rem);
letter-spacing: -0.03em;
}
.reading h1{
font-size: clamp(1.8rem, 3.5vw, 2.6rem);
line-height: 1.15;
letter-spacing: -0.02em;
}
@media (max-width: 760px){
.landing-hero h1{
font-size: clamp(2rem, 10vw, 3.2rem);
}
.search-hero h1{
font-size: clamp(1.7rem, 7vw, 2.3rem);
}
}