Reserve serif glyph width inside vertical title slots
studio CI and deployment / verify-and-deploy (pull_request) Successful in 7m16s

This commit is contained in:
2026-10-28 18:33:43 +08:00
parent c6037664e1
commit 2e5fa40c19
2 changed files with 5 additions and 2 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ export function slotPosition(layout:Layout,slot:Slot):CSSProperties {
export function textSize(layout:Layout,slot:Slot,text:string):number { export function textSize(layout:Layout,slot:Slot,text:string):number {
const [, ,w,h]=slot.box,lines=text.split('\n'); const [, ,w,h]=slot.box,lines=text.split('\n');
const length=(s:string)=>Array.from(s).reduce((n,c)=>n+(/[\u3400-\u9fff]/.test(c)?1:/[A-Z]/.test(c)?.8:.6),0); const length=(s:string)=>Array.from(s).reduce((n,c)=>n+(/[\u3400-\u9fff]/.test(c)?1:/[A-Z]/.test(c)?.8:.6),0);
if(slot.direction==='vertical')return Math.min(w*.9,h/Math.max(1,Array.from(text.replaceAll('\n','')).length)*.88); if(slot.direction==='vertical')return Math.min(w*.75,h/Math.max(1,Array.from(text.replaceAll('\n','')).length)*.88);
if(slot.direction==='rotated')return Math.min(w*.85,h/Math.max(1,length(text))); if(slot.direction==='rotated')return Math.min(w*.85,h/Math.max(1,length(text)));
if(slot.direction==='curved')return Math.min(2.2,Math.max(w,h)*1.1/Math.max(1,length(text))); if(slot.direction==='curved')return Math.min(2.2,Math.max(w,h)*1.1/Math.max(1,length(text)));
const fitted=Math.min(h/(lines.length*1.15),w/Math.max(1,...lines.map(length)))*.92; const fitted=Math.min(h/(lines.length*1.15),w/Math.max(1,...lines.map(length)))*.92;
+4 -1
View File
@@ -17,7 +17,10 @@ const assert=require('node:assert/strict');
const metrics=process.argv.includes('--after-layouts')?JSON.parse(await readFile(dir+'/metrics.json','utf8')).metrics:[]; const metrics=process.argv.includes('--after-layouts')?JSON.parse(await readFile(dir+'/metrics.json','utf8')).metrics:[];
for(let i=1;i<=27&&!process.argv.includes('--after-layouts');i++){ for(let i=1;i<=27&&!process.argv.includes('--after-layouts');i++){
const id='ref-'+String(i).padStart(2,'0');await page.goto(base+'/studio/layouts/'+id,{waitUntil:'networkidle'});await page.locator('article.native-layout').screenshot({path:dir+'/'+id+'.png',style:'.page-tools{visibility:hidden}'}); const id='ref-'+String(i).padStart(2,'0');await page.goto(base+'/studio/layouts/'+id,{waitUntil:'networkidle'});await page.locator('article.native-layout').screenshot({path:dir+'/'+id+'.png',style:'.page-tools{visibility:hidden}'});
const m=await page.locator('article.native-layout').evaluate(el=>({id:el.dataset.layoutId,elements:el.querySelectorAll('[data-element]').length,width:el.clientWidth,height:el.clientHeight,overflow:[...el.querySelectorAll('.native-copy')].filter(e=>e.scrollHeight>e.clientHeight+2||e.scrollWidth>e.clientWidth+2).map(e=>e.closest('[data-element]').dataset.element)}));metrics.push(m);await writeFile(dir+'/metrics.json',JSON.stringify({metrics,images,errors},null,2)); const m=await page.locator('article.native-layout').evaluate(el=>{
const overflow=[...el.querySelectorAll('.native-copy')].filter(e=>e.scrollHeight>e.clientHeight+2||e.scrollWidth>e.clientWidth+2);
return {id:el.dataset.layoutId,elements:el.querySelectorAll('[data-element]').length,width:el.clientWidth,height:el.clientHeight,overflow:overflow.map(e=>e.closest('[data-element]').dataset.element),overflowDetails:overflow.map(e=>{const style=getComputedStyle(e);return {id:e.closest('[data-element]').dataset.element,text:e.textContent,clientWidth:e.clientWidth,scrollWidth:e.scrollWidth,clientHeight:e.clientHeight,scrollHeight:e.scrollHeight,fontSize:style.fontSize,lineHeight:style.lineHeight,letterSpacing:style.letterSpacing,fontFamily:style.fontFamily,fontWeight:style.fontWeight,writingMode:style.writingMode}})};
});metrics.push(m);await writeFile(dir+'/metrics.json',JSON.stringify({metrics,images,errors},null,2));
} }
if(!process.argv.includes('--after-layouts')&&!process.argv.includes('--diagnose'))assert.deepEqual(metrics.filter(m=>m.overflow.length),[],'Default copy must fit every native slot'); if(!process.argv.includes('--after-layouts')&&!process.argv.includes('--diagnose'))assert.deepEqual(metrics.filter(m=>m.overflow.length),[],'Default copy must fit every native slot');
await page.goto(base+'/studio',{waitUntil:'networkidle'});assert.equal(await page.locator('.library-item').count(),27);await page.screenshot({path:dir+'/catalog-desktop.png',fullPage:true}); await page.goto(base+'/studio',{waitUntil:'networkidle'});assert.equal(await page.locator('.library-item').count(),27);await page.screenshot({path:dir+'/catalog-desktop.png',fullPage:true});