fix(etape8): resync hotfix edition depuis NAS (2026-02-19)
This commit is contained in:
@@ -1,35 +1,128 @@
|
||||
---
|
||||
// src/components/LevelToggle.astro
|
||||
const { initialLevel = 1 } = Astro.props;
|
||||
---
|
||||
<div class="level-toggle" role="group" aria-label="Niveau de lecture">
|
||||
<button type="button" class="lvl-btn" data-level="1" aria-pressed="true">Niveau 1</button>
|
||||
<button type="button" class="lvl-btn" data-level="2" aria-pressed="false">Niveau 2</button>
|
||||
<button type="button" class="lvl-btn" data-level="3" aria-pressed="false">Niveau 3</button>
|
||||
|
||||
<div class="level-toggle" role="group" aria-label="Mode d’édition">
|
||||
<button type="button" class="level-btn" data-level="1">Propos</button>
|
||||
<button type="button" class="level-btn" data-level="2">Références</button>
|
||||
<button type="button" class="level-btn" data-level="3">Illustrations</button>
|
||||
<button type="button" class="level-btn" data-level="4">Commentaires</button>
|
||||
</div>
|
||||
|
||||
<script is:inline>
|
||||
<script is:inline define:vars={{ initialLevel }}>
|
||||
(() => {
|
||||
const KEY = "archicratie.readingLevel";
|
||||
const buttons = Array.from(document.querySelectorAll(".lvl-btn"));
|
||||
const BODY = document.body;
|
||||
|
||||
function apply(level) {
|
||||
document.body.setAttribute("data-reading-level", String(level));
|
||||
buttons.forEach((b) => b.setAttribute("aria-pressed", b.dataset.level === String(level) ? "true" : "false"));
|
||||
const wrap = document.querySelector(".level-toggle");
|
||||
if (!wrap) return;
|
||||
|
||||
const buttons = Array.from(wrap.querySelectorAll("button[data-level]"));
|
||||
if (!buttons.length) return;
|
||||
|
||||
const KEY = "archicratie:readingLevel";
|
||||
|
||||
function clampLevel(n) {
|
||||
const x = Number.parseInt(String(n), 10);
|
||||
if (!Number.isFinite(x)) return 1;
|
||||
return Math.min(4, Math.max(1, x));
|
||||
}
|
||||
|
||||
// Valeur par défaut : si rien n'est stocké, on met 1 (citoyen).
|
||||
// Si JS est absent/casse, le site reste lisible (tout s'affiche).
|
||||
const stored = Number(localStorage.getItem(KEY));
|
||||
const level = (stored === 1 || stored === 2 || stored === 3) ? stored : 1;
|
||||
function setActiveUI(lvl) {
|
||||
for (const b of buttons) {
|
||||
const on = String(b.dataset.level) === String(lvl);
|
||||
b.classList.toggle("is-active", on);
|
||||
b.setAttribute("aria-pressed", on ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
apply(level);
|
||||
function captureBeforeLevelSwitch() {
|
||||
const paraId =
|
||||
window.__archiCurrentParaId ||
|
||||
window.__archiLastParaId ||
|
||||
String(location.hash || "").replace(/^#/, "") ||
|
||||
"";
|
||||
|
||||
buttons.forEach((b) => {
|
||||
b.addEventListener("click", () => {
|
||||
const lvl = Number(b.dataset.level);
|
||||
localStorage.setItem(KEY, String(lvl));
|
||||
apply(lvl);
|
||||
});
|
||||
window.__archiLevelSwitchCtx = {
|
||||
paraId,
|
||||
hash: location.hash || "",
|
||||
scrollY: window.scrollY || 0,
|
||||
t: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
function applyLevel(lvl, { persist = true } = {}) {
|
||||
const v = clampLevel(lvl);
|
||||
|
||||
if (BODY) BODY.dataset.readingLevel = String(v);
|
||||
setActiveUI(v);
|
||||
|
||||
if (persist) {
|
||||
try { localStorage.setItem(KEY, String(v)); } catch {}
|
||||
}
|
||||
|
||||
try {
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("archicratie:readingLevel", { detail: { level: v } })
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// init : storage > initialLevel
|
||||
let start = clampLevel(initialLevel);
|
||||
try {
|
||||
const stored = localStorage.getItem(KEY);
|
||||
if (stored) start = clampLevel(stored);
|
||||
} catch {}
|
||||
|
||||
applyLevel(start, { persist: false });
|
||||
|
||||
// clicks
|
||||
wrap.addEventListener("click", (ev) => {
|
||||
const btn = ev.target?.closest?.("button[data-level]");
|
||||
if (!btn) return;
|
||||
ev.preventDefault();
|
||||
|
||||
// ✅ crucial : on capture la position AVANT le reflow lié au changement de niveau
|
||||
captureBeforeLevelSwitch();
|
||||
applyLevel(btn.dataset.level);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.level-toggle{
|
||||
display: inline-flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.level-btn{
|
||||
border: 1px solid rgba(127,127,127,0.40);
|
||||
background: rgba(127,127,127,0.08);
|
||||
border-radius: 999px;
|
||||
padding: 6px 10px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: filter .12s ease, transform .12s ease, background .12s ease, border-color .12s ease;
|
||||
}
|
||||
|
||||
.level-btn:hover{
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
|
||||
.level-btn.is-active{
|
||||
border-color: rgba(160,160,255,0.95);
|
||||
background: rgba(140,140,255,0.18);
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.level-btn.is-active:hover{
|
||||
filter: brightness(1.12);
|
||||
}
|
||||
|
||||
.level-btn:active{
|
||||
transform: translateY(1px);
|
||||
}
|
||||
</style>
|
||||
|
||||
1064
src/components/SidePanel.astro
Normal file
1064
src/components/SidePanel.astro
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user