feat(ui): harmoniser navigation pages d’entrée et recherche
This commit is contained in:
@@ -28,6 +28,7 @@ const tocId = `toc-global-${collection}-${String(basePath).replace(/[^\w-]+/g, "
|
|||||||
|
|
||||||
<nav
|
<nav
|
||||||
class="toc-global"
|
class="toc-global"
|
||||||
|
data-mobile-default="closed"
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
data-toc-global
|
data-toc-global
|
||||||
data-toc-key={`global:${collection}:${basePath}`}
|
data-toc-key={`global:${collection}:${basePath}`}
|
||||||
@@ -35,14 +36,14 @@ const tocId = `toc-global-${collection}-${String(basePath).replace(/[^\w-]+/g, "
|
|||||||
<button
|
<button
|
||||||
class="toc-global__head toc-global__toggle"
|
class="toc-global__head toc-global__toggle"
|
||||||
type="button"
|
type="button"
|
||||||
aria-expanded="true"
|
aria-expanded="false"
|
||||||
aria-controls={tocId}
|
aria-controls={tocId}
|
||||||
>
|
>
|
||||||
<span class="toc-global__title">{label}</span>
|
<span class="toc-global__title">{label}</span>
|
||||||
<span class="toc-global__chevron" aria-hidden="true">▾</span>
|
<span class="toc-global__chevron" aria-hidden="true">▾</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="toc-global__body-clip" id={tocId}>
|
<div class="toc-global__body-clip" id={tocId} hidden>
|
||||||
<div class="toc-global__body">
|
<div class="toc-global__body">
|
||||||
<ol class="toc-global__list">
|
<ol class="toc-global__list">
|
||||||
{entries.map((e) => {
|
{entries.map((e) => {
|
||||||
@@ -291,6 +292,10 @@ const tocId = `toc-global-${collection}-${String(basePath).replace(/[^\w-]+/g, "
|
|||||||
max-height: min(42vh, 360px);
|
max-height: min(42vh, 360px);
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toc-global__body-clip[hidden]{
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark){
|
@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 setOpen = (open, { persist = true } = {}) => {
|
||||||
const isMobile = mq.matches;
|
const isMobile = mq.matches;
|
||||||
nav.classList.toggle("is-collapsed", isMobile && !open);
|
const effectiveOpen = isMobile ? open : true;
|
||||||
toggle.setAttribute("aria-expanded", open ? "true" : "false");
|
|
||||||
if (persist && isMobile) write(open);
|
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 = () => {
|
const initState = () => {
|
||||||
|
|||||||
@@ -7,18 +7,18 @@ const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
|
|||||||
---
|
---
|
||||||
|
|
||||||
{items.length > 0 && (
|
{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
|
<button
|
||||||
class="toc-local__head toc-local__toggle"
|
class="toc-local__head toc-local__toggle"
|
||||||
type="button"
|
type="button"
|
||||||
aria-expanded="true"
|
aria-expanded="false"
|
||||||
aria-controls={tocId}
|
aria-controls={tocId}
|
||||||
>
|
>
|
||||||
<span class="toc-local__title">Dans ce chapitre</span>
|
<span class="toc-local__title">Dans ce chapitre</span>
|
||||||
<span class="toc-local__chevron" aria-hidden="true">▾</span>
|
<span class="toc-local__chevron" aria-hidden="true">▾</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="toc-local__body-clip" id={tocId}>
|
<div class="toc-local__body-clip" id={tocId} hidden>
|
||||||
<div class="toc-local__body">
|
<div class="toc-local__body">
|
||||||
<ol class="toc-local__list">
|
<ol class="toc-local__list">
|
||||||
{items.map((h) => (
|
{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 setOpen = (open, { persist = true, emit = true } = {}) => {
|
||||||
const isMobile = mq.matches;
|
const isMobile = mq.matches;
|
||||||
toc.classList.toggle("is-collapsed", isMobile && !open);
|
const effectiveOpen = isMobile ? open : true;
|
||||||
toggle.setAttribute("aria-expanded", open ? "true" : "false");
|
|
||||||
|
|
||||||
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"));
|
window.dispatchEvent(new CustomEvent("archicratie:tocLocalOpen"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -85,7 +91,7 @@ const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const stored = readState();
|
const stored = readState();
|
||||||
setOpen(stored == null ? true : stored, { persist: false, emit: false });
|
setOpen(stored == null ? false : stored, { persist: false, emit: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
toggle.addEventListener("click", () => {
|
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.a.setAttribute("aria-current", "true");
|
||||||
t.li.classList.add("is-current");
|
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);
|
setOpen(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +223,7 @@ const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
|
|||||||
|
|
||||||
const el = document.getElementById(id);
|
const el = document.getElementById(id);
|
||||||
if (el) openDetailsIfNeeded(el);
|
if (el) openDetailsIfNeeded(el);
|
||||||
setCurrent(id, { autoOpen: true });
|
setCurrent(id, { autoOpen: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
toc.addEventListener("click", (ev) => {
|
toc.addEventListener("click", (ev) => {
|
||||||
@@ -427,5 +434,9 @@ const tocId = `toc-local-${Math.random().toString(36).slice(2, 9)}`;
|
|||||||
margin-top: .42em;
|
margin-top: .42em;
|
||||||
opacity: .55;
|
opacity: .55;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toc-local__body-clip[hidden]{
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
<nav class="site-nav" aria-label="Navigation principale">
|
<nav class="site-nav" aria-label="Navigation principale">
|
||||||
|
<a href="/">Accueil</a>
|
||||||
|
<span aria-hidden="true"> · </span>
|
||||||
|
|
||||||
<a href="/">Accueil</a>
|
<a href="/archicrat-ia/">Essai-thèse — ArchiCraT-IA</a>
|
||||||
<span aria-hidden="true"> · </span>
|
<span aria-hidden="true"> · </span>
|
||||||
|
|
||||||
<a href="/archicrat-ia/">Essai-thèse</a>
|
<a href="/cas-ia/">Cas pratique — Gouvernance IA</a>
|
||||||
<span aria-hidden="true"> · </span>
|
<span aria-hidden="true"> · </span>
|
||||||
|
|
||||||
<a href="/cas-ia/">Cas IA</a>
|
<a href="/glossaire/">Glossaire</a>
|
||||||
<span aria-hidden="true"> · </span>
|
<span aria-hidden="true"> · </span>
|
||||||
|
|
||||||
<a href="/glossaire/">Glossaire</a>
|
|
||||||
<span aria-hidden="true"> · </span>
|
|
||||||
|
|
||||||
<a href="/recherche/">Recherche</a>
|
|
||||||
|
|
||||||
|
<a href="/recherche/">Recherche</a>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -184,7 +184,8 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
|
|||||||
.catch(() => Boolean(__DEV__));
|
.catch(() => Boolean(__DEV__));
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body
|
<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){
|
@media (prefers-color-scheme: dark){
|
||||||
:global(body[data-edition-key="glossaire"][data-sticky-mode="glossary-portal"] #reading-follow .reading-follow__inner){
|
:global(body[data-edition-key="glossaire"][data-sticky-mode="glossary-portal"] #reading-follow .reading-follow__inner){
|
||||||
background: rgba(0,0,0,.6);
|
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;
|
position: fixed;
|
||||||
inset: auto 10px 10px 10px;
|
inset: auto 10px 10px 10px;
|
||||||
z-index: 120;
|
z-index: 120;
|
||||||
@@ -1009,7 +1044,7 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
|
|||||||
transform: translateY(1px);
|
transform: translateY(1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-para-menu{
|
.mobile-para-menu{
|
||||||
touch-action: manipulation;
|
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 docEditionKey = document.body?.dataset?.editionKey || "";
|
||||||
const docStickyMode = String(document.body?.dataset?.stickyMode || "default");
|
const docStickyMode = String(document.body?.dataset?.stickyMode || "default");
|
||||||
const isGlossaryEdition = docEditionKey === "glossaire";
|
const isGlossaryEdition = docEditionKey === "glossaire";
|
||||||
|
const isIntroEdition = docEditionKey === "commencer";
|
||||||
|
|
||||||
const hasLocalGlossaryFollow =
|
const hasLocalGlossaryFollow =
|
||||||
isGlossaryEdition && Boolean(document.getElementById("glossary-hero-follow"));
|
isGlossaryEdition && Boolean(document.getElementById("glossary-hero-follow"));
|
||||||
@@ -1501,45 +1537,45 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateResumeButton() {
|
function updateResumeButton() {
|
||||||
const btn = document.getElementById("resume-btn");
|
const btn = document.getElementById("resume-btn");
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
|
|
||||||
const current = getResumeBookmark();
|
const current = getResumeBookmark();
|
||||||
|
|
||||||
btn.hidden = false;
|
btn.hidden = false;
|
||||||
btn.setAttribute("href", "#");
|
btn.setAttribute("href", "#");
|
||||||
|
|
||||||
if (!current) {
|
if (!current) {
|
||||||
delete btn.dataset.resumeAnchor;
|
delete btn.dataset.resumeAnchor;
|
||||||
delete btn.dataset.resumePath;
|
delete btn.dataset.resumePath;
|
||||||
delete btn.dataset.resumeKind;
|
delete btn.dataset.resumeKind;
|
||||||
btn.setAttribute("aria-disabled", "true");
|
btn.setAttribute("aria-disabled", "true");
|
||||||
btn.classList.add("is-disabled");
|
btn.classList.add("is-disabled");
|
||||||
btn.title = "Aucun marque-page explicite enregistré";
|
btn.title = "Aucun marque-page explicite enregistré";
|
||||||
return;
|
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;
|
window.__archiUpdateResumeButton = updateResumeButton;
|
||||||
|
|
||||||
if (window.location.search.includes("body=")) {
|
if (window.location.search.includes("body=")) {
|
||||||
@@ -1858,7 +1894,7 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
|
|||||||
}
|
}
|
||||||
|
|
||||||
safe("para-tools", () => {
|
safe("para-tools", () => {
|
||||||
if (isGlossaryEdition) return;
|
if (isGlossaryEdition || isIntroEdition) return;
|
||||||
|
|
||||||
for (const p of parasAll) {
|
for (const p of parasAll) {
|
||||||
if (p.querySelector(".para-tools")) continue;
|
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", () => {
|
safe("mobile-para-tools", () => {
|
||||||
if (isGlossaryEdition) return;
|
if (isGlossaryEdition || isIntroEdition) return;
|
||||||
if (!reading) return;
|
if (!reading) return;
|
||||||
|
|
||||||
const isMobileLike = () =>
|
const isMobileLike = () =>
|
||||||
@@ -1985,8 +2021,12 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
|
|||||||
let menuOpen = false;
|
let menuOpen = false;
|
||||||
let touchLongPressActive = false;
|
let touchLongPressActive = false;
|
||||||
|
|
||||||
const LONG_PRESS_DELAY = 460;
|
const LONG_PRESS_DELAY = 520;
|
||||||
const LONG_PRESS_MOVE_TOLERANCE = 18;
|
const isTabletLike = () =>
|
||||||
|
window.matchMedia("(pointer: coarse)").matches &&
|
||||||
|
Math.min(window.innerWidth, window.innerHeight) >= 700;
|
||||||
|
|
||||||
|
const getMoveTolerance = () => isTabletLike() ? 42 : 22;
|
||||||
|
|
||||||
function isInteractiveTarget(node) {
|
function isInteractiveTarget(node) {
|
||||||
const el = node?.closest?.(
|
const el = node?.closest?.(
|
||||||
@@ -2029,7 +2069,12 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
|
|||||||
function movedTooFar(x, y) {
|
function movedTooFar(x, y) {
|
||||||
const dx = Math.abs(Number(x || 0) - pressStartX);
|
const dx = Math.abs(Number(x || 0) - pressStartX);
|
||||||
const dy = Math.abs(Number(y || 0) - pressStartY);
|
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() {
|
function closeMenu() {
|
||||||
@@ -2118,13 +2163,10 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePressEnd() {
|
|
||||||
cancelLongPress();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePressEnd() {
|
function handlePressEnd() {
|
||||||
clearPressTimer();
|
clearPressTimer();
|
||||||
pressPointerId = null;
|
pressPointerId = null;
|
||||||
|
touchLongPressActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
reading.addEventListener("pointerdown", handlePressStart, { passive: true });
|
reading.addEventListener("pointerdown", handlePressStart, { passive: true });
|
||||||
@@ -2162,15 +2204,17 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
|
|||||||
cancelLongPress();
|
cancelLongPress();
|
||||||
}, { passive: true });
|
}, { passive: true });
|
||||||
|
|
||||||
window.addEventListener("scroll", () => {
|
function handleScrollDuringMobileMenu() {
|
||||||
clearPressTimer();
|
// Tant que le timer long-press est en cours, ne pas l'annuler brutalement
|
||||||
if (menuOpen) closeMenu();
|
// sur tablette : iPadOS peut produire un micro-scroll fantôme.
|
||||||
}, { passive: true });
|
if (pressTimer && isTabletLike()) return;
|
||||||
|
|
||||||
document.addEventListener("scroll", () => {
|
|
||||||
clearPressTimer();
|
clearPressTimer();
|
||||||
if (menuOpen) closeMenu();
|
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) => {
|
document.addEventListener("click", (ev) => {
|
||||||
const p = ev.target?.closest?.('.reading p[id^="p-"]');
|
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);
|
nav.classList.toggle("is-collapsed", !open);
|
||||||
toggle.setAttribute("aria-expanded", open ? "true" : "false");
|
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
|
const key = nav.dataset.tocKey
|
||||||
? `archicratie:${nav.dataset.tocKey || ""}`
|
? `archicratie:${nav.dataset.tocKey || ""}`
|
||||||
: nav.classList.contains("toc-local")
|
: nav.classList.contains("toc-local")
|
||||||
@@ -2580,9 +2632,16 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
|
|||||||
}
|
}
|
||||||
|
|
||||||
function syncAutoCollapse() {
|
function syncAutoCollapse() {
|
||||||
const shouldOpen = nearTopZone();
|
// Sur mobile/tablette, les TOC restent fermées par défaut.
|
||||||
|
// Elles ne s’ouvrent 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 qu’on quitte le haut.
|
// Desktop : comportement historique conservé.
|
||||||
|
const shouldOpen = nearTopZone();
|
||||||
setTocOpen(tocGlobal, shouldOpen, false);
|
setTocOpen(tocGlobal, shouldOpen, false);
|
||||||
setTocOpen(tocLocal, shouldOpen, false);
|
setTocOpen(tocLocal, shouldOpen, false);
|
||||||
}
|
}
|
||||||
@@ -2607,45 +2666,12 @@ const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ??
|
|||||||
schedule();
|
schedule();
|
||||||
});
|
});
|
||||||
|
|
||||||
safe("mobile-toc-collapse", () => {
|
/*
|
||||||
const isMobile = () => window.innerWidth <= 760;
|
* TOC accordions are owned by EditionToc.astro / LocalToc.astro.
|
||||||
|
* Keep only the top-zone auto-collapse below; the previous legacy
|
||||||
const bindToggle = (rootSel, headSel) => {
|
* mobile-toc-collapse binder toggled an unused .is-open state and
|
||||||
document.querySelectorAll(rootSel).forEach((box) => {
|
* added duplicate click listeners on the same headers.
|
||||||
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 });
|
|
||||||
});
|
|
||||||
|
|
||||||
safe("reading-follow", () => {
|
safe("reading-follow", () => {
|
||||||
if (!reading || !followEl) return;
|
if (!reading || !followEl) return;
|
||||||
|
|||||||
@@ -7,15 +7,62 @@ entries.sort((a, b) => (a.data.order ?? 9999) - (b.data.order ?? 9999));
|
|||||||
---
|
---
|
||||||
|
|
||||||
<SiteLayout title="Essai-thèse — ArchiCraT-IA">
|
<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>
|
<section class="edition-note" aria-labelledby="note-lecteur-title">
|
||||||
{entries.map((e) => (
|
<p class="landing-kicker">Note au lecteur</p>
|
||||||
<li>
|
<h2 id="note-lecteur-title">Statut du travail</h2>
|
||||||
<a href={`/archicrat-ia/${String(e.id).replace(/\.(md|mdx)$/i, "")}/`}>
|
|
||||||
{e.data.title}
|
<p>
|
||||||
</a>
|
Le texte que vous vous apprêtez à lire ne constitue pas une théorie close
|
||||||
</li>
|
ni un système achevé. Il s’agit d’un travail de longue élaboration, ayant
|
||||||
))}
|
progressivement pris la forme d’une hypothèse structurée : celle d’une
|
||||||
</ul>
|
méta-grammaire des régulations collectives, désignée ici sous le nom
|
||||||
|
d’archicratie.
|
||||||
|
</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,
|
||||||
|
l’opacification 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,
|
||||||
|
à l’approfondissement 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>
|
</SiteLayout>
|
||||||
@@ -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">
|
<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>
|
<h1>Gouvernance des systèmes IA</h1>
|
||||||
{entries.map((e) => (
|
|
||||||
<li>
|
<p class="landing-lead">
|
||||||
<a href={`/cas-ia/${String(e.id).replace(/\.(md|mdx)$/i, "")}/`}>
|
Une mise à l’épreuve du paradigme archicratique à travers les systèmes
|
||||||
{e.data.title}
|
contemporains d’intelligence artificielle.
|
||||||
</a>
|
</p>
|
||||||
</li>
|
</header>
|
||||||
))}
|
|
||||||
</ul>
|
<!-- 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 d’expérimentation destiné à en éprouver
|
||||||
|
la portée, les limites et les conditions d’opérabilité.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Les systèmes d’intelligence artificielle offrent un environnement
|
||||||
|
particulièrement exigeant : complexité technique, opacité croissante,
|
||||||
|
enchevêtrement d’acteurs, transformations rapides des cadres de régulation.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
L’analyse 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 n’a pas vocation à clore l’analyse, mais à ouvrir un espace
|
||||||
|
d’investigation : il s’agit 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 d’analyse</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>
|
</SiteLayout>
|
||||||
@@ -4,7 +4,7 @@ import DocumentDePresentation from "../../content/commencer/document-de-presenta
|
|||||||
---
|
---
|
||||||
|
|
||||||
<EditionLayout
|
<EditionLayout
|
||||||
title="Document de présentation"
|
title="Entrevoir l’Archicratie"
|
||||||
editionLabel="Document d’entrée"
|
editionLabel="Document d’entrée"
|
||||||
editionKey="commencer"
|
editionKey="commencer"
|
||||||
statusLabel="Présentation"
|
statusLabel="Présentation"
|
||||||
@@ -12,7 +12,20 @@ import DocumentDePresentation from "../../content/commencer/document-de-presenta
|
|||||||
level={1}
|
level={1}
|
||||||
version="0.1.0"
|
version="0.1.0"
|
||||||
>
|
>
|
||||||
<h1>Document de présentation</h1>
|
<h1 class="commencer-title">Entrevoir l’Archicratie...</h1>
|
||||||
|
|
||||||
<DocumentDePresentation />
|
<DocumentDePresentation />
|
||||||
|
<nav class="landing-actions presentation-next" aria-label="Suite de lecture">
|
||||||
|
<a class="landing-btn landing-btn--primary" href="/archicrat-ia/">
|
||||||
|
Plonger dans l’essai-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>
|
</EditionLayout>
|
||||||
@@ -3,55 +3,70 @@ import SiteLayout from "../layouts/SiteLayout.astro";
|
|||||||
---
|
---
|
||||||
|
|
||||||
<SiteLayout title="Archicratie — Édition web">
|
<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>
|
<p class="landing-lead">
|
||||||
Ce site présente le noyau conceptuel du paradigme archicratique :
|
Une recherche indépendante sur les architectures de régulation qui rendent
|
||||||
une théorie des architectures de régulation qui rendent possible la co-viabilité
|
possible la co-viabilité des sociétés complexes.
|
||||||
des sociétés complexes.
|
</p>
|
||||||
</p>
|
|
||||||
|
|
||||||
<hr />
|
<div class="landing-actions" aria-label="Entrées principales">
|
||||||
|
<a class="landing-btn landing-btn--primary" href="/commencer/">
|
||||||
|
Entrevoir l’archicratie
|
||||||
|
</a>
|
||||||
|
<a class="landing-btn" href="/glossaire/">
|
||||||
|
Explorer son glossaire
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
<h2>Document d’entré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>
|
<div class="landing-grid">
|
||||||
Le document suivant propose une première entrée dans le paradigme archicratique.
|
<a class="landing-card" href="/archicrat-ia/">
|
||||||
</p>
|
<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 class="landing-card" href="/cas-ia/">
|
||||||
👉 <a href="/commencer/">Lire le document de présentation</a>
|
<strong>Cas pratique — Gouvernance IA</strong>
|
||||||
</p>
|
<span>
|
||||||
|
Une mise à l’épreuve contemporaine du paradigme à travers la
|
||||||
|
gouvernance des systèmes d’intelligence artificielle.
|
||||||
|
</span>
|
||||||
|
<small>Explorer le cas pratique →</small>
|
||||||
|
</a>
|
||||||
|
|
||||||
<hr />
|
<a class="landing-card" href="/glossaire/">
|
||||||
|
<strong>Glossaire</strong>
|
||||||
<h2>Accès principaux</h2>
|
<span>
|
||||||
|
La cartographie conceptuelle du système : notions, scènes,
|
||||||
<ul>
|
dynamiques, tensions et méta-régimes.
|
||||||
<li>
|
</span>
|
||||||
<a href="/archicrat-ia/">
|
<small>Entrer dans le glossaire →</small>
|
||||||
Essai-thèse — ArchiCraT-IA
|
</a>
|
||||||
</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="/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>
|
</SiteLayout>
|
||||||
@@ -1,41 +1,51 @@
|
|||||||
---
|
---
|
||||||
import SiteLayout from "../../layouts/SiteLayout.astro";
|
import SiteLayout from "../../layouts/SiteLayout.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<SiteLayout title="Recherche">
|
<SiteLayout title="Recherche">
|
||||||
<h1>Recherche</h1>
|
<section class="search-page" aria-labelledby="search-title">
|
||||||
<p>Recherche plein texte (statique) dans les pages “édition-livre”.</p>
|
<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;">
|
<section class="landing-section search-panel" aria-label="Formulaire de recherche">
|
||||||
<label>
|
<div class="search-controls">
|
||||||
<span style="display:block;font-size:12px;opacity:0.85;">Terme</span>
|
<label class="search-field search-field--main">
|
||||||
<input id="q" type="search" placeholder="Ex: archicratie, régulation, inertie…" style="padding:8px 10px;min-width:280px;">
|
<span>Terme</span>
|
||||||
</label>
|
<input id="q" type="search" autocomplete="off" placeholder="Ex. archicratie, régulation, inertie…" />
|
||||||
|
</label>
|
||||||
|
|
||||||
<label>
|
<label class="search-field">
|
||||||
<span style="display:block;font-size:12px;opacity:0.85;">Édition</span>
|
<span>Édition</span>
|
||||||
<select id="edition" style="padding:8px 10px;">
|
<select id="edition">
|
||||||
<option value="">Toutes</option>
|
<option value="">Toutes</option>
|
||||||
<option value="archicratie">Archicratie</option>
|
<option value="archicrat-ia">Essai-thèse</option>
|
||||||
<option value="traite">Traité</option>
|
<option value="cas-ia">Cas IA</option>
|
||||||
<option value="ia">Cas IA</option>
|
<option value="glossaire">Glossaire</option>
|
||||||
<option value="glossaire">Glossaire</option>
|
<option value="commencer">Commencer</option>
|
||||||
<option value="atlas">Atlas</option>
|
</select>
|
||||||
</select>
|
</label>
|
||||||
</label>
|
|
||||||
|
|
||||||
<label>
|
<label class="search-field">
|
||||||
<span style="display:block;font-size:12px;opacity:0.85;">Niveau</span>
|
<span>Niveau</span>
|
||||||
<select id="level" style="padding:8px 10px;">
|
<select id="level">
|
||||||
<option value="">Tous</option>
|
<option value="">Tous</option>
|
||||||
<option value="1">1</option>
|
<option value="1">1</option>
|
||||||
<option value="2">2</option>
|
<option value="2">2</option>
|
||||||
<option value="3">3</option>
|
<option value="3">3</option>
|
||||||
</select>
|
<option value="4">4</option>
|
||||||
</label>
|
</select>
|
||||||
</div>
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="status" style="margin:10px 0;opacity:0.9;"></div>
|
<p id="status" class="search-status" aria-live="polite"></p>
|
||||||
<ol id="results" style="padding-left:18px;"></ol>
|
<ol id="results" class="search-results"></ol>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
||||||
<script is:inline>
|
<script is:inline>
|
||||||
(() => {
|
(() => {
|
||||||
@@ -52,10 +62,10 @@ import SiteLayout from "../../layouts/SiteLayout.astro";
|
|||||||
pfPromise = (async () => {
|
pfPromise = (async () => {
|
||||||
try {
|
try {
|
||||||
const pagefind = await import("/pagefind/pagefind.js");
|
const pagefind = await import("/pagefind/pagefind.js");
|
||||||
// init facultatif, mais accélère si on clique dans l’input
|
|
||||||
await pagefind.init?.();
|
await pagefind.init?.();
|
||||||
return pagefind;
|
return pagefind;
|
||||||
} catch {
|
} catch (e) {
|
||||||
|
console.error("[Recherche] Pagefind init failed:", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
@@ -69,25 +79,26 @@ import SiteLayout from "../../layouts/SiteLayout.astro";
|
|||||||
return Object.keys(filters).length ? filters : null;
|
return Object.keys(filters).length ? filters : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearResults() {
|
|
||||||
results.innerHTML = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function setStatus(msg) {
|
function setStatus(msg) {
|
||||||
status.textContent = msg;
|
status.textContent = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearResults() {
|
||||||
|
results.innerHTML = "";
|
||||||
|
}
|
||||||
|
|
||||||
async function runSearch() {
|
async function runSearch() {
|
||||||
const term = q.value.trim();
|
const term = q.value.trim();
|
||||||
|
|
||||||
if (!term) {
|
if (!term) {
|
||||||
setStatus("Tape un terme pour chercher.");
|
setStatus("Tape un terme pour lancer une recherche.");
|
||||||
clearResults();
|
clearResults();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pagefind = await getPagefind();
|
const pagefind = await getPagefind();
|
||||||
if (!pagefind) {
|
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();
|
clearResults();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -96,49 +107,56 @@ import SiteLayout from "../../layouts/SiteLayout.astro";
|
|||||||
const filters = currentFilters();
|
const filters = currentFilters();
|
||||||
if (filters) opts.filters = filters;
|
if (filters) opts.filters = filters;
|
||||||
|
|
||||||
setStatus("Recherche…");
|
setStatus("Recherche en cours…");
|
||||||
|
|
||||||
const search = await pagefind.debouncedSearch(term, opts, 250);
|
const search = await pagefind.debouncedSearch(term, opts, 250);
|
||||||
if (search === null) return;
|
if (search === null) return;
|
||||||
|
|
||||||
const items = await Promise.all(search.results.slice(0, 20).map(r => r.data()));
|
const items = await Promise.all(search.results.slice(0, 24).map((r) => r.data()));
|
||||||
setStatus(`${items.length} résultat(s) (sur ${search.results.length}).`);
|
|
||||||
|
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) {
|
for (const item of items) {
|
||||||
const li = document.createElement("li");
|
const li = document.createElement("li");
|
||||||
li.style.marginBottom = "12px";
|
li.className = "search-result";
|
||||||
|
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
|
a.className = "search-result__title";
|
||||||
a.href = item.url;
|
a.href = item.url;
|
||||||
a.textContent = item.meta?.title || item.url;
|
a.textContent = item.meta?.title || item.url;
|
||||||
|
|
||||||
const meta = document.createElement("div");
|
const meta = document.createElement("div");
|
||||||
meta.style.fontSize = "12px";
|
meta.className = "search-result__meta";
|
||||||
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(" · ");
|
|
||||||
|
|
||||||
const ex = document.createElement("div");
|
const edition = item.meta?.edition ? `édition : ${item.meta.edition}` : "";
|
||||||
ex.style.marginTop = "6px";
|
const level = item.meta?.level ? `niveau : ${item.meta.level}` : "";
|
||||||
ex.innerHTML = item.excerpt || "";
|
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);
|
li.appendChild(a);
|
||||||
if (meta.textContent) li.appendChild(meta);
|
if (meta.textContent) li.appendChild(meta);
|
||||||
li.appendChild(ex);
|
li.appendChild(excerpt);
|
||||||
results.appendChild(li);
|
results.appendChild(li);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Précharge quand focus => UX meilleure
|
|
||||||
q.addEventListener("focus", () => { getPagefind(); });
|
q.addEventListener("focus", () => { getPagefind(); });
|
||||||
|
|
||||||
q.addEventListener("input", runSearch);
|
q.addEventListener("input", runSearch);
|
||||||
ed.addEventListener("change", runSearch);
|
ed.addEventListener("change", runSearch);
|
||||||
lv.addEventListener("change", runSearch);
|
lv.addEventListener("change", runSearch);
|
||||||
|
|
||||||
setStatus("Tape un terme pour chercher.");
|
setStatus("Tape un terme pour lancer une recherche.");
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</SiteLayout>
|
</SiteLayout>
|
||||||
@@ -65,20 +65,94 @@ a:hover { text-decoration: underline; }
|
|||||||
header{
|
header{
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 50;
|
z-index: 1000;
|
||||||
|
isolation: isolate;
|
||||||
|
|
||||||
background: rgba(255,255,255,.92);
|
background: rgba(0,0,0,.82);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(12px);
|
||||||
-webkit-backdrop-filter: blur(10px);
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
|
||||||
border-bottom: 1px solid rgba(127,127,127,0.35);
|
border-bottom: 1px solid rgba(127,127,127,0.28);
|
||||||
padding: 12px 16px;
|
padding: 10px 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light){
|
||||||
|
header{
|
||||||
|
background: rgba(255,255,255,.90);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark){
|
@media (prefers-color-scheme: dark){
|
||||||
header{ background: rgba(0,0,0,.72); }
|
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; }
|
main { padding: 0; }
|
||||||
|
|
||||||
.reading {
|
.reading {
|
||||||
@@ -90,12 +164,10 @@ main { padding: 0; }
|
|||||||
letter-spacing: 0.005em;
|
letter-spacing: 0.005em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reading h1 {
|
.reading > h1{
|
||||||
line-height: 1.2;
|
font-size: clamp(1.8rem, 3.5vw, 2.6rem);
|
||||||
margin: 0 0 10px;
|
line-height: 1.15;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
/* polish */
|
|
||||||
letter-spacing: -0.01em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.reading p { margin: 0 0 12px; }
|
.reading p { margin: 0 0 12px; }
|
||||||
@@ -626,4 +698,320 @@ html{ scroll-behavior: smooth; }
|
|||||||
|
|
||||||
.glossary-alpha-group h3{
|
.glossary-alpha-group h3{
|
||||||
margin-bottom: 8px;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user