mirror of
https://github.com/Misterio77/Foundry.git
synced 2026-08-24 02:14:13 -05:00
feat(projects/khora): color-code calendar events
Render calendar colors beside both event and calendar rows, including conversion of khal named and xterm palette values. Assisted-by: pi (gpt-5.6-sol)
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
_DEFAULT = "#3584e4"
|
||||
_ANSI = (
|
||||
"#241f31",
|
||||
"#c01c28",
|
||||
"#26a269",
|
||||
"#a2734c",
|
||||
"#1c71d8",
|
||||
"#a347ba",
|
||||
"#2aa1b3",
|
||||
"#deddda",
|
||||
"#5e5c64",
|
||||
"#ed333b",
|
||||
"#57e389",
|
||||
"#f8e45c",
|
||||
"#62a0ea",
|
||||
"#c061cb",
|
||||
"#5bc8d7",
|
||||
"#ffffff",
|
||||
)
|
||||
_NAMED = dict(
|
||||
zip(
|
||||
(
|
||||
"black",
|
||||
"dark red",
|
||||
"dark green",
|
||||
"brown",
|
||||
"dark blue",
|
||||
"dark magenta",
|
||||
"dark cyan",
|
||||
"white",
|
||||
"dark gray",
|
||||
"light red",
|
||||
"light green",
|
||||
"yellow",
|
||||
"light blue",
|
||||
"light magenta",
|
||||
"light cyan",
|
||||
"light gray",
|
||||
),
|
||||
_ANSI,
|
||||
strict=True,
|
||||
)
|
||||
)
|
||||
_HEX_COLOR = re.compile(r"#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?(?:[0-9a-fA-F]{2})?")
|
||||
|
||||
|
||||
def display_color(value: str | None) -> str:
|
||||
"""Turn khal's terminal-oriented color values into GTK-friendly hex."""
|
||||
if not value or value == "auto":
|
||||
return _DEFAULT
|
||||
if _HEX_COLOR.fullmatch(value):
|
||||
return value
|
||||
if value in _NAMED:
|
||||
return _NAMED[value]
|
||||
if value.isdigit() and 0 <= (index := int(value)) <= 255:
|
||||
return _xterm_color(index)
|
||||
return _DEFAULT
|
||||
|
||||
|
||||
def _xterm_color(index: int) -> str:
|
||||
if index < 16:
|
||||
return _ANSI[index]
|
||||
if index < 232:
|
||||
index -= 16
|
||||
levels = (0, 95, 135, 175, 215, 255)
|
||||
red, remainder = divmod(index, 36)
|
||||
green, blue = divmod(remainder, 6)
|
||||
return f"#{levels[red]:02x}{levels[green]:02x}{levels[blue]:02x}"
|
||||
gray = 8 + (index - 232) * 10
|
||||
return f"#{gray:02x}{gray:02x}{gray:02x}"
|
||||
@@ -8,6 +8,7 @@ gi.require_version("Adw", "1")
|
||||
gi.require_version("Gtk", "4.0")
|
||||
from gi.repository import Adw, Gio, GLib, Gtk
|
||||
|
||||
from .colors import display_color
|
||||
from .khal_adapter import KhalRepository
|
||||
from .model import Event
|
||||
|
||||
@@ -83,6 +84,7 @@ class KhoraWindow(Adw.ApplicationWindow):
|
||||
toggle = Gtk.Switch(active=True, valign=Gtk.Align.CENTER)
|
||||
toggle.connect("notify::active", self._on_calendar_toggled, calendar.name)
|
||||
row = Adw.ActionRow(title=calendar.name, activatable=True)
|
||||
row.add_prefix(self._color_dot(calendar.color))
|
||||
row.add_suffix(toggle)
|
||||
row.set_activatable_widget(toggle)
|
||||
calendars.append(row)
|
||||
@@ -136,7 +138,15 @@ class KhoraWindow(Adw.ApplicationWindow):
|
||||
details = f"{event.time_label} · {event.calendar}"
|
||||
if event.location:
|
||||
details += f" · {event.location}"
|
||||
return Adw.ActionRow(title=event.summary, subtitle=details)
|
||||
row = Adw.ActionRow(title=event.summary, subtitle=details)
|
||||
row.add_prefix(KhoraWindow._color_dot(event.color))
|
||||
return row
|
||||
|
||||
@staticmethod
|
||||
def _color_dot(color: str | None) -> Gtk.Label:
|
||||
dot = Gtk.Label(valign=Gtk.Align.CENTER)
|
||||
dot.set_markup(f'<span foreground="{display_color(color)}" size="18000">●</span>')
|
||||
return dot
|
||||
|
||||
def _on_calendar_toggled(self, button: Gtk.Switch, _property, name: str) -> None:
|
||||
if button.get_active():
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
from khora.colors import display_color
|
||||
|
||||
|
||||
def test_preserves_html_colors() -> None:
|
||||
assert display_color("#c01c28") == "#c01c28"
|
||||
|
||||
|
||||
def test_converts_khal_named_colors() -> None:
|
||||
assert display_color("light blue") == "#62a0ea"
|
||||
|
||||
|
||||
def test_converts_xterm_color_cube() -> None:
|
||||
assert display_color("196") == "#ff0000"
|
||||
|
||||
|
||||
def test_unknown_colors_use_accent_fallback() -> None:
|
||||
assert display_color("auto") == "#3584e4"
|
||||
assert display_color("chartreuse, probably") == "#3584e4"
|
||||
Reference in New Issue
Block a user