Skip to main content

Start adding a set of automated scripts

ID
0b2d5d6
date
2025-11-27 03:44:08+00:00
author
Alex Chan <alex@alexwlchan.net>
parent
4aaf80a
message
Start adding a set of automated scripts
changed files
8 files, 403 additions

Changed files

.github/dependabot.yml (0) → .github/dependabot.yml (243)

diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..9452b32
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+version: 2
+updates:
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "daily"
+      time: "09:00"
+  - package-ecosystem: "pip"
+    directory: "/"
+    schedule:
+      interval: "daily"
+      time: "09:00"

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

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..a09eede
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,41 @@
+name: Test
+
+on:
+  push:
+    branches:
+    - main
+
+  pull_request:
+    branches:
+    - main
+
+jobs:
+  test:
+    strategy:
+      matrix:
+        python-version:
+          - "3.12"
+          - "3.13"
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v4
+
+    - name: Set up Python
+      uses: actions/setup-python@v5
+      with:
+        python-version: ${{ matrix.python-version }}
+        cache: 'pip'
+        cache-dependency-path: 'dev_requirements.txt'
+
+    - name: Install dependencies
+      run: pip install -r dev_requirements.txt
+
+    - name: Check formatting
+      run: |
+        ruff check .
+        ruff format --check .
+
+    - name: Check types
+      run: mypy scripts/*.py --strict

css/syntax_highlighting.1c4c93a.css (0) → css/syntax_highlighting.1c4c93a.css (3311)

diff --git a/css/syntax_highlighting.1c4c93a.css b/css/syntax_highlighting.1c4c93a.css
new file mode 100644
index 0000000..c2afd1a
--- /dev/null
+++ b/css/syntax_highlighting.1c4c93a.css
@@ -0,0 +1,130 @@
+/* Syntax highlighting styles. */
+pre {
+  --red:     var(--default-primary-color-light);
+  --green:   #1bad0e;
+  --blue:    #115bda;
+  --magenta: #c311d0;
+  --yellow:  #c8a711;
+
+  --comments:    var(--red);
+  --literals:    var(--magenta);
+  --strings:     var(--green);
+  --names:       var(--blue);
+  --punctuation: var(--accent-grey);
+  --mark:        #ffeb12b3;
+
+  @media (prefers-color-scheme: dark) {
+    --red:     var(--default-primary-color-dark);
+    --green:   #5ff042;
+    --blue:    #40c3ff;
+    --magenta: #ff42fc;
+    --yellow:  #fffc42;
+    --mark:    #fffc42cc;
+  }
+
+  /* Comment, Comment.{Hash, Multiline, Single, Special} */
+  .c, .ch, .cm, .c1, .cs {
+    color: var(--comments);
+  }
+
+  /* Numbers and booleans:
+   *   Literal.Number, Literal.Number.{Bin, Float, Hex, Integer, Oct},
+   *   Integer.Long,
+   *   Keyword.{Constant, Reserved}
+   *   Name.Constant
+   */
+  .m, .mb, .mf, .mh, .mi, .mo, .il, .kc, .bp, .no {
+    color: var(--literals);
+  }
+
+  /* Strings:
+   *   Literal.String, Literal.String.{Affix, Backtick, Char, Delimiter,
+   *   …, Doc, Escape, Double, Heredoc, Interpol, Other, Regex, Single,
+   *   …, Symbol} */
+  .s, .sa, .sb, .sc, .dl, .sd, .se, .s2, .sh, .si, .sx, .sr, .s1, .ss {
+    color: var(--strings);
+  }
+
+  /* Name */
+  .n { color: var(--names); }
+
+  /* Punctuation, Generic.Output */
+  .p, .go {
+    color: var(--punctuation);
+  }
+
+  /* Rust-specific errors */
+  .rustc_error   { color: var(--red); font-weight: bold; }
+  .rustc_warning { color: var(--green); }
+  .rustc_value   { color: var(--yellow); }
+  .rustc_lineno  { color: var(--blue); }
+
+  mark {
+    background-color: var(--mark);
+    padding:       2px 0;
+    margin:       -2px 0;
+    border-radius: 2px;
+  }
+}
+
+/* In console snippets:
+ *
+ *    - don't allow selecting the $ or the following space
+ *      See https://alexwlchan.net/2021/10/console-copying/
+ *      See https://stackoverflow.com/a/4407335/1558022
+ *    - color the prompt blue
+ *
+ * gp = Generic.Prompt, w = Whitespace
+ */
+.language-console .gp,
+.language-console .gp + .w,
+.language-irb .gp,
+.language-irb .gp + .w {
+  color: var(--blue);
+  -webkit-touch-callout: none; /* iOS Safari */
+    -webkit-user-select: none; /* Safari */
+     -khtml-user-select: none; /* Konqueror HTML */
+       -moz-user-select: none; /* Firefox */
+        -ms-user-select: none; /* Internet Explorer/Edge */
+            user-select: none; /* Non-prefixed version, currently
+                                  supported by Chrome and Opera */
+}
+
+/* Don't highlight the XML declaration at the top of an XML snippet.
+ * cp = Comment.Preproc*/
+.language-xml .cp {
+  color: var(--punctuation);
+}
+
+/* All my Caddy and Go-formatted code uses tabs; ensure it's a 4-wide tab
+ * rather than 8-wide, which is the default stylesheet in Safari */
+.language-caddy,
+.language-go {
+  tab-size: 4;
+}
+
+/* Highlight HTML tags in blue.
+ * Name.{Tag, Attribute} */
+.language-html {
+  .nt, .na {
+    color: var(--names);
+  }
+}
+
+.language-css {
+  /* Don't highlight media queries. */
+  .n {
+    color: var(--body-text);
+  }
+
+  /* Highlight CSS colours in magenta. Name.Constant */
+  .no {
+    color: var(--literals);
+  }
+
+  /* Highlight selectors and properties in blue.
+   * Name.{Class, Tag, Literal, Property} */
+  .nc, .nt, .nl, .py {
+    color: var(--names)
+  };
+}

css/variables.2477498.scss (0) → css/variables.2477498.scss (4005)

diff --git a/css/variables.2477498.scss b/css/variables.2477498.scss
new file mode 100644
index 0000000..69a46fb
--- /dev/null
+++ b/css/variables.2477498.scss
@@ -0,0 +1,126 @@
+@use "sass:color";
+@use "utils/functions.scss" as *;
+
+/* Why 751px and not 750px? To work around a subpixel bug in WebKit,
+ * where I get a hairline crack on the right-hand side of my cards
+ * in the two column view. :( */
+$max-width: 751px;
+$default-padding: 20px;
+
+:root {
+  /* ====================
+   * Font and text styles
+   * ==================== */
+  --text-font-family: Charter, Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif;
+  --mono-font-family: Menlo, Consolas, monospace;
+
+  --font-size: 13pt;
+
+  --line-height: 1.5em;
+
+  --meta-scaling-factor:     0.82;
+  --footnote-scaling-factor: 0.95;
+
+  /* =============================
+   * Margins and page layout stuff
+   * ============================= */
+  --max-width: #{$max-width};
+
+  --grid-gap: 10px;
+
+  --default-padding: #{$default-padding};
+
+  --border-radius: 10px;
+  --border-style:  solid;
+  --border-width:  3px;
+
+  /* Every page has a tint color that affects the nav, links, headings,
+   * and so on.
+   *
+   * Set a default color for every page, which may be overwritten by CSS
+   * appended to the <head>.
+   */
+  --default-primary-color-light: #d01c11;
+  --default-primary-color-dark:  #f45858;
+
+  --primary-color-light: var(--default-primary-color-light);
+  --primary-color-dark:  var(--default-primary-color-dark);
+
+  --nav-bg-image-light: url('/h/d01c11.png');
+  --nav-bg-image-dark:  url('/h/ff4242.png');
+
+  --link-color: var(--primary-color);
+
+  /* A collection of light/dark greys tones.
+   *
+   * Every so often I wonder about rationalising the number of grey tones that
+   * I'm using, but I haven't found a selection that I like yet.
+   */
+  --body-text-light: #202020;
+  --body-text-dark:  #c7c7c7;
+
+  --accent-grey-light: #999;
+  --accent-grey-dark:  #9a9a9a;
+
+  --block-border-color-light: #dfdfdf;
+  --block-background-light:   #f3f3f3;
+
+  --block-border-color-dark: #434343;
+  --block-background-dark:   #1d1d1d;
+
+  --screenshot-border-light: #f0f0f0;
+  --screenshot-border-dark:  #3f3f3f;
+
+  /* My background texture image is "White Waves Pattern" by Stas Pimenov,
+   * with reduced contrast.  The dark variant has inverted colours.
+   *
+   * From https://www.toptal.com/designers/subtlepatterns/white-waves-pattern/
+   */
+  --background-texture-light: url("/static/white-waves.png");
+  --background-color-light:   #fafafa;
+
+  --background-texture-dark:  url("/static/black-waves.png");
+  --background-color-dark:    #0d0d0d;
+}
+
+/* Select the appropriate light/dark shades depending on the user's theme.
+ *
+ * I could use the `light-dark()` CSS function, but it's fairly new and
+ * this approach is fine, so I'm sticking with media queries for now.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark
+ */
+:root {
+    --body-text:          var(--body-text-light);
+    --primary-color:      var(--primary-color-light);
+    --accent-grey:        var(--accent-grey-light);
+    --block-border-color: var(--block-border-color-light);
+    --block-background:   var(--block-background-light);
+    --screenshot-border:  var(--screenshot-border-light);
+    --background-image:   var(--background-texture-light);
+    --background-color:   var(--background-color-light);
+    --nav-bg-image:       var(--nav-bg-image-light);
+}
+
+@media (prefers-color-scheme: dark) {
+  :root {
+    --body-text:           var(--body-text-dark);
+    --primary-color:       var(--primary-color-dark);
+    --accent-grey:         var(--accent-grey-dark);
+    --block-border-color:  var(--block-border-color-dark);
+    --block-background:    var(--block-background-dark);
+    --screenshot-border:   var(--screenshot-border-dark);
+    --background-image:    var(--background-texture-dark);
+    --background-color:    var(--background-color-dark);
+    --nav-bg-image:        var(--nav-bg-image-dark);
+  }
+}
+
+@media print {
+  :root {
+    --accent-grey: #555;
+
+    /* Don't show the background texture when printing; it's not important */
+    --background-image: none;
+    --background-color: none;
+  }
+}

dev_requirements.in (0) → dev_requirements.in (10)

diff --git a/dev_requirements.in b/dev_requirements.in
new file mode 100644
index 0000000..8881953
--- /dev/null
+++ b/dev_requirements.in
@@ -0,0 +1,2 @@
+mypy
+ruff

dev_requirements.txt (0) → dev_requirements.txt (341)

diff --git a/dev_requirements.txt b/dev_requirements.txt
new file mode 100644
index 0000000..d5b2b08
--- /dev/null
+++ b/dev_requirements.txt
@@ -0,0 +1,12 @@
+# This file was autogenerated by uv via the following command:
+#    uv pip compile dev_requirements.in --output-file dev_requirements.txt
+mypy==1.18.2
+    # via -r dev_requirements.in
+mypy-extensions==1.1.0
+    # via mypy
+pathspec==0.12.1
+    # via mypy
+ruff==0.14.6
+    # via -r dev_requirements.in
+typing-extensions==4.15.0
+    # via mypy

scripts/palette.py (0) → scripts/palette.py (228)

diff --git a/scripts/palette.py b/scripts/palette.py
new file mode 100644
index 0000000..7985b7c
--- /dev/null
+++ b/scripts/palette.py
@@ -0,0 +1,16 @@
+from typing import TypedDict
+
+
+class Colours(TypedDict):
+    red: str
+    green: str
+    blue: str
+    magenta: str
+    yellow: str
+    highlight: str
+
+
+class Palette(TypedDict):
+    id: str
+    light: Colours
+    dark: Colours

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

diff --git a/scripts/vendor_css_files.py b/scripts/vendor_css_files.py
new file mode 100755
index 0000000..cc26aae
--- /dev/null
+++ b/scripts/vendor_css_files.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+"""
+Copy a new set of CSS files from a local checkout of my website, and
+create a `palette.json` in the root of the repo.
+"""
+
+import glob
+from pathlib import Path
+import re
+import shutil
+import subprocess
+
+
+def get_alexwlchan_net_css(css_name: str) -> tuple[str, str]:
+    """
+    Get a copy of a CSS file from a local checkout of my website.
+
+    This returns a tuple: the commit ID and CSS text.
+    """
+    repo_path = Path.home() / "repos/alexwlchan.net"
+    css_path = repo_path / "src/_scss" / css_name
+
+    # Get the commit ID of the last change to this file
+    output = subprocess.check_output(
+        ["git", "rev-list", "-1", "HEAD", "--", str(css_path)],
+        text=True,
+        cwd=repo_path,
+    )
+    commit_id = output[:7]
+
+    vendor_path = Path("css") / f"{css_path.stem}.{commit_id}{css_path.suffix}"
+    vendor_path.parent.mkdir(exist_ok=True)
+
+    # 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"):
+            Path(f).unlink()
+
+        shutil.copyfile(css_path, vendor_path)
+
+    return commit_id, vendor_path.read_text()
+
+
+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
+    return m.group("colour")
+
+
+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")
+
+    print(light_red)
+    print(dark_red)