34 lines
3.7 KiB
TypeScript
34 lines
3.7 KiB
TypeScript
import type {Idea,Slide} from '../content/ideas';
|
||
type Template=NonNullable<Idea['template']>;
|
||
export function Ref17Cover({template,slide,masthead=template.masthead,guides=false}:{template:Template;slide:Slide;masthead?:string[];guides?:boolean}){
|
||
const scale=10,W=template.width*scale,H=template.height*scale;
|
||
const slot=(id:string)=>{const s=template.slots.find(s=>s.id===id);if(!s)throw Error('Missing source slot '+id);return s.box.map(v=>v*scale)};
|
||
const [mx,my,mw,mh]=slot('I01'),[cx,cy,cw,ch]=slot('I02'),[dx,dy,dw,dh]=slot('D02'),[bx,by,bw,bh]=slot('D03'),[lx,ly,lw,lh]=slot('D01');
|
||
const [aX,aY,aW,aH]=slot('T01'),[bX,bY,bW,bH]=slot('T02'),[tX,tY,tW,tH]=slot('T03'),[sX,sY,sW,sH]=slot('T04');
|
||
const first=masthead[0]||'STUDY',second=masthead[1]||'Skills',body=slide.body.split('\n').slice(0,3);
|
||
const font1=Math.min(aH*1.2,aW/Math.max(1,first.length*.72)),font2=Math.min(bH,bW/Math.max(1,second.length*.59));
|
||
const titleSize=Math.min(tH*.72,tW/Math.max(1,Array.from(slide.heading).length*1.06));
|
||
const bodySize=Math.min(32,...body.map(s=>sW/Math.max(1,Array.from(s).reduce((n,c)=>n+(/[\u3400-\u9fff]/.test(c)?1:.5),0))));
|
||
const accent=slide.accent||'#d8ddd4';
|
||
return <svg xmlns="http://www.w3.org/2000/svg" viewBox={`0 0 ${W} ${H}`} width={W} height={H} role="img" aria-label={`${slide.label||slide.heading},ref-17 模板封面试版`} data-layout-id={template.id} style={{display:'block',width:'100%',height:'auto'}}>
|
||
<title>{(slide.label||slide.heading)+' · 模板试版'}</title><desc>源自 ref-17 的九个固定构件。图片位使用色块,占位文案可替换,暂无具体工具内容。</desc>
|
||
<rect width={W} height={H} fill={template.paper}/>
|
||
<g data-slot="I01"><rect x={mx} y={my} width={mw} height={mh} fill={slide.color}/></g>
|
||
<g data-slot="I02"><ellipse cx={cx+cw/2} cy={cy+ch/2} rx={cw/2} ry={ch/2} fill={accent}/></g>
|
||
<g data-slot="D02" fill="none" stroke={template.ink} strokeWidth="2" opacity=".75"><rect x={dx+1} y={dy+9} width={dw-2} height={dh-18} rx={(dh-18)/2}/><path d={`M${dx+19} ${dy+dh/2}H${dx+dw-19}`}/></g>
|
||
<g data-slot="D01"><path d={`M${lx} ${ly+lh/2}H${lx+lw}`} stroke={template.ink} strokeWidth="2"/></g>
|
||
<g data-slot="D03"><rect x={bx} y={by} width={bw} height={bh} fill={accent}/></g>
|
||
<g fill={template.ink} fontFamily="Georgia, 'Times New Roman', serif" fontWeight="400">
|
||
<text data-slot="T01" x={aX} y={aY+aH*.9} fontSize={font1} letterSpacing={-font1*.035}>{first}</text>
|
||
<text data-slot="T02" x={bX} y={bY+bH*.76} fontSize={font2} letterSpacing={-font2*.045}>{second}</text>
|
||
</g>
|
||
<text data-slot="T03" x={tX} y={tY+tH*.8} fill={template.ink} fontFamily="'PingFang SC', 'Microsoft YaHei', sans-serif" fontWeight="600" fontSize={titleSize} letterSpacing={-titleSize*.025}>{slide.heading}</text>
|
||
<g data-slot="T04" fill={template.ink} fontFamily="Arial, 'PingFang SC', sans-serif">
|
||
<text x={sX} y={sY+32} fontSize="22" letterSpacing="2">{slide.kicker||'TEMPLATE / XX'}</text>
|
||
{body.map((line,i)=><text key={i} x={sX} y={sY+135+i*58} fontSize={bodySize}>{line}</text>)}
|
||
<text x={sX} y={sY+sH-62} fontSize="19" letterSpacing="1">CONTENT</text><text x={sX} y={sY+sH-26} fontSize="19" letterSpacing="1">PLACEHOLDER</text>
|
||
</g>
|
||
{guides&&<g aria-hidden="true" fontFamily="Arial,sans-serif">{template.slots.map(s=>{const[x,y,w,h]=s.box.map(v=>v*scale),color=({text:'#2c64d8',image:'#d36b30',decoration:'#08875d'} as Record<string,string>)[s.kind]||'#666';return <g key={s.id}><rect x={x} y={y} width={w} height={h} fill={color} fillOpacity=".04" stroke={color} strokeWidth="2" strokeDasharray="8 5"/><rect x={x} y={y} width="66" height="29" fill={color}/><text x={x+6} y={y+22} fontSize="24" fill="white">{s.id}</text></g>})}</g>}
|
||
</svg>;
|
||
}
|