"""Per-app glyph artwork for the shared icon family. A glyph is a raw SVG fragment drawn in the 1024x1024 master canvas. It does not need to be perfectly positioned: :mod:`python_pkg.app_icons.render` measures the rendered ink and recentres the fragment, so every icon in the family sits at the same optical height. Fragments inherit ``fill="none"``, ``stroke``, ``stroke-width`` and round caps from the wrapping group. A fragment that needs a filled silhouette instead overrides those locally and uses :data:`~python_pkg.app_icons.style.ACCENT_MARKER` for its colour. """ from __future__ import annotations from dataclasses import dataclass from typing import Final @dataclass(frozen=True) class Glyph: """One app's artwork. Parameters: name (str): Stable identifier, used as the ``--glyph`` CLI value. description (str): What the glyph depicts, for ``--list`` output. body (str): SVG fragment drawn in the 1024x1024 master canvas. """ name: str description: str body: str # A cloud silhouette outline with a download arrow underneath: a client that # pulls files off a remote dufs server. _CLOUD_DOWN = """\ """ # Bar, two plates and two collars. Plate spacing is well above the minimum # negative space so the bar does not fill in at launcher size. _BARBELL = """\ """ # Plain clock face. Deliberately no bell "ears": at launcher size they read as # noise rather than as an alarm clock. _CLOCK = """\ """ # Shield outline guarding filled cutlery. The fork is paired with a knife on # purpose: a lone three-tine fork reads as a trident at small sizes. _SHIELD_CUTLERY = """\ """ # Two ticked-off list rows. More specific to a notes/todo app than a lone # checkmark, and still legible at 48dp. _CHECKLIST = """\ """ # Two interlocking stadium (pill-ring) outlines, both rotated -45 deg and # offset along the anti-diagonal so their strokes overlap in the middle -- # reads as both "habit-stacking" (linked items) and "don't break the chain". # Ring height is tall enough that the 72px stroke leaves a genuinely hollow # interior (height - 2*stroke-width well above MIN_NEGATIVE_SPACE); a # shorter ring's stroke fills the interior solid and reads as a blob. _CHAIN_LINK = """\ """ GLYPHS: Final[dict[str, Glyph]] = { glyph.name: glyph for glyph in ( Glyph("cloud-down", "Cloud with a download arrow", _CLOUD_DOWN), Glyph("barbell", "Barbell with plates and collars", _BARBELL), Glyph("clock", "Clock face with hands", _CLOCK), Glyph("shield-cutlery", "Shield guarding a fork and knife", _SHIELD_CUTLERY), Glyph("checklist", "Two ticked-off list rows", _CHECKLIST), Glyph("chain-link", "Two interlocking chain links", _CHAIN_LINK), ) } def get_glyph(name: str) -> Glyph: """Look up a glyph by name. Parameters: name (str): Glyph identifier, e.g. ``"barbell"``. Returns: Glyph: The matching glyph. Raises: KeyError: If no glyph with that name exists. The message lists the available names, since this is usually a CLI typo. """ try: return GLYPHS[name] except KeyError: available = ", ".join(sorted(GLYPHS)) msg = f"unknown glyph {name!r}; available: {available}" raise KeyError(msg) from None