diff --git a/apps/studio/src/components/Ref17Cover.tsx b/apps/studio/src/components/Ref17Cover.tsx new file mode 100644 index 0000000..5f88822 --- /dev/null +++ b/apps/studio/src/components/Ref17Cover.tsx @@ -0,0 +1,33 @@ +import type {Idea,Slide} from '../content/ideas'; +type Template=NonNullable; +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 + {slide.label||slide.heading} · 模板试版源自 ref-17 的九个固定构件。图片位使用色块,占位文案可替换,暂无具体工具内容。 + + + + + + + + {first} + {second} + + {slide.heading} + + {slide.kicker||'TEMPLATE / XX'} + {body.map((line,i)=>{line})} + CONTENTPLACEHOLDER + + {guides&&} + ; +} diff --git a/apps/studio/src/components/TemplateTrial.tsx b/apps/studio/src/components/TemplateTrial.tsx new file mode 100644 index 0000000..5a3e4ee --- /dev/null +++ b/apps/studio/src/components/TemplateTrial.tsx @@ -0,0 +1,29 @@ +import {useState} from 'react'; +import Head from 'next/head'; +import Link from 'next/link'; +import {ideaMarkdown,type Idea,type Slide} from '../content/ideas'; +import {Ref17Cover} from './Ref17Cover'; +export function TemplateTrial({idea}:{idea:Idea}){ + const template=idea.template!; + const [slides,setSlides]=useState(idea.slides),[active,setActive]=useState(0),[masthead,setMasthead]=useState(template.masthead),[guides,setGuides]=useState(false),[notice,setNotice]=useState(''); + const selected=slides[active],current={...idea,slides,template:{...template,masthead}}; + const update=(patch:Partial)=>setSlides(old=>old.map((slide,i)=>i===active?{...slide,...patch}:slide)); + const download=(text:string,type:string,name:string)=>{const url=URL.createObjectURL(new Blob([text],{type})),a=document.createElement('a');a.href=url;a.download=name;a.click();setTimeout(()=>URL.revokeObjectURL(url),500)}; + async function exportSvg(){await document.fonts.ready;const svg=document.querySelector(`[data-proof="${selected.key}"] svg`);if(!svg)return;download(new XMLSerializer().serializeToString(svg),'image/svg+xml',`ref-17-${selected.key}.svg`);setNotice('已下载当前封面 SVG,可继续编辑文字与图形。')} + const reset=()=>{setSlides(idea.slides);setMasthead(template.masthead);setGuides(false);setNotice('已恢复初始试版。')}; + return
{idea.title} · Studio +
← 我的创作STUDIO / TEMPLATE PROOF排版教程 ↗
+
REF-17 · 同一母版 / 四张试版

先试封面,再填内容。

英文刊头、圆形叠标、左下主图与右侧窄栏保持同一套坐标。三组合集先用主题占位,暂不放入具体 Skills。

01 母版02 笔记复习03 教学资料04 英语学习
+