Files
computer-playbook/plugins/lookup/design.py
T
kevinveenbirkenbachandClaude Opus 5.5 724c4c2b5d feat(design): render a lockup on brand chrome in the frame text color
A generated lockup drew its title in the primary color with an
on-primary outline. On a header or sidebar that a role maps onto the
frame token, that put primary-colored text on a primary-toned ground.

A slot now takes `frame: true` in the role's design entry. The asset
action receives a second color pair from the palette, the on-frame
color as fill and the frame color as outline, and the renderer picks
the pair per slot. Slots without the flag render as before.

Keycloak calls the asset action directly and already rendered its
brand slot in the on-frame color, so it passes that color for both
pairs and keeps its output.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-07 15:38:09 +02:00

64 lines
2.3 KiB
Python

from __future__ import annotations
from pathlib import Path
from typing import Any
from ansible.errors import AnsibleError
from ansible.plugins.loader import lookup_loader
from ansible.plugins.lookup import LookupBase
from utils.design.branding import asset_urls, resolve_branding
ASSET_DIR = "design"
class LookupModule(LookupBase):
"""
lookup('design', application_id)
Returns the resolved corporate branding of one role:
logo absolute logo path, or False when the replacement is disabled
title title text, or False when the replacement is disabled
name role README H1
label title, else name (for installers that require a site name)
slots {name: {width, height, text_only, frame}}
domain canonical domain of the role
dest CDN directory the generated assets are written to
urls {"favicon_ico": url, "<slot>": {"png": url, "svg": url}}
"""
def _sub(self, name: str, terms: list, variables: dict[str, Any]) -> Any:
plugin = lookup_loader.get(
name,
loader=getattr(self, "_loader", None),
templar=getattr(self, "_templar", None),
)
return plugin.run(terms, variables=variables)[0]
def run(self, terms, variables: dict[str, Any] | None = None, **kwargs):
variables = variables or {}
if len(terms) != 1:
raise AnsibleError("design: expects exactly one application_id")
application_id = str(terms[0]).strip()
root = variables.get("playbook_dir")
if not root:
raise AnsibleError("design: 'playbook_dir' is unavailable")
applications = self._sub("applications", [], variables)
try:
branding = resolve_branding(applications, application_id, Path(str(root)))
except (KeyError, ValueError) as exc:
raise AnsibleError(f"design: {exc}") from exc
cdn = self._sub("cdn", [application_id], variables)
base_url = f"{cdn['urls']['role']['release']['img'].rstrip('/')}/{ASSET_DIR}"
return [
{
**branding,
"domain": self._sub("domain", [application_id], variables),
"dest": str(Path(cdn["role"]["release"]["img"]) / ASSET_DIR),
"urls": asset_urls(base_url, branding["slots"]),
}
]