johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
// The pages' colours, held to WCAG 2.2's AA contrast (1.4.3): text and
// what it is drawn on at least 4.5:1, in every theme web/src/tokens.css
// defines: light, dark as the system asks for it and as chosen, and each
// other. A colour is only ever text on some surfaces, which PAIRS names;
// one drawn over another, as a diff's changed word is over its line, is
// composed as the browser would. A new colour that is text goes in PAIRS.
//
// node harness/contrast.mjs
//
// The pairs and how they are measured are web/src/lib/contrast.ts's, which
// the theme editor holds a theme of someone's own to as well.
//
// Prints each pair that falls short as `theme: text on surface ratio`,
// failing if any, and that the two copies of dark agree.
import { readFileSync } from 'node:fs'
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { AA, block, blocks, shortfalls } from '../web/src/lib/contrast.ts'
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const css = readFileSync(join(root, 'web/src/tokens.css'), 'utf8')
const { light, dark, chosenDark, shared } = blocks(css)
const themes = { light, dark }
for (const [, id] of css.matchAll(/^\[data-theme='([\w-]+)'\] \{/gm))
if (id !== 'light' && id !== 'dark')
themes[id] = { ...light, ...shared, ...block(css, `[data-theme='${id}']`) }
const problems = []
for (const [id, env] of Object.entries(themes))
for (const s of shortfalls(env))
problems.push(`${id}: ${s.text} on ${s.on} ${s.ratio.toFixed(2)}:1, under ${AA}:1`)
for (const [name, value] of Object.entries(dark))
if (chosenDark[name] !== value)
problems.push(`dark: --${name} is ${value} as the system asks, ${chosenDark[name]} as chosen`)
for (const p of problems) console.log(p)
if (problems.length) process.exit(1)
console.log(
`contrast: ${Object.keys(themes).length} themes, every text at least ${AA}:1 on what it is drawn on`,
)