diff --git a/.DS_Store b/.DS_Store index f912345..336b29d 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/cms.py b/cms.py index 61612d3..3edc84d 100755 --- a/cms.py +++ b/cms.py @@ -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 "" in page: + # Template ohne {{header}}-Platzhalter: Baustein automatisch setzen + idx = page.index("") + len("") + page = page[:idx] + "\n
\n" + header_html + "\n
\n" + page[idx:] if "{{footer}}" in template: page = page.replace("{{footer}}", footer_html) elif footer_html and "" 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); + } } } diff --git a/images/hfglogo.png b/images/hfglogo.png new file mode 100644 index 0000000..84161e7 Binary files /dev/null and b/images/hfglogo.png differ diff --git a/md/header.md b/md/header.md new file mode 100644 index 0000000..71ee792 --- /dev/null +++ b/md/header.md @@ -0,0 +1,9 @@ +--- +titel: Header +--- + +# Meine Website + +Dieser Header-Baustein wird automatisch ueber den Inhalt **aller** Seiten gesetzt. + +- [Startseite](index.html) diff --git a/output/index.html b/output/index.html index 8c182bd..c7efd00 100644 --- a/output/index.html +++ b/output/index.html @@ -8,9 +8,14 @@
-

startseite

+

Meine Website

+

Dieser Header-Baustein wird automatisch ueber den Inhalt aller Seiten gesetzt.

+
+

startseite

Neue Seite. hier kommen alle inhalte hin.