Soapbox: statisk blogg med mobilvennlig markdown-editor

Flask-app som genererer statiske sider til public/ og serverer dem
sammen med et admin-grensesnitt (/admin). Innhold ligger som markdown
og bilder i et git-repo (data/content), brukere i sqlite.

- Editor med toolbar, live server-side forhåndsvisning, bildeopplasting
  via knapp, dra-og-slipp og lim inn. Bilder nedskaleres og EXIF fjernes.
- Hovedbruker publiserer under /<slug>/, gjester under /<bruker>/<slug>/.
  Slug lages fra tittelen og fryses ved publisering.
- Alle interne lenker er relative, så siden kan flyttes mellom domener og
  sub-paths (SOAPBOX_BASE_PATH) uten rebuild.
- Tema 'green' med CSS-variabler, mørk modus og WCAG-kontrast.
- Containerfile (python:alpine + git), compose.yaml og Caddyfile-eksempel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
This commit is contained in:
Ole-Morten Duesund 2026-08-26 12:12:33 +02:00
commit 7ab2320be6
35 changed files with 2726 additions and 0 deletions

31
soapbox/slug.py Normal file
View file

@ -0,0 +1,31 @@
"""Lager URL-vennlige slugs fra titler.
Norske tegn translittereres eksplisitt (æae, øoe, åaa) fordi generisk
unicode-normalisering ville mistet dem helt ("blåbær" "blbr").
"""
from __future__ import annotations
import re
import unicodedata
_NORDIC = str.maketrans(
{"æ": "ae", "ø": "oe", "å": "aa", "ä": "ae", "ö": "oe", "ü": "ue", "ß": "ss"}
)
def slugify(text: str) -> str:
text = text.lower().translate(_NORDIC)
text = unicodedata.normalize("NFKD", text).encode("ascii", "ignore").decode()
text = re.sub(r"[^a-z0-9]+", "-", text).strip("-")
return text or "post"
def unique_slug(base: str, taken: set[str]) -> str:
"""Returnerer ``base`` eller ``base-2``, ``base-3`` … til den er ledig."""
if base not in taken:
return base
n = 2
while f"{base}-{n}" in taken:
n += 1
return f"{base}-{n}"