Skip to main content

Create the basic palette

ID
aad50ee
date
2025-11-27 03:55:19+00:00
author
Alex Chan <alex@alexwlchan.net>
parent
0b2d5d6
message
Create the basic palette
changed files
7 files, 112 additions, 21 deletions

Changed files

.github/workflows/test.yml (709) → .github/workflows/test.yml (758)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a09eede..f5d1a61 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -39,3 +39,6 @@ jobs:
 
     - name: Check types
       run: mypy scripts/*.py --strict
+
+    - name: Run tests
+      run: pytest scripts

css/syntax_highlighting.1c4c93a.css (3311) → css/syntax_highlighting.94fa872.css (3366)

diff --git a/css/syntax_highlighting.1c4c93a.css b/css/syntax_highlighting.94fa872.css
similarity index 89%
rename from css/syntax_highlighting.1c4c93a.css
rename to css/syntax_highlighting.94fa872.css
index c2afd1a..3e9e576 100644
--- a/css/syntax_highlighting.1c4c93a.css
+++ b/css/syntax_highlighting.94fa872.css
@@ -1,25 +1,26 @@
 /* Syntax highlighting styles. */
 pre {
-  --red:     var(--default-primary-color-light);
-  --green:   #1bad0e;
-  --blue:    #115bda;
-  --magenta: #c311d0;
-  --yellow:  #c8a711;
+  --red:       var(--default-primary-color-light);
+  --green:     #1bad0e;
+  --blue:      #115bda;
+  --magenta:   #c311d0;
+  --yellow:    #c8a711;
+  --highlight: #ffeb12b3;
 
   --comments:    var(--red);
   --literals:    var(--magenta);
   --strings:     var(--green);
   --names:       var(--blue);
   --punctuation: var(--accent-grey);
-  --mark:        #ffeb12b3;
+  --mark:        var(--highlight);
 
   @media (prefers-color-scheme: dark) {
-    --red:     var(--default-primary-color-dark);
-    --green:   #5ff042;
-    --blue:    #40c3ff;
-    --magenta: #ff42fc;
-    --yellow:  #fffc42;
-    --mark:    #fffc42cc;
+    --red:       var(--default-primary-color-dark);
+    --green:     #5ff042;
+    --blue:      #40c3ff;
+    --magenta:   #ff42fc;
+    --yellow:    #fffc42;
+    --highlight: #fffc42cc;
   }
 
   /* Comment, Comment.{Hash, Multiline, Single, Special} */

dev_requirements.in (10) → dev_requirements.in (17)

diff --git a/dev_requirements.in b/dev_requirements.in
index 8881953..daf7d81 100644
--- a/dev_requirements.in
+++ b/dev_requirements.in
@@ -1,2 +1,3 @@
 mypy
+pytest
 ruff

dev_requirements.txt (341) → dev_requirements.txt (520)

diff --git a/dev_requirements.txt b/dev_requirements.txt
index d5b2b08..f2b9f6c 100644
--- a/dev_requirements.txt
+++ b/dev_requirements.txt
@@ -1,11 +1,21 @@
 # This file was autogenerated by uv via the following command:
 #    uv pip compile dev_requirements.in --output-file dev_requirements.txt
+iniconfig==2.3.0
+    # via pytest
 mypy==1.18.2
     # via -r dev_requirements.in
 mypy-extensions==1.1.0
     # via mypy
+packaging==25.0
+    # via pytest
 pathspec==0.12.1
     # via mypy
+pluggy==1.6.0
+    # via pytest
+pygments==2.19.2
+    # via pytest
+pytest==9.0.1
+    # via -r dev_requirements.in
 ruff==0.14.6
     # via -r dev_requirements.in
 typing-extensions==4.15.0

palette.json (0) → palette.json (362)

diff --git a/palette.json b/palette.json
new file mode 100644
index 0000000..6b7693e
--- /dev/null
+++ b/palette.json
@@ -0,0 +1,19 @@
+{
+  "id": "2477498-94fa872",
+  "light": {
+    "red": "#d01c11",
+    "green": "#1bad0e",
+    "blue": "#115bda",
+    "magenta": "#c311d0",
+    "yellow": "#c8a711",
+    "highlight": "#ffeb12b3"
+  },
+  "dark": {
+    "red": "#f45858",
+    "green": "#5ff042",
+    "blue": "#40c3ff",
+    "magenta": "#ff42fc",
+    "yellow": "#fffc42",
+    "highlight": "#fffc42cc"
+  }
+}
\ No newline at end of file

scripts/test_vendor_css_files.py (0) → scripts/test_vendor_css_files.py (572)

diff --git a/scripts/test_vendor_css_files.py b/scripts/test_vendor_css_files.py
new file mode 100644
index 0000000..6f73e54
--- /dev/null
+++ b/scripts/test_vendor_css_files.py
@@ -0,0 +1,21 @@
+import pytest
+
+from vendor_css_files import get_colour_variable
+
+
+@pytest.mark.parametrize(
+    "css, name, colour",
+    [
+        # Simplest case
+        ("--red: #ff0000;", "red", "#ff0000"),
+        # Variable whitespace between varname and hex string
+        ("--red:   #ff0000;", "red", "#ff0000"),
+        # Alpha channel
+        ("--red: #ff0000ff;", "red", "#ff0000ff"),
+    ],
+)
+def test_get_colour_variable(css: str, name: str, colour: str) -> None:
+    """
+    Extract colour variables from CSS.
+    """
+    assert get_colour_variable(css, name=name) == colour

scripts/vendor_css_files.py (1999) → scripts/vendor_css_files.py (3379)

diff --git a/scripts/vendor_css_files.py b/scripts/vendor_css_files.py
index cc26aae..5a4669e 100755
--- a/scripts/vendor_css_files.py
+++ b/scripts/vendor_css_files.py
@@ -5,11 +5,14 @@ create a `palette.json` in the root of the repo.
 """
 
 import glob
+import json
 from pathlib import Path
 import re
 import shutil
 import subprocess
 
+from palette import Colours, Palette
+
 
 def get_alexwlchan_net_css(css_name: str) -> tuple[str, str]:
     """
@@ -34,7 +37,7 @@ def get_alexwlchan_net_css(css_name: str) -> tuple[str, str]:
     # If we don't have a vendored copy of the file in this repo, delete
     # any previously-vendored copies then copy in the new version.
     if not vendor_path.exists():
-        for f in glob.glob("syntax_highlighting.*.scss"):
+        for f in glob.glob(f"css/{css_path.stem}.*"):
             Path(f).unlink()
 
         shutil.copyfile(css_path, vendor_path)
@@ -46,8 +49,17 @@ def get_colour_variable(css: str, *, name: str) -> str:
     """
     Extracts a CSS variable from a snippet of CSS.
     """
-    m = re.search(f"--{name}:" + r"\s+(?P<colour>#[0-9a-f]{6}([0-9a-f]{2})?);", css)
-    assert m is not None
+    # Example matches:
+    #
+    #     --red: #ff0000;
+    #     --red:   #ff0000;
+    #     --red: #ff0000ff;
+    #
+    m = re.search(f"--{name}:" + r"\s*(?P<colour>#[0-9a-f]{6}([0-9a-f]{2})?);", css)
+
+    if m is None:
+        raise ValueError(f"cannot find variable --{name} in CSS")
+
     return m.group("colour")
 
 
@@ -55,10 +67,34 @@ if __name__ == "__main__":
     variable_id, variable_css = get_alexwlchan_net_css("variables.scss")
     syntax_id, syntax_css = get_alexwlchan_net_css("components/syntax_highlighting.css")
 
-    # Get the default primary colour, which is used for my two shades
-    # of red.
-    light_red = get_colour_variable(variable_css, name="default-primary-color-light")
-    dark_red = get_colour_variable(variable_css, name="default-primary-color-dark")
+    light_colours: Colours = {
+        "red": get_colour_variable(variable_css, name="default-primary-color-light"),
+        "green": get_colour_variable(syntax_css, name="green"),
+        "blue": get_colour_variable(syntax_css, name="blue"),
+        "magenta": get_colour_variable(syntax_css, name="magenta"),
+        "yellow": get_colour_variable(syntax_css, name="yellow"),
+        "highlight": get_colour_variable(syntax_css, name="highlight"),
+    }
+
+    # Get the first block of dark theme colours from the syntax highlighting
+    # CSS. This is a bit crude, but it works for now.
+    _, dark_syntax_css = syntax_css.split("@media (prefers-color-scheme: dark) {")
+    dark_colours: Colours = {
+        "red": get_colour_variable(variable_css, name="default-primary-color-dark"),
+        "green": get_colour_variable(dark_syntax_css, name="green"),
+        "blue": get_colour_variable(dark_syntax_css, name="blue"),
+        "magenta": get_colour_variable(dark_syntax_css, name="magenta"),
+        "yellow": get_colour_variable(dark_syntax_css, name="yellow"),
+        "highlight": get_colour_variable(dark_syntax_css, name="highlight"),
+    }
+
+    palette: Palette = {
+        "id": f"{variable_id}-{syntax_id}",
+        "light": light_colours,
+        "dark": dark_colours,
+    }
+
+    with open("palette.json", "w") as out_file:
+        out_file.write(json.dumps(palette, indent=2))
 
-    print(light_red)
-    print(dark_red)
+    print(f"Written palette {palette['id']} to palette.json")