feat(ui): harmoniser navigation pages d’entrée et recherche
This commit is contained in:
@@ -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 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(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;
|
||||
|
||||
Reference in New Issue
Block a user