aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scripts/theme-studio/app.js40
-rw-r--r--scripts/theme-studio/browser-gates.js13
-rw-r--r--scripts/theme-studio/theme-studio.html53
3 files changed, 76 insertions, 30 deletions
diff --git a/scripts/theme-studio/app.js b/scripts/theme-studio/app.js
index e0344ea36..b8369f9b8 100644
--- a/scripts/theme-studio/app.js
+++ b/scripts/theme-studio/app.js
@@ -722,25 +722,35 @@ function renderDashboardPreview(){const a='dashboard',L=[];
L.push(' theme-studio-palette-generator-spec.org');
return previewLines(L);}
function renderMu4ePreview(){const a='mu4e',L=[];
- L.push(os(a,'mu4e-title-face','mu4e')+' '+os(a,'mu4e-context-face','[Personal]')+' '+os(a,'mu4e-ok-face','online')+' '+os(a,'mu4e-warning-face','2 retry')+' '+os(a,'mu4e-modeline-face','12/340'));
+ const pad=(s,n)=>{s=String(s);return s.length>=n?s.slice(0,n):s+' '.repeat(n-s.length);};
+ // One header line: the flags column in mu4e-header-marks-face, the rest of the
+ // row in the message's state face (unread, replied, flagged, ...).
+ const row=(flags,date,from,subj,face)=>
+ os(a,'mu4e-header-marks-face',pad(flags,4))+os(a,face,pad(date,12)+pad(from,17)+subj);
+ // status / context bar
+ L.push(os(a,'mu4e-title-face','mu4e')+' '+os(a,'mu4e-context-face','[Personal]')+' '+os(a,'mu4e-ok-face','online')+' '+os(a,'mu4e-warning-face','2 retrying')+' '+os(a,'mu4e-modeline-face','[12/340]'));
L.push('');
- L.push(os(a,'mu4e-header-title-face','Date Flags From Subject'));
- L.push(os(a,'mu4e-header-value-face','2026-06-08')+' '+os(a,'mu4e-header-marks-face','N')+' '+os(a,'mu4e-unread-face','Christine')+' '+os(a,'mu4e-unread-face','Unread message'));
- L.push(os(a,'mu4e-header-value-face','2026-06-07')+' '+os(a,'mu4e-header-marks-face','R')+' '+os(a,'mu4e-header-face','Bob')+' '+os(a,'mu4e-replied-face','Replied thread'));
- L.push(os(a,'mu4e-header-value-face','2026-06-06')+' '+os(a,'mu4e-header-marks-face','F')+' '+os(a,'mu4e-header-face','Carol')+' '+os(a,'mu4e-forwarded-face','Forwarded note'));
- L.push(os(a,'mu4e-header-value-face','2026-06-05')+' '+os(a,'mu4e-header-marks-face','D')+' '+os(a,'mu4e-draft-face','(draft)')+' '+os(a,'mu4e-draft-face','Draft in progress'));
- L.push(os(a,'mu4e-header-value-face','2026-06-04')+' '+os(a,'mu4e-header-marks-face','T')+' '+os(a,'mu4e-trashed-face','Dan')+' '+os(a,'mu4e-moved-face','Trashed and moved'));
- L.push(os(a,'mu4e-header-highlight-face','2026-06-03 ! Evan Flagged ')+os(a,'mu4e-flagged-face','important')+os(a,'mu4e-related-face',' (related)'));
+ // column header + the message list, one row per state
+ L.push(os(a,'mu4e-header-title-face',pad('Flags',4)+pad('Date',12)+pad('From',17)+'Subject'));
+ L.push(row('N','2026-06-14','Christine Park','Re: quarterly numbers','mu4e-unread-face'));
+ L.push(row('','2026-06-13','Bob Lin','Lunch on Friday?','mu4e-header-face'));
+ // current line at point: the whole row gets the highlight background
+ L.push(os(a,'mu4e-header-highlight-face',row('R','2026-06-13','dev-list','merged the parser fix','mu4e-replied-face')));
+ L.push(row('F','2026-06-12','Carol Reyes','Fwd: the signed contract','mu4e-forwarded-face'));
+ L.push(row('D','2026-06-11','(draft)','Notes to finish later','mu4e-draft-face'));
+ L.push(row('T','2026-06-10','spam@nowhere','You have won a prize','mu4e-trashed-face'));
+ L.push(row('','2026-06-09','Erin (cc)','thread you follow','mu4e-related-face'));
+ L.push(row('!','2026-06-08','Frank Diaz','budget needs sign-off','mu4e-flagged-face'));
L.push('');
- L.push(os(a,'mu4e-header-key-face','From:')+' '+os(a,'mu4e-contact-face','Christine <christine@example.com>'));
- L.push(os(a,'mu4e-header-key-face','To:')+' '+os(a,'mu4e-special-header-value-face','craig, list@gnu.org'));
- L.push(os(a,'mu4e-header-key-face','Attach:')+' '+os(a,'mu4e-attach-number-face','[1]')+' report.pdf link '+os(a,'mu4e-url-number-face','[2]')+' '+os(a,'mu4e-link-face','https://gnu.org'));
+ // a message view below the list
+ L.push(os(a,'mu4e-header-key-face','From:')+' '+os(a,'mu4e-contact-face','Christine Park <christine@example.com>'));
+ L.push(os(a,'mu4e-header-key-face','To:')+' '+os(a,'mu4e-special-header-value-face','craig, dev-list@gnu.org'));
+ L.push(os(a,'mu4e-header-key-face','Subject:')+' '+os(a,'mu4e-header-value-face','Re: quarterly numbers'));
L.push('');
- L.push(' body with a '+os(a,'mu4e-highlight-face','search hit')+' and '+os(a,'mu4e-region-code','code region')+'.');
- L.push(' '+os(a,'mu4e-cited-1-face','> level 1')+' '+os(a,'mu4e-cited-2-face','>> 2')+' '+os(a,'mu4e-cited-3-face','>>> 3')+' '+os(a,'mu4e-cited-4-face','> 4')+' '+os(a,'mu4e-cited-5-face','> 5')+' '+os(a,'mu4e-cited-6-face','> 6')+' '+os(a,'mu4e-cited-7-face','> 7'));
- L.push(' '+os(a,'mu4e-system-face','*** system message ***')+' '+os(a,'mu4e-footer-face','-- sent with mu4e'));
+ L.push(' Body with a '+os(a,'mu4e-highlight-face','search hit')+', a link '+os(a,'mu4e-url-number-face','[1]')+' '+os(a,'mu4e-link-face','https://example.com')+', and a '+os(a,'mu4e-region-code','code region')+'.');
+ L.push(' '+os(a,'mu4e-system-face','*** mu: 340 messages indexed ***'));
+ L.push(' '+os(a,'mu4e-footer-face','-- Sent with mu4e'));
L.push('');
- L.push(os(a,'mu4e-compose-header-face','Subject:')+' new mail');
L.push(os(a,'mu4e-compose-separator-face','--text follows this line--'));
return previewLines(L);}
function renderOrgFacesPreview(){const a='org-faces',L=[];
diff --git a/scripts/theme-studio/browser-gates.js b/scripts/theme-studio/browser-gates.js
index 87038552c..550177c34 100644
--- a/scripts/theme-studio/browser-gates.js
+++ b/scripts/theme-studio/browser-gates.js
@@ -765,6 +765,19 @@ if(location.hash==='#mdtest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c){
}
document.title='MDTEST '+(ok?'PASS':'FAIL');
const d=document.createElement('div');d.id='mdtest';d.textContent='MDTEST '+(ok?'PASS':'FAIL')+(notes.length?' fails='+notes.join(','):'');document.body.appendChild(d);}
+// mu4e-preview gate (open with #mupreviewtest): the mu4e preview is a realistic
+// headers list + message view, and every data-face it emits is a real mu4e face.
+if(location.hash==='#mupreviewtest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c){ok=false;notes.push(n);}};
+ const box=document.createElement('div');box.innerHTML=renderMu4ePreview();
+ const valid=new Set((APPS['mu4e']&&APPS['mu4e'].faces||[]).map(r=>r[0]));
+ const used=[...box.querySelectorAll('[data-face]')].map(e=>e.dataset.face);
+ A(used.length>=20,'preview exercises many faces ('+used.length+')');
+ const bad=used.filter(f=>!valid.has(f));
+ A(bad.length===0,'every data-face is a real mu4e face; bad='+bad.join(','));
+ for(const f of ['mu4e-unread-face','mu4e-flagged-face','mu4e-replied-face','mu4e-draft-face','mu4e-trashed-face','mu4e-header-highlight-face','mu4e-header-marks-face','mu4e-contact-face','mu4e-compose-separator-face'])
+ A(used.includes(f),'preview includes '+f);
+ document.title='MUPREVIEWTEST '+(ok?'PASS':'FAIL');
+ const d=document.createElement('div');d.id='mupreviewtest';d.textContent='MUPREVIEWTEST '+(ok?'PASS':'FAIL')+(notes.length?' fails='+notes.join(','):'');document.body.appendChild(d);}
// Box-cluster gate (open with #boxtest): the box control is a 2x2 cluster of
// four radio buttons (none / line / pressed / raised); the color swatch shows
// only while a box style is active.
diff --git a/scripts/theme-studio/theme-studio.html b/scripts/theme-studio/theme-studio.html
index ad05c0465..8bf0a5c8c 100644
--- a/scripts/theme-studio/theme-studio.html
+++ b/scripts/theme-studio/theme-studio.html
@@ -2341,25 +2341,35 @@ function renderDashboardPreview(){const a='dashboard',L=[];
L.push(' theme-studio-palette-generator-spec.org');
return previewLines(L);}
function renderMu4ePreview(){const a='mu4e',L=[];
- L.push(os(a,'mu4e-title-face','mu4e')+' '+os(a,'mu4e-context-face','[Personal]')+' '+os(a,'mu4e-ok-face','online')+' '+os(a,'mu4e-warning-face','2 retry')+' '+os(a,'mu4e-modeline-face','12/340'));
+ const pad=(s,n)=>{s=String(s);return s.length>=n?s.slice(0,n):s+' '.repeat(n-s.length);};
+ // One header line: the flags column in mu4e-header-marks-face, the rest of the
+ // row in the message's state face (unread, replied, flagged, ...).
+ const row=(flags,date,from,subj,face)=>
+ os(a,'mu4e-header-marks-face',pad(flags,4))+os(a,face,pad(date,12)+pad(from,17)+subj);
+ // status / context bar
+ L.push(os(a,'mu4e-title-face','mu4e')+' '+os(a,'mu4e-context-face','[Personal]')+' '+os(a,'mu4e-ok-face','online')+' '+os(a,'mu4e-warning-face','2 retrying')+' '+os(a,'mu4e-modeline-face','[12/340]'));
L.push('');
- L.push(os(a,'mu4e-header-title-face','Date Flags From Subject'));
- L.push(os(a,'mu4e-header-value-face','2026-06-08')+' '+os(a,'mu4e-header-marks-face','N')+' '+os(a,'mu4e-unread-face','Christine')+' '+os(a,'mu4e-unread-face','Unread message'));
- L.push(os(a,'mu4e-header-value-face','2026-06-07')+' '+os(a,'mu4e-header-marks-face','R')+' '+os(a,'mu4e-header-face','Bob')+' '+os(a,'mu4e-replied-face','Replied thread'));
- L.push(os(a,'mu4e-header-value-face','2026-06-06')+' '+os(a,'mu4e-header-marks-face','F')+' '+os(a,'mu4e-header-face','Carol')+' '+os(a,'mu4e-forwarded-face','Forwarded note'));
- L.push(os(a,'mu4e-header-value-face','2026-06-05')+' '+os(a,'mu4e-header-marks-face','D')+' '+os(a,'mu4e-draft-face','(draft)')+' '+os(a,'mu4e-draft-face','Draft in progress'));
- L.push(os(a,'mu4e-header-value-face','2026-06-04')+' '+os(a,'mu4e-header-marks-face','T')+' '+os(a,'mu4e-trashed-face','Dan')+' '+os(a,'mu4e-moved-face','Trashed and moved'));
- L.push(os(a,'mu4e-header-highlight-face','2026-06-03 ! Evan Flagged ')+os(a,'mu4e-flagged-face','important')+os(a,'mu4e-related-face',' (related)'));
+ // column header + the message list, one row per state
+ L.push(os(a,'mu4e-header-title-face',pad('Flags',4)+pad('Date',12)+pad('From',17)+'Subject'));
+ L.push(row('N','2026-06-14','Christine Park','Re: quarterly numbers','mu4e-unread-face'));
+ L.push(row('','2026-06-13','Bob Lin','Lunch on Friday?','mu4e-header-face'));
+ // current line at point: the whole row gets the highlight background
+ L.push(os(a,'mu4e-header-highlight-face',row('R','2026-06-13','dev-list','merged the parser fix','mu4e-replied-face')));
+ L.push(row('F','2026-06-12','Carol Reyes','Fwd: the signed contract','mu4e-forwarded-face'));
+ L.push(row('D','2026-06-11','(draft)','Notes to finish later','mu4e-draft-face'));
+ L.push(row('T','2026-06-10','spam@nowhere','You have won a prize','mu4e-trashed-face'));
+ L.push(row('','2026-06-09','Erin (cc)','thread you follow','mu4e-related-face'));
+ L.push(row('!','2026-06-08','Frank Diaz','budget needs sign-off','mu4e-flagged-face'));
L.push('');
- L.push(os(a,'mu4e-header-key-face','From:')+' '+os(a,'mu4e-contact-face','Christine <christine@example.com>'));
- L.push(os(a,'mu4e-header-key-face','To:')+' '+os(a,'mu4e-special-header-value-face','craig, list@gnu.org'));
- L.push(os(a,'mu4e-header-key-face','Attach:')+' '+os(a,'mu4e-attach-number-face','[1]')+' report.pdf link '+os(a,'mu4e-url-number-face','[2]')+' '+os(a,'mu4e-link-face','https://gnu.org'));
+ // a message view below the list
+ L.push(os(a,'mu4e-header-key-face','From:')+' '+os(a,'mu4e-contact-face','Christine Park <christine@example.com>'));
+ L.push(os(a,'mu4e-header-key-face','To:')+' '+os(a,'mu4e-special-header-value-face','craig, dev-list@gnu.org'));
+ L.push(os(a,'mu4e-header-key-face','Subject:')+' '+os(a,'mu4e-header-value-face','Re: quarterly numbers'));
L.push('');
- L.push(' body with a '+os(a,'mu4e-highlight-face','search hit')+' and '+os(a,'mu4e-region-code','code region')+'.');
- L.push(' '+os(a,'mu4e-cited-1-face','> level 1')+' '+os(a,'mu4e-cited-2-face','>> 2')+' '+os(a,'mu4e-cited-3-face','>>> 3')+' '+os(a,'mu4e-cited-4-face','> 4')+' '+os(a,'mu4e-cited-5-face','> 5')+' '+os(a,'mu4e-cited-6-face','> 6')+' '+os(a,'mu4e-cited-7-face','> 7'));
- L.push(' '+os(a,'mu4e-system-face','*** system message ***')+' '+os(a,'mu4e-footer-face','-- sent with mu4e'));
+ L.push(' Body with a '+os(a,'mu4e-highlight-face','search hit')+', a link '+os(a,'mu4e-url-number-face','[1]')+' '+os(a,'mu4e-link-face','https://example.com')+', and a '+os(a,'mu4e-region-code','code region')+'.');
+ L.push(' '+os(a,'mu4e-system-face','*** mu: 340 messages indexed ***'));
+ L.push(' '+os(a,'mu4e-footer-face','-- Sent with mu4e'));
L.push('');
- L.push(os(a,'mu4e-compose-header-face','Subject:')+' new mail');
L.push(os(a,'mu4e-compose-separator-face','--text follows this line--'));
return previewLines(L);}
function renderOrgFacesPreview(){const a='org-faces',L=[];
@@ -3482,6 +3492,19 @@ if(location.hash==='#mdtest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c){
}
document.title='MDTEST '+(ok?'PASS':'FAIL');
const d=document.createElement('div');d.id='mdtest';d.textContent='MDTEST '+(ok?'PASS':'FAIL')+(notes.length?' fails='+notes.join(','):'');document.body.appendChild(d);}
+// mu4e-preview gate (open with #mupreviewtest): the mu4e preview is a realistic
+// headers list + message view, and every data-face it emits is a real mu4e face.
+if(location.hash==='#mupreviewtest'){let ok=true;const notes=[];const A=(c,n)=>{if(!c){ok=false;notes.push(n);}};
+ const box=document.createElement('div');box.innerHTML=renderMu4ePreview();
+ const valid=new Set((APPS['mu4e']&&APPS['mu4e'].faces||[]).map(r=>r[0]));
+ const used=[...box.querySelectorAll('[data-face]')].map(e=>e.dataset.face);
+ A(used.length>=20,'preview exercises many faces ('+used.length+')');
+ const bad=used.filter(f=>!valid.has(f));
+ A(bad.length===0,'every data-face is a real mu4e face; bad='+bad.join(','));
+ for(const f of ['mu4e-unread-face','mu4e-flagged-face','mu4e-replied-face','mu4e-draft-face','mu4e-trashed-face','mu4e-header-highlight-face','mu4e-header-marks-face','mu4e-contact-face','mu4e-compose-separator-face'])
+ A(used.includes(f),'preview includes '+f);
+ document.title='MUPREVIEWTEST '+(ok?'PASS':'FAIL');
+ const d=document.createElement('div');d.id='mupreviewtest';d.textContent='MUPREVIEWTEST '+(ok?'PASS':'FAIL')+(notes.length?' fails='+notes.join(','):'');document.body.appendChild(d);}
// Box-cluster gate (open with #boxtest): the box control is a 2x2 cluster of
// four radio buttons (none / line / pressed / raised); the color swatch shows
// only while a box style is active.