mirror of
https://github.com/caelestia-dots/cli.git
synced 2026-10-13 23:33:32 -05:00
feat: more template variables (#147)
* feat(templates): add rgb/hsl channel variables to colour templates * fix(templates): coerce colour channel values to str in dynamic templates
This commit is contained in:
@@ -171,12 +171,15 @@ Custom user templates can be defined in `~/.config/caelestia/templates/`.
|
||||
`{{ <color>.<format> }}`
|
||||
|
||||
- `<color>` is a theme color role derived from the Material You color system (e.g. `primary`, `secondary`, `background`)
|
||||
- `<format>` is the output format: `hex` or `rgb`
|
||||
- `<format>` is the output format: `hex`, `rgb`, `hsl`, or a single channel (`red`, `green`, `blue`, `hue`, `saturation`, `lightness`)
|
||||
|
||||
#### Examples
|
||||
|
||||
- `{{ primary.hex }}` outputs `3f4ba2`
|
||||
- `{{ primary.rgb }}` outputs `rgb(193, 132, 207)`
|
||||
- `{{ primary.red }}` outputs `193`
|
||||
- `{{ primary.hsl }}` outputs `hsl(268,41%,66%)`
|
||||
- `{{ primary.hue }}` outputs `268`
|
||||
|
||||
Output files are written to `~/.local/state/caelestia/theme/`. You can symlink them to your desired locations.
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
class Colour:
|
||||
_rgb_vals: tuple[int, ...]
|
||||
_hex_vals: tuple[str, ...]
|
||||
_hsl_vals: tuple[int, int, int]
|
||||
|
||||
def __init__(self, hex: str):
|
||||
hex = hex.ljust(8, "f")
|
||||
self._hex_vals = tuple(hex[i : i + 2] for i in range(0, 7, 2))
|
||||
self._rgb_vals = tuple(int(h, 16) for h in self._hex_vals)
|
||||
self._hsl_vals = self._to_hsl(self._rgb_vals)
|
||||
|
||||
@property
|
||||
def hex(self) -> str:
|
||||
@@ -23,6 +25,54 @@ class Colour:
|
||||
def rgbalpha(self) -> str:
|
||||
return f"rgba({','.join(map(str, self._rgb_vals))})"
|
||||
|
||||
@property
|
||||
def red(self) -> int:
|
||||
return self._rgb_vals[0]
|
||||
|
||||
@property
|
||||
def green(self) -> int:
|
||||
return self._rgb_vals[1]
|
||||
|
||||
@property
|
||||
def blue(self) -> int:
|
||||
return self._rgb_vals[2]
|
||||
|
||||
@property
|
||||
def hsl(self) -> str:
|
||||
return f"hsl({self._hsl_vals[0]},{self._hsl_vals[1]}%,{self._hsl_vals[2]}%)"
|
||||
|
||||
@property
|
||||
def hue(self) -> int:
|
||||
return self._hsl_vals[0]
|
||||
|
||||
@property
|
||||
def saturation(self) -> int:
|
||||
return self._hsl_vals[1]
|
||||
|
||||
@property
|
||||
def lightness(self) -> int:
|
||||
return self._hsl_vals[2]
|
||||
|
||||
@staticmethod
|
||||
def _to_hsl(rgb: tuple[int, ...]) -> tuple[int, int, int]:
|
||||
r, g, b = (v / 255 for v in rgb[:3])
|
||||
cmax, cmin = max(r, g, b), min(r, g, b)
|
||||
delta = cmax - cmin
|
||||
|
||||
lightness = (cmax + cmin) / 2
|
||||
saturation = 0 if delta == 0 else delta / (1 - abs(2 * lightness - 1))
|
||||
|
||||
if delta == 0:
|
||||
hue = 0
|
||||
elif cmax == r:
|
||||
hue = 60 * (((g - b) / delta) % 6)
|
||||
elif cmax == g:
|
||||
hue = 60 * (((b - r) / delta) + 2)
|
||||
else:
|
||||
hue = 60 * (((r - g) / delta) + 4)
|
||||
|
||||
return round(hue), round(saturation * 100), round(lightness * 100)
|
||||
|
||||
|
||||
def get_dynamic_colours(colours: dict[str, str]) -> dict[str, Colour]:
|
||||
return {name: Colour(code) for name, code in colours.items()}
|
||||
|
||||
@@ -60,7 +60,7 @@ def gen_replace_dynamic(colours: dict[str, str], template: Path, mode: str) -> s
|
||||
col, form = data
|
||||
if col not in colours_dyn or not hasattr(colours_dyn[col], form):
|
||||
return match.group()
|
||||
return getattr(colours_dyn[col], form)
|
||||
return str(getattr(colours_dyn[col], form))
|
||||
|
||||
# match atomic {{ . }} pairs
|
||||
dotField = r"\{\{((?:(?!\{\{|\}\}).)*)\}\}"
|
||||
|
||||
Reference in New Issue
Block a user