Files
website/tools/content/site_themes.py
T

88 lines
2.6 KiB
Python

import re
import jsonfile
THEMES_FILE = "themes.json"
DESKTOP_FILE = "desktop.json"
THEME_MODES = ["dark", "light"]
COLOR_KEYS = [
"accent",
"selection",
"muted",
"background",
"dark_background",
"lighter_background",
"foreground",
"red",
"yellow",
"orange",
"green",
"cyan",
"blue",
"magenta",
]
HEX_COLOR_PATTERN = re.compile(r"^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$")
ID_PATTERN = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
def load_themes() -> list[dict]:
return jsonfile.load(THEMES_FILE)
def save_themes(themes: list[dict]) -> None:
jsonfile.save(THEMES_FILE, themes)
def find_theme(themes: list[dict], theme_id: str) -> dict | None:
return next((theme for theme in themes if theme.get("id") == theme_id), None)
def default_theme_id() -> str | None:
try:
return jsonfile.load(DESKTOP_FILE).get("defaultTheme")
except (OSError, ValueError):
return None
def set_default_theme(theme_id: str) -> None:
desktop = jsonfile.load(DESKTOP_FILE)
desktop["defaultTheme"] = theme_id
jsonfile.save(DESKTOP_FILE, desktop)
def check_theme(theme: dict) -> dict:
if not ID_PATTERN.match(theme.get("id", "")):
raise ValueError("Theme id must be lowercase letters, numbers and dashes")
if theme.get("mode") not in THEME_MODES:
raise ValueError("Mode must be dark or light")
for key in COLOR_KEYS:
if not HEX_COLOR_PATTERN.match(theme.get("colors", {}).get(key, "")):
raise ValueError(f"{key} must be a hex color like #818cf8")
for color in theme.get("activeBorder") or []:
if not HEX_COLOR_PATTERN.match(color):
raise ValueError("Active border colors must be hex colors")
return theme
def save_theme(original_id: str | None, theme: dict) -> None:
check_theme(theme)
themes = load_themes()
duplicate = find_theme(themes, theme["id"])
if duplicate and theme["id"] != original_id:
raise ValueError(f"A theme with the id {theme['id']} already exists")
if original_id is None:
themes.append(theme)
else:
index = next(index for index, item in enumerate(themes) if item.get("id") == original_id)
themes[index] = theme
if original_id != theme["id"] and default_theme_id() == original_id:
set_default_theme(theme["id"])
save_themes(themes)
def remove_theme(theme_id: str) -> None:
if default_theme_id() == theme_id:
raise ValueError("That is the default theme. Pick another default first")
themes = [theme for theme in load_themes() if theme.get("id") != theme_id]
save_themes(themes)