From 7ada22e68545d8a6f4d165f1813fb901ac6feb6d Mon Sep 17 00:00:00 2001 From: Andrew Michael McNutt Date: Sat, 18 Jan 2025 17:24:24 -0700 Subject: [PATCH] bunch of random ui stuff --- apps/lil-buddy/src/App.svelte | 14 +- apps/lil-buddy/src/lib/api-calls.ts | 123 ++++++++++++++++- apps/lil-buddy/src/lib/styles.ts | 2 + apps/lil-buddy/src/linting/FocusedTest.svelte | 104 ++++++++++----- apps/lil-buddy/src/linting/LintPicker.svelte | 42 ++++++ apps/lil-buddy/src/linting/LintTest.svelte | 111 ++++++++-------- apps/lil-buddy/src/linting/LintTests.svelte | 46 +++---- apps/lil-buddy/src/linting/MainTab.svelte | 2 + .../src/linting/ProgramCommand.svelte | 90 +++++++++++++ .../src/linting/VisualSummarizer.svelte | 1 + .../src/linting/VisualSummaryNode.svelte | 124 ------------------ .../linting/summary-nodes/DispatchNode.svelte | 20 +-- .../summary-nodes/QuantifierNode.svelte | 41 +----- .../summary-nodes/visual-summary-utils.ts | 64 +++++++++ 14 files changed, 477 insertions(+), 307 deletions(-) create mode 100644 apps/lil-buddy/src/linting/LintPicker.svelte create mode 100644 apps/lil-buddy/src/linting/ProgramCommand.svelte delete mode 100644 apps/lil-buddy/src/linting/VisualSummaryNode.svelte create mode 100644 apps/lil-buddy/src/linting/summary-nodes/visual-summary-utils.ts diff --git a/apps/lil-buddy/src/App.svelte b/apps/lil-buddy/src/App.svelte index 9660c5b..2bf68aa 100644 --- a/apps/lil-buddy/src/App.svelte +++ b/apps/lil-buddy/src/App.svelte @@ -2,6 +2,8 @@ import LintCustomizationTab from "./linting/MainTab.svelte"; import { buttonStyle } from "./lib/styles"; import store from "./stores/store"; + import LintPicker from "./linting/LintPicker.svelte"; + import NewLintSuggestion from "./linting/NewLintSuggestion.svelte"; $: lint = $store.lints.find((lint) => lint.id === $store.focusedLint)!; @@ -12,16 +14,8 @@ > Lil Buddy - {#if lint} - - {/if} + + (`suggest-lint`, prompt, true); + return engineToScaffold[engine](`ai-call`, prompt, true); +} + +export function modifyLintProgram( + inputPrompt: string, + program: string, + engine: Engine +) { + const prompt = ` + +# Color check language documentation + +A valid program starts with an expression, as described below. The only allowed syntax is listed here. + +Expressions +Conjunction | Quantifier | Comparison | Boolean + +Value = Variable | Number | Boolean | ColorString +Notes: + +- ColorString: strings defined using web valid hex colors, such as #ff00ff +- Variable is a string that is a variable name + +Predefined variables: colors, background + +Conjunctions: +{and: [EXPR, EXPR, ...]} +{or: [EXPR, EXPR, EXPR]} +{not: EXPR} + +Quantifiers +{all: {varbs: Variable, predicate: EXPR, where?: EXPR, in: Variable | Map}} +{exist: {varbs: Variable, predicate: EXPR, where?: EXPR, in: Variable | Map}} +Notes: + +- varbs each listed variable into the scope, as well as variables like index(a) for a variable a +- To slice you might do something like {...where: {"<" : {"left": "index(a)", "right": 3}}}. This is important! There is no other way to subset or filter for quantifiers. THE IN CLAUSE MUST ONLY HAVE A VARIABLE AND THING ELSE. + +Comparisons: +{"==": {left: Value, right: Value}} +{"!=": {left: Value, right: Value}} +{"<": {left: Value, right: Value}} +{">": {left: Value, right: Value}} +{"similar": {left: Value, right: Value, threshold: Number}} +Notes + +- Threshold has units of dE2000s, so 10 would be glance-ably different. + +Math Operations: +{"\*": {left: Number | Variable, right: Number | Variable}} +{"+": {left: Number | Variable, right: Number | Variable}} +{"/": {left: Number | Variable, right: Number | Variable}} +{"-": {left: Number | Variable, right: Number | Variable}} +{absDiff: {left: Number | Variable, right: Number | Variable}} +{"%": {left: Number | Variable, right: Number | Variable}} + +Value Comparisons: +{dist: {left: Color | Variable, right: Color | Variable}, space: COLOR_SPACE } +{deltaE: {left: Color | Variable, right: Color | Variable}, algorithm: '2000' | etc } +{contrast: {left: Color | Variable, right: Color | Variable}, algorithm: | "APCA" | "WCAG21" | "Michelson" | "Weber" | "Lstar" | "DeltaPhi"} + +Aggregates +{count: Variable | Number[] | Color[]} +{sum: Variable | Number[]} +{min: Variable | Number[]} +{max: Variable | Number[]} +{mean: Variable | Number[]} +{std: Variable | Number[]} +{first: Variable | Number[]} +{last: Variable | Number[]} +{extent: Variable | Number[]} + +Color Manipulations: +{toSpace: Variable, space: 'lab' | 'hsl' | etc, channel: 'a' | 'b' | 'l' | etc} +{cvdSim: Variable, type: 'protanomaly' | 'deuteranomaly' | 'tritanopia' | 'grayscale'} +{name: Variable} +{inGamut: Variable | Color} +{isTag: Variable | Color, value: string} +Notes + +- toSpace has a shorthand like {"rgb.b": Variable} +- When comparing colors, it can be helpful to switch color spaces. For instance, to check if a value is blue you might switch it to HSL and check if the hue is in a certain range. + +Maps: +{map: Variable | Value[], func: Operation, varb: Variable} +{sort: Variable | Value[], func: Operation, varb: Variable} +{filter: Variable | Value[], func: EXPR, varb: Variable} +{reverse: Variable | Value[]} +{speed: Variable | Value[]} + + +# LintProgram Examples + +Example prompt: All colors should be color blind friendly for deuteranopia +Example Result: +{"not": {"exist": { + "in": "colors", + "varbs": ["a", "b"], + "predicate": { + "!=": {"left": { "cvdSim": "a", "type": "deuteranopia" }, "right": { "cvdSim": "b", "type": "deuteranopia" } + }}}}} + +Example prompt: Colors should not be extreme +Example Result: +{"all": { + "in": "colors", + "varb": "a", + "predicate": { + "all": {"in": ["#000000", "#ffffff"], "varb": "b", + "predicate": { "!=": { "left": "a", "right": "b" } }, + }}}} + + +# Task and output format +Given a lint prompt, suggest a lint using the color check linting language. Your response should be a JSON object written in the above JSON DSL. You must be explicit in your response and include all necessary information. If a list of colors is suggested you should guess what those colors are and give explicit values. + +ONLY RETURN THE JSON AND NOTHING ELSE. DO NOT MAKE ANY COMMENTS. + +Prompt: ${JSON.stringify(inputPrompt)} + +Your response: `; + return engineToScaffold[engine](`ai-call`, prompt, true); } diff --git a/apps/lil-buddy/src/lib/styles.ts b/apps/lil-buddy/src/lib/styles.ts index 9c0a4f1..3057ed4 100644 --- a/apps/lil-buddy/src/lib/styles.ts +++ b/apps/lil-buddy/src/lib/styles.ts @@ -1 +1,3 @@ export const buttonStyle = "p-2 rounded border"; +export const simpleTooltipRowStyle = + "text-left px-2 hover:bg-stone-300 cursor-pointer"; diff --git a/apps/lil-buddy/src/linting/FocusedTest.svelte b/apps/lil-buddy/src/linting/FocusedTest.svelte index 918fb52..bb703bb 100644 --- a/apps/lil-buddy/src/linting/FocusedTest.svelte +++ b/apps/lil-buddy/src/linting/FocusedTest.svelte @@ -5,6 +5,7 @@ export let lint: LintProgram; import { runLint } from "../lib/utils"; import VisualSummarizer from "./VisualSummarizer.svelte"; + import LintTest from "./LintTest.svelte"; $: focusedTest = $store.focusedTest; $: testPal = focusedTest ? focusedTest.type === "passing" @@ -37,22 +38,53 @@ $: blameData = (lintResult.kind === "success" && lintResult.blameData) || []; $: errors = lintRun.errors; $: pairData = blameData as number[][]; + $: program = lint.program; -{#if testPal} - -{/if} {#if currentLintAppliesToCurrentPalette && testPal} - {#if lintResult.kind === "success" && lintResult.passes}
This lint passes for the current palette
{/if} {#if lintResult.kind === "success" && !lintResult.passes && !errors} -
-
-
- This lint fails for the current palette. -
+
+
+ This lint fails for the current palette. +
+
+ {/if} +{/if} +{#if testPal} + +{/if} +
+ {#if testPal && focusedTest} + { + const newTests = [...lint.expectedPassingTests].filter( + (_, i) => i !== focusedTest.index + ); + store.setCurrentLintExpectedPassingTests(newTests); + }} + pal={testPal} + updatePal={(newPal) => { + const oldTests = + focusedTest.type === "passing" + ? lint.expectedPassingTests + : lint.expectedFailingTests; + const newTests = [...oldTests]; + newTests[focusedTest.index] = newPal; + if (focusedTest.type === "passing") { + store.setCurrentLintExpectedPassingTests(newTests); + } else { + store.setCurrentLintExpectedFailingTests(newTests); + } + }} + /> + {/if} + + {#if currentLintAppliesToCurrentPalette && testPal} + {#if lintResult.kind === "success" && !lintResult.passes && !errors} +
The following colors are blamed. Using Blame mode + {#if lint.blameMode === "pair"} +
+ {#each pairData as pair} +
+ testPal.colors[x]), + }} + /> +
+ {/each} +
+ {:else} + x).map((x) => testPal.colors[x]), + }} + /> + {/if}
- {#if lint.blameMode === "pair"} -
- {#each pairData as pair} -
- testPal.colors[x]), - }} - /> -
- {/each} -
- {:else} - x).map((x) => testPal.colors[x]), - }} - /> - {/if} + {/if} + {:else} +
+ This lint does not apply to the current palette due to a mismatch between + its tags and the palette's tags
{/if} -{:else} -
- This lint does not apply to the current palette due to a mismatch between - its tags and the palette's tags -
-{/if} +
diff --git a/apps/lil-buddy/src/linting/LintPicker.svelte b/apps/lil-buddy/src/linting/LintPicker.svelte new file mode 100644 index 0000000..2faabb9 --- /dev/null +++ b/apps/lil-buddy/src/linting/LintPicker.svelte @@ -0,0 +1,42 @@ + + + +
+ {#each Object.entries(lintGroups) as [groupName, items]} + {#each items || [] as lint} + + {/each} +
+ {/each} +
+ +
diff --git a/apps/lil-buddy/src/linting/LintTest.svelte b/apps/lil-buddy/src/linting/LintTest.svelte index 4f059fb..7f9e57b 100644 --- a/apps/lil-buddy/src/linting/LintTest.svelte +++ b/apps/lil-buddy/src/linting/LintTest.svelte @@ -7,68 +7,60 @@ import Background from "../components/Background.svelte"; import { buttonStyle } from "../lib/styles"; export let pal: Palette; - export let blamedSet: Set = new Set(); export let updatePal: (newPal: Palette) => void; export let removeCase: () => void; - export let pivotRight: boolean = false; - export let clickFocus: () => void; + $: bgLum = pal.background.luminance(); + $: textColor = bgLum > 0.4 ? "#00000066" : "#ffffffaa";
- -
- - + +
+ + - updatePal({ ...pal, background: newColor })} - bg={pal.background} - colorSpace={pal.colorSpace} - onSpaceChange={(newSpace) => { - updatePal({ - ...pal, - // @ts-ignore - colors: pal.colors.map((x) => x.toColorSpace(newSpace)), - // @ts-ignore - colorSpace: newSpace, - }); - }} - /> -
- Colors: [{pal.colors.map((x) => `"${x.toHex()}"`).join(", ")}] -
-
-
+
{#each pal.colors as color, idx} - +
Tags
{#each color.tags as tag, jdx} -
+
{tag} + > +
+
+
+ {#each color.tags as tag} +
{tag}
+ {/each} +
+
+ {/each}
+
diff --git a/apps/lil-buddy/src/linting/LintTests.svelte b/apps/lil-buddy/src/linting/LintTests.svelte index e3e201f..b8eb6ff 100644 --- a/apps/lil-buddy/src/linting/LintTests.svelte +++ b/apps/lil-buddy/src/linting/LintTests.svelte @@ -3,6 +3,7 @@ import AddTest from "./AddTest.svelte"; import type { LintProgram, LintResult } from "color-buddy-palette-lint"; import type { Palette } from "color-buddy-palette"; + import PalPreview from "../components/PalPreview.svelte"; import store from "../stores/store"; import { runLint } from "../lib/utils"; export let lint: LintProgram; @@ -31,38 +32,27 @@ }) as TestResult[]; -
+
-
Expected to be passing:
+
Palettes that should pass this test:
{#each passingTestResults as passing, idx} -
- - store.setFocusedTest({ type: "passing", index: idx })} - removeCase={() => { - const newTests = [...lint.expectedPassingTests].filter( - (_, i) => i !== idx - ); - store.setCurrentLintExpectedPassingTests(newTests); - }} - pal={passing.pal} - blamedSet={new Set(passing.blame)} - updatePal={(newPal) => { - const newTests = [...lint.expectedPassingTests]; - newTests[idx] = newPal; - store.setCurrentLintExpectedPassingTests(newTests); - }} - /> +
+ {/each}
{#each failingTestResults as failing, idx} -
- { + store.setFocusedTest({ type: "failing", index: idx }); + }} + > + + {#if failing.result.kind === "success"} {#if !failing.result?.passes}
Correct
@@ -103,7 +99,7 @@
Incorrect
{/if} {/if} -
+ {/each}
Clean up Program +
{generatePrettyText(program)} diff --git a/apps/lil-buddy/src/linting/ProgramCommand.svelte b/apps/lil-buddy/src/linting/ProgramCommand.svelte new file mode 100644 index 0000000..57d0858 --- /dev/null +++ b/apps/lil-buddy/src/linting/ProgramCommand.svelte @@ -0,0 +1,90 @@ + + + +
+
What would you like your check to be able to do?
+
+