import React from 'react'; import type {CSSProperties} from 'react'; type Part={id:string;kind:string;role:string;box:number[];asset:string;text?:string|null;direction?:string;mask?:string;underlay?:string}; export type Layout={id:string;width:number;height:number;background:string;elements:Part[]}; // The manifest is copied from the post's JSON block. This file is consumer code, not a Wiki route. export function LayoutPoster({id,layout,text={},images={},assetBase=''}:{id:string;layout:Layout;text?:Record;images?:Record;assetBase?:string}){ if(layout.id!==id)throw Error('版面 ID 不一致'); for(const[kind,values]of [['text',text],['image',images]] as const)for(const key of Object.keys(values))if(!layout.elements.some(e=>key===id+'/'+e.id&&kind===e.kind))throw Error('构件类型或所属版面不一致:'+key); const src=(url:string)=>url.startsWith('/')?assetBase+url:url; return
{layout.elements.map(e=>{ const[x,y,w,h]=e.box,key=id+'/'+e.id,position:CSSProperties={position:'absolute',left:x/layout.width*100+'%',top:y/layout.height*100+'%',width:w/layout.width*100+'%',height:h/layout.height*100+'%',zIndex:e.kind==='text'?3:e.kind==='decoration'?2:1}; if(e.kind==='text'&&Object.hasOwn(text,key)){ if(e.direction==='curved')throw Error('弧形文字须使用本设计专用 SVG 路径,不能直接改成直排'); const vertical=e.direction==='vertical'||e.direction==='rotated',lines=text[key].split('\n'),units=Math.max(1,...lines.map(line=>Array.from(line).reduce((n,c)=>n+(/[\u3400-\u9fff]/.test(c)?1:.56),0))),size=vertical?Math.min(w,h/Math.max(1,text[key].length)):Math.min(h/(lines.length*1.1),w/units); return {e.underlay&&}{text[key]}; } return {e.kind==='text'?e.text||e.role+'(未辨识原字形)':''}; })}
; }