header template hinzugefügt

This commit is contained in:
florian committed 2026-10-03 10:54:47 +02:00
1 parent fac4f10062
commit 92f8e00fb5
6 files changed
+51 -20

No files matched your search

Vendored
BIN
View File
Binary file not shown.
+34 -18
View File
@@ -31,7 +31,8 @@ for d in (MD_DIR, TPL_DIR, CSS_DIR, OUT_DIR):
SLUG_RE = re.compile(r"^[a-z0-9][a-z0-9_-]*$", re.IGNORECASE)
START_PAGE = "startseite"
FOOTER_PAGE = "footer" # Baustein: wird in jede Seite eingefuegt, nicht eigenstaendig exportiert
HEADER_PAGE = "header" # Baustein: wird ueber den Inhalt jeder Seite gesetzt
FOOTER_PAGE = "footer" # Baustein: wird unter den Inhalt jeder Seite gesetzt
# ---------------------------------------------------------------- markdown
@@ -174,7 +175,7 @@ def md_path(slug):
def list_pages():
pages = []
for f in sorted(os.listdir(MD_DIR)):
if f.endswith(".md") and f[:-3] != FOOTER_PAGE:
if f.endswith(".md") and f[:-3] not in (HEADER_PAGE, FOOTER_PAGE):
pages.append(f[:-3])
return pages
@@ -197,12 +198,26 @@ def delete_page(slug):
# ------------------------------------------------------------------ export
def render_page(raw, template, footer_html=""):
def block_html(slug):
"""Rendert einen Baustein (header/footer) als HTML, leer wenn nicht vorhanden."""
if os.path.exists(md_path(slug)):
_, body = parse_md(load_page(slug))
return md_to_html(body)
return ""
def render_page(raw, template, header_html="", footer_html=""):
meta, body = parse_md(raw)
html = md_to_html(body)
page = (template
.replace("{{titel}}", _escape(meta.get("titel", "")))
.replace("{{inhalt}}", html))
if "{{header}}" in template:
page = page.replace("{{header}}", header_html)
elif header_html and "<body>" in page:
# Template ohne {{header}}-Platzhalter: Baustein automatisch setzen
idx = page.index("<body>") + len("<body>")
page = page[:idx] + "\n<header>\n" + header_html + "\n</header>\n" + page[idx:]
if "{{footer}}" in template:
page = page.replace("{{footer}}", footer_html)
elif footer_html and "</body>" in page:
@@ -232,14 +247,12 @@ def export_site():
if f.endswith(".css"):
shutil.copy2(os.path.join(CSS_DIR, f), os.path.join(OUT_DIR, "css", f))
footer_html = ""
if os.path.exists(md_path(FOOTER_PAGE)):
_, fbody = parse_md(load_page(FOOTER_PAGE))
footer_html = md_to_html(fbody)
footer_html = block_html(FOOTER_PAGE)
header_html = block_html(HEADER_PAGE)
exported = []
for slug in list_pages():
page, _ = render_page(load_page(slug), template, footer_html)
page, _ = render_page(load_page(slug), template, header_html, footer_html)
# startseite.md wird zur index.html
out_name = "index.html" if slug == START_PAGE else slug + ".html"
with open(os.path.join(OUT_DIR, out_name), "w", encoding="utf-8") as fh:
@@ -276,10 +289,11 @@ class Handler(BaseHTTPRequestHandler):
self._send(200, ADMIN_HTML, "text/html; charset=utf-8")
elif path == "/api/pages":
self._json({"pages": list_pages(), "start": START_PAGE,
"header": os.path.exists(md_path(HEADER_PAGE)),
"footer": os.path.exists(md_path(FOOTER_PAGE))})
elif path.startswith("/api/page/"):
slug = unquote(path[len("/api/page/"):])
if slug == FOOTER_PAGE or slug in list_pages():
if slug in (HEADER_PAGE, FOOTER_PAGE) or slug in list_pages():
self._json({"slug": slug, "raw": load_page(slug)})
else:
self._json({"error": "Seite nicht gefunden"}, 404)
@@ -304,10 +318,10 @@ class Handler(BaseHTTPRequestHandler):
self._json({"ok": True, "slug": slug})
elif path == "/api/delete":
slug = data.get("slug", "")
if slug != FOOTER_PAGE and slug not in list_pages():
if slug not in (HEADER_PAGE, FOOTER_PAGE) and slug not in list_pages():
return self._json({"error": "Seite nicht gefunden"}, 404)
if slug in (START_PAGE, FOOTER_PAGE):
return self._json({"error": "Startseite und Footer-Baustein koennen nicht geloescht werden."}, 400)
if slug in (START_PAGE, HEADER_PAGE, FOOTER_PAGE):
return self._json({"error": "Startseite und Bausteine koennen nicht geloescht werden."}, 400)
delete_page(slug)
self._json({"ok": True})
elif path == "/api/preview":
@@ -384,12 +398,14 @@ async function loadPages() {
if (p === current) a.className = "active";
$("pages").appendChild(a);
}
if (d.footer) {
const a = document.createElement("a");
a.textContent = "footer (Baustein)";
a.onclick = () => openPage("footer");
if (current === "footer") a.className = "active";
$("pages").appendChild(a);
for (const b of [["header", d.header], ["footer", d.footer]]) {
if (b[1]) {
const a = document.createElement("a");
a.textContent = b[0] + " (Baustein)";
a.onclick = () => openPage(b[0]);
if (current === b[0]) a.className = "active";
$("pages").appendChild(a);
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

+9
View File
@@ -0,0 +1,9 @@
---
titel: Header
---
# Meine Website
Dieser Header-Baustein wird automatisch ueber den Inhalt **aller** Seiten gesetzt.
- [Startseite](index.html)
+6 -1
View File
@@ -8,9 +8,14 @@
</head>
<body>
<header>
<h1>startseite</h1>
<h1>Meine Website</h1>
<p>Dieser Header-Baustein wird automatisch ueber den Inhalt <strong>aller</strong> Seiten gesetzt.</p>
<ul>
<li><a href="index.html">Startseite</a></li>
</ul>
</header>
<main>
<h1>startseite</h1>
<p>Neue Seite. hier kommen alle inhalte hin.</p>
</main>
<footer>
+2 -1
View File
@@ -8,9 +8,10 @@
</head>
<body>
<header>
<h1>{{titel}}</h1>
{{header}}
</header>
<main>
<h1>{{titel}}</h1>
{{inhalt}}
</main>
<footer>