diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-09 21:48:42 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-09 21:48:42 -0500 |
| commit | a1d9839ac97c050c1f0c8ddd38e0b2418faefdcf (patch) | |
| tree | ac00f4515d558280ab8506ea7c343184d995eb6d /scripts/theme-studio | |
| parent | 35abac5bf53beb265282bd16fec6c5c2e2627cfb (diff) | |
| download | dotemacs-a1d9839ac97c050c1f0c8ddd38e0b2418faefdcf.tar.gz dotemacs-a1d9839ac97c050c1f0c8ddd38e0b2418faefdcf.zip | |
feat(theme-studio): order add-all around the base as -n .. base .. +n
Add-all inserted every step after the source, giving base, -2, -1, +1, +2. Now the darker steps go before the base and the lighter ones after, so the palette reads -2 -1 base +1 +2, matching the preview row and how a ramp reads left to right.
Inserting a darker step before the base shifted the base's index, so I bump the selected index to keep the selection (and the next preview's base) on the base color rather than drifting onto an inserted step. The #ramptest gate now checks the steps surround the base in order.
Diffstat (limited to 'scripts/theme-studio')
| -rw-r--r-- | scripts/theme-studio/app.js | 20 | ||||
| -rw-r--r-- | scripts/theme-studio/theme-studio.html | 20 |
2 files changed, 24 insertions, 16 deletions
diff --git a/scripts/theme-studio/app.js b/scripts/theme-studio/app.js index 7732914a..c3050548 100644 --- a/scripts/theme-studio/app.js +++ b/scripts/theme-studio/app.js @@ -335,20 +335,24 @@ function renderRamp(){ if(dups.length)parts.push('name already in palette, will be skipped on add: '+dups.join(', ')); rampNote(parts.join(' | '),dups.length>0); } -// Insert a step adjacent to the source swatch, keeping the ramp siblings in -// -n..+n order. A name collision is flagged and skipped (never overwrites); a -// hex that already exists under another name is added but flagged as a duplicate. +// Insert a step around the source swatch so the family reads -n .. base .. +n: +// darker (negative) steps go before the base, lighter (positive) ones after, each +// ordered among its existing siblings. A name collision is skipped (never +// overwrites); a hex matching another entry is added but flagged as a duplicate. function rampInsertIndex(off){ const bn=rampBase.name,re=new RegExp('^'+bn.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')+'([+-]\\d+)$'); - let src=PALETTE.findIndex(p=>p[1]===bn);if(src<0)src=PALETTE.length-1; - let idx=src+1;while(idx<PALETTE.length){const m=PALETTE[idx][1].match(re);if(m&&parseInt(m[1],10)<off){idx++;continue;}break;} - return idx; + let src=PALETTE.findIndex(p=>p[1]===bn);if(src<0)src=PALETTE.length; + const sib=i=>{const m=i>=0&&i<PALETTE.length&&PALETTE[i][1].match(re);return m?parseInt(m[1],10):NaN;}; + if(off>0){let idx=src+1;while(idx<PALETTE.length){const v=sib(idx);if(v>0&&v<off){idx++;continue;}break;}return idx;} + let idx=src;while(idx>0){const v=sib(idx-1);if(v<0&&v>off){idx--;continue;}break;}return idx; } function addRampStep(s){ const nm=rampStepName(s.offset); if(PALETTE.some(p=>p[1].toLowerCase()===nm.toLowerCase())){rampNote('"'+nm+'" already exists — rename or skip',true);return false;} const dup=PALETTE.find(p=>p[0].toLowerCase()===s.hex.toLowerCase()); - PALETTE.splice(rampInsertIndex(s.offset),0,[s.hex,nm]);const healed=healGone(nm,s.hex);renderPalette();buildTable();buildUITable(); + const at=rampInsertIndex(s.offset);PALETTE.splice(at,0,[s.hex,nm]); + if(selectedIdx!=null&&at<=selectedIdx)selectedIdx++; // a darker step inserted before the base keeps the selection on the base + const healed=healGone(nm,s.hex);renderPalette();buildTable();buildUITable(); if(healed){renderCode();applyGround();} rampNote(dup?('added "'+nm+'" (same hex as "'+dup[1]+'")'):('added "'+nm+'"'),false);return true; } @@ -1039,7 +1043,7 @@ if(location.hash==='#ramptest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c A(document.querySelectorAll('#rampprev .rchip .rhex').length===4,'each step tile shows its hex'); addAllRampSteps(); const names=PALETTE.map(p=>p[1]),bi=names.indexOf('blue'); - A(names.slice(bi,bi+5).join(',')==='blue,blue-2,blue-1,blue+1,blue+2','order after blue: '+names.slice(bi,bi+5).join(',')); + A(names.slice(bi-2,bi+3).join(',')==='blue-2,blue-1,blue,blue+1,blue+2','order around blue: '+names.slice(Math.max(0,bi-2),bi+3).join(',')); const before=PALETTE.length;addAllRampSteps();A(PALETTE.length===before,'re-add should skip existing names'); A(/skipped \(name already in palette\): blue-2, blue-1, blue\+1, blue\+2/.test(document.getElementById('rampmsg').textContent),'add-all names the skipped collisions: '+document.getElementById('rampmsg').textContent); renderRamp(); diff --git a/scripts/theme-studio/theme-studio.html b/scripts/theme-studio/theme-studio.html index ab7d115c..529f5d30 100644 --- a/scripts/theme-studio/theme-studio.html +++ b/scripts/theme-studio/theme-studio.html @@ -861,20 +861,24 @@ function renderRamp(){ if(dups.length)parts.push('name already in palette, will be skipped on add: '+dups.join(', ')); rampNote(parts.join(' | '),dups.length>0); } -// Insert a step adjacent to the source swatch, keeping the ramp siblings in -// -n..+n order. A name collision is flagged and skipped (never overwrites); a -// hex that already exists under another name is added but flagged as a duplicate. +// Insert a step around the source swatch so the family reads -n .. base .. +n: +// darker (negative) steps go before the base, lighter (positive) ones after, each +// ordered among its existing siblings. A name collision is skipped (never +// overwrites); a hex matching another entry is added but flagged as a duplicate. function rampInsertIndex(off){ const bn=rampBase.name,re=new RegExp('^'+bn.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')+'([+-]\\d+)$'); - let src=PALETTE.findIndex(p=>p[1]===bn);if(src<0)src=PALETTE.length-1; - let idx=src+1;while(idx<PALETTE.length){const m=PALETTE[idx][1].match(re);if(m&&parseInt(m[1],10)<off){idx++;continue;}break;} - return idx; + let src=PALETTE.findIndex(p=>p[1]===bn);if(src<0)src=PALETTE.length; + const sib=i=>{const m=i>=0&&i<PALETTE.length&&PALETTE[i][1].match(re);return m?parseInt(m[1],10):NaN;}; + if(off>0){let idx=src+1;while(idx<PALETTE.length){const v=sib(idx);if(v>0&&v<off){idx++;continue;}break;}return idx;} + let idx=src;while(idx>0){const v=sib(idx-1);if(v<0&&v>off){idx--;continue;}break;}return idx; } function addRampStep(s){ const nm=rampStepName(s.offset); if(PALETTE.some(p=>p[1].toLowerCase()===nm.toLowerCase())){rampNote('"'+nm+'" already exists — rename or skip',true);return false;} const dup=PALETTE.find(p=>p[0].toLowerCase()===s.hex.toLowerCase()); - PALETTE.splice(rampInsertIndex(s.offset),0,[s.hex,nm]);const healed=healGone(nm,s.hex);renderPalette();buildTable();buildUITable(); + const at=rampInsertIndex(s.offset);PALETTE.splice(at,0,[s.hex,nm]); + if(selectedIdx!=null&&at<=selectedIdx)selectedIdx++; // a darker step inserted before the base keeps the selection on the base + const healed=healGone(nm,s.hex);renderPalette();buildTable();buildUITable(); if(healed){renderCode();applyGround();} rampNote(dup?('added "'+nm+'" (same hex as "'+dup[1]+'")'):('added "'+nm+'"'),false);return true; } @@ -1565,7 +1569,7 @@ if(location.hash==='#ramptest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c A(document.querySelectorAll('#rampprev .rchip .rhex').length===4,'each step tile shows its hex'); addAllRampSteps(); const names=PALETTE.map(p=>p[1]),bi=names.indexOf('blue'); - A(names.slice(bi,bi+5).join(',')==='blue,blue-2,blue-1,blue+1,blue+2','order after blue: '+names.slice(bi,bi+5).join(',')); + A(names.slice(bi-2,bi+3).join(',')==='blue-2,blue-1,blue,blue+1,blue+2','order around blue: '+names.slice(Math.max(0,bi-2),bi+3).join(',')); const before=PALETTE.length;addAllRampSteps();A(PALETTE.length===before,'re-add should skip existing names'); A(/skipped \(name already in palette\): blue-2, blue-1, blue\+1, blue\+2/.test(document.getElementById('rampmsg').textContent),'add-all names the skipped collisions: '+document.getElementById('rampmsg').textContent); renderRamp(); |
