Skip to content

Commit

Permalink
bunch of random ui stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
mcnuttandrew committed Jan 19, 2025
1 parent c819093 commit 7ada22e
Show file tree
Hide file tree
Showing 14 changed files with 477 additions and 307 deletions.
14 changes: 4 additions & 10 deletions apps/lil-buddy/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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)!;
</script>
Expand All @@ -12,16 +14,8 @@
>
Lil Buddy

{#if lint}
<button
class={buttonStyle}
on:click={() => {
store.setFocusedLint(false);
}}
>
Customize Another Check
</button>
{/if}
<LintPicker />

<NewLintSuggestion />
<a
class={buttonStyle}
Expand Down
123 changes: 122 additions & 1 deletion apps/lil-buddy/src/lib/api-calls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,5 +231,126 @@ You should include an extra field in your output called "comments" that explains
Prompt: ${JSON.stringify(lintPrompt)}
Your response: `;
return engineToScaffold[engine]<string>(`suggest-lint`, prompt, true);
return engineToScaffold[engine]<string>(`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]<string>(`ai-call`, prompt, true);
}
2 changes: 2 additions & 0 deletions apps/lil-buddy/src/lib/styles.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export const buttonStyle = "p-2 rounded border";
export const simpleTooltipRowStyle =
"text-left px-2 hover:bg-stone-300 cursor-pointer";
104 changes: 68 additions & 36 deletions apps/lil-buddy/src/linting/FocusedTest.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -37,22 +38,53 @@
$: blameData = (lintResult.kind === "success" && lintResult.blameData) || [];
$: errors = lintRun.errors;
$: pairData = blameData as number[][];
$: program = lint.program;
</script>

{#if testPal}
<VisualSummarizer lint={lint.program} pal={testPal} />
{/if}
{#if currentLintAppliesToCurrentPalette && testPal}
<PalPreview pal={{ ...testPal }} />
{#if lintResult.kind === "success" && lintResult.passes}
<div class="text-green-500">This lint passes for the current palette</div>
{/if}
{#if lintResult.kind === "success" && !lintResult.passes && !errors}
<div>
<div class="flex">
<div class="text-red-500 mr-2">
This lint fails for the current palette.
</div>
<div class="flex">
<div class="text-red-500 mr-2">
This lint fails for the current palette.
</div>
</div>
{/if}
{/if}
{#if testPal}
<VisualSummarizer lint={program} pal={testPal} />
{/if}
<div class="border p-2 rounded">
{#if testPal && focusedTest}
<LintTest
removeCase={() => {
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}
<div class="border">
The following colors are blamed. Using
<select
value={lint.blameMode}
Expand All @@ -67,33 +99,33 @@
<option>pair</option>
</select>
Blame mode
{#if lint.blameMode === "pair"}
<div class="flex flex-wrap">
{#each pairData as pair}
<div class="mr-2 mb-1 border-2 border-black rounded">
<PalPreview
pal={{
...testPal,
colors: pair.map((x) => testPal.colors[x]),
}}
/>
</div>
{/each}
</div>
{:else}
<PalPreview
pal={{
...testPal,
colors: blameData.flatMap((x) => x).map((x) => testPal.colors[x]),
}}
/>
{/if}
</div>
{#if lint.blameMode === "pair"}
<div class="flex flex-wrap">
{#each pairData as pair}
<div class="mr-2 mb-1 border-2 border-black rounded">
<PalPreview
pal={{
...testPal,
colors: pair.map((x) => testPal.colors[x]),
}}
/>
</div>
{/each}
</div>
{:else}
<PalPreview
pal={{
...testPal,
colors: blameData.flatMap((x) => x).map((x) => testPal.colors[x]),
}}
/>
{/if}
{/if}
{:else}
<div class="text-red-500">
This lint does not apply to the current palette due to a mismatch between
its tags and the palette's tags
</div>
{/if}
{:else}
<div class="text-red-500">
This lint does not apply to the current palette due to a mismatch between
its tags and the palette's tags
</div>
{/if}
</div>
42 changes: 42 additions & 0 deletions apps/lil-buddy/src/linting/LintPicker.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script lang="ts">
import type { LintProgram } from "color-buddy-palette-lint";
import ChevDown from "virtual:icons/fa6-solid/angle-down";
import store from "../stores/store";
import Tooltip from "../components/Tooltip.svelte";
import { simpleTooltipRowStyle, buttonStyle } from "../lib/styles";
$: lintGroups = $store.lints.reduce(
(acc, row) => {
acc[row.group] = (acc[row.group] || []).concat(row);
return acc;
},
{} as Record<string, LintProgram[]>
);
</script>

<Tooltip positionAlongRightEdge={true}>
<div class="flex flex-col text-sm" slot="content">
{#each Object.entries(lintGroups) as [groupName, items]}
{#each items || [] as lint}
<button
class={simpleTooltipRowStyle}
on:click={() => {
store.setFocusedLint(lint.id);
}}
>
{lint.name}
</button>
{/each}
<div class="my-3 border-t border-black"></div>
{/each}
</div>
<button
slot="target"
let:toggle
on:click={toggle}
class="{buttonStyle} flex items-center"
>
Select a different lint
<ChevDown class="ml-2 text-sm" />
</button>
</Tooltip>
Loading

0 comments on commit 7ada22e

Please sign in to comment.