diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-29 22:48:28 -0400 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-29 22:48:28 -0400 |
| commit | db903ea32b10ac2f8d10c7e718d81b68492225cc (patch) | |
| tree | 2cd59ebf7a825a51a62933037cfbbefd11ebdc07 /scripts/theme-studio | |
| parent | d94b0dc1603acae7abef0a00bc096ef45d79636b (diff) | |
| download | dotemacs-db903ea32b10ac2f8d10c7e718d81b68492225cc.tar.gz dotemacs-db903ea32b10ac2f8d10c7e718d81b68492225cc.zip | |
feat(theme-studio): render nov-reading preview as a book page
The nov-reading app fell back to the generic preview (face names in their own colors), which doesn't show what a palette looks like. I added a renderer that draws a real book page per palette: a mock page of Hawthorne's "Dr. Heidegger's Experiment" in sepia, dark, and light, with a small-caps byline, a drop cap, and justified serif prose. Each page takes its background and foreground from its palette face, so tuning a palette repaints its page.
Diffstat (limited to 'scripts/theme-studio')
| -rw-r--r-- | scripts/theme-studio/app.js | 1 | ||||
| -rw-r--r-- | scripts/theme-studio/previews.js | 23 | ||||
| -rw-r--r-- | scripts/theme-studio/theme-studio.html | 24 |
3 files changed, 48 insertions, 0 deletions
diff --git a/scripts/theme-studio/app.js b/scripts/theme-studio/app.js index bcba9c4c7..75ff9f581 100644 --- a/scripts/theme-studio/app.js +++ b/scripts/theme-studio/app.js @@ -561,6 +561,7 @@ const PACKAGE_PREVIEWS={ org:renderOrgPreview,magit:renderMagitPreview,elfeed:renderElfeedPreview,eat:renderEatPreview, dashboard:renderDashboardPreview,mu4e:renderMu4ePreview,gnus:renderGnusPreview,orgfaces:renderOrgFacesPreview,lsp:renderLspPreview,gitgutter:renderGitGutterPreview, flycheck:renderFlycheckPreview,dired:renderDiredPreview,dirvish:renderDirvishPreview,calibredb:renderCalibredbPreview, + novreading:renderNovReadingPreview, erc:renderErcPreview,orgdrill:renderOrgdrillPreview,orgnoter:renderOrgnoterPreview,signel:renderSignelPreview, pearl:renderPearlPreview,slack:renderSlackPreview,telega:renderTelegaPreview,shr:renderShrPreview, nerdicons:renderNerdIconsPreview diff --git a/scripts/theme-studio/previews.js b/scripts/theme-studio/previews.js index 72bf242e2..e6d740eea 100644 --- a/scripts/theme-studio/previews.js +++ b/scripts/theme-studio/previews.js @@ -468,6 +468,29 @@ function renderShrPreview(){const a='shr',L=[]; L.push(os(a,'shr-text','some ')+os(a,'shr-code','inline_code()')+os(a,'shr-text',', a ')+os(a,'shr-mark','highlighted mark')+os(a,'shr-text',', ')+os(a,'shr-strike-through','struck out')+os(a,'shr-text',', a footnote')+os(a,'shr-sup','[1]')+os(a,'shr-text',',')); L.push(os(a,'shr-text','an ')+os(a,'shr-abbreviation','HTML')+os(a,'shr-text',' abbreviation, and an ')+os(a,'shr-sliced-image','[image]')+os(a,'shr-text',' slice.')); return previewLines(L);} +// nov-reading: a realistic book page per palette, not the line-based format. +// Each palette face supplies the page bg+fg (via ofs); the serif typography and +// hierarchy are CSS so the preview reads like an actual novel page. Tuning a +// palette face repaints its page. data-owner-app/-face keep face-locate working. +function novReadingPage(a,face,label){ + const cls=isLocateOnPane(a,curApp())?' class="locate-onpane"':''; + const title=attresc(formatLocateTitle(locateFaceMeta(a,face,LOCATE_REG))); + const page=ofs(a,face)+";width:34em;max-width:100%;border-radius:6px;box-shadow:0 1px 8px #0007;padding:24px 30px 18px;font:13pt/1.62 Georgia,'Times New Roman',serif"; + return `<div data-owner-app="${a}" data-face="${face}"${cls} title="${title}" style="${page}">` + +`<div style="text-align:center;font-variant:small-caps;letter-spacing:.08em;font-size:10pt;opacity:.72;margin-bottom:3px">Nathaniel Hawthorne · Twice-Told Tales</div>` + +`<div style="text-align:center;font:italic 600 16pt/1.3 Georgia,serif;margin:.15em 0 1em">Dr. Heidegger’s Experiment</div>` + +`<p style="margin:0 0 .75em">` + +`<span style="float:left;font:600 320%/.74 Georgia,serif;padding:6px 8px 0 0">T</span>` + +`hat very singular man, old Dr. Heidegger, once invited four venerable friends to meet him in his study. There were three white-bearded gentlemen, Mr. Medbourne, Colonel Killigrew, and Mr. Gascoigne, and a withered gentlewoman whose name was the Widow Wycherly.</p>` + +`<p style="margin:0 0 .75em;text-indent:1.4em">They were all melancholy old creatures, who had been unfortunate in life, and whose greatest misfortune it was that they were not long ago in their graves. <em>If the powder be genuine,</em> said the doctor, the rose of half a century should bloom again.</p>` + +`<div style="text-align:center;font-size:9.5pt;opacity:.6;margin-top:.7em">${esc(label)} · 12</div>` + +`</div>`;} +function renderNovReadingPreview(){ + const a='nov-reading',faces=(APPS[a]&&APPS[a].faces)||[]; + if(!faces.length)return genericPreview(a); + let h='<div style="padding:14px 16px;display:flex;flex-direction:column;gap:18px;align-items:center">'; + for(const row of faces)h+=novReadingPage(a,row[0],row[1]); + return h+'</div>';} function renderSlackPreview(){const a='slack',L=[]; L.push(os(a,'slack-room-info-title-room-name-face','#general')+' '+os(a,'slack-room-info-title-face','Acme Workspace')); L.push(os(a,'slack-room-info-section-title-face','Topic')+' '+os(a,'slack-room-info-section-label-face','daily standup')+' '+os(a,'slack-room-unread-face','3 unread')); diff --git a/scripts/theme-studio/theme-studio.html b/scripts/theme-studio/theme-studio.html index e71658f62..e3d88a46a 100644 --- a/scripts/theme-studio/theme-studio.html +++ b/scripts/theme-studio/theme-studio.html @@ -3136,6 +3136,29 @@ function renderShrPreview(){const a='shr',L=[]; L.push(os(a,'shr-text','some ')+os(a,'shr-code','inline_code()')+os(a,'shr-text',', a ')+os(a,'shr-mark','highlighted mark')+os(a,'shr-text',', ')+os(a,'shr-strike-through','struck out')+os(a,'shr-text',', a footnote')+os(a,'shr-sup','[1]')+os(a,'shr-text',',')); L.push(os(a,'shr-text','an ')+os(a,'shr-abbreviation','HTML')+os(a,'shr-text',' abbreviation, and an ')+os(a,'shr-sliced-image','[image]')+os(a,'shr-text',' slice.')); return previewLines(L);} +// nov-reading: a realistic book page per palette, not the line-based format. +// Each palette face supplies the page bg+fg (via ofs); the serif typography and +// hierarchy are CSS so the preview reads like an actual novel page. Tuning a +// palette face repaints its page. data-owner-app/-face keep face-locate working. +function novReadingPage(a,face,label){ + const cls=isLocateOnPane(a,curApp())?' class="locate-onpane"':''; + const title=attresc(formatLocateTitle(locateFaceMeta(a,face,LOCATE_REG))); + const page=ofs(a,face)+";width:34em;max-width:100%;border-radius:6px;box-shadow:0 1px 8px #0007;padding:24px 30px 18px;font:13pt/1.62 Georgia,'Times New Roman',serif"; + return `<div data-owner-app="${a}" data-face="${face}"${cls} title="${title}" style="${page}">` + +`<div style="text-align:center;font-variant:small-caps;letter-spacing:.08em;font-size:10pt;opacity:.72;margin-bottom:3px">Nathaniel Hawthorne · Twice-Told Tales</div>` + +`<div style="text-align:center;font:italic 600 16pt/1.3 Georgia,serif;margin:.15em 0 1em">Dr. Heidegger’s Experiment</div>` + +`<p style="margin:0 0 .75em">` + +`<span style="float:left;font:600 320%/.74 Georgia,serif;padding:6px 8px 0 0">T</span>` + +`hat very singular man, old Dr. Heidegger, once invited four venerable friends to meet him in his study. There were three white-bearded gentlemen, Mr. Medbourne, Colonel Killigrew, and Mr. Gascoigne, and a withered gentlewoman whose name was the Widow Wycherly.</p>` + +`<p style="margin:0 0 .75em;text-indent:1.4em">They were all melancholy old creatures, who had been unfortunate in life, and whose greatest misfortune it was that they were not long ago in their graves. <em>If the powder be genuine,</em> said the doctor, the rose of half a century should bloom again.</p>` + +`<div style="text-align:center;font-size:9.5pt;opacity:.6;margin-top:.7em">${esc(label)} · 12</div>` + +`</div>`;} +function renderNovReadingPreview(){ + const a='nov-reading',faces=(APPS[a]&&APPS[a].faces)||[]; + if(!faces.length)return genericPreview(a); + let h='<div style="padding:14px 16px;display:flex;flex-direction:column;gap:18px;align-items:center">'; + for(const row of faces)h+=novReadingPage(a,row[0],row[1]); + return h+'</div>';} function renderSlackPreview(){const a='slack',L=[]; L.push(os(a,'slack-room-info-title-room-name-face','#general')+' '+os(a,'slack-room-info-title-face','Acme Workspace')); L.push(os(a,'slack-room-info-section-title-face','Topic')+' '+os(a,'slack-room-info-section-label-face','daily standup')+' '+os(a,'slack-room-unread-face','3 unread')); @@ -3288,6 +3311,7 @@ const PACKAGE_PREVIEWS={ org:renderOrgPreview,magit:renderMagitPreview,elfeed:renderElfeedPreview,eat:renderEatPreview, dashboard:renderDashboardPreview,mu4e:renderMu4ePreview,gnus:renderGnusPreview,orgfaces:renderOrgFacesPreview,lsp:renderLspPreview,gitgutter:renderGitGutterPreview, flycheck:renderFlycheckPreview,dired:renderDiredPreview,dirvish:renderDirvishPreview,calibredb:renderCalibredbPreview, + novreading:renderNovReadingPreview, erc:renderErcPreview,orgdrill:renderOrgdrillPreview,orgnoter:renderOrgnoterPreview,signel:renderSignelPreview, pearl:renderPearlPreview,slack:renderSlackPreview,telega:renderTelegaPreview,shr:renderShrPreview, nerdicons:renderNerdIconsPreview |
