hadalized 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hadalized/__init__.py +1 -0
- hadalized/__main__.py +6 -0
- hadalized/base.py +137 -0
- hadalized/cache.py +121 -0
- hadalized/cli/__init__.py +1 -0
- hadalized/cli/main.py +221 -0
- hadalized/color.py +595 -0
- hadalized/config.py +442 -0
- hadalized/const.py +6 -0
- hadalized/convert.py.bak +1903 -0
- hadalized/homedirs.py +69 -0
- hadalized/options.py +134 -0
- hadalized/palette.py +133 -0
- hadalized/templates/colors.html +21 -0
- hadalized/templates/config.toml +15 -0
- hadalized/templates/generic.txt +1 -0
- hadalized/templates/item.html +1 -0
- hadalized/templates/lua_module.lua +6 -0
- hadalized/templates/model_dump.json +1 -0
- hadalized/templates/neovim.lua +24 -0
- hadalized/templates/neovim_palette.lua +7 -0
- hadalized/templates/palette.html +53 -0
- hadalized/templates/palette_info.json +1 -0
- hadalized/templates/palette_test.toml +10 -0
- hadalized/templates/starship-all.toml +98 -0
- hadalized/templates/starship.toml +233 -0
- hadalized/templates/wezterm.toml +45 -0
- hadalized/web.py +168 -0
- hadalized/writer.py +243 -0
- hadalized-0.4.0.dist-info/METADATA +79 -0
- hadalized-0.4.0.dist-info/RECORD +33 -0
- hadalized-0.4.0.dist-info/WHEEL +4 -0
- hadalized-0.4.0.dist-info/entry_points.txt +4 -0
hadalized/color.py
ADDED
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
"""Color string parsing and information extraction."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from enum import StrEnum, auto
|
|
5
|
+
from typing import Self
|
|
6
|
+
|
|
7
|
+
from coloraide import Color as ColorBase
|
|
8
|
+
from pydantic import Field, PrivateAttr
|
|
9
|
+
|
|
10
|
+
from hadalized.base import BaseNode
|
|
11
|
+
|
|
12
|
+
type ColorField = ColorInfo | str
|
|
13
|
+
"""A field value containing either full ColorInfo for a specific space / gamut
|
|
14
|
+
parseable string representation of a color."""
|
|
15
|
+
|
|
16
|
+
type ColorFieldStr = str
|
|
17
|
+
|
|
18
|
+
type ColorFieldHandler = Callable[[ColorField], ColorField]
|
|
19
|
+
"""A function that can be mapped across"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Ref:
|
|
23
|
+
"""Color definitions references."""
|
|
24
|
+
|
|
25
|
+
black: ColorField = "oklch(0.10 0.01 220)"
|
|
26
|
+
darkgray: ColorField = "oklch(0.30 0.01 220)"
|
|
27
|
+
darkslategray: ColorField = "oklch(0.30 0.03 220)"
|
|
28
|
+
gray: ColorField = "oklch(0.50 0.01 220)"
|
|
29
|
+
slategray: ColorField = "oklch(0.600 0.03 220)"
|
|
30
|
+
lightgray: ColorField = "oklch(0.70 0.01 220)"
|
|
31
|
+
lightslategray: ColorField = "oklch(0.700 0.02 220)"
|
|
32
|
+
white: ColorField = "oklch(0.995 0.01 220)"
|
|
33
|
+
# blues, high chroma
|
|
34
|
+
b12: ColorField = "oklch(0.125 0.030 220)"
|
|
35
|
+
b13: ColorField = "oklch(0.130 0.030 220)"
|
|
36
|
+
b14: ColorField = "oklch(0.140 0.030 220)"
|
|
37
|
+
b16: ColorField = "oklch(0.1625 0.030 220)"
|
|
38
|
+
b20: ColorField = "oklch(0.200 .030 220)"
|
|
39
|
+
b25: ColorField = "oklch(0.250 .030 220)"
|
|
40
|
+
b30: ColorField = "oklch(0.300 .035 220)"
|
|
41
|
+
b35: ColorField = "oklch(0.350 .035 220)"
|
|
42
|
+
# grays, mid chroma
|
|
43
|
+
g20: ColorField = "oklch(0.200 .010 220)"
|
|
44
|
+
g30: ColorField = "oklch(0.300 .010 220)"
|
|
45
|
+
g35: ColorField = "oklch(0.350 .010 220)"
|
|
46
|
+
g45: ColorField = "oklch(0.450 .010 220)"
|
|
47
|
+
g60: ColorField = "oklch(0.600 .010 220)"
|
|
48
|
+
g65: ColorField = "oklch(0.650 .010 220)"
|
|
49
|
+
g70: ColorField = "oklch(0.700 .010 220)"
|
|
50
|
+
g75: ColorField = "oklch(0.750 .010 220)"
|
|
51
|
+
g80: ColorField = "oklch(0.800 .010 220)"
|
|
52
|
+
g90: ColorField = "oklch(0.900 .010 220)"
|
|
53
|
+
# Sun / Day high chroma
|
|
54
|
+
s80: ColorField = "oklch(0.800 .020 100)"
|
|
55
|
+
s85: ColorField = "oklch(0.850 .020 100)"
|
|
56
|
+
s90: ColorField = "oklch(0.900 .020 100)"
|
|
57
|
+
s91: ColorField = "oklch(0.910 .020 100)"
|
|
58
|
+
s92: ColorField = "oklch(0.925 .020 100)"
|
|
59
|
+
s95: ColorField = "oklch(0.950 .020 100)"
|
|
60
|
+
s97: ColorField = "oklch(0.975 .015 100)"
|
|
61
|
+
s99: ColorField = "oklch(0.990 .010 100)"
|
|
62
|
+
s100: ColorField = "oklch(0.995 .010 100)"
|
|
63
|
+
# whites, low chroma
|
|
64
|
+
w13: ColorField = "oklch(0.13 0.005 220)"
|
|
65
|
+
w14: ColorField = "oklch(0.14 0.005 220)"
|
|
66
|
+
w16: ColorField = "oklch(0.16 0.005 220)"
|
|
67
|
+
w20: ColorField = "oklch(0.20 0.005 220)"
|
|
68
|
+
w25: ColorField = "oklch(0.25 0.005 220)"
|
|
69
|
+
w30: ColorField = "oklch(0.30 0.005 220)"
|
|
70
|
+
w35: ColorField = "oklch(0.35 0.005 220)"
|
|
71
|
+
w80: ColorField = "oklch(0.800 .005 100)"
|
|
72
|
+
w85: ColorField = "oklch(0.850 .005 100)"
|
|
73
|
+
w90: ColorField = "oklch(0.900 .005 100)"
|
|
74
|
+
w91: ColorField = "oklch(0.910 .005 100)"
|
|
75
|
+
w92: ColorField = "oklch(0.925 .005 100)"
|
|
76
|
+
w95: ColorField = "oklch(0.950 .005 100)"
|
|
77
|
+
w97: ColorField = "oklch(0.975 .005 100)"
|
|
78
|
+
w99: ColorField = "oklch(0.990 .005 100)"
|
|
79
|
+
w100: ColorField = "oklch(0.995 .005 100)"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ColorSpace(StrEnum):
|
|
83
|
+
"""Colorspace constants."""
|
|
84
|
+
|
|
85
|
+
srgb = auto()
|
|
86
|
+
display_p3 = "display-p3"
|
|
87
|
+
oklch = auto()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class ColorFieldType(StrEnum):
|
|
91
|
+
"""Constants representing nodes in a ColorInfo object.
|
|
92
|
+
|
|
93
|
+
Use in build directives to declaratively apply transformations to
|
|
94
|
+
Palette ColorMap fields.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
info = auto()
|
|
98
|
+
"""Indicates a ColorField is a ``ColorInfo`` instance."""
|
|
99
|
+
hex = auto()
|
|
100
|
+
"""Indicates a ColorField should be a RGB hex code in a specified gamut."""
|
|
101
|
+
oklch = auto()
|
|
102
|
+
"""Indicates a ColorField should be a oklch css code in a specified gamut."""
|
|
103
|
+
css = auto()
|
|
104
|
+
"""Indicates a ColorField should be a css code in a specified gamut."""
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class ColorInfo(BaseNode):
|
|
108
|
+
"""Detailed information about a specific color.
|
|
109
|
+
|
|
110
|
+
Use the `parse` function to instantiate an instance rather than doing so
|
|
111
|
+
directly to ensure the raw value is parseable.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
raw: str = Field(examples=["oklch(0.6 0.2 25)", "#010203"])
|
|
115
|
+
# parsed: ColorBase = Field(exclude=True)
|
|
116
|
+
"""Parseable color definition, e.g., a css value."""
|
|
117
|
+
gamut: str = Field(
|
|
118
|
+
default=ColorSpace.srgb,
|
|
119
|
+
examples=["srgb", "display-p3"],
|
|
120
|
+
)
|
|
121
|
+
"""Target gamut to fit the raw color definition to."""
|
|
122
|
+
raw_oklch: ColorFieldStr
|
|
123
|
+
"""Raw input in the oklch colorspace."""
|
|
124
|
+
oklch: ColorFieldStr
|
|
125
|
+
"""OKLCH value fit to the specified `gamut`."""
|
|
126
|
+
css: ColorFieldStr
|
|
127
|
+
"""CSS value in the gamut."""
|
|
128
|
+
hex: ColorFieldStr
|
|
129
|
+
"""24 or 32-bit hex representation for RGB gamuts."""
|
|
130
|
+
is_in_gamut: bool
|
|
131
|
+
"""Indicates whether the raw value is within the color gamut."""
|
|
132
|
+
max_oklch_chroma: float
|
|
133
|
+
"""The maximum oklch chroma value determined from the fit method."""
|
|
134
|
+
_color: ColorBase | None = PrivateAttr(None)
|
|
135
|
+
"""Parsed instance."""
|
|
136
|
+
|
|
137
|
+
def color(self) -> ColorBase:
|
|
138
|
+
"""Coloraide.Color object parsed from the definition.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
A coloraide.Color instance.
|
|
142
|
+
|
|
143
|
+
"""
|
|
144
|
+
if self._color is None:
|
|
145
|
+
self._color = ColorBase(self.raw)
|
|
146
|
+
return self._color
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class Parser:
|
|
150
|
+
"""Parse raw color strings."""
|
|
151
|
+
|
|
152
|
+
def __init__(self, gamut: str = ColorSpace.srgb, fit_method: str = "raytrace"):
|
|
153
|
+
"""Set gamut and fit method."""
|
|
154
|
+
self.gamut = gamut
|
|
155
|
+
self.fit_method = fit_method
|
|
156
|
+
|
|
157
|
+
@staticmethod
|
|
158
|
+
def _to_hex(val: ColorBase) -> str:
|
|
159
|
+
"""Convert RGB to their corresponding 24-bit or 34-bit hex color code.
|
|
160
|
+
|
|
161
|
+
Used primarily to extract a hex code for use
|
|
162
|
+
in programs--such as neovim--that only allow specifying colors
|
|
163
|
+
via RGB channels.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
A hex color code.
|
|
167
|
+
|
|
168
|
+
"""
|
|
169
|
+
if val.space() != ColorSpace.srgb:
|
|
170
|
+
val = ColorBase(ColorSpace.srgb, val.coords(), alpha=val.alpha())
|
|
171
|
+
return val.to_string(hex=True)
|
|
172
|
+
|
|
173
|
+
def _fit(self, val: ColorBase) -> ColorBase:
|
|
174
|
+
return val.clone().fit(self.gamut, method=self.fit_method)
|
|
175
|
+
|
|
176
|
+
def _max_oklch_chroma(self, val: ColorBase) -> float:
|
|
177
|
+
"""Determine maximum OKLCH chroma in the gamut for fixed lightness and hue.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
OKLCH chroma value.
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
if val.space() != ColorSpace.oklch:
|
|
184
|
+
val = val.convert("oklch")
|
|
185
|
+
lightness, _, hue = val.coords()
|
|
186
|
+
cmax = ColorBase("oklch", (lightness, 0.4, hue))
|
|
187
|
+
return self._fit(cmax).get("chroma")
|
|
188
|
+
|
|
189
|
+
def __call__(self, val: ColorField) -> ColorInfo:
|
|
190
|
+
"""Parse a string representation of a color.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
A ColorInfo instance parsed from the input string. Raises a
|
|
194
|
+
ValueError if the input is not parseable.
|
|
195
|
+
|
|
196
|
+
"""
|
|
197
|
+
if isinstance(val, ColorInfo):
|
|
198
|
+
return val
|
|
199
|
+
raw_color = ColorBase(val)
|
|
200
|
+
if raw_color.space() != ColorSpace.oklch:
|
|
201
|
+
raw_oklch = raw_color.convert(ColorSpace.oklch)
|
|
202
|
+
else:
|
|
203
|
+
raw_oklch = raw_color
|
|
204
|
+
|
|
205
|
+
oklch_fit = self._fit(raw_oklch)
|
|
206
|
+
color = oklch_fit.convert(self.gamut)
|
|
207
|
+
|
|
208
|
+
inst = ColorInfo(
|
|
209
|
+
raw=val,
|
|
210
|
+
raw_oklch=raw_oklch.to_string(),
|
|
211
|
+
gamut=self.gamut,
|
|
212
|
+
oklch=oklch_fit.to_string(),
|
|
213
|
+
css=color.to_string(),
|
|
214
|
+
hex=self._to_hex(color),
|
|
215
|
+
is_in_gamut=raw_oklch.convert(self.gamut).in_gamut(),
|
|
216
|
+
max_oklch_chroma=self._max_oklch_chroma(raw_oklch),
|
|
217
|
+
)
|
|
218
|
+
inst._color = raw_color
|
|
219
|
+
return inst
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class Extractor:
|
|
223
|
+
"""A ColorFieldHandler that extracts ``ColorInfo`` field values.
|
|
224
|
+
|
|
225
|
+
Attrs:
|
|
226
|
+
field (ColorFieldType): Which field will be extracted.
|
|
227
|
+
is_identity: Indicates whether the extractor is the identity function.
|
|
228
|
+
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
def __init__(self, field: str | ColorFieldType):
|
|
232
|
+
"""Validate input as a ColorFieldType."""
|
|
233
|
+
self.field = ColorFieldType(field)
|
|
234
|
+
self.is_identity = self.field == ColorFieldType.info
|
|
235
|
+
|
|
236
|
+
def __call__(self, val: ColorField) -> ColorField:
|
|
237
|
+
"""Extract field value from the input.
|
|
238
|
+
|
|
239
|
+
Calling twice results in a TypeError, to avoid uncaught errors
|
|
240
|
+
when chaining extractors. An expection is when the extractor
|
|
241
|
+
represents the identity function.
|
|
242
|
+
|
|
243
|
+
Raises:
|
|
244
|
+
TypeError: When the input is not a ``ColorInfo`` instance.
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
A ``ColorInfo`` field value defined by the ``field`` attr
|
|
248
|
+
or the ColorInfo instance itself in case when the extractor is
|
|
249
|
+
the identity function.
|
|
250
|
+
|
|
251
|
+
"""
|
|
252
|
+
if not isinstance(val, ColorInfo):
|
|
253
|
+
clsname = ColorInfo.__name__
|
|
254
|
+
raise TypeError(f"Input type {type(val)} is not a {clsname} instance.")
|
|
255
|
+
return val if self.is_identity else val[self.field]
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class Hue(StrEnum):
|
|
259
|
+
"""Named hues. These represent the fields of a ``Hues`` instance."""
|
|
260
|
+
|
|
261
|
+
red = auto()
|
|
262
|
+
orange = auto()
|
|
263
|
+
yellow = auto()
|
|
264
|
+
lime = auto()
|
|
265
|
+
green = auto()
|
|
266
|
+
mint = auto()
|
|
267
|
+
cyan = auto()
|
|
268
|
+
azure = auto()
|
|
269
|
+
blue = auto()
|
|
270
|
+
violet = auto()
|
|
271
|
+
magenta = auto()
|
|
272
|
+
rose = auto()
|
|
273
|
+
|
|
274
|
+
@staticmethod
|
|
275
|
+
def get(index: int) -> Hue:
|
|
276
|
+
"""Get a Hue color by integer index.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
Hue value corresponding to the index.
|
|
280
|
+
|
|
281
|
+
"""
|
|
282
|
+
return _hue_lu[index]
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
_hue_lu = (
|
|
286
|
+
Hue.red, # 0
|
|
287
|
+
Hue.orange, # 1
|
|
288
|
+
Hue.yellow, # 2
|
|
289
|
+
Hue.lime, # 3
|
|
290
|
+
Hue.green, # 4
|
|
291
|
+
Hue.mint, # 5
|
|
292
|
+
Hue.cyan, # 6
|
|
293
|
+
Hue.azure, # 7
|
|
294
|
+
Hue.blue, # 8
|
|
295
|
+
Hue.violet, # 9
|
|
296
|
+
Hue.magenta, # 10, A
|
|
297
|
+
Hue.rose, # 11, B
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
class HueAlias(BaseNode):
|
|
302
|
+
"""A mapping from indexed color names to ``Hues`` fields."""
|
|
303
|
+
|
|
304
|
+
c0: Hue = Hue.get(0)
|
|
305
|
+
c1: Hue = Hue.get(1)
|
|
306
|
+
c2: Hue = Hue.get(2)
|
|
307
|
+
c3: Hue = Hue.get(3)
|
|
308
|
+
c4: Hue = Hue.get(4)
|
|
309
|
+
c5: Hue = Hue.get(5)
|
|
310
|
+
c6: Hue = Hue.get(6)
|
|
311
|
+
c7: Hue = Hue.get(7)
|
|
312
|
+
c8: Hue = Hue.get(8)
|
|
313
|
+
c9: Hue = Hue.get(9)
|
|
314
|
+
ca: Hue = Hue.get(0xA)
|
|
315
|
+
cb: Hue = Hue.get(0xB)
|
|
316
|
+
|
|
317
|
+
def model_post_init(self, context, /) -> None:
|
|
318
|
+
"""Validate each Hue appears exactly once.
|
|
319
|
+
|
|
320
|
+
Raises:
|
|
321
|
+
ValueError: If there are not the same number of values as field names.
|
|
322
|
+
|
|
323
|
+
"""
|
|
324
|
+
required_len = len(self)
|
|
325
|
+
vals = (v for _, v in self)
|
|
326
|
+
if len(set(vals)) != required_len:
|
|
327
|
+
raise ValueError(f"Instance must contain {required_len} unique values.")
|
|
328
|
+
return super().model_post_init(context)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class ColorMap(BaseNode):
|
|
332
|
+
"""Base dataclass for mappings of the form color name -> ColorInfo.
|
|
333
|
+
|
|
334
|
+
The fields can either be a complete object containing data for all
|
|
335
|
+
gamuts, gamut specific color info, or a string. While the model itself
|
|
336
|
+
does not enforce uniformity of type among the strings, the data structure
|
|
337
|
+
should typically be equivalent to one of
|
|
338
|
+
Mapping[str, ColorInfo]
|
|
339
|
+
Mapping[str, GamutColor]
|
|
340
|
+
Mapping[str, str]
|
|
341
|
+
Instances containing values other than ColorInfo are obtained via transform
|
|
342
|
+
methods.
|
|
343
|
+
"""
|
|
344
|
+
|
|
345
|
+
_field_type: ColorFieldType | None = PrivateAttr(default=None)
|
|
346
|
+
|
|
347
|
+
@property
|
|
348
|
+
def field_type(self) -> ColorFieldType | None:
|
|
349
|
+
"""What the field values represent."""
|
|
350
|
+
return self._field_type
|
|
351
|
+
|
|
352
|
+
def map(self, handler: ColorFieldHandler) -> Self:
|
|
353
|
+
"""Apply a generic color field handler to each field.
|
|
354
|
+
|
|
355
|
+
Example handlers enclude
|
|
356
|
+
- field extractors, e.g., mapping a parsed instance to specific field
|
|
357
|
+
- parsers, to convert from string color definitions to ColorInfo fields
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
A new ColorMap instance with the handler applied to each field.
|
|
361
|
+
|
|
362
|
+
"""
|
|
363
|
+
data: dict[str, ColorField] = {k: handler(v) for k, v in self}
|
|
364
|
+
inst = self.model_validate(data)
|
|
365
|
+
if isinstance(handler, Extractor):
|
|
366
|
+
inst._field_type = handler.field
|
|
367
|
+
elif isinstance(handler, Parser):
|
|
368
|
+
inst._field_type = ColorFieldType.info
|
|
369
|
+
return inst
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
class Hues(ColorMap):
|
|
373
|
+
"""Named accents.
|
|
374
|
+
|
|
375
|
+
A ``Hues`` instance serves primarily to color text and highlights.
|
|
376
|
+
|
|
377
|
+
"""
|
|
378
|
+
|
|
379
|
+
red: ColorField = "oklch(0.575 0.185 25)"
|
|
380
|
+
orange: ColorField = "oklch(0.650 0.150 60)"
|
|
381
|
+
yellow: ColorField = "oklch(0.675 0.120 100)"
|
|
382
|
+
lime: ColorField = "oklch(0.650 0.130 115)"
|
|
383
|
+
green: ColorField = "oklch(0.575 0.165 130)"
|
|
384
|
+
mint: ColorField = "oklch(0.675 0.130 155)"
|
|
385
|
+
cyan: ColorField = "oklch(0.625 0.100 180)"
|
|
386
|
+
azure: ColorField = "oklch(0.675 0.110 225)"
|
|
387
|
+
blue: ColorField = "oklch(0.575 0.140 250)"
|
|
388
|
+
violet: ColorField = "oklch(0.575 0.185 290)"
|
|
389
|
+
magenta: ColorField = "oklch(0.575 0.185 330)"
|
|
390
|
+
rose: ColorField = "oklch(0.675 0.100 360)"
|
|
391
|
+
|
|
392
|
+
# @staticmethod
|
|
393
|
+
# def neutral() -> Hues:
|
|
394
|
+
# """Neutral hues.
|
|
395
|
+
#
|
|
396
|
+
# Returns:
|
|
397
|
+
# A neutral mode selection of hues.
|
|
398
|
+
#
|
|
399
|
+
# """
|
|
400
|
+
# return Hues()
|
|
401
|
+
|
|
402
|
+
@staticmethod
|
|
403
|
+
def dark() -> Hues:
|
|
404
|
+
"""Dark mode hues.
|
|
405
|
+
|
|
406
|
+
Returns:
|
|
407
|
+
A dark mode selection of hues.
|
|
408
|
+
|
|
409
|
+
"""
|
|
410
|
+
return Hues(
|
|
411
|
+
red="oklch(0.60 0.185 25)",
|
|
412
|
+
orange="oklch(0.650 0.150 60)",
|
|
413
|
+
yellow="oklch(0.700 0.120 100)",
|
|
414
|
+
lime="oklch(0.675 0.120 115)",
|
|
415
|
+
green="oklch(0.650 0.165 130)",
|
|
416
|
+
mint="oklch(0.715 0.130 155)",
|
|
417
|
+
cyan="oklch(0.650 0.100 180)",
|
|
418
|
+
azure="oklch(0.725 0.110 225)",
|
|
419
|
+
blue="oklch(0.625 0.150 250)",
|
|
420
|
+
violet="oklch(0.625 0.185 290)",
|
|
421
|
+
magenta="oklch(0.625 0.185 330)",
|
|
422
|
+
rose="oklch(0.700 0.100 360)",
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
@staticmethod
|
|
426
|
+
def light() -> Hues:
|
|
427
|
+
"""Light mode hues.
|
|
428
|
+
|
|
429
|
+
Returns:
|
|
430
|
+
A light mode selection of hues.
|
|
431
|
+
|
|
432
|
+
"""
|
|
433
|
+
return Hues(
|
|
434
|
+
red="oklch(0.550 0.185 25)",
|
|
435
|
+
orange="oklch(0.650 0.150 60)",
|
|
436
|
+
yellow="oklch(0.650 0.120 100)",
|
|
437
|
+
lime="oklch(0.650 0.130 115)",
|
|
438
|
+
green="oklch(0.575 0.165 130)",
|
|
439
|
+
mint="oklch(0.650 0.130 155)",
|
|
440
|
+
cyan="oklch(0.550 0.100 180)",
|
|
441
|
+
azure="oklch(0.650 0.110 225)",
|
|
442
|
+
blue="oklch(0.575 0.140 250)",
|
|
443
|
+
violet="oklch(0.550 0.185 290)",
|
|
444
|
+
magenta="oklch(0.550 0.185 330)",
|
|
445
|
+
rose="oklch(0.625 0.100 360)",
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
@staticmethod
|
|
449
|
+
def highlights() -> Hues:
|
|
450
|
+
"""Highlight hues.
|
|
451
|
+
|
|
452
|
+
Returns:
|
|
453
|
+
A selection of hues to use in highlights.
|
|
454
|
+
|
|
455
|
+
"""
|
|
456
|
+
return Hues(
|
|
457
|
+
red="oklch(0.800 0.100 25)",
|
|
458
|
+
orange="oklch(0.850 0.100 60)",
|
|
459
|
+
yellow="oklch(0.950 0.200 100)",
|
|
460
|
+
lime="oklch(0.855 0.100 115)",
|
|
461
|
+
green="oklch(0.85 0.100 130)",
|
|
462
|
+
mint="oklch(0.875 0.100 155)",
|
|
463
|
+
cyan="oklch(0.900 0.100 180)",
|
|
464
|
+
azure="oklch(0.875 0.100 225)",
|
|
465
|
+
blue="oklch(0.825 0.100 250)",
|
|
466
|
+
violet="oklch(0.825 0.200 290)",
|
|
467
|
+
magenta="oklch(0.825 0.200 330)",
|
|
468
|
+
rose="oklch(0.825 0.200 360)",
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
@staticmethod
|
|
472
|
+
def bright() -> Hues:
|
|
473
|
+
"""Highlight hues.
|
|
474
|
+
|
|
475
|
+
Returns:
|
|
476
|
+
A selection of brighter hues.
|
|
477
|
+
|
|
478
|
+
"""
|
|
479
|
+
return Hues(
|
|
480
|
+
red="oklch(0.675 0.200 25)",
|
|
481
|
+
orange="oklch(0.75 0.175 60)",
|
|
482
|
+
yellow="oklch(0.80 0.165 100)",
|
|
483
|
+
lime="oklch(0.800 0.185 120)",
|
|
484
|
+
green="oklch(0.800 0.200 135)",
|
|
485
|
+
mint="oklch(0.800 0.195 155)",
|
|
486
|
+
cyan="oklch(0.800 0.145 180)",
|
|
487
|
+
azure="oklch(0.800 0.135 225)",
|
|
488
|
+
blue="oklch(0.800 0.100 250)",
|
|
489
|
+
violet="oklch(0.800 0.100 290)",
|
|
490
|
+
magenta="oklch(0.800 0.185 330)",
|
|
491
|
+
rose="oklch(0.800 0.120 360)",
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
class Bases(ColorMap):
|
|
496
|
+
"""Configuration node for foregrounds and backgrounds.
|
|
497
|
+
|
|
498
|
+
Colors are grouped primarily into
|
|
499
|
+
|
|
500
|
+
- backgrounds (main and overlays),
|
|
501
|
+
- foreground colors
|
|
502
|
+
- opposite overlays
|
|
503
|
+
"""
|
|
504
|
+
|
|
505
|
+
bg: ColorField = Ref.b13
|
|
506
|
+
"""Primary background color."""
|
|
507
|
+
bg1: ColorField = Ref.b14
|
|
508
|
+
"""Secondary background color."""
|
|
509
|
+
bg2: ColorField = Ref.b16
|
|
510
|
+
"""Tertiary background color."""
|
|
511
|
+
bg3: ColorField = Ref.b20
|
|
512
|
+
"""Overlay background 1."""
|
|
513
|
+
bg4: ColorField = Ref.b25
|
|
514
|
+
"""Overlay background 2."""
|
|
515
|
+
bg5: ColorField = Ref.b30
|
|
516
|
+
"""Overlay background 3."""
|
|
517
|
+
bg6: ColorField = Ref.b35
|
|
518
|
+
"""Overlay."""
|
|
519
|
+
hidden: ColorField = Ref.g45
|
|
520
|
+
"""Strongly de-mphasized foreground text."""
|
|
521
|
+
subfg: ColorField = Ref.g70
|
|
522
|
+
"""De-emphasized foreground text."""
|
|
523
|
+
fg: ColorField = Ref.w80
|
|
524
|
+
"""Primary foreground text."""
|
|
525
|
+
emph: ColorField = Ref.w85
|
|
526
|
+
"""Emphasized foreground text."""
|
|
527
|
+
op2: ColorField = Ref.s80
|
|
528
|
+
"""Tertiary opposite background color."""
|
|
529
|
+
op1: ColorField = Ref.s85
|
|
530
|
+
"""Secondary opposite background color."""
|
|
531
|
+
op: ColorField = Ref.s90
|
|
532
|
+
"""Primary opposite background color."""
|
|
533
|
+
|
|
534
|
+
@staticmethod
|
|
535
|
+
def dark() -> Bases:
|
|
536
|
+
"""Dark mode bases.
|
|
537
|
+
|
|
538
|
+
Returns:
|
|
539
|
+
A dark mode selection of bases.
|
|
540
|
+
|
|
541
|
+
"""
|
|
542
|
+
return Bases()
|
|
543
|
+
|
|
544
|
+
@staticmethod
|
|
545
|
+
def light() -> Bases:
|
|
546
|
+
"""Light mode bases.
|
|
547
|
+
|
|
548
|
+
Returns:
|
|
549
|
+
A dark mode selection of bases.
|
|
550
|
+
|
|
551
|
+
"""
|
|
552
|
+
dark = Bases.dark()
|
|
553
|
+
return Bases(
|
|
554
|
+
bg=Ref.s100,
|
|
555
|
+
bg1=Ref.s99,
|
|
556
|
+
bg2=Ref.s95,
|
|
557
|
+
bg3=Ref.s92,
|
|
558
|
+
bg4=Ref.s99,
|
|
559
|
+
bg5=Ref.s85,
|
|
560
|
+
bg6=Ref.s80,
|
|
561
|
+
hidden=Ref.g75,
|
|
562
|
+
subfg=Ref.g60,
|
|
563
|
+
fg=Ref.g30,
|
|
564
|
+
emph=Ref.g20,
|
|
565
|
+
op2=dark.bg3,
|
|
566
|
+
op1=dark.bg2,
|
|
567
|
+
op=dark.bg,
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
class Grayscale(ColorMap):
|
|
572
|
+
"""Grayscale monochromatic named colors that are palette independent."""
|
|
573
|
+
|
|
574
|
+
black: ColorField = "oklch(0.10 0.01 220)"
|
|
575
|
+
darkgray: ColorField = "oklch(0.30 0.01 220)"
|
|
576
|
+
neutralgray: ColorField = "oklch(0.50 0.01 220)"
|
|
577
|
+
lightgray: ColorField = "oklch(0.70 0.01 220)"
|
|
578
|
+
white: ColorField = "oklch(0.995 0.003 220)"
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
def parse(
|
|
582
|
+
val: str,
|
|
583
|
+
gamut: str = ColorSpace.srgb,
|
|
584
|
+
fit_method: str = "raytrace",
|
|
585
|
+
) -> ColorInfo:
|
|
586
|
+
"""Parse a string representation of a color.
|
|
587
|
+
|
|
588
|
+
Generate a ``Parser`` instance and call it on the input.
|
|
589
|
+
|
|
590
|
+
Returns:
|
|
591
|
+
A ColorInfo instance parsed from the input string. Raises a
|
|
592
|
+
ValueError if the input is not parseable.
|
|
593
|
+
|
|
594
|
+
"""
|
|
595
|
+
return Parser(gamut=gamut, fit_method=fit_method)(val)
|