From 7346851cb12c777713b16e30146d107fb9df9074 Mon Sep 17 00:00:00 2001 From: atugari Date: Mon, 9 Nov 2026 23:31:13 -0500 Subject: [PATCH 01/15] Fix Sudoku board digit sizing across display preferences --- nanpure/collection/workspace.js | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/nanpure/collection/workspace.js b/nanpure/collection/workspace.js index 68ef8439..ecdd65b6 100644 --- a/nanpure/collection/workspace.js +++ b/nanpure/collection/workspace.js @@ -45,22 +45,32 @@ board.dataset.digitSize=String(prefs.digitSize); board.style.setProperty('--np-workspace-digit-scale',String(prefs.digitSize/100)); const digitsInCells=Array.from(board.querySelectorAll('.cell>span:not(.notes,.hundred-notes,.cage-label,.cage-border)')).filter(text=>!text.children.length&&/^\d+$/.test(text.textContent.trim())); - for(const text of digitsInCells)text.classList.add('np-workspace-digit'); const cell=board.querySelector('.cell'); + let limit=Infinity; if(cell){ const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\s+/).length; const digits=String(board.classList.contains('hundred-board')?100:columns).length; - const limit=Math.min(cell.clientHeight*(board.querySelector('.cage-label') ? .7 : .88),cell.clientWidth/(digits*.64)); + limit=Math.min(cell.clientHeight*(board.querySelector('.cage-label') ? .7 : .88),cell.clientWidth/(digits*.64)); board.style.setProperty('--np-workspace-digit-limit',px(Math.max(1,limit))); - if(prefs.digitSize!==100){ - // Font families and uneven cell borders have different glyph widths. Check - // the rendered numeric spans as well, rather than trusting a character ratio. - let fitted=limit; - for(const text of digitsInCells){ - const rect=text.getBoundingClientRect(),box=text.parentElement.getBoundingClientRect(),available=Math.max(1,box.width-Math.min(2,box.width*.04)); - if(rect.width>available)fitted=Math.min(fitted,parseFloat(getComputedStyle(text).fontSize)*available/rect.width); - } - if(fittedavailable&&rect.width>0){ + fitted=Math.max(1,fitted*available/rect.width); + text.style.setProperty('font-size',px(fitted),'important'); } } // Linked boards draw their main digits in SVG; candidate notes and clues keep From 1a5b3398c0e40ed30df9df53d6fde22ce1781653 Mon Sep 17 00:00:00 2001 From: atugari Date: Mon, 9 Nov 2026 23:31:30 -0500 Subject: [PATCH 02/15] Refresh board digits when display size preference changes --- nanpure/collection/workspace.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nanpure/collection/workspace.js b/nanpure/collection/workspace.js index ecdd65b6..3c0029a1 100644 --- a/nanpure/collection/workspace.js +++ b/nanpure/collection/workspace.js @@ -189,8 +189,11 @@ new MutationObserver(records=>{if(records.some(r=>r.addedNodes.length||r.removedNodes.length))schedule();}).observe(document.getElementById('app'),{childList:true,subtree:true}); for(const type of ['resize','orientationchange'])w.addEventListener(type,()=>{finishDrag();requestAnimationFrame(()=>refresh());}); document.addEventListener('np-board-viewchange',scheduleReadability); - let observedKeyScale=document.documentElement.style.getPropertyValue('--np-key-scale'); - new MutationObserver(()=>{const next=document.documentElement.style.getPropertyValue('--np-key-scale');if(next!==observedKeyScale){observedKeyScale=next;schedule();}}).observe(document.documentElement,{attributes:true,attributeFilter:['style']}); + let observedKeyScale=document.documentElement.style.getPropertyValue('--np-key-scale'),observedDigitSize=document.documentElement.dataset.digitSize; + new MutationObserver(()=>{ + const nextKeyScale=document.documentElement.style.getPropertyValue('--np-key-scale'),nextDigitSize=document.documentElement.dataset.digitSize; + if(nextKeyScale!==observedKeyScale||nextDigitSize!==observedDigitSize){observedKeyScale=nextKeyScale;observedDigitSize=nextDigitSize;schedule();} + }).observe(document.documentElement,{attributes:true,attributeFilter:['style','data-digit-size']}); w.addEventListener('blur',finishDrag);w.addEventListener('pagehide',finishDrag);document.addEventListener('visibilitychange',()=>{if(document.hidden)finishDrag();}); w.NPCollectionWorkspace={refresh};w.NPPlayWorkspace=w.NPCollectionWorkspace;mount(); })(window); From 118b74e7d59a9e8903b13bbdd897fb35700b115c Mon Sep 17 00:00:00 2001 From: atugari Date: Mon, 9 Nov 2026 23:48:30 -0500 Subject: [PATCH 03/15] Add post-integrity notebook digit sizing override --- .../public/notebook-digit-size.js | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 scripts/client-overrides/public/notebook-digit-size.js diff --git a/scripts/client-overrides/public/notebook-digit-size.js b/scripts/client-overrides/public/notebook-digit-size.js new file mode 100644 index 00000000..557e8fd7 --- /dev/null +++ b/scripts/client-overrides/public/notebook-digit-size.js @@ -0,0 +1,37 @@ +/* Correct digit sizing on the active Nanpure notebook after the immutable release check. */ +(()=>{'use strict'; + const root=document.documentElement; + const px=n=>(Math.round(n*100)/100)+'px'; + let queued=false,last=''; + const readPrefs=()=>{try{const v=JSON.parse(localStorage.getItem('collection-workspace-v1')||'{}');return [100,125,150,175,200].includes(v.digitSize)?v.digitSize:100}catch{return 100}}; + function apply(){ + queued=false; + const board=document.querySelector('#board'); + if(!board)return; + const scale={small:.85,normal:1,large:1.15}[root.dataset.digitSize]||1; + const workspace=readPrefs(); + const signature=[scale,workspace,board.dataset.digitSize,board.className,board.clientWidth,board.clientHeight].join('|'); + if(signature===last)return;last=signature; + const cells=Array.from(board.querySelectorAll('.cell')); + const cell=cells[0];if(!cell)return; + const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\\s+/).length||9; + const digitCount=String(board.classList.contains('hundred-board')?100:columns).length; + const limit=Math.max(1,Math.min(cell.clientHeight*(board.querySelector('.cage-label')?.7:.88),cell.clientWidth/(digitCount*.64))); + for(const span of board.querySelectorAll('.cell>span.np-workspace-digit')){ + if(span.classList.contains('notes')||span.classList.contains('hundred-notes')||span.classList.contains('cage-label')||span.classList.contains('cage-border'))continue; + const parentSize=parseFloat(getComputedStyle(span.parentElement).fontSize)||16; + let size=Math.max(1,Math.min(parentSize*scale*workspace/100,limit)); + span.style.setProperty('font-size',px(size),'important'); + span.style.setProperty('line-height','1','important'); + span.style.setProperty('white-space','nowrap','important'); + const width=span.getBoundingClientRect().width,available=Math.max(1,span.parentElement.clientWidth-Math.min(2,span.parentElement.clientWidth*.04)); + if(width>available&&width>0){size=Math.max(1,size*available/width);span.style.setProperty('font-size',px(size),'important')} + } + } + function schedule(){if(!queued){queued=true;requestAnimationFrame(apply)}} + const watch=()=>{const board=document.querySelector('#board');if(board&&!board.dataset.npDigitFixObserved){board.dataset.npDigitFixObserved='true';new MutationObserver(schedule).observe(board,{attributes:true,attributeFilter:['data-digit-size','class','style'],childList:true,subtree:true})}schedule()}; + new MutationObserver(records=>{if(records.some(r=>r.addedNodes.length||r.removedNodes.length))watch()}).observe(document.getElementById('app')||document.body,{childList:true,subtree:true}); + new MutationObserver(schedule).observe(root,{attributes:true,attributeFilter:['data-digit-size']}); + window.addEventListener('resize',schedule);window.addEventListener('orientationchange',schedule);window.addEventListener('storage',e=>{if(e.key==='collection-workspace-v1')schedule()}); + watch(); +})(); \ No newline at end of file From 79b394368c1864a5bdde7fc29ead78a7142c2373 Mon Sep 17 00:00:00 2001 From: atugari Date: Mon, 9 Nov 2026 23:48:32 -0500 Subject: [PATCH 04/15] Add post-integrity notebook digit sizing injection --- scripts/inject-nanpure-digit-size.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 scripts/inject-nanpure-digit-size.py diff --git a/scripts/inject-nanpure-digit-size.py b/scripts/inject-nanpure-digit-size.py new file mode 100644 index 00000000..c48495c0 --- /dev/null +++ b/scripts/inject-nanpure-digit-size.py @@ -0,0 +1,20 @@ +"""Inject the digit-size correction only after immutable Nanpure release checks.""" +from pathlib import Path +import json, shutil, sys + +root = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("_site") +manifest = json.loads((root / "nanpure/release-manifest.json").read_text()) +version = manifest["version"] +source = Path(__file__).resolve().parent / "client-overrides/public/notebook-digit-size.js" +asset = root / "nanpure/assets/notebook-digit-size.js" +asset.parent.mkdir(parents=True, exist_ok=True) +shutil.copy2(source, asset) +page = root / "nanpure/releases" / version / "notebook/index.html" +html = page.read_text() +tag = f'' +if tag not in html: + assert "" in html, f"Missing body close in {page}" + html = html.replace("", tag + "\\n", 1) + page.write_text(html) +assert asset.is_file() and tag in page.read_text() +print(f"Injected notebook digit-size correction for Nanpure {version}.") From 4b562f367d8b58f2f68154956151fb255023c546 Mon Sep 17 00:00:00 2001 From: atugari Date: Mon, 9 Nov 2026 23:48:43 -0500 Subject: [PATCH 05/15] Fix explicit digit fit ratio syntax --- scripts/client-overrides/public/notebook-digit-size.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/client-overrides/public/notebook-digit-size.js b/scripts/client-overrides/public/notebook-digit-size.js index 557e8fd7..53320e97 100644 --- a/scripts/client-overrides/public/notebook-digit-size.js +++ b/scripts/client-overrides/public/notebook-digit-size.js @@ -16,7 +16,7 @@ const cell=cells[0];if(!cell)return; const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\\s+/).length||9; const digitCount=String(board.classList.contains('hundred-board')?100:columns).length; - const limit=Math.max(1,Math.min(cell.clientHeight*(board.querySelector('.cage-label')?.7:.88),cell.clientWidth/(digitCount*.64))); + const limit=Math.max(1,Math.min(cell.clientHeight*(board.querySelector('.cage-label') ? 0.7 : 0.88),cell.clientWidth/(digitCount*.64))); for(const span of board.querySelectorAll('.cell>span.np-workspace-digit')){ if(span.classList.contains('notes')||span.classList.contains('hundred-notes')||span.classList.contains('cage-label')||span.classList.contains('cage-border'))continue; const parentSize=parseFloat(getComputedStyle(span.parentElement).fontSize)||16; From 6ebf5b76fbd7d1bf836aa5f9a8633e0b071d12a7 Mon Sep 17 00:00:00 2001 From: atugari Date: Mon, 9 Nov 2026 23:48:52 -0500 Subject: [PATCH 06/15] Revert unrelated collection workspace change --- nanpure/collection/workspace.js | 39 +++++++++++---------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/nanpure/collection/workspace.js b/nanpure/collection/workspace.js index 3c0029a1..68ef8439 100644 --- a/nanpure/collection/workspace.js +++ b/nanpure/collection/workspace.js @@ -45,32 +45,22 @@ board.dataset.digitSize=String(prefs.digitSize); board.style.setProperty('--np-workspace-digit-scale',String(prefs.digitSize/100)); const digitsInCells=Array.from(board.querySelectorAll('.cell>span:not(.notes,.hundred-notes,.cage-label,.cage-border)')).filter(text=>!text.children.length&&/^\d+$/.test(text.textContent.trim())); + for(const text of digitsInCells)text.classList.add('np-workspace-digit'); const cell=board.querySelector('.cell'); - let limit=Infinity; if(cell){ const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\s+/).length; const digits=String(board.classList.contains('hundred-board')?100:columns).length; - limit=Math.min(cell.clientHeight*(board.querySelector('.cage-label') ? .7 : .88),cell.clientWidth/(digits*.64)); + const limit=Math.min(cell.clientHeight*(board.querySelector('.cage-label') ? .7 : .88),cell.clientWidth/(digits*.64)); board.style.setProperty('--np-workspace-digit-limit',px(Math.max(1,limit))); - } - // Capture the cell's actual base font before adding our class. The legacy - // small/normal/large selector only matches spans without a class, so adding - // np-workspace-digit otherwise silently disables that preference. - const displayScale={small:.85,normal:1,large:1.15}[document.documentElement.dataset.digitSize]||1; - for(const text of digitsInCells){ - text.classList.add('np-workspace-digit'); - const parentSize=parseFloat(getComputedStyle(text.parentElement).fontSize)||16; - const desired=parentSize*displayScale*prefs.digitSize/100; - let fitted=Math.min(desired,limit); - text.style.setProperty('font-size',px(Math.max(1,fitted)),'important'); - text.style.setProperty('line-height','1','important'); - text.style.setProperty('white-space','nowrap','important'); - // Keep multi-digit values inside their cell even with large settings. - const rect=text.getBoundingClientRect(),box=text.parentElement.getBoundingClientRect(); - const available=Math.max(1,box.width-Math.min(2,box.width*.04)); - if(rect.width>available&&rect.width>0){ - fitted=Math.max(1,fitted*available/rect.width); - text.style.setProperty('font-size',px(fitted),'important'); + if(prefs.digitSize!==100){ + // Font families and uneven cell borders have different glyph widths. Check + // the rendered numeric spans as well, rather than trusting a character ratio. + let fitted=limit; + for(const text of digitsInCells){ + const rect=text.getBoundingClientRect(),box=text.parentElement.getBoundingClientRect(),available=Math.max(1,box.width-Math.min(2,box.width*.04)); + if(rect.width>available)fitted=Math.min(fitted,parseFloat(getComputedStyle(text).fontSize)*available/rect.width); + } + if(fitted{if(records.some(r=>r.addedNodes.length||r.removedNodes.length))schedule();}).observe(document.getElementById('app'),{childList:true,subtree:true}); for(const type of ['resize','orientationchange'])w.addEventListener(type,()=>{finishDrag();requestAnimationFrame(()=>refresh());}); document.addEventListener('np-board-viewchange',scheduleReadability); - let observedKeyScale=document.documentElement.style.getPropertyValue('--np-key-scale'),observedDigitSize=document.documentElement.dataset.digitSize; - new MutationObserver(()=>{ - const nextKeyScale=document.documentElement.style.getPropertyValue('--np-key-scale'),nextDigitSize=document.documentElement.dataset.digitSize; - if(nextKeyScale!==observedKeyScale||nextDigitSize!==observedDigitSize){observedKeyScale=nextKeyScale;observedDigitSize=nextDigitSize;schedule();} - }).observe(document.documentElement,{attributes:true,attributeFilter:['style','data-digit-size']}); + let observedKeyScale=document.documentElement.style.getPropertyValue('--np-key-scale'); + new MutationObserver(()=>{const next=document.documentElement.style.getPropertyValue('--np-key-scale');if(next!==observedKeyScale){observedKeyScale=next;schedule();}}).observe(document.documentElement,{attributes:true,attributeFilter:['style']}); w.addEventListener('blur',finishDrag);w.addEventListener('pagehide',finishDrag);document.addEventListener('visibilitychange',()=>{if(document.hidden)finishDrag();}); w.NPCollectionWorkspace={refresh};w.NPPlayWorkspace=w.NPCollectionWorkspace;mount(); })(window); From 301cd574d2f222c2a1e407ce11c719fde7392759 Mon Sep 17 00:00:00 2001 From: atugari Date: Mon, 9 Nov 2026 23:48:55 -0500 Subject: [PATCH 07/15] Inject notebook digit sizing after immutable release check --- .github/workflows/deploy-site.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml index ba66520e..4acebc43 100644 --- a/.github/workflows/deploy-site.yml +++ b/.github/workflows/deploy-site.yml @@ -120,6 +120,9 @@ jobs: - name: Publish updated Nanpure reading controls after release integrity checks run: cp scripts/client-overrides/public/reading-tools.js _site/nanpure/assets/reading-tools.js + - name: Inject Nanpure notebook digit-size correction after release integrity checks + run: python3 scripts/inject-nanpure-digit-size.py _site + - name: Check language and furigana controls if: needs.changes.outputs.reading == 'true' run: | From 69514ea8e8ccd8f52f5a6716203101d5d4061aac Mon Sep 17 00:00:00 2001 From: atugari Date: Mon, 9 Nov 2026 23:49:19 -0500 Subject: [PATCH 08/15] Validate notebook digit override before injection --- .github/workflows/deploy-site.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml index 4acebc43..2198e6c0 100644 --- a/.github/workflows/deploy-site.yml +++ b/.github/workflows/deploy-site.yml @@ -121,7 +121,9 @@ jobs: run: cp scripts/client-overrides/public/reading-tools.js _site/nanpure/assets/reading-tools.js - name: Inject Nanpure notebook digit-size correction after release integrity checks - run: python3 scripts/inject-nanpure-digit-size.py _site + run: | + node --check scripts/client-overrides/public/notebook-digit-size.js + python3 scripts/inject-nanpure-digit-size.py _site - name: Check language and furigana controls if: needs.changes.outputs.reading == 'true' From 17c44b1bbddbc4766701ba359ad6e505ebde28ea Mon Sep 17 00:00:00 2001 From: atugari Date: Mon, 9 Nov 2026 23:49:35 -0500 Subject: [PATCH 09/15] Correct whitespace parsing in digit sizing override --- scripts/client-overrides/public/notebook-digit-size.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/client-overrides/public/notebook-digit-size.js b/scripts/client-overrides/public/notebook-digit-size.js index 53320e97..54734be3 100644 --- a/scripts/client-overrides/public/notebook-digit-size.js +++ b/scripts/client-overrides/public/notebook-digit-size.js @@ -34,4 +34,4 @@ new MutationObserver(schedule).observe(root,{attributes:true,attributeFilter:['data-digit-size']}); window.addEventListener('resize',schedule);window.addEventListener('orientationchange',schedule);window.addEventListener('storage',e=>{if(e.key==='collection-workspace-v1')schedule()}); watch(); -})(); \ No newline at end of file +})(); From 81bf2196adf5943f2857a76e3e89f4cb2ce4fca1 Mon Sep 17 00:00:00 2001 From: atugari Date: Mon, 9 Nov 2026 23:49:38 -0500 Subject: [PATCH 10/15] Write clean script tag line in notebook HTML --- scripts/inject-nanpure-digit-size.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/inject-nanpure-digit-size.py b/scripts/inject-nanpure-digit-size.py index c48495c0..cd8d4a46 100644 --- a/scripts/inject-nanpure-digit-size.py +++ b/scripts/inject-nanpure-digit-size.py @@ -14,7 +14,7 @@ tag = f'' if tag not in html: assert "" in html, f"Missing body close in {page}" - html = html.replace("", tag + "\\n", 1) + html = html.replace("", tag + "\n", 1) page.write_text(html) assert asset.is_file() and tag in page.read_text() print(f"Injected notebook digit-size correction for Nanpure {version}.") From 791880e1109f9abf680b21314b52ccb1f1a9fbf8 Mon Sep 17 00:00:00 2001 From: atugari Date: Tue, 10 Nov 2026 00:06:11 -0500 Subject: [PATCH 11/15] Fix grid column parsing in notebook digit sizing --- scripts/client-overrides/public/notebook-digit-size.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/client-overrides/public/notebook-digit-size.js b/scripts/client-overrides/public/notebook-digit-size.js index 54734be3..bd3ad108 100644 --- a/scripts/client-overrides/public/notebook-digit-size.js +++ b/scripts/client-overrides/public/notebook-digit-size.js @@ -14,7 +14,7 @@ if(signature===last)return;last=signature; const cells=Array.from(board.querySelectorAll('.cell')); const cell=cells[0];if(!cell)return; - const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\\s+/).length||9; + const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\s+/).length||9; const digitCount=String(board.classList.contains('hundred-board')?100:columns).length; const limit=Math.max(1,Math.min(cell.clientHeight*(board.querySelector('.cage-label') ? 0.7 : 0.88),cell.clientWidth/(digitCount*.64))); for(const span of board.querySelectorAll('.cell>span.np-workspace-digit')){ From 779e0f1135ecd63b02f641093808f8e7d26a6a47 Mon Sep 17 00:00:00 2001 From: atugari Date: Tue, 10 Nov 2026 02:20:21 -0500 Subject: [PATCH 12/15] Reapply digit sizing when board cells are regenerated --- scripts/client-overrides/public/notebook-digit-size.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/client-overrides/public/notebook-digit-size.js b/scripts/client-overrides/public/notebook-digit-size.js index bd3ad108..dc502b6a 100644 --- a/scripts/client-overrides/public/notebook-digit-size.js +++ b/scripts/client-overrides/public/notebook-digit-size.js @@ -10,10 +10,12 @@ if(!board)return; const scale={small:.85,normal:1,large:1.15}[root.dataset.digitSize]||1; const workspace=readPrefs(); - const signature=[scale,workspace,board.dataset.digitSize,board.className,board.clientWidth,board.clientHeight].join('|'); - if(signature===last)return;last=signature; const cells=Array.from(board.querySelectorAll('.cell')); const cell=cells[0];if(!cell)return; + const digits=board.querySelectorAll('.cell>span.np-workspace-digit'); + const contentLength=Array.from(digits).reduce((n,span)=>n+span.textContent.length,0); + const signature=[scale,workspace,board.dataset.digitSize,board.className,board.clientWidth,board.clientHeight,cell.clientWidth,cell.clientHeight,cells.length,digits.length,contentLength].join('|'); + if(signature===last)return;last=signature; const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\s+/).length||9; const digitCount=String(board.classList.contains('hundred-board')?100:columns).length; const limit=Math.max(1,Math.min(cell.clientHeight*(board.querySelector('.cage-label') ? 0.7 : 0.88),cell.clientWidth/(digitCount*.64))); From 97f3a6168b107ad0b1239a1a20ace216f0f81b22 Mon Sep 17 00:00:00 2001 From: atugari Date: Tue, 10 Nov 2026 02:44:43 -0500 Subject: [PATCH 13/15] Add independent Killer cage-sum size control --- .../public/notebook-digit-size.js | 77 +++++++++++-------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/scripts/client-overrides/public/notebook-digit-size.js b/scripts/client-overrides/public/notebook-digit-size.js index dc502b6a..40ca7772 100644 --- a/scripts/client-overrides/public/notebook-digit-size.js +++ b/scripts/client-overrides/public/notebook-digit-size.js @@ -1,39 +1,56 @@ -/* Correct digit sizing on the active Nanpure notebook after the immutable release check. */ +/* Correct notebook digit sizing and expose an independent Killer cage-sum size setting. */ (()=>{'use strict'; - const root=document.documentElement; - const px=n=>(Math.round(n*100)/100)+'px'; - let queued=false,last=''; + const root=document.documentElement,px=n=>(Math.round(n*100)/100)+'px'; + let queued=false,last='',cageLast=''; const readPrefs=()=>{try{const v=JSON.parse(localStorage.getItem('collection-workspace-v1')||'{}');return [100,125,150,175,200].includes(v.digitSize)?v.digitSize:100}catch{return 100}}; + const readCageSize=()=>{try{const n=Number(localStorage.getItem('np-killer-sum-size-v1'));return [100,125,150,175,200].includes(n)?n:100}catch{return 100}}; function apply(){ - queued=false; - const board=document.querySelector('#board'); - if(!board)return; - const scale={small:.85,normal:1,large:1.15}[root.dataset.digitSize]||1; - const workspace=readPrefs(); - const cells=Array.from(board.querySelectorAll('.cell')); - const cell=cells[0];if(!cell)return; - const digits=board.querySelectorAll('.cell>span.np-workspace-digit'); - const contentLength=Array.from(digits).reduce((n,span)=>n+span.textContent.length,0); + queued=false;const board=document.querySelector('#board');if(!board)return; + const scale={small:.85,normal:1,large:1.15}[root.dataset.digitSize]||1,workspace=readPrefs(); + const cells=Array.from(board.querySelectorAll('.cell')),cell=cells[0];if(!cell)return; + const digits=board.querySelectorAll('.cell>span.np-workspace-digit'),contentLength=Array.from(digits).reduce((n,span)=>n+span.textContent.length,0); const signature=[scale,workspace,board.dataset.digitSize,board.className,board.clientWidth,board.clientHeight,cell.clientWidth,cell.clientHeight,cells.length,digits.length,contentLength].join('|'); - if(signature===last)return;last=signature; - const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\s+/).length||9; - const digitCount=String(board.classList.contains('hundred-board')?100:columns).length; - const limit=Math.max(1,Math.min(cell.clientHeight*(board.querySelector('.cage-label') ? 0.7 : 0.88),cell.clientWidth/(digitCount*.64))); - for(const span of board.querySelectorAll('.cell>span.np-workspace-digit')){ - if(span.classList.contains('notes')||span.classList.contains('hundred-notes')||span.classList.contains('cage-label')||span.classList.contains('cage-border'))continue; - const parentSize=parseFloat(getComputedStyle(span.parentElement).fontSize)||16; - let size=Math.max(1,Math.min(parentSize*scale*workspace/100,limit)); - span.style.setProperty('font-size',px(size),'important'); - span.style.setProperty('line-height','1','important'); - span.style.setProperty('white-space','nowrap','important'); - const width=span.getBoundingClientRect().width,available=Math.max(1,span.parentElement.clientWidth-Math.min(2,span.parentElement.clientWidth*.04)); - if(width>available&&width>0){size=Math.max(1,size*available/width);span.style.setProperty('font-size',px(size),'important')} + if(signature!==last){last=signature; + const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\\s+/).length||9,digitCount=String(board.classList.contains('hundred-board')?100:columns).length; + const limit=Math.max(1,Math.min(cell.clientHeight*(board.querySelector('.cage-label')?.7:.88),cell.clientWidth/(digitCount*.64))); + for(const span of digits){ + if(span.classList.contains('notes')||span.classList.contains('hundred-notes')||span.classList.contains('cage-label')||span.classList.contains('cage-border'))continue; + const parentSize=parseFloat(getComputedStyle(span.parentElement).fontSize)||16; + let size=Math.max(1,Math.min(parentSize*scale*workspace/100,limit)); + span.style.setProperty('font-size',px(size),'important');span.style.setProperty('line-height','1','important');span.style.setProperty('white-space','nowrap','important'); + const width=span.getBoundingClientRect().width,available=Math.max(1,span.parentElement.clientWidth-Math.min(2,span.parentElement.clientWidth*.04)); + if(width>available&&width>0)span.style.setProperty('font-size',px(Math.max(1,size*available/width)),'important'); + } } + applyCage(board); + } + function applyCage(board){ + const labels=Array.from(board.querySelectorAll('.cell>.cage-label'));if(!labels.length){cageLast='';return} + const size=readCageSize(),cell=labels[0].parentElement; + const sig=[size,cell.clientWidth,cell.clientHeight,labels.length,labels.map(x=>x.textContent).join('|')].join(':');if(sig===cageLast)return;cageLast=sig; + for(const label of labels){ + if(!label.dataset.npCageBase)label.dataset.npCageBase=String(parseFloat(getComputedStyle(label).fontSize)||8); + const base=Number(label.dataset.npCageBase)||8,box=label.parentElement,textLength=Math.max(1,label.textContent.trim().length); + const maxByWidth=Math.max(1,box.clientWidth*.72/(textLength*.62)),maxByHeight=Math.max(1,box.clientHeight*.34); + label.style.setProperty('font-size',px(Math.min(base*size/100,maxByWidth,maxByHeight)),'important'); + label.style.setProperty('line-height','1','important');label.style.setProperty('white-space','nowrap','important'); + } + } + function ensureCageControl(){ + const board=document.querySelector('#board');if(!board?.querySelector('.cage-label'))return; + const dialog=document.querySelector('.np-workspace-dialog');if(!dialog||dialog.querySelector('[data-cage-sum-size]'))return; + const size=[100,125,150,175,200].includes(readCageSize())?readCageSize():100; + const label=document.createElement('label');label.dataset.cageSumSetting='true';label.append('キラー合計の数字サイズ'); + const select=document.createElement('select');select.dataset.cageSumSize='true';select.setAttribute('aria-label','キラー合計の数字サイズ'); + for(const n of [100,125,150,175,200]){const option=document.createElement('option');option.value=String(n);option.textContent=n+'%'+(n===100?'(標準)':'');select.append(option)} + select.value=String(size);select.addEventListener('change',()=>{try{localStorage.setItem('np-killer-sum-size-v1',select.value)}catch{}cageLast='';schedule()}); + label.append(select);const digit=dialog.querySelector('[data-digit-size]')?.closest('label');if(digit?.parentNode)digit.parentNode.insertBefore(label,digit.nextSibling);else dialog.prepend(label); } function schedule(){if(!queued){queued=true;requestAnimationFrame(apply)}} - const watch=()=>{const board=document.querySelector('#board');if(board&&!board.dataset.npDigitFixObserved){board.dataset.npDigitFixObserved='true';new MutationObserver(schedule).observe(board,{attributes:true,attributeFilter:['data-digit-size','class','style'],childList:true,subtree:true})}schedule()}; - new MutationObserver(records=>{if(records.some(r=>r.addedNodes.length||r.removedNodes.length))watch()}).observe(document.getElementById('app')||document.body,{childList:true,subtree:true}); + const watch=()=>{const board=document.querySelector('#board');if(board&&!board.dataset.npDigitFixObserved){board.dataset.npDigitFixObserved='true';new MutationObserver(schedule).observe(board,{attributes:true,attributeFilter:['data-digit-size','class','style'],childList:true,subtree:true})}ensureCageControl();schedule()}; + new MutationObserver(records=>{if(records.some(r=>r.addedNodes.length||r.removedNodes.length)){watch();ensureCageControl()}}).observe(document.getElementById('app')||document.body,{childList:true,subtree:true}); new MutationObserver(schedule).observe(root,{attributes:true,attributeFilter:['data-digit-size']}); - window.addEventListener('resize',schedule);window.addEventListener('orientationchange',schedule);window.addEventListener('storage',e=>{if(e.key==='collection-workspace-v1')schedule()}); + window.addEventListener('resize',()=>{last='';cageLast='';schedule()});window.addEventListener('orientationchange',()=>{last='';cageLast='';schedule()}); + window.addEventListener('storage',e=>{if(e.key==='collection-workspace-v1'||e.key==='np-killer-sum-size-v1'){last='';cageLast='';schedule()}}); watch(); -})(); +})(); \ No newline at end of file From 50ea4e127fd65828118330aa95b804afe50a763c Mon Sep 17 00:00:00 2001 From: atugari Date: Tue, 10 Nov 2026 02:45:19 -0500 Subject: [PATCH 14/15] Fix whitespace parsing in digit sizing helper --- scripts/client-overrides/public/notebook-digit-size.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/client-overrides/public/notebook-digit-size.js b/scripts/client-overrides/public/notebook-digit-size.js index 40ca7772..0def775c 100644 --- a/scripts/client-overrides/public/notebook-digit-size.js +++ b/scripts/client-overrides/public/notebook-digit-size.js @@ -12,7 +12,7 @@ const signature=[scale,workspace,board.dataset.digitSize,board.className,board.clientWidth,board.clientHeight,cell.clientWidth,cell.clientHeight,cells.length,digits.length,contentLength].join('|'); if(signature!==last){last=signature; const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\\s+/).length||9,digitCount=String(board.classList.contains('hundred-board')?100:columns).length; - const limit=Math.max(1,Math.min(cell.clientHeight*(board.querySelector('.cage-label')?.7:.88),cell.clientWidth/(digitCount*.64))); + const limit=Math.max(1,Math.min(cell.clientHeight*(board.querySelector('.cage-label') ? .7 : .88),cell.clientWidth/(digitCount*.64))); for(const span of digits){ if(span.classList.contains('notes')||span.classList.contains('hundred-notes')||span.classList.contains('cage-label')||span.classList.contains('cage-border'))continue; const parentSize=parseFloat(getComputedStyle(span.parentElement).fontSize)||16; From 0948956c63e106df7f4551a3317bd46be8d60e16 Mon Sep 17 00:00:00 2001 From: atugari Date: Tue, 10 Nov 2026 02:45:38 -0500 Subject: [PATCH 15/15] Correct grid column whitespace parsing --- scripts/client-overrides/public/notebook-digit-size.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/client-overrides/public/notebook-digit-size.js b/scripts/client-overrides/public/notebook-digit-size.js index 0def775c..94eb9075 100644 --- a/scripts/client-overrides/public/notebook-digit-size.js +++ b/scripts/client-overrides/public/notebook-digit-size.js @@ -11,7 +11,7 @@ const digits=board.querySelectorAll('.cell>span.np-workspace-digit'),contentLength=Array.from(digits).reduce((n,span)=>n+span.textContent.length,0); const signature=[scale,workspace,board.dataset.digitSize,board.className,board.clientWidth,board.clientHeight,cell.clientWidth,cell.clientHeight,cells.length,digits.length,contentLength].join('|'); if(signature!==last){last=signature; - const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\\s+/).length||9,digitCount=String(board.classList.contains('hundred-board')?100:columns).length; + const columns=getComputedStyle(board).gridTemplateColumns.trim().split(/\s+/).length||9,digitCount=String(board.classList.contains('hundred-board')?100:columns).length; const limit=Math.max(1,Math.min(cell.clientHeight*(board.querySelector('.cage-label') ? .7 : .88),cell.clientWidth/(digitCount*.64))); for(const span of digits){ if(span.classList.contains('notes')||span.classList.contains('hundred-notes')||span.classList.contains('cage-label')||span.classList.contains('cage-border'))continue;