Rich-text fields (hero lead, paragraphs, FAQ-style copy, datenschutz sections, etc.) now use a proper toolbar editor - bold/italic/underline buttons plus a per-selection font picker drawn from the same curated font list as the Design tab - instead of typed **markdown** syntax. Content is stored as a small allowlisted HTML subset (strong/em/u/span with a validated data-font/br) and sanitized server-side with sanitize-html on every save (admin/lib/rich-sanitize.js), independent of what the client sends - verified this rejects script tags, event handlers, and made-up font names while preserving legitimate markup, and that re-saving already-sanitized content is a no-op. The Astro site mirrors the same allowlist at render time for defense-in-depth (src/lib/rich-sanitize.ts) and only requests Google Fonts for fonts actually referenced somewhere in content, in addition to the two Design-tab fonts - verified a font used via a data-font span gets its own Google Fonts request and [data-font] CSS rule in the built page, and that unused fonts don't get requested. Migrated the three existing fields that used the old markdown-lite syntax (**bold**/*italic*) to real HTML so they keep rendering correctly under the new system. Also replaces the single long scrolling admin page with a tabbed sidebar (grouped "Inhalte"/"Design") to cut down on clutter, per feedback that the all-in-one-page layout was hard to navigate.
36 lines
1.2 KiB
HTML
36 lines
1.2 KiB
HTML
<!doctype html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<meta name="robots" content="noindex, nofollow" />
|
|
<title>larpaso · Editor</title>
|
|
<link rel="stylesheet" href="/admin/style.css" />
|
|
</head>
|
|
<body>
|
|
<header class="topbar">
|
|
<h1>larpaso · Editor</h1>
|
|
<div class="topbar-actions">
|
|
<span id="status" class="status" aria-live="polite"></span>
|
|
<button id="save-btn" type="button">Speichern</button>
|
|
<button id="publish-btn" type="button" class="btn-accent">Speichern & veröffentlichen</button>
|
|
<form method="POST" action="/admin/logout"><button type="submit" class="btn-ghost">Abmelden</button></form>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="layout">
|
|
<nav id="section-nav" class="section-nav" aria-label="Abschnitte"></nav>
|
|
<main id="sections"></main>
|
|
</div>
|
|
|
|
<div id="log" class="build-log" hidden>
|
|
<div class="build-log-header">
|
|
<span>Build-Ausgabe</span>
|
|
<button id="log-close" type="button" class="btn-ghost">Schließen</button>
|
|
</div>
|
|
<pre id="log-output"></pre>
|
|
</div>
|
|
|
|
<script src="/admin/app.js"></script>
|
|
</body>
|
|
</html>
|