diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-10 00:19:34 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-10 00:19:34 -0500 |
| commit | 74db9a526503c9cc0c273f4523ad7ef76b61fb64 (patch) | |
| tree | a95aef60f22ca6ee5cd13d2e906c541c268dae41 /scripts/theme-studio/theme-studio.html | |
| parent | ebe18d51ad99fe0a5916516c47d5dda3315e9add (diff) | |
| download | dotemacs-74db9a526503c9cc0c273f4523ad7ef76b61fb64.tar.gz dotemacs-74db9a526503c9cc0c273f4523ad7ef76b61fb64.zip | |
feat(theme-studio): add color-family sort
sortFamilies orders the strips for display: neutrals first by lightness, then chromatic families by base hue, ties broken by base lightness then base hex. Each family's members come back sorted dark to light. Hue is compared rounded so a sub-degree hue hair from gamut quantization doesn't outrank lightness. Sorting is display-only; the stored palette order is untouched.
Phase 2 of the color-families spec, pure logic. Four node tests cover the hue order, the neutral pin, within-family lightness order, and the (hue, then lightness) ordering invariant. Suite 91 to 95 green.
Diffstat (limited to 'scripts/theme-studio/theme-studio.html')
| -rw-r--r-- | scripts/theme-studio/theme-studio.html | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/scripts/theme-studio/theme-studio.html b/scripts/theme-studio/theme-studio.html index 1716db9b..27df2a83 100644 --- a/scripts/theme-studio/theme-studio.html +++ b/scripts/theme-studio/theme-studio.html @@ -613,6 +613,24 @@ function stepRepointPlan(oldRanked,newMembers){ } return {map,removed}; } + +// Order a family's members dark to light by OKLCH lightness. +function sortFamilyMembers(fam){return Object.assign({},fam,{members:[...fam.members].sort((a,b)=>oklchOf(a.hex).L-oklchOf(b.hex).L)});} +// Order families for display: neutrals first (by base lightness), then chromatic +// by base hue, ties broken by base lightness then base hex. Each family's members +// are lightness-sorted. Display-only — the stored palette order is untouched. +function sortFamilies(families){ + const keyed=families.map(f=>{const c=oklchOf(f.base);return {f,neutral:!!f.neutral,H:c.H,L:c.L,base:f.base};}); + keyed.sort((a,b)=>{ + if(a.neutral!==b.neutral)return a.neutral?-1:1; + if(a.neutral&&b.neutral)return a.L-b.L; + const ah=Math.round(a.H),bh=Math.round(b.H); // a hue hair shouldn't outrank lightness + if(ah!==bh)return ah-bh; + if(a.L!==b.L)return a.L-b.L; + return a.base.toLowerCase()<b.base.toLowerCase()?-1:a.base.toLowerCase()>b.base.toLowerCase()?1:0; + }); + return keyed.map(k=>sortFamilyMembers(k.f)); +} // Pure color/UI-boundary helpers (normHex, ratingColor, textOn), inlined from // app-util.js. textOn uses rl from the colormath core above. // Pure color/UI-boundary helpers: hex-input parsing, the contrast-rating status |
