diff --git a/README.md b/README.md index d09c76dc..ef06f981 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@ First time you start it up you should also run `yarn prep data` # User study burn down -- [ ] Make lints fast / non blocking as much as possible - [ ] Make deactivation story make sense in new context - [ ] Get most of the lints converted - [ ] Tour? - [ ] roles, palette level semantics - [ ] Design adjustments for smaller screens +- [x] Make lints fast / non blocking as much as possible # Language todos diff --git a/src/lib/ColorLint.test.ts b/src/lib/ColorLint.test.ts index 27460d4c..4cd62b42 100644 --- a/src/lib/ColorLint.test.ts +++ b/src/lib/ColorLint.test.ts @@ -4,7 +4,6 @@ import { Color } from "./Color"; import type { Palette } from "../stores/color-store"; import ColorNameDiscriminability, { getName } from "./lints/name-discrim"; -import BackgroundDifferentiability from "./lints/background-differentiability"; import BUILT_INS from "./lints/built-in-lints"; import { CreateCustomLint } from "./lints/CustomLint"; import { suggestLintFix } from "./linter-tools/lint-fixer"; @@ -84,6 +83,9 @@ test("ColorLint - ColorBlind", async () => { const ughWhat = ["#00ffff", "#00faff", "#00e4ff", "#fdfdfc", "#00ffff"]; test("ColorLint - BackgroundDifferentiability", async () => { const examplePal = makePalFromHexes(ughWhat); + const BackgroundDifferentiability = CreateCustomLint( + BUILT_INS.find((x) => x.id === "background-contrast-built-in")! + ); const exampleLint = new BackgroundDifferentiability(examplePal).run(); expect(exampleLint.passes).toBe(false); expect(exampleLint.message).toBe( diff --git a/src/lib/linter-tools/lint-fixer.ts b/src/lib/linter-tools/lint-fixer.ts index 90040c3c..ef111b6b 100644 --- a/src/lib/linter-tools/lint-fixer.ts +++ b/src/lib/linter-tools/lint-fixer.ts @@ -4,7 +4,11 @@ import type { LintResult } from "../lints/ColorLint"; import { manualLints } from "../linter"; import { Color } from "../Color"; -function AIFix(palette: Palette, message: string, engine: string) { +export async function suggestLintAIFix( + palette: Palette, + message: string, + engine: string +) { const colorSpace = palette.colorSpace; return suggestFix(palette, message, engine as any).then((x) => { if (x.length === 0) { @@ -26,14 +30,6 @@ function AIFix(palette: Palette, message: string, engine: string) { }); } -export async function suggestLintAIFix( - palette: Palette, - lint: LintResult, - engine?: string -) { - return AIFix(palette, lint.message, engine || "openai"); -} - const fixDirectory: Record = {}; manualLints.forEach((x) => { const demo = new x({} as any); diff --git a/src/lib/linter-tools/lint-worker.worker.ts b/src/lib/linter-tools/lint-worker.worker.ts index 308eabfd..d33a2597 100644 --- a/src/lib/linter-tools/lint-worker.worker.ts +++ b/src/lib/linter-tools/lint-worker.worker.ts @@ -35,18 +35,20 @@ const hydratePal = (pal: string): Palette => { let lintStore: CustomLint[] = []; let storeLoaded = false; const storeName = "color-pal-lints"; +const simpleLintCache = new Map(); async function dispatch(cmd: Command) { switch (cmd.type) { case "load-lints": idb.get(storeName).then((x) => { lintStore = x.lints; storeLoaded = true; - console.log("loaded lints", lintStore); return ""; }); return ""; case "run-lint": - // TODO add a cache here + if (simpleLintCache.has(cmd.content)) { + return simpleLintCache.get(cmd.content); + } const pal = hydratePal(cmd.content); // if store not loaded, wait while (!storeLoaded) { @@ -66,14 +68,13 @@ async function dispatch(cmd: Command) { hasHeuristicFix: x.hasHeuristicFix, }; }); - console.log("ran lints", result); + simpleLintCache.set(cmd.content, result); return result; default: return "no-op"; } } -console.log("start up"); self.onmessage = async (event: MessageEvent) => { const result = await dispatch(event.data); self.postMessage({ id: event.data.id, content: result }); diff --git a/src/lib/linter.ts b/src/lib/linter.ts index e1eb8b74..b4deb0b6 100644 --- a/src/lib/linter.ts +++ b/src/lib/linter.ts @@ -7,7 +7,7 @@ import ColorSimilarity from "./lints/color-similarity"; import BackgroundDifferentiability from "./lints/background-differentiability"; import SequentialOrder from "./lints/sequential-order"; import DivergingOrder from "./lints/diverging-order"; -import BackgroundContrast from "./lints/contrast"; +// import BackgroundContrast from "./lints/contrast"; import Fair from "./lints/fair"; import EvenDistribution from "./lints/even-distribution"; import type { CustomLint } from "./lints/CustomLint"; @@ -20,7 +20,7 @@ export const manualLints = [ BackgroundDifferentiability, SequentialOrder, DivergingOrder, - BackgroundContrast, + // BackgroundContrast, ...Fair, // EvenDistribution, ]; diff --git a/src/lib/lints/ColorLint.ts b/src/lib/lints/ColorLint.ts index 407b9860..26485083 100644 --- a/src/lib/lints/ColorLint.ts +++ b/src/lib/lints/ColorLint.ts @@ -1,6 +1,4 @@ import type { Palette } from "../../stores/color-store"; -// import { suggestFix } from "../api-calls"; -// import { Color } from "../Color"; export type TaskType = "sequential" | "diverging" | "categorical"; export type LintLevel = "error" | "warning"; @@ -23,18 +21,12 @@ export class ColorLint { checkData: CheckData; palette: Palette; message: string = ""; - hasParam: boolean = false; hasHeuristicFix: boolean = false; config: { val?: ParamType } = {}; - defaultParam: ParamType = false as any; isCustom: false | string = false; group: string = ""; description: string = ""; blameMode: "pair" | "single" | "none" = "none"; - paramOptions: - | { type: "number"; min: number; max: number; step: number } - | { type: "enum"; options: string[] } - | { type: "none" } = { type: "none" }; level: LintLevel = "error"; constructor(Palette: Palette) { @@ -43,32 +35,7 @@ export class ColorLint { this.passes = false; } - copy() { - const copy = new ColorLint(this.palette); - copy.name = this.name; - copy.taskTypes = this.taskTypes; - copy.passes = this.passes; - copy.checkData = this.checkData; - copy.message = this.message; - copy.hasParam = this.hasParam; - copy.config = this.config; - copy.defaultParam = this.defaultParam; - copy.hasHeuristicFix = this.hasHeuristicFix; - copy.level = this.level; - copy.group = this.group; - copy.description = this.description; - copy.paramOptions = this.paramOptions; - copy.isCustom = this.isCustom; - return copy; - } - run() { - const { evalConfig } = this.palette; - this.config = { - ...evalConfig[this.name], - val: evalConfig[this.name]?.val || this.defaultParam, - }; - const { passCheck, data } = this._runCheck(); this.passes = passCheck; this.checkData = data as CheckData; diff --git a/src/lib/lints/built-in-lints.ts b/src/lib/lints/built-in-lints.ts index 2a1d6aab..5294d3ab 100644 --- a/src/lib/lints/built-in-lints.ts +++ b/src/lib/lints/built-in-lints.ts @@ -155,6 +155,31 @@ const BUILT_INS: CustomLint[] = [ id: "mutually-distinct-built-in", blameMode: "pair" as const, }, + { + program: toString({ + all: { + in: "colors", + varb: "a", + predicate: { + ">": { + left: { + contrast: { left: "a", right: "background" }, + algorithm: "APCA", + }, + right: 4.5, + }, + }, + }, + }), + name: "Background Contrast", + taskTypes: ["sequential", "diverging", "categorical"] as const, + level: "error", + group: "accessibility", + description: `All colors in a palette should have a sufficient contrast ratio with the background color. This is because if they are not, then they will not be differentiable from each other in some contexts. Valid algorithms are APCA, WCAG21, Michelson, Weber, Lstar, DeltaPhi.`, + failMessage: `These colors ({{blame}}) do not have a sufficient contrast ratio with the background and may be hard to discriminate in some contexts.`, + id: "background-contrast-built-in", + blameMode: "single" as const, + }, ]; export default BUILT_INS; diff --git a/src/lib/lints/color-similarity.ts b/src/lib/lints/color-similarity.ts index 59dbba24..127ecb02 100644 --- a/src/lib/lints/color-similarity.ts +++ b/src/lib/lints/color-similarity.ts @@ -4,16 +4,9 @@ import type { TaskType } from "./ColorLint"; export default class ColorSimilarity extends ColorLint { name = "Colors are differentiable in order"; taskTypes = ["sequential", "diverging", "categorical"] as TaskType[]; - hasParam = true; - defaultParam: number = 10; group: string = "usability"; description: string = `Opt for colors that are perceptually distinguishable in a logical sequence when designing visual elements like charts or graphs. This ensures that viewers can easily recognize the order or progression of data points. For categorical this means that when only a small number of colors are used, they should be as different as possible. For sequential and diverging, this means that the colors should be as different as possible in order.`; - paramOptions: { type: "number"; min: number; max: number; step: number } = { - type: "number", - min: 10, - max: 100, - step: 1, - }; + _runCheck() { const { colors } = this.palette; const des = []; @@ -22,7 +15,7 @@ export default class ColorSimilarity extends ColorLint { } const failingIndexes = des.reduce((acc, x, idx) => { - if (x < this.config.val!) { + if (x < 10) { return [...acc, idx]; } return acc; diff --git a/src/lib/lints/contrast.ts b/src/lib/lints/contrast.ts index 79d77014..8cdaba4f 100644 --- a/src/lib/lints/contrast.ts +++ b/src/lib/lints/contrast.ts @@ -13,7 +13,6 @@ type Algorithm = export default class BackgroundContrast extends ColorLint { name = "Background Contrast"; taskTypes = ["sequential", "diverging", "categorical"] as TaskType[]; - hasParam = true; defaultParam = "APCA" as Algorithm; paramOptions: { type: "enum"; options: string[] } = { type: "enum", diff --git a/src/lib/lints/fair.ts b/src/lib/lints/fair.ts index 8e2e5508..8519caa6 100644 --- a/src/lib/lints/fair.ts +++ b/src/lib/lints/fair.ts @@ -44,13 +44,6 @@ class FairBase extends ColorLint { group = "design"; // hasParam = true; level: "error" | "warning" = "warning"; - // defaultParam = 1; - // paramOptions: { type: "number"; min: number; max: number; step: 1 } = { - // type: "number", - // min: 2, - // max: 20, - // step: 1, - // }; description: string = `Do the colors stand out equally? A color palette is described as fair if both chroma and luminance ranges are below a certain threshold and unfair if one of them is above a certain threshold. For sequential and diverging palettes, only the chroma range is considered.`; buildMessage(): string { diff --git a/src/linting/EvalResponse.svelte b/src/linting/EvalResponse.svelte index 53a626e9..c37e2ee9 100644 --- a/src/linting/EvalResponse.svelte +++ b/src/linting/EvalResponse.svelte @@ -105,31 +105,6 @@ > Ignore for this palette - {#if requestState === "loading"}
Loading...