aboutsummaryrefslogtreecommitdiff
path: root/scripts/theme-studio/browser-gates.js
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/theme-studio/browser-gates.js')
-rw-r--r--scripts/theme-studio/browser-gates.js90
1 files changed, 87 insertions, 3 deletions
diff --git a/scripts/theme-studio/browser-gates.js b/scripts/theme-studio/browser-gates.js
index 372937f18..3e5e12628 100644
--- a/scripts/theme-studio/browser-gates.js
+++ b/scripts/theme-studio/browser-gates.js
@@ -25,6 +25,7 @@ if(location.hash==='#selftest')pkgSelftest();
// the shared mkLockCell. (2) reset/erase batch actions update editable rows but
// leave locked rows (syntax bare-kind, ui:, pkg: keys) untouched.
if(location.hash==='#locktest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c){ok=false;notes.push(n);}};
+ const cssRgb=h=>{const [r,g,b]=hex2rgb(h);return 'rgb('+r+', '+g+', '+b+')';};
LOCKED.clear();buildTable();
{const k=CATS.map(c=>c[0]).filter(k=>k!=='bg'&&k!=='p')[0];
const tr=document.querySelector('#legbody tr[data-kind="'+k+'"]'),step=tr.querySelector('.cstep'),dd=tr.querySelector('.cdd'),lb=tr.querySelector('.lockbtn');
@@ -41,6 +42,15 @@ if(location.hash==='#locktest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c
const tr=document.querySelector('#uibody tr[data-face="region"]'),fg=tr.cells[2].querySelector('.cdd'),bg=tr.cells[3].querySelector('.cdd');
A(fg.classList.contains('is-default'),'compact default color button has default outline class');
A(!bg.classList.contains('is-default'),'compact assigned color button does not have default outline class');}
+ {setSyntaxFg('kw','');buildTable();
+ const dd=document.querySelector('#legbody tr[data-kind="kw"] .cdd');
+ A(dd&&dd.style.backgroundColor===cssRgb(MAP['p']),'syntax default fg swatch shows inherited fg color');}
+ {UIMAP['fringe'].bg=null;buildUITable();
+ const dd=document.querySelector('#uibody tr[data-face="fringe"]').cells[3].querySelector('.cdd');
+ A(dd&&dd.style.backgroundColor===cssRgb(MAP['bg']),'ui default bg swatch shows inherited ground color');}
+ {const app=curApp(),face=APPS[app].faces[0][0];PKGMAP[app][face].fg=null;PKGMAP[app][face].inherit=null;buildPkgTable();
+ const dd=document.querySelector('#pkgbody tr[data-face="'+face+'"]').cells[2].querySelector('.cdd');
+ A(dd&&dd.style.backgroundColor===cssRgb(MAP['p']),'package default fg swatch shows inherited/default fg color');}
{PALETTE=[['#000000','bg','ground'],['#ffffff','fg','ground'],['#222222','gray-dark','gray'],['#888888','gray-mid','gray'],['#dddddd','gray-light','gray']];setSyntaxFg('bg','#000000');setSyntaxFg('p','#ffffff');setSyntaxFg('kw','#888888');LOCKED.clear();buildTable();
const tr=document.querySelector('#legbody tr[data-kind="kw"]'),btns=tr.querySelectorAll('.cstepbtn');btns[1].click();
A(MAP['kw']==='#dddddd'&&tr.querySelector('.cdd').dataset.val==='#dddddd','syntax right arrow steps to lighter color');btns[0].click();
@@ -134,6 +144,12 @@ if(location.hash==='#mocktest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c
A([...document.querySelectorAll('#mockframe .fr')].some(e=>e.textContent.trim()),'fringe-indicator-present');
const mlbar=Q('[data-face="mode-line"]');
A(mlbar&&/box-shadow/.test(mlbar.getAttribute('style')||''),'mode-line-box');
+ const textBox=Q('.mbuftext'),border=Q('[data-face="vertical-border"]'),mock=document.getElementById('mockframe');
+ if(textBox&&border&&mock){
+ const tr=textBox.getBoundingClientRect(),br=border.getBoundingClientRect();
+ const ch=parseFloat(getComputedStyle(textBox).fontSize)*0.65;
+ A(br.left-tr.right<=ch*4.8,'vertical-border-near-text');
+ }else A(false,'vertical-border-layout-elements-present');
UIMAP['line-number-current-line'].bold=true;buildMockFrame();
const curNum=Q('[data-face="line-number-current-line"]');
A(curNum&&/font-weight:\s*bold/.test(curNum.getAttribute('style')||''),'line-number-honors-weight');
@@ -151,6 +167,62 @@ if(location.hash==='#mocktest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c
A(pkgBtn()&&pkgBtn().classList.contains('on')&&PKGMAP[app][face].bold===true,'pkg style button visual state turns on after rebuild');
document.title='MOCKTEST '+(ok?'PASS':'FAIL');
const d=document.createElement('div');d.id='mocktest';d.textContent='MOCKTEST '+(ok?'PASS':'FAIL')+(notes.length?' | '+notes.join(' ; '):'');document.body.appendChild(d);}
+// Palette-generator gate (open with #generatortest): previewing is non-mutating,
+// clicking a generated tile loads the existing selector, adding creates a normal
+// singleton base column, and appending a preview column commits all span members
+// under one stable column id.
+if(location.hash==='#generatortest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c){ok=false;notes.push(n);}};
+ const before=JSON.stringify(PALETTE);
+ A(document.getElementById('genaccents').value==='5','default accent count is 5');
+ A(document.getElementById('gensource').value==='palette','default generator source is palette');
+ A(document.querySelector('label:has(#genintent)').title==='what kind of candidate colors to look for','intent label hover explains the control');
+ A(document.getElementById('genintent').title.includes('Pure exploration'),'intent select hover explains random');
+ A([...document.getElementById('genintent').options].some(o=>o.value==='fill-hue-gaps'),'fill hue gaps intent is available');
+ document.getElementById('genintent').value='fill-hue-gaps';syncGeneratorControls();
+ A(document.getElementById('genintent').title.includes('underrepresented hue regions'),'fill hue gaps hover explains hue bonus');
+ document.getElementById('genintent').value='near-palette';syncGeneratorControls();
+ A(document.getElementById('genintent').title.includes('current palette base colors'),'intent select hover updates for selected intent');
+ A(!document.getElementById('genscheme'),'legacy scheme control is removed from the generator UI');
+ A(!document.getElementById('genhue'),'legacy base hue control is removed from the generator UI');
+ document.getElementById('genaccents').value='3';
+ document.getElementById('genintent').value='fill-gaps';
+ document.getElementById('genvibe').value='warm';
+ document.getElementById('gensource').value='palette';
+ previewGenerator();
+ A(GEN_PROPOSAL&&GEN_PROPOSAL.intent==='fill-gaps'&&GEN_PROPOSAL.vibe==='warm'&&GEN_PROPOSAL.sourceMode==='palette','intent/vibe/source feed the generator proposal');
+ A(JSON.stringify(PALETTE)===before,'preview does not mutate palette');
+ A(document.querySelectorAll('#genpreview .gencol').length===3,'renders requested preview columns');
+ A(parseInt(getComputedStyle(document.querySelector('#genpreview .genchip')).width,10)===128,'generated candidate tile width matches palette tiles');
+ A(parseInt(getComputedStyle(document.querySelector('#genpreview .genchip')).height,10)===58,'generated candidate tile height matches palette tiles');
+ A([...document.querySelectorAll('#genpreview .gencol')].every(c=>c.querySelectorAll('.genchip').length===1),'preview columns show only one base tile each');
+ const tile=document.querySelector('#genpreview .genchip[data-col="0"][data-member="0"]');
+ A(!!tile,'base generated tile exists');
+ const tileHex=tile&&tile.dataset.hex,tileName=tile&&tile.dataset.name;
+ if(tile)tile.click();
+ A(document.getElementById('newhexstr').value===tileHex,'generated tile loads selector hex');
+ A(document.getElementById('newname').value===tileName,'generated tile loads selector name');
+ document.getElementById('genaccents').value='2';
+ previewGenerator();
+ A(document.querySelectorAll('#genpreview .gencol').length===2,'preview again replaces old preview columns');
+ A(!document.querySelector('#genpreview .genchip.sel'),'preview again clears generated tile selection');
+ document.getElementById('genaccents').value='3';
+ previewGenerator();
+ addColor();
+ A(PALETTE.some(p=>p[0]===tileHex&&p[1]===tileName),'add color commits selected generated tile');
+ const afterSingle=PALETTE.length;
+ previewGenerator();
+ const append=document.querySelector('#genpreview .genappend[data-col="0"]');
+ A(!!append,'append generated column button exists');
+ if(append)append.click();
+ A(PALETTE.length===afterSingle+1,'append commits one generated base color');
+ const added=PALETTE.slice(-1);
+ A(new Set(added.map(p=>p[2])).size===1,'appended generated span has one stable column id');
+ A(!/[+-]\d+$/.test(added[0][1]),'appended generated color is a base name, not a signed span neighbor');
+ GEN_PROPOSAL={summary:{generated:1,rejected:0,minContrast:null},columns:[{name:'medium-aquamarine',members:[{name:'medium-aquamarine',hex:'#66cdaa',offset:0,columnId:'medium-aquamarine'}]}]};
+ renderGeneratorPreview();
+ A(document.querySelector('#genpreview .genchip .gn').textContent==='medium aquamarine','generated tile names display spaces instead of hyphens');
+ document.title='GENERATORTEST '+(ok?'PASS':'FAIL');
+ const d=document.createElement('div');d.id='generatortest';d.textContent='GENERATORTEST '+(ok?'PASS':'FAIL')+(notes.length?' | '+notes.join(' ; '):'');document.body.appendChild(d);}
if(location.hash.startsWith('#pick')){openPicker();const m=location.hash.slice(5);if(m){const b=document.querySelector('.pmode button[data-m="'+m+'"]');if(b)b.click();}}
if(location.hash==='#cursortest'){document.getElementById('newhexstr').value='#67809c';openPicker();const sc=document.getElementById('svcur'),hc=document.getElementById('huecur');const L=parseFloat(sc.style.left||'0'),T=parseFloat(sc.style.top||'0'),H=parseFloat(hc.style.top||'0');const ok=L>1&&T>1&&H>1;document.title='CURSORTEST '+(ok?'PASS':'FAIL');const d=document.createElement('div');d.id='cursortest';d.textContent='CURSORTEST '+(ok?'PASS':'FAIL')+' left='+sc.style.left+' top='+sc.style.top+' hue='+hc.style.top;document.body.appendChild(d);}
if(location.hash.startsWith('#app')){const ap=location.hash.slice(4),s=document.getElementById('appsel');if(s&&ap){s.value=ap;pkgChanged();}}
@@ -219,15 +291,27 @@ if(location.hash==='#contrasttest'){let ok=true;const notes=[];const A=(c,n)=>{i
UIMAP['region']={fg:null,bg:'#202830',bold:false,italic:false,underline:false,strike:false};
buildUITable();
const cell=document.getElementById('uicr-region');
- A(cell&&/^worst:/.test(cell.textContent),'region shows the worst-case readout: '+(cell&&cell.textContent));
- A(cell&&cell.textContent.includes('#67809c'),'limiting fg is keyword blue: '+(cell&&cell.textContent));
- A(cell&&/\b(PASS|FAIL)\b/.test(cell.textContent),'readout carries a verdict');
+ A(cell&&/^\d+\.\d (PASS|FAIL)$/.test(cell.textContent.trim()),'region shows compact worst-case readout: '+(cell&&cell.textContent));
+ A(cell&&!cell.textContent.includes('#67809c'),'compact readout omits limiting fg details: '+(cell&&cell.textContent));
+ A(cell&&cell.title.includes('kw (keyword) #67809c'),'hover names failing keyword blue: '+(cell&&cell.title));
+ const badge=document.querySelector('#uiprev-region .crerr');
+ A(badge&&badge.textContent.trim()===cell.textContent.trim(),'region preview shows failing contrast badge: '+(badge&&badge.textContent));
+ A(badge&&badge.title.includes('kw (keyword) #67809c'),'preview badge hover carries failures: '+(badge&&badge.title));
+ const firstFail=badge&&badge.title.split('\n')[1];
+ A(firstFail&&firstFail.includes('kw (keyword) #67809c'),'failures are sorted from worst first: '+firstFail);
const fl=floor('#202830',fgSetForFace('region').set);
A(fl.limitingHex==='#67809c','floor limiting is blue, got '+fl.limitingHex);
A(Math.abs(fl.ratio-contrast('#67809c','#202830'))<1e-9,'floor ratio matches blue-on-bg');
+ UIMAP['region']={fg:'#f0fef0',bg:'#202830',bold:false,italic:false,underline:false,strike:false};
+ buildUITable();
+ const pairCell=document.getElementById('uicr-region'),pairWant=contrast('#f0fef0','#202830');
+ A(pairCell&&Math.abs(parseFloat(pairCell.textContent)-pairWant)<0.06,'region with explicit fg rates its own fg/bg pair: got '+(pairCell&&pairCell.textContent.trim())+' want '+pairWant.toFixed(1));
+ A(!document.querySelector('#uiprev-region .crerr'),'region with explicit fg does not show covered-text error badge');
+ A(pairCell&&!pairCell.title.includes('#67809c'),'region explicit fg hover omits underlying syntax failures: '+(pairCell&&pairCell.title));
const ml=document.getElementById('uicr-mode-line');
A(worstCellHtml('mode-line')===null,'mode-line is out of scope (single-pair)');
A(ml&&/^\d/.test(ml.textContent.trim()),'mode-line cell is a numeric ratio: '+(ml&&ml.textContent));
+ UIMAP['region']={fg:null,bg:'#202830',bold:false,italic:false,underline:false,strike:false};
setSyntaxFg('p','');CATS.forEach(c=>{if(c[0]!=='bg')setSyntaxFg(c[0],'');});buildUITable();
const empty=document.getElementById('uicr-region');
A(empty&&empty.textContent.trim()==='no fg set','empty set reads the no-set message: '+(empty&&empty.textContent));