From 0e69a0977cc24e6131373504928ab72c3bdb5b11 Mon Sep 17 00:00:00 2001 From: MotherSphere Date: Wed, 14 Oct 2026 13:24:51 +0200 Subject: [PATCH 1/4] chore(deps): update tauri to 2.12.3 and refresh the lockfile Also set resolver = "3" so lockfile updates only pick versions that build on rust-version 1.90. --- Cargo.lock | 120 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 14 ++++--- 2 files changed, 68 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07f072e..9d1a4e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,7 +140,7 @@ checksum = "4f8abc12baad266b1c8cec146854c195b5864b4221d4b2ca7296a7ae82d9e451" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -175,7 +175,7 @@ checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -428,9 +428,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f74872d07caf508b30a21f6836e7d7016a2eaf7d9ff4f48deaa58cd8a0407630" +checksum = "6651c9ed80effdc7db0ff72512157f901af5e3549e341e24b1dd4887d836d838" dependencies = [ "find-msvc-tools", "shlex", @@ -630,7 +630,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d045de693cb712d0b22c6a64be5b953f67b3ce00ab5ad3dd5d8b441886ab8e1a" dependencies = [ "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -659,7 +659,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -670,7 +670,7 @@ checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" dependencies = [ "darling_core", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -717,9 +717,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e" dependencies = [ "serde_core", ] @@ -796,7 +796,7 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -928,9 +928,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" [[package]] name = "erased-serde" @@ -1002,7 +1002,7 @@ checksum = "3e91d94c6885390b81782d7ee60fd6583b33907333a8b340de25ccf468353315" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -1068,7 +1068,7 @@ checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -1139,7 +1139,7 @@ checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -2844,7 +2844,7 @@ checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -3006,9 +3006,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +checksum = "ab508826f74a77ca9d5aba6ff19b522583ee3eaf28a19384ff3d0e5835fadf6e" dependencies = [ "dyn-clone", "ref-cast", @@ -3102,7 +3102,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -3118,9 +3118,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -3137,7 +3137,7 @@ checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -3172,7 +3172,7 @@ dependencies = [ "indexmap 2.14.2", "jiff", "schemars 0.9.0", - "schemars 1.2.2", + "schemars 1.2.3", "serde_core", "serde_json", "serde_with_macros", @@ -3188,7 +3188,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -3269,9 +3269,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.16.2" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e" +checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b" [[package]] name = "socket2" @@ -3369,9 +3369,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "swift-rs" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e45c444e496845d3f2a351146bff59aae4975b2280238df1dfaa0c7d1846f38e" +checksum = "cefd87076fd385308ee4aff597256c902f1fbb4d031de1558efc12f8ffefadd9" dependencies = [ "base64 0.21.7", "serde", @@ -3401,9 +3401,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.6" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -3427,7 +3427,7 @@ checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -3502,9 +3502,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.12.2" +version = "2.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d061d042ccd2df9c9f1508c1e63d835278c0a4c8801eb41764080e51f2eaaf34" +checksum = "c404ecf956ff241bf6b39dd688614724e1bf1f63255abb4fc46d1c40371672ea" dependencies = [ "anyhow", "bytes", @@ -3553,9 +3553,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59563ca5b331fd97f27ee9672ec8d36d33bb3c9e2c9f6710a1a5687256052e45" +checksum = "2eea0b6302f82c574b21af6fc6ae6e86183b9280853c22621d0abf0936911ffc" dependencies = [ "anyhow", "cargo_toml", @@ -3574,11 +3574,11 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e50213e463086ecc283d7e9f51c30cc0fd304ad457425158018be26dbf0d0a80" +checksum = "02f468f9a9bcd404f57e5c191d91024e3de953d4b610f78c2907e7110615cb1c" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "brotli", "ico", "json-patch", @@ -3601,9 +3601,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8129fb43bb6e0d6b73ad3315cd172beaab17cd28899c594b1b32c80edbbfd99c" +checksum = "131bffec939b20642380317f8403a33c8888489925e14bb965ceaff0d949b1cb" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3631,9 +3631,9 @@ dependencies = [ [[package]] name = "tauri-plugin-dialog" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf9a5c92e39bdd84f22f6be9230e39d0c4e140345f71ffe6058dca4f71127cf" +checksum = "3dca325d6e66e9170f2e1b9631722e4e544bcbc51781575d266abdaba697bd51" dependencies = [ "log", "raw-window-handle", @@ -3649,9 +3649,9 @@ dependencies = [ [[package]] name = "tauri-plugin-fs" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "466eb32466fe5021b6728b06862f9ff14a9f7e1af890047654e03a96d7c0e1bb" +checksum = "213fae2d85d4b76b06de5915d1862db9fa74541171f9d2c15da6ac9bd6e788c6" dependencies = [ "anyhow", "dunce", @@ -3673,9 +3673,9 @@ dependencies = [ [[package]] name = "tauri-plugin-opener" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39404b2572927e0d3ed30a7ca226037f7508d22e79c96ee6ef0d42b6a4b3345" +checksum = "85dead674ee41937d042ee855d785f07ee67206f19402200c12b9255964d5ac8" dependencies = [ "dunce", "glob", @@ -3852,7 +3852,7 @@ checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -3903,9 +3903,9 @@ checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" [[package]] name = "tokio" -version = "1.53.2" +version = "1.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044" +checksum = "ce3335fa71841cda333a58d7615b03901380ecf09d59b3296d21f8bbac0dde4e" dependencies = [ "bytes", "libc", @@ -4159,9 +4159,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "unicode-normalization" @@ -4211,9 +4211,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.27.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97277d36b9c3ace13e58fa6e753f8b0bbbf302a18dd193240d70f9e29681059a" +checksum = "7cc1186384beb7dd8eedea376413fd654937285ea6c9cfbb928dc3043ea4b606" dependencies = [ "getrandom 0.4.3", "js-sys", @@ -4330,7 +4330,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", "wasm-bindgen-shared", ] @@ -4905,7 +4905,7 @@ checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", "synstructure", ] @@ -4953,7 +4953,7 @@ dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", "zbus_names", "zvariant", "zvariant_utils", @@ -4996,7 +4996,7 @@ checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", "synstructure", ] @@ -5030,7 +5030,7 @@ checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -5069,7 +5069,7 @@ dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", "zvariant_utils", ] @@ -5082,6 +5082,6 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 3.0.6", + "syn 3.0.9", "winnow 1.0.4", ] diff --git a/Cargo.toml b/Cargo.toml index 00736f3..fefc48e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,17 +7,19 @@ license = "GPL-3.0-or-later" repository = "https://github.com/Project-Colony/MemoryStick" edition = "2021" rust-version = "1.90" +# Lockfile updates pick only versions that build on rust-version. +resolver = "3" [build-dependencies] -tauri-build = "2.7.1" -serde_json = "1.0.151" +tauri-build = "2.7.2" +serde_json = "1.0.154" [dependencies] -tauri = "2.12.2" -tauri-plugin-dialog = "2.8.1" -tauri-plugin-opener = "2.7.0" +tauri = "2.12.3" +tauri-plugin-dialog = "2.8.2" +tauri-plugin-opener = "2.7.1" serde = { version = "1.0.229", features = ["derive"] } -serde_json = "1.0.151" +serde_json = "1.0.154" dirs = "7.0.0" percent-encoding = "2.3.2" comrak = { version = "0.56.0", default-features = false } From 50bb44b1531472dd621f7a08b33c5f50c1d0bf20 Mon Sep 17 00:00:00 2001 From: MotherSphere Date: Wed, 14 Oct 2026 13:24:51 +0200 Subject: [PATCH 2/4] ci: install Rust with rustup instead of a third-party action Dependabot cannot move dtolnay/rust-toolchain pinned on master. The MSRV job pins its toolchain with RUSTUP_TOOLCHAIN and checks rustc's version. Also points the themes check at Project-Colony-Resources 8931f2b. --- .github/workflows/ci.yml | 38 ++++++++++++++++++++--------------- .github/workflows/release.yml | 16 ++++++++------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 751b03d..2b6900a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,13 +33,13 @@ jobs: with: persist-credentials: false - # Pinned to master with `toolchain: stable` rather than to the `stable` - # branch: that branch is rebased onto every master commit, so a SHA - # pinned on it stops being reachable from any branch. - - uses: dtolnay/rust-toolchain@e2a55d2ffb04f378e9626c28d38b36d230d1e12f # master, 2026-10-09 - with: - toolchain: stable - components: clippy, rustfmt + # rustup is on every GitHub-hosted runner image: no third-party action to + # pin, and nothing for Dependabot to lose track of. + - name: Install Rust + shell: bash + run: | + rustup toolchain install stable --profile minimal -c clippy,rustfmt --no-self-update + rustup default stable - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 with: @@ -83,6 +83,10 @@ jobs: # rust-version in Cargo.toml is a promise; this job is what keeps it. It # builds and tests on exactly that toolchain, read from Cargo.toml so the # two cannot drift apart. + # + # RUSTUP_TOOLCHAIN is what pins the cargo invocations: it outranks both the + # runner's rustup default and any rust-toolchain.toml. The rustc check makes + # a pin that silently stopped working fail loudly. msrv: name: MSRV runs-on: ubuntu-latest @@ -98,10 +102,10 @@ jobs: version=$(sed -n 's/^rust-version = "\(.*\)"$/\1/p' Cargo.toml) [ -n "$version" ] || { echo "::error::could not read rust-version from Cargo.toml"; exit 1; } echo "version=$version" >> "$GITHUB_OUTPUT" + echo "RUSTUP_TOOLCHAIN=$version" >> "$GITHUB_ENV" - - uses: dtolnay/rust-toolchain@e2a55d2ffb04f378e9626c28d38b36d230d1e12f # master, 2026-10-09 - with: - toolchain: ${{ steps.msrv.outputs.version }} + - name: Install Rust ${{ steps.msrv.outputs.version }} + run: rustup toolchain install "$RUSTUP_TOOLCHAIN" --profile minimal --no-self-update - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 with: @@ -113,7 +117,10 @@ jobs: sudo apt-get install -y libwebkit2gtk-4.1-dev - name: Build and test on the declared floor - run: cargo test --locked + run: | + rustc --version | grep -q "^rustc ${RUSTUP_TOOLCHAIN}[. ]" \ + || { echo "::error::expected rustc ${RUSTUP_TOOLCHAIN}, got $(rustc --version)"; exit 1; } + cargo test --locked colony-themes: name: Colony themes @@ -122,10 +129,9 @@ jobs: run: shell: bash env: - # A Project-Colony-Resources commit whose generated/ matches the one - # colony-ui 0.1.6 was published from. Bump it together with - # src/ui/vendor/colony/README.md. - COLONY_RESOURCES_REV: 7247b814fd9afbb17e3c4f44315ec9333c3a31b0 + # The Project-Colony-Resources commit src/ui/vendor/colony/ is copied + # from. Bump it together with src/ui/vendor/colony/README.md. + COLONY_RESOURCES_REV: 8931f2b38422fe75757db6218a6bcbc8caa06a85 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -139,7 +145,7 @@ jobs: curl -fsSL --retry 3 "$base/css/colony-accents.css" | cmp - src/ui/vendor/colony/colony-accents.css curl -fsSL --retry 3 "$base/themes.json" | cmp - src/ui/vendor/colony/themes.json - - name: Every theme defines the colours src/ui/ uses + - name: Every theme defines the colours src/ui/ uses, and accent labels stay legible run: python3 .github/scripts/check-colony-themes.py # render() in src/ui/app.js is the only place a document's scripts, frames diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8e57f82..75b3d26 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -93,13 +93,15 @@ jobs: ref: ${{ needs.release-please.outputs.tag_name || inputs.tag }} persist-credentials: false - # Pinned to master with `toolchain: stable` rather than to the `stable` - # branch: that branch is rebased onto every master commit, so a SHA - # pinned on it stops being reachable from any branch. - - uses: dtolnay/rust-toolchain@e2a55d2ffb04f378e9626c28d38b36d230d1e12f # master, 2026-10-09 - with: - toolchain: stable - targets: ${{ matrix.target }} + # rustup is on every GitHub-hosted runner image, so there is no + # third-party toolchain action to pin. Adding the target is a no-op on + # the legs that build for their own host; the Intel macOS leg needs it. + - name: Install Rust + shell: bash + run: | + rustup toolchain install stable --profile minimal --no-self-update + rustup default stable + rustup target add ${{ matrix.target }} # No build cache here: SignPath forbids release builds that reuse # outputs of earlier, unverified builds. From da3a7c35e734068e9c7d95986e9c98aa8fde8c9f Mon Sep 17 00:00:00 2001 From: MotherSphere Date: Wed, 14 Oct 2026 13:24:51 +0200 Subject: [PATCH 3/4] fix(ui): draw text on an accent in Colony's ink or paper Vendors the current Colony themes (Project-Colony-Resources 8931f2b), which export --colony-ink and --colony-paper. theme.js sets --on-accent to whichever contrasts more with the accent in use, as colony-ui's contrast_on() does, for the selected contents entry, category, choice, switch knob and accent check. The themes check now fails under 4.0:1 for any theme and accent. --- .github/scripts/check-colony-themes.py | 37 +++- docs/third-party-notices.md | 2 +- src/ui/styles.css | 12 +- src/ui/theme.js | 8 + src/ui/vendor/colony/README.md | 20 +- src/ui/vendor/colony/colony-accents.css | 9 +- src/ui/vendor/colony/colony-themes.css | 4 +- src/ui/vendor/colony/themes.json | 248 +++++++++++++++++++++++- 8 files changed, 312 insertions(+), 28 deletions(-) diff --git a/.github/scripts/check-colony-themes.py b/.github/scripts/check-colony-themes.py index ad95511..dd416c8 100644 --- a/.github/scripts/check-colony-themes.py +++ b/.github/scripts/check-colony-themes.py @@ -8,6 +8,11 @@ colony-accents.css sets the accent colours once for every theme, so a variable it defines counts as defined everywhere, and every accent the picker offers must be one of them. + +Text on an accent fill (the selected contents entry, category and choice) +takes --colony-ink or --colony-paper, whichever contrasts more, as theme.js +does. That must reach 4.0:1 on every theme's own accent and on every accent +override. """ import json @@ -20,21 +25,35 @@ def variables(css_file): - """{selector: set of --colony-* names}, comments out first: the file + """{selector: {--colony-* name: value}}, comments out first: the file header quotes a selector.""" css = re.sub(r"/\*.*?\*/", "", (vendor / css_file).read_text(encoding="utf-8"), flags=re.S) return { - selector.strip(): set(re.findall(r"(--colony-[a-z0-9-]+):", body)) + selector.strip(): dict(re.findall(r"(--colony-[a-z0-9-]+):\s*([^;]+);", body)) for selector, body in re.findall(r"([^{}]+)\{([^}]*)\}", css) } +def contrast(a, b): + """WCAG contrast ratio of two #rrggbb colours, as theme.js computes it.""" + + def luminance(color): + r, g, b = ( + c / 12.92 if c <= 0.03928 else ((c + 0.055) / 1.055) ** 2.4 + for c in (int(color[i : i + 2], 16) / 255 for i in (1, 3, 5)) + ) + return 0.2126 * r + 0.7152 * g + 0.0722 * b + + hi, lo = sorted((luminance(a), luminance(b)), reverse=True) + return (hi + 0.05) / (lo + 0.05) + + themes = { re.search(r'\[data-colony-theme="([^"]+)"\]', selector).group(1): defined for selector, defined in variables("colony-themes.css").items() if "[data-colony-theme=" in selector } -accents = variables("colony-accents.css").get(":root", set()) +accents = variables("colony-accents.css").get(":root", {}) theme_list = json.loads((vendor / "themes.json").read_text(encoding="utf-8")) listed = {variant["slug"] for family in theme_list["families"] for variant in family["variants"]} @@ -45,10 +64,18 @@ def variables(css_file): if accent["cssVar"] not in accents: errors.append(f"themes.json: accent {accent['key']} has no {accent['cssVar']} in colony-accents.css") for path in sorted(ui.glob("*.*")): - for var in sorted(set(re.findall(r"--colony-[a-z0-9-]+", path.read_text(encoding="utf-8"))) - accents): + for var in sorted(set(re.findall(r"--colony-[a-z0-9-]+", path.read_text(encoding="utf-8"))) - accents.keys()): missing = [slug for slug, defined in themes.items() if var not in defined] if missing: errors.append(f"{path.name}: {var} is missing from {', '.join(missing)}") +overrides = {accent["key"]: accents.get(accent["cssVar"]) for accent in theme_list["accents"]} +for slug, defined in themes.items(): + for name, color in {"its own": defined.get("--colony-accent-blue"), **overrides}.items(): + if not color or "--colony-ink" not in accents or "--colony-paper" not in accents: + continue # already reported above + best = max(contrast(accents[end], color) for end in ("--colony-ink", "--colony-paper")) + if best < 4.0: + errors.append(f"{slug}: text on {name} accent {color} reaches only {best:.2f}:1") -print("\n".join(errors) or f"OK: all {len(themes)} themes define every --colony-* variable in src/ui/") +print("\n".join(errors) or f"OK: all {len(themes)} themes define every --colony-* variable in src/ui/, and text on every accent reaches 4.0:1") sys.exit(1 if errors else 0) diff --git a/docs/third-party-notices.md b/docs/third-party-notices.md index 0bb86d2..6b65ff1 100644 --- a/docs/third-party-notices.md +++ b/docs/third-party-notices.md @@ -11,7 +11,7 @@ every build. | KaTeX | 0.19.0 | MIT | `src/ui/vendor/katex/katex.min.js`, `katex.min.css` ([LICENSE](../src/ui/vendor/katex/LICENSE)) | https://github.com/KaTeX/KaTeX | | KaTeX fonts | 0.19.0 | OFL-1.1 | `src/ui/vendor/katex/fonts/` (notice in each font file, licence text in [LICENSE](../src/ui/vendor/katex/LICENSE)) | https://github.com/KaTeX/KaTeX | | Mermaid | 11.17.2 | MIT | `src/ui/vendor/mermaid/mermaid.min.js` ([LICENSE](../src/ui/vendor/mermaid/LICENSE)) | https://github.com/mermaid-js/mermaid | -| Colony themes and accents | Project-Colony-Resources `7247b81` (colony-ui 0.1.6) | GPL-3.0-or-later, like MemoryStick | `src/ui/vendor/colony/` ([README](../src/ui/vendor/colony/README.md)) | https://github.com/Project-Colony/Project-Colony-Resources | +| Colony themes and accents | Project-Colony-Resources `8931f2b` | GPL-3.0-or-later, like MemoryStick | `src/ui/vendor/colony/` ([README](../src/ui/vendor/colony/README.md)) | https://github.com/Project-Colony/Project-Colony-Resources | | JetBrains Mono Nerd Font | 2.304, Nerd Fonts 3.4.0 | OFL-1.1 | `src/ui/fonts/JetBrainsMonoNerdFont-*.ttf` ([LICENSE](../src/ui/fonts/LICENSE)) | https://github.com/ryanoasis/nerd-fonts | | OpenDyslexic | 0.990 | OFL-1.1 | `src/ui/fonts/OpenDyslexic-Regular.otf` ([LICENSE](../src/ui/fonts/LICENSE)) | https://opendyslexic.org | | Font Awesome 6 Free Solid | 6.7.2 | OFL-1.1 (font), CC-BY-4.0 (icons) | `src/ui/fonts/fa-solid-900.ttf` ([LICENSE](../src/ui/fonts/LICENSE)) | https://fontawesome.com | diff --git a/src/ui/styles.css b/src/ui/styles.css index 2e72c94..25f13c9 100644 --- a/src/ui/styles.css +++ b/src/ui/styles.css @@ -154,7 +154,8 @@ button { font: inherit; color: inherit; } #toc-nav > ul { padding-left: 0; } #toc-nav li { margin: 4px 0; } /* Colony's selection rule: the section being read gets the accent behind - it, hover gets bg-card-hover, the rest stays muted. */ + it, with --on-accent text (theme.js), hover gets bg-card-hover, the rest + stays muted. */ #toc-nav a { color: var(--colony-text-muted); text-decoration: none; @@ -165,7 +166,7 @@ button { font: inherit; color: inherit; } cursor: pointer; } #toc-nav a:hover { background: var(--colony-bg-card-hover); color: var(--colony-text-primary); } -#toc-nav a[aria-current] { background: var(--colony-accent-blue); color: var(--colony-text-primary); } +#toc-nav a[aria-current] { background: var(--colony-accent-blue); color: var(--on-accent); } body.toc-open #main { margin-left: 280px; } @@ -372,7 +373,7 @@ body.drag-over #drop-hint .hint-title { color: var(--colony-accent-blue); } cursor: pointer; } .category:hover { background: var(--colony-bg-card-hover); } -.category[aria-current] { background: var(--colony-accent-blue); color: var(--colony-text-primary); } +.category[aria-current] { background: var(--colony-accent-blue); color: var(--on-accent); } .prefs-content h2 { margin: 0 0 4px; @@ -414,6 +415,7 @@ body.drag-over #drop-hint .hint-title { color: var(--colony-accent-blue); } .setting-label { font-size: calc(14px * var(--font-scale)); } .setting-desc { color: var(--colony-text-muted); font-size: calc(12px * var(--font-scale)); margin-top: 2px; } .setting-desc:empty { display: none; } +.setting-value { color: var(--colony-text-secondary); font-size: calc(13px * var(--font-scale)); } .switch { position: relative; @@ -438,7 +440,7 @@ body.drag-over #drop-hint .hint-title { color: var(--colony-accent-blue); } transition: transform 0.15s; } .switch[aria-checked="true"] { background: var(--colony-accent-blue); } -.switch[aria-checked="true"] .knob { transform: translateX(18px); background: var(--colony-text-primary); } +.switch[aria-checked="true"] .knob { transform: translateX(18px); background: var(--on-accent); } .switch:disabled { opacity: 0.5; cursor: default; } .segmented { display: flex; flex-wrap: wrap; gap: 4px; } @@ -451,7 +453,7 @@ body.drag-over #drop-hint .hint-title { color: var(--colony-accent-blue); } cursor: pointer; } .segmented button:hover { background: var(--colony-btn-hover); } -.segmented button[aria-checked="true"] { background: var(--colony-accent-blue); color: var(--colony-text-primary); } +.segmented button[aria-checked="true"] { background: var(--colony-accent-blue); color: var(--on-accent); } /* Theme cards: the variant's swatch background crossed by its accent, its name bottom-left in its own text colour, a check on the chosen one. */ diff --git a/src/ui/theme.js b/src/ui/theme.js index 3317cfe..4cfb770 100644 --- a/src/ui/theme.js +++ b/src/ui/theme.js @@ -92,6 +92,13 @@ function contrast(a, b) { return (hi + 0.05) / (lo + 0.05); } +// Text on an accent fill: Colony's ink or paper (colony-accents.css), +// whichever contrasts more, as colony-ui's contrast_on() picks. +function onAccent(color) { + const [ink, paper] = [cssVar('--colony-ink'), cssVar('--colony-paper')]; + return contrast(ink, color) >= contrast(paper, color) ? ink : paper; +} + function applyAppearance() { // Back to the theme's own palette first, then the user's changes on top. for (const field of Object.keys(HIGH_CONTRAST)) $root.style.removeProperty('--colony-' + field); @@ -104,6 +111,7 @@ function applyAppearance() { // No override, or auto accent, leaves the theme's own accent. const accent = !prefs.autoAccent && themeList.accents.find((a) => a.key === prefs.accent); if (accent) $root.style.setProperty('--colony-accent-blue', accentColor(accent)); + $root.style.setProperty('--on-accent', onAccent(cssVar('--colony-accent-blue'))); if (prefs.highContrast) { // colony_ui's is_light: YIQ luma of the background over 0.5. diff --git a/src/ui/vendor/colony/README.md b/src/ui/vendor/colony/README.md index 7a48300..18901e1 100644 --- a/src/ui/vendor/colony/README.md +++ b/src/ui/vendor/colony/README.md @@ -3,15 +3,16 @@ `colony-themes.css`, `colony-accents.css` and `themes.json` are copied unmodified from [Project-Colony-Resources](https://github.com/Project-Colony/Project-Colony-Resources) -`generated/`, at commit `7247b814fd9afbb17e3c4f44315ec9333c3a31b0`. Its -`generated/` is the same as at the commit colony-ui 0.1.6 was published -from, so MemoryStick shows the same colours as Colony. They are -GPL-3.0-or-later, like MemoryStick. +`generated/`, at commit `8931f2b38422fe75757db6218a6bcbc8caa06a85`. Its +theme and accent colours are the ones colony-ui 0.1.6 draws, so MemoryStick +shows the same colours as Colony. They are GPL-3.0-or-later, like +MemoryStick. - `colony-themes.css` defines the `--colony-*` colours of every theme, one block per `[data-colony-theme="-"]`. - `colony-accents.css` defines the shared accent colours, the same in every - theme, as `--colony-accent-` on `:root`. + theme, as `--colony-accent-` on `:root`, and `--colony-ink` and + `--colony-paper`, the two label colours for text on an accent. - `themes.json` lists the families and variants, in Colony's order, with their names and light or dark mode, and the accents with their names. The theme picker and the accent swatches are built from it. @@ -21,14 +22,17 @@ GPL-3.0-or-later, like MemoryStick. later file wins and each theme keeps its own accent. When the user picks an accent, `theme.js` reads its colour from the `:root` rule of `colony-accents.css` and sets it as an inline `--colony-accent-blue`, which -wins over both; the swatches in Preferences read the same rule. +wins over both; the swatches in Preferences read the same rule. It then sets +`--on-accent` to whichever of `--colony-ink` and `--colony-paper` contrasts +more with the accent in use, as colony-ui's `contrast_on()` does, for the +text of a selected entry or choice. `check-colony-themes.py` fails if that +falls under 4.0:1 for any theme and accent. Do not edit them: CI fails when they differ from upstream at that commit. ## Updating -1. Pick the Project-Colony-Resources commit, normally the one the colony-ui - release in use was published from (`.cargo_vcs_info.json` in the crate). +1. Pick the Project-Colony-Resources commit, normally its latest `main`. 2. Download the three files at that commit: ```sh diff --git a/src/ui/vendor/colony/colony-accents.css b/src/ui/vendor/colony/colony-accents.css index dae8da0..63b5f6f 100644 --- a/src/ui/vendor/colony/colony-accents.css +++ b/src/ui/vendor/colony/colony-accents.css @@ -1,9 +1,12 @@ /* - * Project Colony — accent overrides - * @generated by colony-tokens from tokens/accents.toml — DO NOT EDIT. + * Project Colony: accent overrides + * @generated by colony-tokens from tokens/accents.toml. DO NOT EDIT. * * Palette-independent. Load alongside a theme; "auto" means no override, * i.e. keep the theme's own --colony-accent-blue. + * + * --colony-ink and --colony-paper are the label colours for text drawn on an + * accent: use whichever contrasts more, as colony-ui's contrast_on() does. */ :root { --colony-accent-red: #e05555; @@ -14,4 +17,6 @@ --colony-accent-indigo: #7b6bd6; --colony-accent-violet: #b06bd6; --colony-accent-amber: #d4a030; + --colony-ink: #14141a; + --colony-paper: #f7faff; } diff --git a/src/ui/vendor/colony/colony-themes.css b/src/ui/vendor/colony/colony-themes.css index 81dc0a9..3adf4da 100644 --- a/src/ui/vendor/colony/colony-themes.css +++ b/src/ui/vendor/colony/colony-themes.css @@ -1,6 +1,6 @@ /* - * Project Colony — every theme (26 families, 59 variants). - * @generated by colony-tokens from tokens/families/*.toml — DO NOT EDIT. + * Project Colony: every theme (26 families, 59 variants). + * @generated by colony-tokens from tokens/families/*.toml. DO NOT EDIT. * * Apply a theme by setting [data-colony-theme="-"] on a * root element, or by adding the matching .colony-theme-* class. diff --git a/src/ui/vendor/colony/themes.json b/src/ui/vendor/colony/themes.json index 88f868a..b3548c8 100644 --- a/src/ui/vendor/colony/themes.json +++ b/src/ui/vendor/colony/themes.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "source": "https://github.com/Project-Colony/Project-Colony-Resources", - "note": "@generated by colony-tokens from tokens/families/*.toml — DO NOT EDIT.", + "note": "@generated by colony-tokens from tokens/. DO NOT EDIT.", "familyCount": 26, "variantCount": 59, "fields": [ @@ -278,6 +278,10 @@ "cssVar": "--colony-accent-amber" } ], + "contrastEnds": { + "ink": "#14141a", + "paper": "#f7faff" + }, "families": [ { "key": "catppuccin", @@ -3796,7 +3800,7 @@ "bg": "#eceeec", "accent": "#21a04d" }, - "notes": "Green ink on white-grey ceramic — her Planet Diving Suit. A light theme on\npurpose: a dark theme can never say \"white\".\n", + "notes": "Green ink on white-grey ceramic: her Planet Diving Suit. A light theme on\npurpose: a dark theme can never say \"white\".\n", "contrast": { "textPrimaryOnBgPrimary": 5.61, "textMutedOnBgPrimary": 3.5 @@ -3916,7 +3920,7 @@ "bg": "#111010", "accent": "#ffd23e" }, - "notes": "Strict gold-on-black duotone. No brown tint — the gold must stay gold.", + "notes": "Strict gold-on-black duotone. No brown tint: the gold must stay gold.", "contrast": { "textPrimaryOnBgPrimary": 11.96, "textMutedOnBgPrimary": 5.37 @@ -4036,7 +4040,7 @@ "bg": "#1a1622", "accent": "#cfa8ff" }, - "notes": "Lavender ink on deep violet. Her khaki coat is demoted to the success role\nrather than becoming a second surface — two saturated materials side by side\nclashed and were rejected.\n", + "notes": "Lavender ink on deep violet. Her khaki coat is demoted to the success role\nrather than becoming a second surface: two saturated materials side by side\nclashed and were rejected.\n", "contrast": { "textPrimaryOnBgPrimary": 11.4, "textMutedOnBgPrimary": 4.72 @@ -4157,5 +4161,239 @@ } ] } - ] + ], + "labels": { + "en": { + "settings_theme_catppuccin": "Catppuccin", + "settings_theme_catppuccin_latte": "Latte", + "settings_theme_catppuccin_frappe": "Frappé", + "settings_theme_catppuccin_macchiato": "Macchiato", + "settings_theme_catppuccin_mocha": "Mocha", + "settings_theme_gruvbox": "Gruvbox", + "settings_theme_light": "Light mode", + "settings_theme_dark_mode": "Dark mode", + "settings_theme_everblush": "Everblush", + "settings_theme_kanagawa": "Kanagawa", + "settings_theme_kanagawa_journal": "Journal mode", + "settings_theme_kanagawa_dragon": "Dragon mode", + "settings_theme_nord": "Nord", + "settings_theme_dracula": "Dracula", + "settings_theme_solarized": "Solarized", + "settings_theme_tokyonight": "Tokyo Night", + "settings_theme_tokyonight_night": "Night", + "settings_theme_tokyonight_day": "Day", + "settings_theme_rosepine": "Rosé Pine", + "settings_theme_rosepine_main": "Main", + "settings_theme_rosepine_moon": "Moon", + "settings_theme_rosepine_dawn": "Dawn", + "settings_theme_onedark": "One Dark", + "settings_theme_monokai": "Monokai Pro", + "settings_theme_monokai_pro": "Pro", + "settings_theme_monokai_classic": "Classic", + "settings_theme_monokai_spectrum": "Spectrum", + "settings_theme_ayu": "Ayu", + "settings_theme_ayu_mirage": "Mirage", + "settings_theme_everforest": "Everforest", + "settings_theme_material": "Material", + "settings_theme_material_oceanic": "Oceanic", + "settings_theme_material_palenight": "Palenight", + "settings_theme_material_deepocean": "Deep Ocean", + "settings_theme_flexoki": "Flexoki", + "settings_theme_nightfox": "Nightfox", + "settings_theme_nightfox_nightfox": "Nightfox", + "settings_theme_nightfox_dawnfox": "Dawnfox", + "settings_theme_sonokai": "Sonokai", + "settings_theme_sonokai_default": "Default", + "settings_theme_oxocarbon": "Oxocarbon", + "settings_theme_nightowl": "Night Owl", + "settings_theme_iceberg": "Iceberg", + "settings_theme_horizon": "Horizon", + "settings_theme_melange": "Melange", + "settings_theme_synthwave": "Synthwave '84", + "settings_theme_modus": "Modus", + "settings_theme_modus_operandi": "Operandi", + "settings_theme_modus_vivendi": "Vivendi", + "settings_theme_stellar_blade": "Stellar Blade", + "settings_theme_stellar_blade_eve": "EVE", + "settings_theme_stellar_blade_tachy": "Tachy", + "settings_theme_stellar_blade_lily": "Lily", + "settings_theme_stellar_blade_enya": "Enya", + "settings_theme_stellar_blade_kaya": "Kaya", + "settings_theme_parchment": "Parchment", + "settings_accent_red": "Red", + "settings_accent_orange": "Orange", + "settings_accent_yellow": "Yellow", + "settings_accent_green": "Green", + "settings_accent_blue": "Blue", + "settings_accent_indigo": "Indigo", + "settings_accent_violet": "Violet", + "settings_accent_amber": "Amber", + "settings_title": "Preferences", + "settings_close": "Close", + "theme_applied": "Theme applied.", + "settings_cat_general": "General", + "settings_general_desc": "Preferences are saved automatically.", + "settings_cat_appearance": "Appearance", + "settings_appearance_desc": "Adjust the theme, accents, text and visual effects.", + "settings_cat_accessibility": "Accessibility", + "settings_accessibility_desc": "Make the interface easier to see, read and use.", + "settings_cat_about": "About", + "settings_section_theme": "Theme", + "settings_theme_desc": "Applies immediately to the whole interface.", + "settings_section_colors": "Colors & accents", + "settings_colors_desc": "Pick an accent, or keep the one the theme was designed with.", + "settings_auto_accent": "Auto accent from background", + "settings_auto_accent_desc": "Uses the theme's own accent instead of the one picked above.", + "settings_default_accent": "Theme accent", + "settings_section_typography": "Typography", + "settings_typography_desc": "The interface font and its base size.", + "settings_font_family": "Font", + "settings_font_family_desc": "Switches to OpenDyslexic when the dyslexia-friendly font is on.", + "settings_font_size": "Text size", + "settings_font_size_desc": "Base size of every text in the interface.", + "settings_font_size_small": "Small", + "settings_font_size_default": "Default", + "settings_font_size_large": "Large", + "settings_font_size_xlarge": "Extra large", + "settings_section_effects": "Effects", + "settings_effects_desc": "Visual extras. Always off while Reduce motion is on.", + "settings_animations": "Animations", + "settings_animations_desc": "Animated transitions and fades.", + "settings_section_preview": "Preview", + "settings_preview_desc": "A live sample of your current choices.", + "settings_preview_card": "Preview card", + "settings_preview_body": "Body text looks like this.", + "settings_preview_button": "Button", + "settings_section_vision": "Vision", + "settings_vision_desc": "Options that make the interface easier to see.", + "settings_high_contrast": "High contrast", + "settings_high_contrast_desc": "Increases the contrast of text and borders.", + "settings_dyslexia_font": "Dyslexia-friendly font", + "settings_dyslexia_font_desc": "Replaces the interface font with OpenDyslexic.", + "settings_section_motion": "Motion", + "settings_motion_desc": "Calm the interface down.", + "settings_reduce_motion": "Reduce motion", + "settings_reduce_motion_desc": "Turns off every animation and transition.", + "settings_section_reading": "Reading", + "settings_reading_desc": "Reading comfort options.", + "settings_text_size_a11y": "Text size", + "settings_text_size_a11y_desc": "Scales all text. Multiplies with the size chosen in Appearance." + }, + "fr": { + "settings_theme_catppuccin": "Catppuccin", + "settings_theme_catppuccin_latte": "Latte", + "settings_theme_catppuccin_frappe": "Frappé", + "settings_theme_catppuccin_macchiato": "Macchiato", + "settings_theme_catppuccin_mocha": "Mocha", + "settings_theme_gruvbox": "Gruvbox", + "settings_theme_light": "Mode clair", + "settings_theme_dark_mode": "Mode sombre", + "settings_theme_everblush": "Everblush", + "settings_theme_kanagawa": "Kanagawa", + "settings_theme_kanagawa_journal": "Mode journal", + "settings_theme_kanagawa_dragon": "Mode dragon", + "settings_theme_nord": "Nord", + "settings_theme_dracula": "Dracula", + "settings_theme_solarized": "Solarized", + "settings_theme_tokyonight": "Tokyo Night", + "settings_theme_tokyonight_night": "Nuit", + "settings_theme_tokyonight_day": "Jour", + "settings_theme_rosepine": "Rosé Pine", + "settings_theme_rosepine_main": "Principal", + "settings_theme_rosepine_moon": "Lune", + "settings_theme_rosepine_dawn": "Aurore", + "settings_theme_onedark": "One Dark", + "settings_theme_monokai": "Monokai Pro", + "settings_theme_monokai_pro": "Pro", + "settings_theme_monokai_classic": "Classic", + "settings_theme_monokai_spectrum": "Spectrum", + "settings_theme_ayu": "Ayu", + "settings_theme_ayu_mirage": "Mirage", + "settings_theme_everforest": "Everforest", + "settings_theme_material": "Material", + "settings_theme_material_oceanic": "Oceanic", + "settings_theme_material_palenight": "Palenight", + "settings_theme_material_deepocean": "Deep Ocean", + "settings_theme_flexoki": "Flexoki", + "settings_theme_nightfox": "Nightfox", + "settings_theme_nightfox_nightfox": "Nightfox", + "settings_theme_nightfox_dawnfox": "Dawnfox", + "settings_theme_sonokai": "Sonokai", + "settings_theme_sonokai_default": "Défaut", + "settings_theme_oxocarbon": "Oxocarbon", + "settings_theme_nightowl": "Night Owl", + "settings_theme_iceberg": "Iceberg", + "settings_theme_horizon": "Horizon", + "settings_theme_melange": "Mélange", + "settings_theme_synthwave": "Synthwave '84", + "settings_theme_modus": "Modus", + "settings_theme_modus_operandi": "Operandi", + "settings_theme_modus_vivendi": "Vivendi", + "settings_theme_stellar_blade": "Stellar Blade", + "settings_theme_stellar_blade_eve": "EVE", + "settings_theme_stellar_blade_tachy": "Tachy", + "settings_theme_stellar_blade_lily": "Lily", + "settings_theme_stellar_blade_enya": "Enya", + "settings_theme_stellar_blade_kaya": "Kaya", + "settings_theme_parchment": "Parchemin", + "settings_accent_red": "Rouge", + "settings_accent_orange": "Orange", + "settings_accent_yellow": "Jaune", + "settings_accent_green": "Vert", + "settings_accent_blue": "Bleu", + "settings_accent_indigo": "Indigo", + "settings_accent_violet": "Violet", + "settings_accent_amber": "Ambre", + "settings_title": "Préférences", + "settings_close": "Fermer", + "theme_applied": "Thème appliqué.", + "settings_cat_general": "Général", + "settings_general_desc": "Les préférences sont enregistrées automatiquement.", + "settings_cat_appearance": "Apparence", + "settings_appearance_desc": "Ajustez le thème, les accents, le texte et les effets visuels.", + "settings_cat_accessibility": "Accessibilité", + "settings_accessibility_desc": "Rendez l'interface plus facile à voir, à lire et à utiliser.", + "settings_cat_about": "À propos", + "settings_section_theme": "Thème", + "settings_theme_desc": "S'applique immédiatement à toute l'interface.", + "settings_section_colors": "Couleurs & accents", + "settings_colors_desc": "Choisissez un accent, ou gardez celui du thème.", + "settings_auto_accent": "Accent automatique selon le fond", + "settings_auto_accent_desc": "Utilise l'accent du thème plutôt que celui choisi ci-dessus.", + "settings_default_accent": "Accent du thème", + "settings_section_typography": "Typographie", + "settings_typography_desc": "La police de l'interface et sa taille de base.", + "settings_font_family": "Police", + "settings_font_family_desc": "Passe à OpenDyslexic quand la police adaptée à la dyslexie est activée.", + "settings_font_size": "Taille du texte", + "settings_font_size_desc": "Taille de base de tous les textes de l'interface.", + "settings_font_size_small": "Petit", + "settings_font_size_default": "Par défaut", + "settings_font_size_large": "Grand", + "settings_font_size_xlarge": "Très grand", + "settings_section_effects": "Effets", + "settings_effects_desc": "Extras visuels. Toujours désactivés quand Réduire les animations est activé.", + "settings_animations": "Animations", + "settings_animations_desc": "Transitions et fondus animés.", + "settings_section_preview": "Aperçu", + "settings_preview_desc": "Un aperçu en direct de vos choix actuels.", + "settings_preview_card": "Carte d'aperçu", + "settings_preview_body": "Le texte courant ressemble à ceci.", + "settings_preview_button": "Bouton", + "settings_section_vision": "Vision", + "settings_vision_desc": "Options pour rendre l'interface plus lisible.", + "settings_high_contrast": "Contraste élevé", + "settings_high_contrast_desc": "Augmente le contraste du texte et des bordures.", + "settings_dyslexia_font": "Police adaptée à la dyslexie", + "settings_dyslexia_font_desc": "Remplace la police de l'interface par OpenDyslexic.", + "settings_section_motion": "Mouvement", + "settings_motion_desc": "Apaisez l'interface.", + "settings_reduce_motion": "Réduire les animations", + "settings_reduce_motion_desc": "Désactive toutes les animations et transitions.", + "settings_section_reading": "Lecture", + "settings_reading_desc": "Options de confort de lecture.", + "settings_text_size_a11y": "Taille du texte", + "settings_text_size_a11y_desc": "Agrandit tout le texte. Se multiplie avec la taille choisie dans Apparence." + } + } } From 7af7dafbcba6ffe1eb882a6e528cca56ecb4e575 Mon Sep 17 00:00:00 2001 From: MotherSphere Date: Wed, 14 Oct 2026 13:24:51 +0200 Subject: [PATCH 4/4] feat(ui): show the font in use, describe the preview and translate math errors --- src/ui/app.js | 2 +- src/ui/i18n/en.json | 6 +++++- src/ui/i18n/fr.json | 6 +++++- src/ui/preferences.js | 11 +++++------ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/ui/app.js b/src/ui/app.js index a034f3e..bda5bfe 100644 --- a/src/ui/app.js +++ b/src/ui/app.js @@ -192,7 +192,7 @@ function postProcess() { el.outerHTML = html; } } catch (err) { - el.textContent = '\uf071 ' + err.message; + el.textContent = '\uf071 ' + t('error_math', String(err.message || err)); } }); } diff --git a/src/ui/i18n/en.json b/src/ui/i18n/en.json index 6edd4cc..e46024c 100644 --- a/src/ui/i18n/en.json +++ b/src/ui/i18n/en.json @@ -18,6 +18,7 @@ "error_cannot_open_link": "Cannot open the link: {detail}", "error_cannot_save": "The preferences could not be saved: {detail}", "error_diagram": "Diagram error: {detail}", + "error_math": "Math error: {detail}", "error_interface": "Interface error: {detail}", "theme_applied": "Theme applied.", "toast_dismiss": "Dismiss", @@ -43,7 +44,9 @@ "preferences_auto_accent": "Auto accent from background", "preferences_auto_accent_desc": "Uses each theme's own accent instead.", "preferences_section_typography": "Typography", - "preferences_typography_desc": "Configure the text size.", + "preferences_typography_desc": "The interface font and its base size.", + "preferences_font_family": "Font", + "preferences_font_family_desc": "Switches to OpenDyslexic when the dyslexia font is on, in Accessibility. Code stays monospaced.", "preferences_font_size": "Text size", "preferences_font_size_desc": "Base text size.", "preferences_size_small": "Small", @@ -55,6 +58,7 @@ "preferences_animations": "Animations", "preferences_animations_desc": "The contents panel slides in, and links to a heading scroll to it smoothly.", "preferences_section_preview": "Preview", + "preferences_preview_desc": "A sample in the current theme, accent, font and size.", "preferences_preview_heading": "A heading", "preferences_preview_body": "Body text, as a document shows it, with a link and some inline code.", "preferences_preview_link": "A link", diff --git a/src/ui/i18n/fr.json b/src/ui/i18n/fr.json index 017823a..7dfe3b6 100644 --- a/src/ui/i18n/fr.json +++ b/src/ui/i18n/fr.json @@ -18,6 +18,7 @@ "error_cannot_open_link": "Impossible d'ouvrir le lien : {detail}", "error_cannot_save": "Les préférences n'ont pas pu être enregistrées : {detail}", "error_diagram": "Erreur dans le diagramme : {detail}", + "error_math": "Erreur dans la formule : {detail}", "error_interface": "Erreur de l'interface : {detail}", "theme_applied": "Thème appliqué.", "toast_dismiss": "Fermer", @@ -43,7 +44,9 @@ "preferences_auto_accent": "Accent automatique selon le fond", "preferences_auto_accent_desc": "Utilise plutôt l'accent propre à chaque thème.", "preferences_section_typography": "Typographie", - "preferences_typography_desc": "Configurez la taille du texte.", + "preferences_typography_desc": "La police de l'interface et sa taille de base.", + "preferences_font_family": "Police", + "preferences_font_family_desc": "Passe à OpenDyslexic quand la police dyslexie est activée, dans Accessibilité. Le code reste à chasse fixe.", "preferences_font_size": "Taille du texte", "preferences_font_size_desc": "Taille de base du texte.", "preferences_size_small": "Petite", @@ -55,6 +58,7 @@ "preferences_animations": "Animations", "preferences_animations_desc": "Le panneau du sommaire glisse, et les liens vers un titre y défilent en douceur.", "preferences_section_preview": "Aperçu", + "preferences_preview_desc": "Un échantillon dans le thème, l'accent, la police et la taille actuels.", "preferences_preview_heading": "Un titre", "preferences_preview_body": "Du texte, tel qu'un document l'affiche, avec un lien et un peu de code.", "preferences_preview_link": "Un lien", diff --git a/src/ui/preferences.js b/src/ui/preferences.js index a615169..a19a35e 100644 --- a/src/ui/preferences.js +++ b/src/ui/preferences.js @@ -126,10 +126,6 @@ function themePicker() { } function accentPicker() { - // The check takes whichever of the theme's text and background reads - // better on the swatch. - const ink = (color) => [cssVar('--colony-text-primary'), cssVar('--colony-bg-primary')] - .sort((a, b) => contrast(b, color) - contrast(a, color))[0]; return h('div.accents', { role: 'radiogroup', 'aria-label': t('preferences_section_colors') }, themeList.accents.map((accent) => { const selected = !prefs.autoAccent && prefs.accent === accent.key; @@ -141,7 +137,7 @@ function accentPicker() { 'aria-label': name, title: name, 'data-id': `accent-${accent.key}`, - style: { '--swatch': color, color: ink(color) }, + style: { '--swatch': color, color: onAccent(color) }, onclick: () => change((p) => { p.accent = accent.key; p.autoAccent = false; }), }, selected ? icon(GLYPH.check) : ''); })); @@ -191,6 +187,9 @@ const PAGES = { toggle('auto-accent', t('preferences_auto_accent'), t('preferences_auto_accent_desc'), prefs.autoAccent === true, (p) => { p.autoAccent = !p.autoAccent; })), section('typography', t('preferences_section_typography'), t('preferences_typography_desc'), + // Read-only: the dyslexia font, in Accessibility, is the only choice. + setting(t('preferences_font_family'), t('preferences_font_family_desc'), + h('span.setting-value', { 'data-id': 'font-family' }, prefs.dyslexiaFont === true ? 'OpenDyslexic' : 'JetBrainsMono Nerd Font')), choice('font-size', t('preferences_font_size'), t('preferences_font_size_desc'), sizeOptions(['small', 'default', 'large']), ['small', 'large'].includes(prefs.fontSize) ? prefs.fontSize : 'default', (p, v) => { p.fontSize = v; })), @@ -199,7 +198,7 @@ const PAGES = { toggle('animations', t('preferences_animations'), t('preferences_animations_desc'), prefs.animations !== false && !reducedMotion(), (p) => { p.animations = p.animations === false; }, reducedMotion())), - section('preview', t('preferences_section_preview'), '', preview()), + section('preview', t('preferences_section_preview'), t('preferences_preview_desc'), preview()), ], accessibility: () => [ section('vision', t('preferences_section_vision'), t('preferences_vision_desc'),