css start

This commit is contained in:
florian committed 2026-10-03 11:51:03 +02:00
1 parent 92f8e00fb5
commit dc1b35f344
9 files changed
+546 -10

No files matched your search

+49 -4
View File
@@ -37,10 +37,12 @@ FOOTER_PAGE = "footer" # Baustein: wird unter den Inhalt jeder Seite gesetzt
# ---------------------------------------------------------------- markdown
def md_to_html(text):
def md_to_html(text, headings=None):
"""Minimaler Markdown->HTML-Konverter:
Ueberschriften, **fett**, *kursiv*, `code`, [Links](url),
Listen, Code-Bloecke, > Zitate, --- Trennlinien, Absaetze.
Ueberschriften bekommen id-Anker; in headings (Liste) werden
optional (anker, text) aller Ueberschriften gesammelt.
"""
lines = text.replace("\r\n", "\n").split("\n")
out = []
@@ -48,6 +50,7 @@ def md_to_html(text):
in_code = False
in_list = False
list_tag = None
used_ids = {}
def inline(s):
s = re.sub(r"`([^`]+)`", r"<code>\1</code>", s)
@@ -89,11 +92,28 @@ def md_to_html(text):
i += 1
continue
# Rohe HTML-Zeilen (z.B. <div>, <svg>) unveraendert durchreichen
if stripped.startswith("<"):
close_list()
out.append(stripped)
i += 1
continue
m = re.match(r"^(#{1,6})\s+(.*)$", stripped)
if m:
close_list()
level = len(m.group(1))
out.append("<h%d>%s</h%d>" % (level, inline(_escape(m.group(2))), level))
text_h = m.group(2)
hid = _slugify(text_h)
if hid in used_ids:
used_ids[hid] += 1
hid = "%s-%d" % (hid, used_ids[hid])
else:
used_ids[hid] = 0
if headings is not None:
headings.append((hid, text_h))
out.append('<h%d id="%s">%s</h%d>'
% (level, hid, inline(_escape(text_h)), level))
i += 1
continue
@@ -136,7 +156,7 @@ def md_to_html(text):
close_list()
para = [stripped]
while (i + 1 < len(lines) and lines[i + 1].strip()
and not re.match(r"^(#{1,6}\s|[-*+]\s|\d+\.\s|>|```|-{3,}$)",
and not re.match(r"^(#{1,6}\s|[-*+]\s|\d+\.\s|>|```|-{3,}$|<)",
lines[i + 1].strip())):
i += 1
para.append(lines[i].strip())
@@ -151,6 +171,23 @@ def _escape(s):
return (s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;"))
def _slugify(s):
"""Ueberschriftentext -> HTML-id (ankertauglich, klein, ohne Sonderzeichen)."""
s = s.lower()
for k, v in (("ä", "ae"), ("ö", "oe"), ("ü", "ue"), ("ß", "ss")):
s = s.replace(k, v)
s = re.sub(r"[^a-z0-9]+", "-", s).strip("-")
return s or "abschnitt"
def heading_nav(headings):
"""Baut die Anker-Linkliste (Text-Links auf die Ueberschriften der Seite)."""
if not headings:
return ""
return "".join('<a href="#%s">%s</a>' % (hid, _escape(text))
for hid, text in headings)
# ------------------------------------------------------------------- seiten
def parse_md(raw):
@@ -208,10 +245,18 @@ def block_html(slug):
def render_page(raw, template, header_html="", footer_html=""):
meta, body = parse_md(raw)
html = md_to_html(body)
headings = []
html = md_to_html(body, headings)
anker_html = heading_nav(headings)
page = (template
.replace("{{titel}}", _escape(meta.get("titel", "")))
.replace("{{inhalt}}", html))
if "{{anker}}" in template:
page = page.replace("{{anker}}", anker_html)
elif anker_html and "{{header}}" in template:
# Template ohne {{anker}}-Platzhalter: Anker ans Ende des Headers
page = page.replace("{{header}}",
header_html + '\n<nav class="anker-nav">' + anker_html + "</nav>")
if "{{header}}" in template:
page = page.replace("{{header}}", header_html)
elif header_html and "<body>" in page: