feat: component system v1.0 - paintbrush toolkit
- components/registry.js: 8 components (canvas,card,decor,badge,title,pills,toolCards,bigText) - components/render.js: component renderer - External AI: learn HLDP -> read registry -> pick components -> POST /api/compose - Demo: 0-yuan cover generated via module API
This commit is contained in:
parent
5d1527a38e
commit
93c795bf21
14
components/registry.js
Normal file
14
components/registry.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// 封面组件注册表 v1.0 · 外部AI的菜单
|
||||||
|
// 读 HLDP-SPEC-v2.0.md → 读本文件 → 选组件 → 组合 → POST /api/compose
|
||||||
|
// 国作登字-2026-A-00037559
|
||||||
|
|
||||||
|
export const COMPONENTS = [
|
||||||
|
{ id:"canvas", name:"画布", desc:"底板,宽高底色", params:{ width:{type:"number",default:1080}, height:{type:"number",default:1440}, bg:{type:"color",default:"#FDF8F3"} } },
|
||||||
|
{ id:"card", name:"卡片容器", desc:"白色圆角大卡片", params:{ radius:{type:"number",default:60}, padding:{type:"string",default:"60px 70px 50px"}, shadow:{type:"boolean",default:true} } },
|
||||||
|
{ id:"decor", name:"装饰圆", desc:"半透明渐变圆点缀角落", params:{ side:{type:"enum",values:["top-right","bottom-left","both"],default:"both"}, color:{type:"enum",values:["orange","blue"],default:"orange"} } },
|
||||||
|
{ id:"badge", name:"标签徽章", desc:"顶行小标签", params:{ text:{type:"string",required:true}, style:{type:"enum",values:["accent","normal"],default:"accent"} } },
|
||||||
|
{ id:"title", name:"大标题", desc:"多行多色标题", params:{ lines:{type:"array",required:true,desc:"每行文字"}, colors:{type:"array",desc:"dark/green/orange"}, size:{type:"number",default:68} } },
|
||||||
|
{ id:"pills", name:"标签组", desc:"一排药丸标签", params:{ items:{type:"array",required:true}, zeros:{type:"array",desc:"强调项索引"} } },
|
||||||
|
{ id:"toolCards", name:"工具卡片组", desc:"一排工具卡(图标+名+描述+价格)", params:{ items:{type:"array",required:true,desc:"[[emoji,name,desc,price],...]"} } },
|
||||||
|
{ id:"bigText", name:"大字强调区", desc:"底部渐变强调区", params:{ main:{type:"string",required:true}, sub:{type:"string"} } }
|
||||||
|
]
|
||||||
33
components/render.js
Normal file
33
components/render.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
const FONT = "'Noto Sans CJK SC','WenQuanYi Micro Hei',sans-serif"
|
||||||
|
export function renderComponents(config) {
|
||||||
|
const { canvas:cv={}, stack=[] } = config
|
||||||
|
const W=cv.width||1080, H=cv.height||1440, bg=cv.bg||'#FDF8F3'
|
||||||
|
let css=`*{margin:0;padding:0;box-sizing:border-box}body{width:${W}px;height:${H}px;overflow:hidden;font-family:${FONT};background:${bg};display:flex;justify-content:center;align-items:center}`
|
||||||
|
css+=`.card{border-radius:60px;box-shadow:0 20px 80px rgba(0,0,0,.06);background:#fff;display:flex;flex-direction:column;width:960px;height:1320px;padding:60px 70px 50px;position:relative}`
|
||||||
|
css+=`.deco{position:absolute;border-radius:50%}.deco-tr{top:-100px;right:-80px;width:320px;height:320px;background:radial-gradient(circle,rgba(224,123,57,.08),transparent 70%)}.deco-bl{bottom:200px;left:-60px;width:180px;height:180px;background:radial-gradient(circle,rgba(74,144,164,.06),transparent 70%)}`
|
||||||
|
css+=`.badge{display:inline-flex;padding:10px 24px;border-radius:24px;font-size:20px;font-weight:800}.badge-a{background:rgba(224,123,57,.12);color:#2D5016;border:2px solid rgba(224,123,57,.25)}.badge-n{background:#FDF8F3;color:#2D5016;border:2px solid rgba(224,123,57,.12)}`
|
||||||
|
css+=`.th1{font-size:68px;font-weight:900;line-height:1.15;letter-spacing:2px;margin-bottom:16px}.tl{display:block}.td{color:#1A1A1A}.tg{color:#2D5016}.to{color:#E07B39}`
|
||||||
|
css+=`.pw{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:40px}.pi{display:inline-block;padding:8px 20px;border-radius:24px;font-size:20px;font-weight:700}.pz{background:#2D5016;color:#fff;font-size:24px}.pn{background:rgba(224,123,57,.08);color:#E07B39}`
|
||||||
|
css+=`.tg{display:flex;gap:16px;margin-bottom:24px}.tc{flex:1;background:#FDF8F3;border-radius:20px;padding:24px 16px;text-align:center}.tci{font-size:36px;margin-bottom:10px}.tcn{font-size:18px;font-weight:700;color:#1A1A1A;margin-bottom:4px}.tcd{font-size:14px;color:#8B8680;margin-top:4px}.tcp{font-size:22px;font-weight:900;color:#E07B39;margin-top:8px}`
|
||||||
|
css+=`.bs{text-align:center;padding:28px;background:linear-gradient(135deg,rgba(224,123,57,.06),rgba(45,80,22,.06));border-radius:24px;margin-top:auto}.bm{font-size:56px;font-weight:900;color:#E07B39;line-height:1}.bsb{font-size:18px;color:#8B8680;margin-top:8px}`
|
||||||
|
css+=`.tr{display:flex;gap:12px;margin-bottom:30px;align-items:center}`
|
||||||
|
|
||||||
|
let body='',inCard=false
|
||||||
|
for(const c of stack){
|
||||||
|
const p=c.params||{}
|
||||||
|
switch(c.component){
|
||||||
|
case'card':body+='<div class="card">';inCard=true;break
|
||||||
|
case'decor':
|
||||||
|
if(p.side==='top-right'||p.side==='both')body+='<div class="deco deco-tr"></div>'
|
||||||
|
if(p.side==='bottom-left'||p.side==='both')body+='<div class="deco deco-bl"></div>';break
|
||||||
|
case'badge':body+=`<span class="badge badge-${p.style==='normal'?'n':'a'}">${p.text||''}</span>`;break
|
||||||
|
case'topRow':body+='<div class="tr">';break
|
||||||
|
case'title':{const l=p.lines||[],co=p.colors||l.map(()=>'d');body+='<div class="th1">';l.forEach((x,i)=>body+=`<span class="tl t${co[i]||'d'}">${x}</span>`);body+='</div>';break}
|
||||||
|
case'pills':{const it=p.items||[],zz=p.zeros||[];body+='<div class="pw">';it.forEach((t,i)=>body+=`<span class="pi ${zz.includes(i)?'pz':'pn'}">${t}</span>`);body+='</div>';break}
|
||||||
|
case'toolCards':{const tc=p.items||[];body+='<div class="tg">';tc.forEach(t=>body+=`<div class="tc"><div class="tci">${t[0]||''}</div><div class="tcn">${t[1]||''}</div><div class="tcd">${t[2]||''}</div><div class="tcp">${t[3]||''}</div></div>`);body+='</div>';break}
|
||||||
|
case'bigText':body+=`<div class="bs"><div class="bm">${p.main||''}</div>`;if(p.sub)body+=`<div class="bsb">${p.sub}</div>`;body+='</div>';break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(inCard)body+='</div>'
|
||||||
|
return`<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><style>${css}</style></head><body>${body}</body></html>`
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user