Files
computer-playbook/tests/unit/python/utils/design/test_preview.py
T
kevinveenbirkenbachandClaude Opus 5.5 024259e89d feat(design): recolour single-colour logos per slot and preview every app's assets
A logo whose solid pixels share one colour (alpha >= 128, every channel within 24) is detected once per file and tinted to the text colour of each slot: frame_fill on frame slots, fill elsewhere, plus a prefers-color-scheme: dark variant in the SVG of page slots and the page text colour for the favicon. Edge pixels below half opacity are ignored so antialiasing does not count as a second colour. Multi-colour logos render byte-identical to before.

make design-logos (alias i8delo) renders every role with a design entry from one logo and base colour into an HTML page with day and night tiles, without a deploy. Slots render in four threads and roles in one process per CPU: the full preview went from 287.6s to 33.2s with identical output (diff -rq over 1229 PNGs). A GPU does not pay off for these PIL resizes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 16:06:30 +01:00

69 lines
2.4 KiB
Python

import tempfile
import unittest
from pathlib import Path
from PIL import Image, ImageDraw
from utils.design.branding import DESIGN_ROLE
from utils.design.preview import build_preview, design_roles, role_domain
from . import PROJECT_ROOT
ROLES_DIR = PROJECT_ROOT / "roles"
ROLE = "web-app-gitea"
def _mono_logo(path: Path) -> str:
image = Image.new("RGBA", (120, 120), (0, 0, 0, 0))
ImageDraw.Draw(image).ellipse((10, 10, 110, 110), fill="#000000")
image.save(path)
return str(path)
class TestDesignRoles(unittest.TestCase):
def test_lists_design_consumers_without_the_provider(self) -> None:
roles = design_roles(ROLES_DIR)
self.assertIn(ROLE, roles)
self.assertNotIn(DESIGN_ROLE, roles)
self.assertEqual(roles, sorted(roles))
class TestRoleDomain(unittest.TestCase):
def test_renders_the_primary_domain_into_the_canonical_domain(self) -> None:
domain = role_domain(ROLES_DIR, ROLE, "example.org")
self.assertTrue(domain.endswith(".example.org"), domain)
self.assertNotIn("{{", domain)
def test_falls_back_to_the_role_name_without_domains(self) -> None:
self.assertEqual(
role_domain(ROLES_DIR, "does-not-exist", "example.org"),
"does-not-exist.example.org",
)
class TestBuildPreview(unittest.TestCase):
def test_writes_every_slot_day_and_night_and_an_index(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
logo = _mono_logo(root / "logo.png")
index = build_preview(
logo, "#8DB33A", "example.org", [ROLE], root / "out", PROJECT_ROOT
)
html = index.read_text(encoding="utf-8") # nocheck: cache-read
role_dir = root / "out" / ROLE
self.assertIn(ROLE, html)
self.assertIn("monochrome, recolored per slot", html)
self.assertNotIn("{{", html)
self.assertTrue((role_dir / "favicon.ico").is_file())
pngs = {path.name for path in role_dir.glob("*.png")}
day = {name for name in pngs if not name.endswith(".night.png")}
self.assertTrue(day)
for name in day:
with self.subTest(slot=name):
self.assertIn(f"{ROLE}/{name}", html)
self.assertTrue(any(name.endswith(".night.png") for name in pngs))
if __name__ == "__main__":
unittest.main()