aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-09 21:48:42 -0500
committerCraig Jennings <c@cjennings.net>2026-06-09 21:48:42 -0500
commita1d9839ac97c050c1f0c8ddd38e0b2418faefdcf (patch)
treeac00f4515d558280ab8506ea7c343184d995eb6d /scripts
parent35abac5bf53beb265282bd16fec6c5c2e2627cfb (diff)
downloaddotemacs-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')
-rw-r--r--scripts/theme-studio/app.js20
-rw-r--r--scripts/theme-studio/theme-studio.html20
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();