diff --git a/.DS_Store b/.DS_Store
index 786dd3c..4704a8a 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/ansicht-dummy.zip b/ansicht-dummy.zip
new file mode 100644
index 0000000..201a64b
Binary files /dev/null and b/ansicht-dummy.zip differ
diff --git a/cms.py b/cms.py
index 9fda398..0fe28f3 100755
--- a/cms.py
+++ b/cms.py
@@ -37,6 +37,16 @@ FOOTER_PAGE = "footer" # Baustein: wird unter den Inhalt jeder Seite gesetzt
# ---------------------------------------------------------------- markdown
+def inline(s):
+ """Inline-Markdown: bilder, code, fett, kursiv, Links."""
+ s = re.sub(r"`([^`]+)`", r"\1", s)
+ s = re.sub(r"!\[([^\]]*)\]\(([^)]+)\)", r'', s)
+ s = re.sub(r"\*\*([^*]+)\*\*", r"\1", s)
+ s = re.sub(r"\*([^*]+)\*", r"\1", s)
+ s = re.sub(r"\[([^\]]+)\]\(([^)]+)\)", r'\1', s)
+ return s
+
+
def md_to_html(text, headings=None):
"""Minimaler Markdown->HTML-Konverter:
Ueberschriften, **fett**, *kursiv*, `code`, [Links](url),
@@ -44,6 +54,8 @@ def md_to_html(text, headings=None):
Ueberschriften bekommen id-Anker; in headings (Liste) werden
optional (anker, text) aller Ueberschriften gesammelt.
"""
+ # vergessenes Trigger-Wort "image" direkt vor einem Bild nicht mit ausgeben
+ text = re.sub(r"\bimage\s*(?=!\[)", "", text, flags=re.IGNORECASE)
lines = text.replace("\r\n", "\n").split("\n")
out = []
i = 0
@@ -51,13 +63,7 @@ def md_to_html(text, headings=None):
in_list = False
list_tag = None
used_ids = {}
-
- def inline(s):
- s = re.sub(r"`([^`]+)`", r"\1", s)
- s = re.sub(r"\*\*([^*]+)\*\*", r"\1", s)
- s = re.sub(r"\*([^*]+)\*", r"\1", s)
- s = re.sub(r"\[([^\]]+)\]\(([^)]+)\)", r'\1', s)
- return s
+ sec_stack = [] # offene Sektionen (pro # mehr eine Ebene, eingerueckt)
def close_list():
nonlocal in_list, list_tag
@@ -112,8 +118,18 @@ def md_to_html(text, headings=None):
used_ids[hid] = 0
if headings is not None:
headings.append((level, hid, text_h))
+ # tiefere Sektionen schliessen, bis die Ebene wieder passt
+ while sec_stack and sec_stack[-1] >= level:
+ out.append("")
+ sec_stack.pop()
+ # ein # mehr als die umgebende Ueberschrift -> Stufe einruecken
+ if sec_stack:
+ out.append('
')
+ else:
+ out.append('
')
out.append('%s'
% (level, hid, inline(_escape(text_h)), level))
+ sec_stack.append(level)
i += 1
continue
@@ -123,6 +139,24 @@ def md_to_html(text, headings=None):
i += 1
continue
+ # Tabellen: | zelle | zelle | mit --- Trennzeile
+ if stripped.startswith("|"):
+ close_list()
+ rows = []
+ j = i
+ while j < len(lines) and lines[j].strip().startswith("|"):
+ rows.append(lines[j].strip())
+ j += 1
+ tbl = _parse_table(rows)
+ if tbl:
+ out.append(tbl)
+ i = j
+ else:
+ # keine gueltige Tabelle -> als normaler Absatz
+ out.append("
%s
" % inline(_escape(stripped)))
+ i += 1
+ continue
+
m = re.match(r"^([-*+])\s+(.*)$", stripped)
if m:
if not in_list or list_tag != "ul":
@@ -156,7 +190,7 @@ def md_to_html(text, headings=None):
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())
@@ -164,6 +198,9 @@ def md_to_html(text, headings=None):
i += 1
close_list()
+ while sec_stack:
+ out.append("
")
+ sec_stack.pop()
return "\n".join(out)
@@ -171,6 +208,54 @@ def _escape(s):
return (s.replace("&", "&").replace("<", "<").replace(">", ">"))
+def _parse_table(rows):
+ """Baut aus |-getrennten Zeilen eine HTML-Tabelle.
+ Zeile 1: Kopfzeile, Zeile 2: Trenner (---, :---, ---:, :---:),
+ danach: Datenzeilen. Liefert None, wenn es keine gueltige Tabelle ist.
+ """
+ def split_row(r):
+ if r.startswith("|"):
+ r = r[1:]
+ if r.endswith("|"):
+ r = r[:-1]
+ return [c.strip() for c in r.split("|")]
+
+ def is_sep(c):
+ return re.match(r"^:?-{2,}:?$", c) is not None
+
+ if len(rows) < 2 or not all(is_sep(c) and c for c in split_row(rows[1])):
+ return None
+
+ aligns = []
+ for c in split_row(rows[1]):
+ left, right = c.startswith(":"), c.endswith(":")
+ if left and right:
+ aligns.append("center")
+ elif right:
+ aligns.append("right")
+ else:
+ aligns.append("left")
+
+ def cell(tag, j, text):
+ style = ' style="text-align: %s"' % aligns[j] if j < len(aligns) else ""
+ return "<%s%s>%s%s>" % (tag, style, inline(text), tag)
+
+ out = ["
", "
"]
+ for j, c in enumerate(split_row(rows[0])):
+ out.append(cell("th", j, _escape(c)))
+ out.append("
")
+ if len(rows) > 2:
+ out.append("")
+ for r in rows[2:]:
+ out.append("
")
+ for j, c in enumerate(split_row(r)):
+ out.append(cell("td", j, _escape(c)))
+ out.append("
")
+ out.append("")
+ out.append("
")
+ return "".join(out)
+
+
def _slugify(s):
"""Ueberschriftentext -> HTML-id (ankertauglich, klein, ohne Sonderzeichen)."""
s = s.lower()
@@ -180,10 +265,11 @@ def _slugify(s):
return s or "abschnitt"
-def heading_nav(headings):
+def heading_nav(headings, prefix=""):
"""Baut die Anker-Navigation als verschachtelte ul/li-Liste:
Eine Ueberschrift mit einem # mehr als die vorherige wird als
- Unterpunkt eingerueckt.
+ Unterpunkt eingerueckt. prefix erlaubt Links auf eine andere Seite
+ (z.B. "index.html" -> href="index.html#anker").
headings: Liste von (level, anker, text).
"""
if not headings:
@@ -205,7 +291,7 @@ def heading_nav(headings):
parts.append("")
levels.pop()
parts.append("")
- parts.append('
")
while len(levels) > 1:
parts.append("")
@@ -269,18 +355,23 @@ def block_html(slug):
return ""
-def render_page(raw, template, header_html="", footer_html=""):
+def render_page(raw, template, header_html="", footer_html="", start_anker_html=""):
meta, body = parse_md(raw)
headings = []
html = md_to_html(body, headings)
anker_html = heading_nav(headings)
page = (template
.replace("{{titel}}", _escape(meta.get("titel", "")))
+ .replace("{{beschreibung}}", _escape(meta.get("beschreibung", "")))
.replace("{{inhalt}}", html))
+ # {{anker-start}}: Navigation der Startseite, verlinkt auf index.html#anker
+ if "{{anker-start}}" in template:
+ page = page.replace("{{anker-start}}", start_anker_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
+ elif (anker_html and "{{anker-start}}" not in template
+ and "{{header}}" in template):
+ # Template ganz ohne Anker-Platzhalter: eigene Anker ans Header-Ende
page = page.replace("{{header}}",
header_html + '\n")
if "{{header}}" in template:
@@ -298,7 +389,17 @@ def render_page(raw, template, header_html="", footer_html=""):
return page, meta.get("titel", "")
-def load_template():
+def load_template(slug=None):
+ """Template fuer eine Seite: templates/.html wenn vorhanden,
+ sonst default.html, sonst das erste gefundene Template."""
+ candidates = []
+ if slug:
+ candidates.append(os.path.join(TPL_DIR, slug + ".html"))
+ candidates.append(os.path.join(TPL_DIR, "default.html"))
+ for c in candidates:
+ if os.path.exists(c):
+ with open(c, encoding="utf-8") as fh:
+ return fh.read()
files = [f for f in os.listdir(TPL_DIR) if f.endswith(".html")]
if not files:
raise SystemExit("Kein Template in templates/ gefunden (z.B. default.html).")
@@ -308,7 +409,6 @@ def load_template():
def export_site():
"""Baut output/: pro MD-Datei eine HTML-Seite, CSS wird kopiert."""
- template = load_template()
# Output leeren und neu aufbauen
if os.path.isdir(OUT_DIR):
shutil.rmtree(OUT_DIR)
@@ -318,12 +418,27 @@ def export_site():
if f.endswith(".css"):
shutil.copy2(os.path.join(CSS_DIR, f), os.path.join(OUT_DIR, "css", f))
+ # Bilder (z.B. Logo/Favicon) nach output/images/ kopieren
+ img_src = os.path.join(ROOT, "images")
+ if os.path.isdir(img_src):
+ shutil.copytree(img_src, os.path.join(OUT_DIR, "images"), dirs_exist_ok=True)
+
footer_html = block_html(FOOTER_PAGE)
header_html = block_html(HEADER_PAGE)
+ # Anker-Navigation der Startseite (fuer Templates mit {{anker-start}},
+ # z.B. impressum: Links auf index.html#anker)
+ start_headings = []
+ if os.path.exists(md_path(START_PAGE)):
+ _, s_body = parse_md(load_page(START_PAGE))
+ md_to_html(s_body, start_headings)
+ start_anker = heading_nav(start_headings, prefix="index.html")
+
exported = []
for slug in list_pages():
- page, _ = render_page(load_page(slug), template, header_html, footer_html)
+ template = load_template(slug)
+ page, _ = render_page(load_page(slug), template, header_html, footer_html,
+ start_anker)
# 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:
@@ -368,6 +483,14 @@ class Handler(BaseHTTPRequestHandler):
self._json({"slug": slug, "raw": load_page(slug)})
else:
self._json({"error": "Seite nicht gefunden"}, 404)
+ elif path == "/api/images":
+ img_dir = os.path.join(ROOT, "images")
+ files = []
+ if os.path.isdir(img_dir):
+ for f in sorted(os.listdir(img_dir)):
+ if os.path.isfile(os.path.join(img_dir, f)) and not f.startswith("."):
+ files.append(f)
+ self._json({"images": files})
elif path == "/api/export":
self._json({"exported": export_site()})
else:
@@ -413,7 +536,11 @@ ADMIN_HTML = """
#side h1 { font-size: 1rem; }
#pages a { display: block; padding: .35rem .5rem; border-radius: 4px; cursor: pointer; text-decoration: none; color: #000; }
#pages a.active, #pages a:hover { background: #ddd; }
- #main { flex: 1; display: flex; flex-direction: column; padding: 1rem; box-sizing: border-box; gap: .5rem; }
+ #main { flex: 1; display: flex; flex-direction: column; padding: 1rem; box-sizing: border-box; gap: .5rem; position: relative; }
+ #imgdrop { position: absolute; top: 3.2rem; left: 1rem; background: #fff; border: 1px solid #999; border-radius: 4px; box-shadow: 0 2px 10px rgba(0,0,0,.25); max-height: 220px; overflow: auto; z-index: 20; min-width: 240px; }
+ #imgdrop .imgdrop-title { font-size: .8rem; padding: .4rem .6rem; background: #eee; }
+ #imglist a { display: block; padding: .35rem .6rem; cursor: pointer; color: #000; }
+ #imglist a:hover { background: #dde8ff; }
#toolbar { display: flex; gap: .5rem; align-items: center; }
button { padding: .45rem .9rem; border: 1px solid #999; border-radius: 4px; background: #fff; cursor: pointer; }
button.primary { background: #0066cc; color: #fff; border-color: #0066cc; }
@@ -441,11 +568,17 @@ ADMIN_HTML = """
+
+
Bild aus images/ einfügen:
+
+
+Hier den Inhalt schreiben. **fett**, *kursiv*, [Link](seite.html), # Ueberschrift, - Liste.
+Das Wort "image" tippen, um ein Bild aus dem images-Ordner einzufuegen.
+
Angaben gemäß § 5 TMG (Telemediengesetz) Rechtlicher Sitz Hochschule für Gestaltung Offenbach am Main Schlossstraße 31, 63065 Offenbach am Main T +49.(0)69.80059-0 F +49.(0)69.80059-109 praesidium@hfg-offenbach.de hfg-offenbach.de
+
+
+
Umsatzsteuer-ID
+
DE232878186
+
+
+
Rechtsform
+
Die Hochschule für Gestaltung Offenbach am Main ist als Hochschule des Landes Hessen zugleich eine Körperschaft des öffentlichen Rechts und eine staatliche Einrichtung. Sie wird durch den Präsidenten Prof. Bernd Kracke gesetzlich vertreten.
+
+
+
Rechtsaufsicht
+
Hessisches Ministerium für Wissenschaft und Kunst, Rheinstr. 23-25, 65185 Wiesbaden
+
+
+
Haftungsausschluss
+
Haftung für Inhalte Diese Website dient lediglich der Information. Ihr Inhalt wurde mit größter Sorgfalt zusammengestellt. Eine Haftung oder Garantie für die Aktualität, Richtigkeit und Vollständigkeit der zur Verfügung gestellten Informationen und Daten ist jedoch ausgeschlossen. Die Hochschule für Gestaltung Offenbach übernimmt insbesondere keinerlei Haftung für eventuelle Schäden oder Konsequenzen, die durch die direkte oder indirekte Nutzung der angebotenen Inhalte entstehen.
+
Hinweise und Korrekturen senden Sie bitte an: Ulrike Grünewald
+
+
+
Haftung für Links
+
Die Hochschule für Gestaltung Offenbach ist als Inhaltsanbieter für die eigenen Inhalte, die sie zur Nutzung bereit hält, nach den allgemeinen Gesetzen verantwortlich.
+
Von diesen eigenen Inhalten sind Querverweise (externe Links) auf die von anderen Anbietern bereit gehaltenen Inhalte zu unterscheiden. Diese fremden Inhalte stammen nicht von der Hochschule für Gestaltung Offenbach und spiegeln auch nicht die Meinung der Hochschule für Gestaltung Offenbach wider, sondern dienen lediglich der Information. Die Hochschule für Gestaltung Offenbach hat weder Einfluss auf die Gestaltung und die Inhalte der gelinkten Seiten noch macht sie sich diese Inhalte zu eigen.
+
Die Webredaktion der Hochschule für Gestaltung Offenbach hat bei der erstmaligen Verknüpfung zwar den fremden Inhalt daraufhin überprüft, ob durch ihn eine mögliche zivilrechtliche oder strafrechtliche Verantwortlichkeit ausgelöst wird. Sie überprüft aber die Inhalte nicht ständig auf Veränderungen, die eine Verantwortlichkeit neu begründen könnten. Bei Bekanntwerden von Rechtsverletzungen werden derartige Links umgehend entfernt, soweit dies technisch möglich und zumutbar ist.
+
Diese Erklärung gilt für alle auf unserer Website angezeigten Links und für alle Inhalte der Seiten, zu denen die bei uns angemeldeten Banner und Links führen.
+
+
+
Hinweise zum Urheberrecht
+
Alle auf dieser Website veröffentlichten Texte, Bild-, Ton- und Filmdokumente befinden sich im Besitz der Hochschule für Gestaltung Offenbach beziehungsweise der jeweils angegebenen Autoren. Eine – auch auszugsweise – Veröffentlichung in elektronischer oder anderer Form bedarf der ausdrücklichen vorherigen schriftlichen Zustimmung der jeweiligen Rechteinhaber. Bitte setzen Sie sich gegebenenfalls mit uns in Verbindung.
+
+
+
Datenschutzerklärung
+
Die Datenschutzerklärung der HfG Offenbach finden Sie HIER.
+
Zusätzliche Information Redaktion auf dieser Seite: Florian Albrecht-Schoeck und Sebastian Kujas
diff --git a/md/impressum.md b/md/impressum.md
new file mode 100644
index 0000000..c11460f
--- /dev/null
+++ b/md/impressum.md
@@ -0,0 +1,48 @@
+---
+titel: impressum
+beschreibung: impressum
+---
+
+# Impressum
+
+Angaben gemäß § 5 TMG (Telemediengesetz)
+Rechtlicher Sitz
+Hochschule für Gestaltung Offenbach am Main
+Schlossstraße 31, 63065 Offenbach am Main
+T +49.(0)69.80059-0
+F +49.(0)69.80059-109
+praesidium@hfg-offenbach.de
+hfg-offenbach.de
+
+# Umsatzsteuer-ID
+DE232878186
+
+# Rechtsform
+Die Hochschule für Gestaltung Offenbach am Main ist als Hochschule des Landes Hessen zugleich eine Körperschaft des öffentlichen Rechts und eine staatliche Einrichtung. Sie wird durch den Präsidenten Prof. Bernd Kracke gesetzlich vertreten.
+
+# Rechtsaufsicht
+Hessisches Ministerium für Wissenschaft und Kunst, Rheinstr. 23-25, 65185 Wiesbaden
+
+# Haftungsausschluss
+Haftung für Inhalte
+Diese Website dient lediglich der Information. Ihr Inhalt wurde mit größter Sorgfalt zusammengestellt. Eine Haftung oder Garantie für die Aktualität, Richtigkeit und Vollständigkeit der zur Verfügung gestellten Informationen und Daten ist jedoch ausgeschlossen. Die Hochschule für Gestaltung Offenbach übernimmt insbesondere keinerlei Haftung für eventuelle Schäden oder Konsequenzen, die durch die direkte oder indirekte Nutzung der angebotenen Inhalte entstehen.
+
+Hinweise und Korrekturen senden Sie bitte an: Ulrike Grünewald
+
+# Haftung für Links
+Die Hochschule für Gestaltung Offenbach ist als Inhaltsanbieter für die eigenen Inhalte, die sie zur Nutzung bereit hält, nach den allgemeinen Gesetzen verantwortlich.
+
+Von diesen eigenen Inhalten sind Querverweise (externe Links) auf die von anderen Anbietern bereit gehaltenen Inhalte zu unterscheiden. Diese fremden Inhalte stammen nicht von der Hochschule für Gestaltung Offenbach und spiegeln auch nicht die Meinung der Hochschule für Gestaltung Offenbach wider, sondern dienen lediglich der Information. Die Hochschule für Gestaltung Offenbach hat weder Einfluss auf die Gestaltung und die Inhalte der gelinkten Seiten noch macht sie sich diese Inhalte zu eigen.
+
+Die Webredaktion der Hochschule für Gestaltung Offenbach hat bei der erstmaligen Verknüpfung zwar den fremden Inhalt daraufhin überprüft, ob durch ihn eine mögliche zivilrechtliche oder strafrechtliche Verantwortlichkeit ausgelöst wird. Sie überprüft aber die Inhalte nicht ständig auf Veränderungen, die eine Verantwortlichkeit neu begründen könnten. Bei Bekanntwerden von Rechtsverletzungen werden derartige Links umgehend entfernt, soweit dies technisch möglich und zumutbar ist.
+
+Diese Erklärung gilt für alle auf unserer Website angezeigten Links und für alle Inhalte der Seiten, zu denen die bei uns angemeldeten Banner und Links führen.
+
+# Hinweise zum Urheberrecht
+Alle auf dieser Website veröffentlichten Texte, Bild-, Ton- und Filmdokumente befinden sich im Besitz der Hochschule für Gestaltung Offenbach beziehungsweise der jeweils angegebenen Autoren. Eine – auch auszugsweise – Veröffentlichung in elektronischer oder anderer Form bedarf der ausdrücklichen vorherigen schriftlichen Zustimmung der jeweiligen Rechteinhaber. Bitte setzen Sie sich gegebenenfalls mit uns in Verbindung.
+
+# Datenschutzerklärung
+Die Datenschutzerklärung der HfG Offenbach finden Sie HIER.
+
+Zusätzliche Information
+Redaktion auf dieser Seite: Florian Albrecht-Schoeck und Sebastian Kujas
diff --git a/md/startseite.md b/md/startseite.md
index c977b89..47c59f2 100644
--- a/md/startseite.md
+++ b/md/startseite.md
@@ -1,5 +1,6 @@
---
-titel: Willkommen
+titel: hfg_linux_usergroup: free software for art and design
+beschreibung: Die hfg_linux_usergroup ist eine Gemeinschaft der HFG Offenbach für freie Software, Open Source und digitale Souveränität in Kunst und Design.
---
# Was ist die hfg_linux_usergroup
@@ -13,9 +14,13 @@ Open Source fördert nicht nur gestalterische Freiheit, sondern auch eine kritis
Die nächsten Termine für den Herbst/Winter 2026 werden aktuell geplant:
## hfg_linux_usergroup_date_1_music
+Platzhalter inhalt, um was geht es hier.
## hfg_linux_usergroup_date_2_image-editing
+Platzhalter inhalt, um was geht es hier.
## hfg_linux_usergroup_date_3_coding-development
+Platzhalter inhalt, um was geht es hier.
## hfg_linux_usergroup_date_4_3d-film-fotogrammetrie
+Platzhalter inhalt, um was geht es hier.
# Wer ist die hfg_linux_usergroup
@@ -26,6 +31,32 @@ Ziel ist es, den Einsatz freier Software in Kunst und Design zu fördern. Durch
# Das hfg_OS_
Das hfg_OS ist ein auf Debian 13 (Trixie) basierendes, Linux-basiertes Betriebssystem. Es wurde speziell für die Bedürfnisse von Künstler:innen und Designer:innen angepasst und wird kontinuierlich weiterentwickelt.
+
-Bald verfügbar: hfg_OS_Falbella-2026-10
+## Versionen
+
+
+
+| Version | Name | Platform | Filesize|
+|:-------|:-------------------:|-----------:|
+| 12.10. | hfg_OS_Falbella | X86 | 4536 MB|
+
+### Haftungsausschluss / Disclaimer
+Diese Linux-Distribution wird unentgeltlich und im Rahmen der jeweiligen Open-Source-Lizenzen (insbesondere der GNU General Public License) bereitgestellt. Die Software wird „wie besehen" („AS IS") ohne jegliche Gewährleistung bereitgestellt – ohne Mängelgewährleistung, ohne Zusicherung von Marktgängigkeit oder Eignung für einen bestimmten Zweck.
+Der Autor übernimmt keinerlei Haftung für Schäden jedweder Art – einschließlich, aber nicht beschränkt auf Datenverlust, Systemausfälle, Betriebsunterbrechungen, Folgeschäden oder indirekte Schäden –, die aus der Nutzung, dem Download, der Installation oder der Weitergabe dieser Distribution entstehen. Die Nutzung erfolgt vollständig auf eigenes Risiko.
+Es besteht kein Anspruch auf Support, Updates, Bugfixes oder Verfügbarkeit der Download-Angebote. Alle enthaltenen Softwarekomponenten bleiben Eigentum ihrer jeweiligen Urheber und unterliegen ihren eigenen Lizenzen. Marken- und Namensrechte Dritter bleiben unberührt.
+Hinweis: Erstelle vor jeder Installation ein Backup deiner Daten.
+
+
+## Integrierte Programme
+
+| Fotografie und Film |
+|:-------------------:|-----------:|
+| RaWTherpee | Darktable|
+| KDNENLive | |
+
+| Programmieren |
+|:-------------------:|-----------:|
+| VIM | KIRA|
+| VSCODIUM | |
diff --git a/output/.DS_Store b/output/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/output/.DS_Store differ
diff --git a/output/css/style.css b/output/css/style.css
index fcf3d28..127a3b5 100644
--- a/output/css/style.css
+++ b/output/css/style.css
@@ -5,7 +5,7 @@ header {
}
.pixel-horse-container {
- width: 100px;
+ width: 240px; /* Pferd + je 70px Landschaft links und rechts */
height: 100px;
position: relative;
margin: 0 auto; /* zentriert im Header */
@@ -18,23 +18,24 @@ header {
position: absolute;
top: 0;
left: 0;
- width: 100px;
+ width: 240px;
height: 100px;
opacity: 0;
- animation: run 0.5s steps(1) infinite;
+ animation: run 1s steps(1) infinite; /* 8 Frames, 125ms pro Frame */
}
.pixel-horse:nth-child(1) { animation-delay: 0s; opacity: 1; }
-.pixel-horse:nth-child(2) { animation-delay: 0.125s; }
-.pixel-horse:nth-child(3) { animation-delay: 0.25s; }
-.pixel-horse:nth-child(4) { animation-delay: 0.375s; }
+.pixel-horse:nth-child(2) { animation-delay: .125s; }
+.pixel-horse:nth-child(3) { animation-delay: .25s; }
+.pixel-horse:nth-child(4) { animation-delay: .375s; }
+.pixel-horse:nth-child(5) { animation-delay: .5s; }
+.pixel-horse:nth-child(6) { animation-delay: .625s; }
+.pixel-horse:nth-child(7) { animation-delay: .75s; }
+.pixel-horse:nth-child(8) { animation-delay: .875s; }
@keyframes run {
- 0%, 24.9% { opacity: 1; }
- 25%, 49.9% { opacity: 0; }
- 50%, 74.9% { opacity: 1; }
- 75%, 99.9% { opacity: 0; }
- 100% { opacity: 1; }
+ 0%, 12.4% { opacity: 1; }
+ 12.5%, 100% { opacity: 0; }
}
/* ================================================================
@@ -46,7 +47,7 @@ header {
--bg: #1a1a1a; /* sehr dunkles Grau */
--text: #ffffff; /* normaler Text weiss */
--dim: #909090; /* gedimmter Text (Footer, Zitate) */
- --heading: #ff9500; /* Ueberschriften orange */
+ --heading: #00ff00; /* Ueberschriften gruen wie die erste Zeile */
--link: #66aaff; /* Links, gut lesbar auf schwarz */
--green: #00ff00; /* Prompt, Code */
--border: #333333;
@@ -93,6 +94,14 @@ main {
color: var(--green);
}
+/* Prompt als Link auf die Startseite, ohne Hover-Effekt */
+a.prompt-link,
+a.prompt-link:hover {
+ color: var(--green);
+ text-decoration: none;
+ text-shadow: none;
+}
+
/* Blinkender Terminal-Cursor hinter dem Prompt */
.cursor {
display: inline-block;
@@ -112,7 +121,7 @@ main {
h1, h2, h3, h4, h5, h6 {
color: var(--heading);
- text-shadow: 0 0 8px rgba(255, 149, 0, 0.35);
+ text-shadow: 0 0 8px rgba(0, 255, 0, 0.35);
letter-spacing: 1px;
font-size: 1rem; /* 14 px, ueberall gleiche Schriftgroesse */
font-weight: normal;
@@ -127,6 +136,35 @@ p {
margin: .8rem 0;
}
+/* ---- Inhalt einruecken: ein # mehr als die uebergeordnete
+ Ueberschrift = eine Stufe (1.5rem) tiefer ---- */
+
+main div.sec {
+ margin-left: 1.5rem;
+}
+
+main div.sec0 {
+ margin-left: 0;
+}
+
+/* ---- Bilder ---- */
+
+img {
+ display: block; /* Text startet immer unter dem Bild */
+ max-width: 1200px; /* Desktop: maximal 500px breit */
+ height: auto;
+ border: 1px solid #333333; /* dunkelgrauer Rand */
+ margin: .8rem 0;
+}
+
+/* Smartphone: Bild ueber die volle Breite */
+@media (max-width: 600px) {
+ img {
+ max-width: 100%;
+ width: 100%;
+ }
+}
+
/* ---- Anker-Navigation im Header (Links auf die Ueberschriften) ---- */
.anker-nav {
@@ -204,6 +242,28 @@ hr {
margin: 1.5rem 0;
}
+/* ---- Tabellen ---- */
+
+table {
+ border-collapse: collapse;
+ margin: 1rem 0;
+}
+
+th, td {
+ border: 1px solid var(--border);
+ padding: .4rem .8rem;
+ text-align: left;
+}
+
+th {
+ color: var(--heading);
+ background: #141414;
+}
+
+td {
+ color: var(--text);
+}
+
/* ---- Code ---- */
code {
diff --git a/output/images/.DS_Store b/output/images/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/output/images/.DS_Store differ
diff --git a/output/images/hfg_os_background_1_fullhd.jpg b/output/images/hfg_os_background_1_fullhd.jpg
new file mode 100644
index 0000000..1d82c45
Binary files /dev/null and b/output/images/hfg_os_background_1_fullhd.jpg differ
diff --git a/output/images/hfglogo.png b/output/images/hfglogo.png
new file mode 100644
index 0000000..84161e7
Binary files /dev/null and b/output/images/hfglogo.png differ
diff --git a/output/images/logo.svg b/output/images/logo.svg
new file mode 100644
index 0000000..9a59969
--- /dev/null
+++ b/output/images/logo.svg
@@ -0,0 +1,148 @@
+
+
+
+
diff --git a/output/images/pferd.png b/output/images/pferd.png
new file mode 100644
index 0000000..29a5085
Binary files /dev/null and b/output/images/pferd.png differ
diff --git a/output/impressum.html b/output/impressum.html
new file mode 100644
index 0000000..a09af28
--- /dev/null
+++ b/output/impressum.html
@@ -0,0 +1,70 @@
+
+
+