aboutsummaryrefslogtreecommitdiff
path: root/scripts/theme-studio/test-app-core.mjs
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-15 20:48:39 -0500
committerCraig Jennings <c@cjennings.net>2026-06-15 20:48:39 -0500
commita4b9e796ca57e7af75b001d5f0f5e4055b686929 (patch)
tree041198b0e4d5d378e6dfceb07c7361fb54556310 /scripts/theme-studio/test-app-core.mjs
parent1b4e5f88353180cf999412faa2be9e0326b78361 (diff)
downloaddotemacs-a4b9e796ca57e7af75b001d5f0f5e4055b686929.tar.gz
dotemacs-a4b9e796ca57e7af75b001d5f0f5e4055b686929.zip
feat(theme-studio): 2D gallery color picker for the assignment dropdowns
- The color dropdown opens a grid, not a long list. - The grid mirrors the palette: ground strip, then a row per family. - Members run dark to light, with the current color outlined. - A default chip clears the assignment. - A (gone) cell shows a color no longer in the palette. - The trigger and step buttons stay the same. - All three tiers share the one dropdown.
Diffstat (limited to 'scripts/theme-studio/test-app-core.mjs')
-rw-r--r--scripts/theme-studio/test-app-core.mjs51
1 files changed, 51 insertions, 0 deletions
diff --git a/scripts/theme-studio/test-app-core.mjs b/scripts/theme-studio/test-app-core.mjs
index 42ce4e0a2..7f537d128 100644
--- a/scripts/theme-studio/test-app-core.mjs
+++ b/scripts/theme-studio/test-app-core.mjs
@@ -9,6 +9,7 @@ import { fileURLToPath } from 'node:url';
import {
nameToHex, normalizePkgFace, buildPkgmap, packagesForExport, mergePackagesInto, effResolve, resolveSyntaxFg, resolveUiAttr, dropdownRowTextColor, paletteOptionList, spanNeighborHex, slugify,
clearPalettePlan, deletePaletteColumnPlan, groundColumnMembersFromPalette, areAllLocked, lockToggleLabel, toggleLockSet,
+ galleryModel,
} from './app-core.js';
import { planPaletteGenerator, entriesForGeneratedColumn } from './palette-generator-core.js';
import { oklch2hex, deltaE } from './colormath.js';
@@ -70,6 +71,56 @@ test('paletteOptionList: Normal — colors within each column are lightest to da
);
});
+const GALLERY_PAL = [
+ ['#111111', 'bg', 'ground'],
+ ['#eeeeee', 'fg', 'ground'],
+ ['#444444', 'gray-dark', 'gray'],
+ ['#cccccc', 'gray-light', 'gray'],
+ ['#888888', 'gray-mid', 'gray'],
+ ['#330000', 'red-dark', 'red'],
+ ['#dd8888', 'red-light', 'red'],
+];
+const GALLERY_GROUND = { bg: '#111111', fg: '#eeeeee' };
+const allCells = m => m.rows.flatMap(r => r.cells);
+
+test('galleryModel: Normal — ground row then one row per family, default cell present', () => {
+ const m = galleryModel('#888888', GALLERY_PAL, GALLERY_GROUND);
+ assert.equal(m.default.hex, '');
+ assert.equal(m.gone, null);
+ assert.equal(m.rows[0].kind, 'ground');
+ assert.deepEqual(m.rows[0].cells.map(c => c.hex), ['#111111', '#eeeeee']);
+ const cols = m.rows.filter(r => r.kind === 'column');
+ assert.equal(cols.length, 2, 'one row per color family');
+ assert.deepEqual(
+ cols.find(r => r.column === 'gray').cells.map(c => c.hex),
+ ['#444444', '#888888', '#cccccc'],
+ 'family members run dark to light',
+ );
+});
+
+test('galleryModel: Normal — exactly the current color is selected', () => {
+ const m = galleryModel('#888888', GALLERY_PAL, GALLERY_GROUND);
+ const selected = allCells(m).filter(c => c.selected);
+ assert.deepEqual(selected.map(c => c.hex), ['#888888']);
+ assert.equal(m.default.selected, false);
+});
+
+test('galleryModel: Boundary — empty cur selects the default cell, nothing in the grid', () => {
+ const m = galleryModel('', GALLERY_PAL, GALLERY_GROUND);
+ assert.equal(m.default.selected, true);
+ assert.equal(m.gone, null);
+ assert.equal(allCells(m).filter(c => c.selected).length, 0);
+});
+
+test('galleryModel: Error — a cur outside the palette surfaces a selected (gone) cell', () => {
+ const m = galleryModel('#abcdef', GALLERY_PAL, GALLERY_GROUND);
+ assert.ok(m.gone, 'gone cell exists');
+ assert.equal(m.gone.hex, '#abcdef');
+ assert.equal(m.gone.name, '(gone)');
+ assert.equal(m.gone.selected, true);
+ assert.equal(allCells(m).filter(c => c.selected).length, 0, 'no grid cell claims the gone color');
+});
+
test('paletteOptionList: Boundary — assignment-only ground colors are selectable', () => {
const list = paletteOptionList('', [['#67809c', 'blue']], { bg: '#0d0b0a', fg: '#f0fef0' });
assert.ok(list.some(([hex, name]) => hex === '#0d0b0a' && name === 'bg'));