soapbox/soapbox/slug.py
Ole-Morten Duesund 7ab2320be6 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
2026-08-26 12:12:33 +02:00

31 lines
883 B
Python

"""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}"