Compare commits

..

5 Commits

Author SHA1 Message Date
codex-bot 34fa403a5d fix(studio): fit default text to production font metrics 2026-11-01 04:44:43 +08:00
Zayden-Jung b76642e06d Merge pull request 'fix(ci): 修复生产浏览器验收的依赖路径' (#35) from codex/fix-acceptance-deps into main
creative workspace CI and deployment / verify-and-deploy (push) Failing after 11m5s
Reviewed-on: #35
2026-10-31 20:20:48 +00:00
codex-bot 2570ea13bd fix(ci): resolve browser acceptance dependencies in workspace
creative workspace review checks / verify (pull_request) Successful in 11m9s
2026-11-01 04:18:44 +08:00
Zayden-Jung d316b0de03 Merge pull request 'fix(ui): 完成啡跃主题与浏览器图标的生产接入' (#34) from codex/brand-ui into main
Endoleap brand checks / verify (push) Successful in 6s
creative workspace CI and deployment / verify-and-deploy (push) Failing after 10m53s
Reviewed-on: #34
2026-10-31 19:38:12 +00:00
Zayden-Jung 861f1b13f6 Merge pull request 'feat(ui): 全站接入啡跃配色、Logo 与浏览器图标' (#33) from codex/brand-ui into main
Endoleap brand checks / verify (push) Successful in 6s
creative workspace CI and deployment / verify-and-deploy (push) Failing after 1m12s
Reviewed-on: #33
2026-10-31 17:48:29 +00:00
3 changed files with 19 additions and 4 deletions
+5 -2
View File
@@ -42,9 +42,12 @@ export function textSize(layout:Layout,slot:Slot,text:string):number {
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);
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)));
// Linux's fallback glyphs extend beyond the nominal vertical line box.
if(slot.direction==='rotated')return Math.min(w*.78,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)));
const fitted=Math.min(h/(lines.length*1.15),w/Math.max(1,...lines.map(length)))*.92;
// Budget for fallback glyph ascent/descent, not just the CSS 1.2 line-height.
// The production Chromium/Noto stack needs about 1.33 em for a visible line.
const fitted=Math.min(h/(lines.length*1.4),w/Math.max(1,...lines.map(length)))*.92;
return /微字|脚注|图注|标签/.test(slot.role)?Math.min(fitted,2.2):fitted;
}
export function imageShape(layout:Layout,slot:Slot):CSSProperties {
+12
View File
@@ -17,3 +17,15 @@ test('geometric templates retain their distinct silhouettes without bitmap masks
});
test('element IDs work on HTTP origins without secure-context randomUUID',()=>{const saved=Object.getOwnPropertyDescriptor(globalThis,'crypto');let calls=0;Object.defineProperty(globalThis,'crypto',{configurable:true,value:{getRandomValues(array){for(let i=0;i<array.length;i++)array[i]=++calls;return array}}});try{const first=newElementId(),second=newElementId();assert.match(first,/^user-[a-f0-9]{32}$/);assert.notEqual(first,second)}finally{Object.defineProperty(globalThis,'crypto',saved)}});
// Measured by ces-control Chromium/Noto in production run 660, at 860px art width.
// These glyph bounds exceed CSS line-height, including single-letter title slots.
test('default copy leaves room for production fallback glyph bounds',()=>{
const cases=[['ref-07','T02',97/73.7143],['ref-08','T01',112/85.2389],['ref-19','T01',287/217.055],['ref-19','T02',298/225.274],['ref-19','T03',313/237.451],['ref-19','T04',306/231.363],['ref-21','T01',195/160.307]];
for(const [id,slotId,glyphExtent] of cases){
const layout=layouts.find(l=>l.id===id),slot=layout.elements.find(s=>s.id===slotId);
const size=textSize(layout,slot,defaultText(layout,slot))*860/layout.width;
const crossAxis=slot.direction==='rotated'?slot.box[2]:slot.box[3];
assert.ok(Math.ceil(size*glyphExtent)<=crossAxis*860/layout.width+2,`${id}/${slotId}: fallback glyphs must fit`);
}
});
+2 -2
View File
@@ -41,11 +41,11 @@ run_api "$RESULT_DIR" verify-studio-library.mjs
docker run --rm --volumes-from prompt-waterfall-wiki-1:ro \
--mount "type=bind,src=$REPO_ROOT,dst=/delivery,readonly" \
--mount "type=bind,src=$RESULT_DIR,dst=/tmp/studio-library" \
-e AUTH_CONFIG_FILE=/auth/config.json -e NODE_PATH=/app/node_modules \
-e AUTH_CONFIG_FILE=/auth/config.json -e NODE_PATH=/repo/apps/waterfall-wiki/node_modules \
--entrypoint node "$TEST_IMAGE" /delivery/scripts/verify-studio-visual.cjs "$MODE"
docker run --rm \
--mount "type=bind,src=$REPO_ROOT,dst=/delivery,readonly" \
--mount "type=bind,src=$RESULT_DIR,dst=/tmp/studio-library" \
-e NODE_PATH=/app/node_modules -e CHROMIUM_PATH=/usr/bin/chromium \
-e NODE_PATH=/repo/apps/waterfall-wiki/node_modules -e CHROMIUM_PATH=/usr/bin/chromium \
-e SCREENSHOT_DIR=/tmp/studio-library/visual \
--entrypoint node "$TEST_IMAGE" /delivery/apps/studio/scripts/infinite-canvas-smoke.cjs