ui: propose modal intercept + readable buttons + open in new tab
This commit is contained in:
164
src/layouts/EditionLayout.astro
Normal file
164
src/layouts/EditionLayout.astro
Normal file
@@ -0,0 +1,164 @@
|
||||
---
|
||||
import ProposeModal from "../components/ProposeModal.astro";
|
||||
import SiteNav from "../components/SiteNav.astro";
|
||||
import LevelToggle from "../components/LevelToggle.astro";
|
||||
import BuildStamp from "../components/BuildStamp.astro";
|
||||
import "../styles/global.css";
|
||||
|
||||
const {
|
||||
title,
|
||||
editionLabel,
|
||||
editionKey,
|
||||
statusLabel,
|
||||
statusKey,
|
||||
level,
|
||||
version
|
||||
} = Astro.props;
|
||||
|
||||
const lvl = level ?? 1;
|
||||
|
||||
const canonical = Astro.site
|
||||
? new URL(Astro.url.pathname, Astro.site).href
|
||||
: Astro.url.href;
|
||||
|
||||
// Cible Gitea (injectée au build)
|
||||
const GITEA_BASE = import.meta.env.PUBLIC_GITEA_BASE ?? "";
|
||||
const GITEA_OWNER = import.meta.env.PUBLIC_GITEA_OWNER ?? "";
|
||||
const GITEA_REPO = import.meta.env.PUBLIC_GITEA_REPO ?? "";
|
||||
---
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>{title ? `${title} — Archicratie` : "Archicratie"}</title>
|
||||
|
||||
<link rel="canonical" href={canonical} />
|
||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||
|
||||
<meta data-pagefind-filter="edition[content]" content={String(editionKey ?? editionLabel)} />
|
||||
<meta data-pagefind-filter="level[content]" content={String(lvl)} />
|
||||
<meta data-pagefind-filter="status[content]" content={String(statusKey ?? statusLabel)} />
|
||||
|
||||
<meta data-pagefind-meta={`edition:${String(editionKey ?? editionLabel)}`} />
|
||||
<meta data-pagefind-meta={`level:${String(lvl)}`} />
|
||||
<meta data-pagefind-meta={`status:${String(statusKey ?? statusLabel)}`} />
|
||||
<meta data-pagefind-meta={`version:${String(version ?? "")}`} />
|
||||
</head>
|
||||
|
||||
<body data-doc-title={title} data-doc-version={version}>
|
||||
<header>
|
||||
<SiteNav />
|
||||
<div class="edition-bar">
|
||||
<span class="badge"><strong>Édition</strong> : {editionLabel}</span>
|
||||
<span class="badge"><strong>Statut</strong> : {statusLabel}</span>
|
||||
<span class="badge"><strong>Niveau</strong> : {lvl}</span>
|
||||
<span class="badge"><strong>Version</strong> : {version}</span>
|
||||
<LevelToggle initialLevel={lvl} />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article class="reading" data-pagefind-body>
|
||||
<slot />
|
||||
<BuildStamp />
|
||||
</article>
|
||||
</main>
|
||||
|
||||
|
||||
<ProposeModal />
|
||||
<!-- IMPORTANT: define:vars injecte les constantes dans le JS sans templating fragile -->
|
||||
<script is:inline define:vars={{ GITEA_BASE, GITEA_OWNER, GITEA_REPO }}>
|
||||
(() => {
|
||||
const title = document.body.dataset.docTitle || document.title;
|
||||
const version = document.body.dataset.docVersion || "";
|
||||
|
||||
const giteaReady = Boolean(GITEA_BASE && GITEA_OWNER && GITEA_REPO);
|
||||
|
||||
function buildIssueURL(anchorId, excerpt) {
|
||||
const base = String(GITEA_BASE).replace(/\/+$/, "");
|
||||
const issue = new URL(`${base}/${GITEA_OWNER}/${GITEA_REPO}/issues/new`);
|
||||
|
||||
const local = new URL(window.location.href);
|
||||
local.hash = anchorId;
|
||||
const path = local.pathname;
|
||||
|
||||
const issueTitle = `[Correction] ${anchorId} — ${title}`;
|
||||
const body = [
|
||||
`Chemin: ${path}`,
|
||||
`URL locale: ${local.toString()}`,
|
||||
`Ancre: #${anchorId}`,
|
||||
`Version: ${version || "(non renseignée)"}`,
|
||||
`Type: type/correction`,
|
||||
`State: state/recevable`,
|
||||
``,
|
||||
`Texte actuel (extrait):`,
|
||||
`> ${excerpt}`,
|
||||
``,
|
||||
`Proposition (remplacer par):`,
|
||||
``,
|
||||
`Justification:`,
|
||||
``,
|
||||
`---`,
|
||||
`Note: issue générée depuis le site (pré-remplissage).`
|
||||
].join("\n");
|
||||
|
||||
issue.searchParams.set("title", issueTitle);
|
||||
issue.searchParams.set("body", body);
|
||||
return issue.toString();
|
||||
}
|
||||
|
||||
const paras = Array.from(document.querySelectorAll(".reading p[id]"));
|
||||
for (const p of paras) {
|
||||
if (p.querySelector(".para-tools")) continue;
|
||||
|
||||
const tools = document.createElement("span");
|
||||
tools.className = "para-tools";
|
||||
|
||||
const a = document.createElement("a");
|
||||
a.className = "para-anchor";
|
||||
a.href = `#${p.id}`;
|
||||
a.setAttribute("aria-label", "Lien vers ce paragraphe");
|
||||
a.textContent = "¶";
|
||||
|
||||
const citeBtn = document.createElement("button");
|
||||
citeBtn.type = "button";
|
||||
citeBtn.className = "para-cite";
|
||||
citeBtn.textContent = "Citer";
|
||||
|
||||
citeBtn.addEventListener("click", async () => {
|
||||
const url = new URL(window.location.href);
|
||||
url.hash = p.id;
|
||||
const cite = `${title}${version ? ` (v${version})` : ""} — ${url.toString()}`;
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(cite);
|
||||
const prev = citeBtn.textContent;
|
||||
citeBtn.textContent = "Copié";
|
||||
setTimeout(() => (citeBtn.textContent = prev), 900);
|
||||
} catch {
|
||||
window.prompt("Copiez la citation :", cite);
|
||||
}
|
||||
});
|
||||
|
||||
tools.appendChild(a);
|
||||
tools.appendChild(citeBtn);
|
||||
|
||||
if (giteaReady) {
|
||||
const propose = document.createElement("a");
|
||||
propose.className = "para-propose";
|
||||
propose.href = "#";
|
||||
propose.textContent = "Proposer";
|
||||
propose.setAttribute("aria-label", "Proposer une correction sur Gitea");
|
||||
|
||||
propose.setAttribute("data-propose","1");
|
||||
|
||||
tools.appendChild(propose);
|
||||
}
|
||||
|
||||
p.appendChild(tools);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user