Files
cms-SiteForge/examples/Studio_V8_22_画布级可视化编辑器_交互演示.html
T
浅念 8884e100f9 upgrade: adopt V8.31.1 (theme 1.3/1.4 redesigns, editor deep-canvas, guided launch, component library)
Overlay 190 upstream items (V8.22→8.31) preserving trade-pro theme,
registry tests, and design docs. Re-applied full patch set on identical
anchors (discovery/env_for/blocks.css/type-mapping/locale-override/
theme_color/frontend entries/test_theme_pro_v3 mods) plus compose pins.

Verified: theme suites 35/35; dual-baseline full run 415 passed vs
pristine 386+29 ours, FAILED-set diff EMPTY (same 10 Windows env fails).
Live: container 8.31.1-dev.1 healthy, hesupipe 192 entries intact,
trade-pro build 203 pages 0 errors.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-26 09:43:17 +08:00

21 lines
25 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>SiteForge V8.22 · 高级可视化编辑器(交互演示)</title><style>
:root{font-family:Inter,-apple-system,BlinkMacSystemFont,"Microsoft Yahei",sans-serif;color:#2c3a4d;background:#f0f3f7}*{box-sizing:border-box}body{margin:0}.app{height:100vh;display:flex;flex-direction:column}.top{height:67px;flex-shrink:0;background:#fff;display:flex;align-items:center;padding:0 18px;gap:16px;border-bottom:1px solid #e8edf2}.logo{font-weight:900;font-size:21px;color:#e67832}.logo small{font-weight:500;font-size:11px;display:block;color:#8a97a8}.file{font-size:13px;font-weight:750;border-left:1px solid #e6e9ee;padding-left:16px}.file small{display:block;font-size:10px;color:#8793a4;font-weight:400;margin-bottom:2px}.devices{margin:auto;display:flex;gap:3px;padding:4px;border-radius:10px;background:#f3f5f8}.devices button{background:transparent;color:#65748a;border:none;border-radius:7px;padding:9px 14px;font-size:12px;cursor:pointer}.devices button.active{color:#c86425;background:#fff;box-shadow:0 2px 6px #2233}.save-state{color:#b8783e;font-size:12px;min-width:65px}.btn{border:1px solid #dde3eb;background:#fff;border-radius:9px;padding:10px 13px;color:#4c5d72;font-weight:750;cursor:pointer}.btn.orange{color:white;background:#de7636;border-color:#de7636}.top .btn{white-space:nowrap}.body{min-height:0;display:grid;grid-template-columns:260px minmax(0,1fr) 295px;flex:1}.side{background:#fff;min-height:0;overflow-y:auto;padding:17px 13px;border-right:1px solid #e5e9f0}.right{border-right:0;border-left:1px solid #e5e9f0}.eyebrow{font-size:10px;font-weight:800;color:#d57635;letter-spacing:1.5px}.side h2{font-size:17px;margin:4px 0 17px}.picker{width:100%;border:1px solid #dfe5ed;border-radius:8px;padding:10px;color:#455871;background:#f9fafc}.add{width:100%;border:0;border-radius:9px;background:#df7c3e;padding:13px;color:#fff;font-weight:800;cursor:pointer;margin:15px 0 8px}.hint{font-size:11px;color:#9aa6b3;line-height:1.7;margin:3px 0 20px}.label{font-size:12px;font-weight:750;color:#66758c;display:block;margin:12px 3px}.block{width:100%;border:1px solid #e4e9ef;border-radius:9px;display:flex;align-items:center;padding:11px;margin-bottom:7px;background:white;gap:9px;cursor:pointer;text-align:left;color:#42546c}.block.sel{border-color:#e18a52;background:#fff7f0}.block .shape{font-size:20px;color:#df8245;background:#fff4e8;border-radius:7px;padding:5px}.block strong{font-size:12px;display:block}.block small{font-size:10px;color:#99a5b4;display:block;padding-top:3px}.lib[hidden]{display:none}.lib{padding:9px;background:#fff8f2;border:1px solid #f2ddce;border-radius:11px}.lib .btn{width:100%;margin:3px 0;text-align:left;font-size:12px}.stage-area{background:#eef2f6;display:flex;flex-direction:column;min-width:0}.stagebar{height:47px;background:#f8fafc;border-bottom:1px solid #e6eaf1;display:flex;align-items:center;justify-content:space-between;padding:0 20px;color:#647388;font-size:12px}.stage{padding:19px;display:flex;justify-content:center;flex:1;min-height:0;overflow:auto}.device{width:100%;max-width:1100px;box-shadow:0 18px 45px #33455d1d;background:white;border-radius:8px;overflow:hidden;transition:max-width .2s;min-height:650px}.device.tablet{max-width:780px}.device.phone{max-width:390px;border:7px solid #263346;border-radius:18px}.device iframe{border:0;display:block;width:100%;height:100%;min-height:660px}.stagefoot{font-size:11px;color:#9aa7b7;padding:9px 18px}.tabs{display:flex;background:#f3f6fa;padding:4px;border-radius:8px;margin-bottom:16px}.tabs button{flex:1;border:0;background:transparent;padding:8px 4px;cursor:pointer;font-size:12px;color:#69788e;border-radius:7px}.tabs button.active{background:white;color:#d36b2c;font-weight:800;box-shadow:0 1px 5px #2332}.prop{margin-bottom:14px}.prop label{font-size:12px;color:#5f7187;display:block;margin-bottom:7px}.prop input,.prop textarea{width:100%;border:1px solid #dee5ed;border-radius:8px;padding:11px;font:inherit;color:#384b62;font-size:13px}.prop textarea{min-height:85px;resize:vertical}.muted{color:#97a2b1;font-size:11px;line-height:1.7}.notice{background:#fff7ed;color:#a86636;border-radius:10px;padding:13px;font-size:12px;line-height:1.65;margin-top:15px}.mobile-head{display:none}@media(max-width:950px){.body{grid-template-columns:220px minmax(0,1fr)}.right{display:none}.top{gap:8px;padding:0 9px}.file,.save-state{display:none}.top .btn{padding:8px;font-size:11px}.devices button{padding:8px 9px}}@media(max-width:650px){.body{grid-template-columns:minmax(0,1fr)}.side{display:none}.logo{font-size:14px}.logo small{display:none}.stage{padding:6px}.mobile-head{display:block;font-size:11px;color:#bf713e}}
</style></head><body><div class="app"><div class="top"><div class="logo">◆ SiteForge<small>VISUAL STUDIO</small></div><div class="file"><small>我的网站 / 首页</small>页面可视化编辑</div><div class="devices"><button class="active" data-device="desktop">▣ 电脑</button><button data-device="tablet">▤ 平板</button><button data-device="phone">▯ 手机</button></div><span class="save-state" id="status">未保存修改</span><button class="btn" id="undo">↶ 撤销</button><button class="btn" id="save">保存草稿</button><button class="btn orange" id="publish">发布设计</button></div><div class="body"><aside class="side"><div class="eyebrow">01 · 页面内容</div><h2>编辑页面</h2><select class="picker"><option>首页 / Home</option></select><button class="add" id="add">+ 添加内容区块</button><div class="lib" id="lib" hidden><button class="btn" data-type="hero">▣ 大图横幅</button><button class="btn" data-type="features">▦ 优势列表</button><button class="btn" data-type="layout">▥ 双列布局</button><button class="btn" data-type="cta">↗ 联系引导</button></div><p class="hint">直接点击中间画布,在浮动工具栏中拖动、复制、调整或新增区块。</p><span class="label">当前页面内容</span><div id="blocks"></div><div class="notice">演示环境:可以编辑和模拟保存,但不会修改任何真实网站、数据库或线上内容。</div></aside><main class="stage-area"><div class="stagebar"><span>● <b>实时画布</b> / 首页</span><span>点击区块直接编辑 · 拖动列宽</span></div><div class="stage"><div class="device" id="device"><iframe id="preview" title="真实可交互画布" sandbox="allow-scripts"></iframe></div></div><div class="stagefoot">这是本地演示数据 · 改动仅保留在当前打开的演示页面</div></main><aside class="side right"><div class="eyebrow">02 · 编辑属性</div><h2>修改选中的内容</h2><div class="tabs"><button class="active" data-tab="content">内容</button><button data-tab="style">样式</button><button data-tab="responsive">手机/平板</button></div><div id="fields"></div></aside></div></div><script>
const CANVAS_BRIDGE="/* V8.22 trusted, sandboxed studio canvas bridge. No arbitrary user code. */\n(function(){\n 'use strict';\n const source='siteforge-studio-canvas';\n const list=()=>Array.from(document.querySelectorAll('.sf-section[data-block]')).filter(n=>!n.parentElement.closest('.sf-section[data-block]'));\n const send=(action,id,extra={})=>parent.postMessage({source,action,blockId:id,...extra},'*');\n let active='', dragging='',resize=null;\n const all=()=>Array.from(document.querySelectorAll('.sf-section[data-block]'));\n const style=document.createElement('style');\n style.textContent=`\n .sf-section[data-block]{position:relative}\n .sf-section[data-block].sf-canvas-selected{outline:2px solid #ec7c35!important;outline-offset:-2px}\n .sf-section[data-block].sf-canvas-drop{box-shadow:inset 0 4px 0 #ef8741!important}\n .sf-section[data-block]:hover{outline:1px dashed #eb995a;outline-offset:-1px}\n .sf-canvas-toolbar{position:absolute;right:7px;top:5px;z-index:2147480000;display:none;align-items:center;gap:3px;padding:5px;background:#263447;color:#fff;border-radius:9px;box-shadow:0 5px 20px #20304450;font:12px/1.4 system-ui,sans-serif;white-space:nowrap;pointer-events:auto}\n .sf-canvas-selected>.sf-canvas-toolbar,.sf-section[data-block]:hover>.sf-canvas-toolbar,.sf-canvas-toolbar:focus-within{display:flex}\n .sf-canvas-toolbar button{background:transparent;color:inherit;border:0;cursor:pointer;padding:5px 7px;border-radius:5px;font:inherit}\n .sf-canvas-toolbar button:hover,.sf-canvas-toolbar button:focus-visible{background:#52687e;outline:1px solid #fff6}\n .sf-canvas-toolbar .sf-canvas-drag{cursor:grab;background:#496174}\n .sf-canvas-toolbar .sf-canvas-danger:hover{background:#ab4d46}\n .sf-canvas-hint{position:fixed;bottom:12px;left:50%;transform:translateX(-50%);background:#1c293ee8;color:white;padding:9px 13px;border-radius:9px;z-index:2147480000;font:12px system-ui;pointer-events:none}\n .sf-layout-grid{position:relative}\n .sf-canvas-resize{position:absolute;z-index:2147480000;top:4px;bottom:4px;width:12px;transform:translateX(-50%);cursor:col-resize;touch-action:none;opacity:0;display:flex;align-items:center;justify-content:center}\n .sf-canvas-resize:after{content:'⋮';background:#e77632;color:white;box-shadow:0 2px 8px #2225;border-radius:8px;font:20px/26px system-ui;text-align:center;width:19px;min-width:19px}\n .sf-section:hover .sf-canvas-resize,.sf-canvas-resize:focus-visible,.sf-canvas-resize.sf-resizing{opacity:1}\n [contenteditable].sf-canvas-editing{outline:2px dashed #df7435!important;border-radius:3px;cursor:text!important}\n @media(max-width:820px){.sf-canvas-resize{display:none!important}}\n `;\n document.head.appendChild(style);\n const types={title:'h1,h2',description:'.sf-hero-copy p,.sf-image-text p,.sf-cta-wrap p'};\n function activate(id,notify=true){\n active=id||'';for(const el of all())el.classList.toggle('sf-canvas-selected',el.dataset.block===id);\n if(notify&&id)send('select',id);\n }\n const topSections=list();\n for(const block of topSections){\n const id=block.dataset.block;\n const bar=document.createElement('div');bar.className='sf-canvas-toolbar';bar.setAttribute('role','toolbar');bar.setAttribute('aria-label','区块快捷操作');\n const controls=[['↕','拖动区块','drag'],['✎','编辑区块','edit'],['↑','上移区块','up'],['↓','下移区块','down'],['+','在下方添加区块','add-after'],['⧉','复制区块','duplicate'],['×','删除区块','delete']];\n for(const [txt,label,action] of controls){\n const b=document.createElement('button');b.type='button';b.textContent=txt;b.title=label;b.setAttribute('aria-label',label);b.dataset.action=action;\n if(action==='drag'){b.draggable=true;b.className='sf-canvas-drag';b.addEventListener('dragstart',e=>{dragging=id;e.dataTransfer.setData('text/plain',id);e.dataTransfer.effectAllowed='move';e.stopPropagation()});b.addEventListener('dragend',()=>{dragging='';list().forEach(el=>el.classList.remove('sf-canvas-drop'))})}\n else {if(action==='delete')b.className='sf-canvas-danger';b.addEventListener('click',e=>{e.preventDefault();e.stopPropagation();activate(id,false);send(action,id)})}\n bar.appendChild(b);\n }\n block.prepend(bar);\n block.addEventListener('click',event=>{\n if(event.target.closest('.sf-canvas-toolbar,.sf-canvas-resize'))return;\n if(event.target.closest('a'))event.preventDefault();\n activate(id);\n });\n block.addEventListener('dragover',event=>{if(!dragging)return;event.preventDefault();event.stopPropagation();block.classList.add('sf-canvas-drop')});\n block.addEventListener('dragleave',event=>{if(!block.contains(event.relatedTarget))block.classList.remove('sf-canvas-drop')});\n block.addEventListener('drop',event=>{if(!dragging)return;event.preventDefault();event.stopPropagation();block.classList.remove('sf-canvas-drop');if(dragging!==id)send('reorder',dragging,{targetId:id});dragging=''});\n }\n // Rich text is not edited as plain text: modifying sanitized HTML would lose formatting.\n for(const section of topSections){\n const id=section.dataset.block;\n for(const [field,selector] of Object.entries(types)){\n const target=section.querySelector(selector);if(!target||target.closest('.sf-section[data-block]')!==section)continue;\n target.title='双击直接修改'+(field==='title'?'标题':'描述');\n target.addEventListener('dblclick',event=>{\n event.stopPropagation();activate(id);const before=target.textContent;\n target.contentEditable='true';target.classList.add('sf-canvas-editing');target.focus();\n let closed=false;\n const finish=commit=>{\n if(closed)return;closed=true;target.removeAttribute('contenteditable');target.classList.remove('sf-canvas-editing');\n const value=target.textContent.replace(/\\r/g,'').trim();\n if(!commit)target.textContent=before;\n else if(value!==before&&value.length<=500)send('inline-text',id,{field,value});\n else if(value.length>500)target.textContent=before;\n };\n target.addEventListener('blur',()=>finish(true),{once:true});\n target.addEventListener('keydown',e=>{if(e.key==='Escape'){e.preventDefault();finish(false);target.blur()}if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();target.blur()} });\n });\n }\n }\n // Desktop-only handles keep the total adjacent width stable and never free-position blocks.\n for(const grid of document.querySelectorAll('.sf-layout-grid[data-layout]')){\n const id=grid.dataset.layout;\n const cols=Array.from(grid.children).filter(el=>el.classList.contains('sf-layout-column'));\n if(cols.length<2)continue;\n for(let i=0;i<cols.length-1;i++){\n const handle=document.createElement('div');handle.className='sf-canvas-resize';handle.tabIndex=0;handle.setAttribute('role','separator');handle.setAttribute('aria-label',`拖动调整第 ${i+1} 列宽度`);\n const place=()=>{const a=cols[i].getBoundingClientRect(),g=grid.getBoundingClientRect();handle.style.left=(a.right-g.left+parseFloat(getComputedStyle(grid).columnGap||'0')/2)+'px'};\n grid.appendChild(handle);place();\n handle.addEventListener('pointerdown',e=>{\n if(e.button!==0||matchMedia('(max-width:820px)').matches)return;\n e.stopPropagation();e.preventDefault();handle.setPointerCapture(e.pointerId);handle.classList.add('sf-resizing');\n const raw=grid.style.getPropertyValue('--sf-layout-cols').trim().split(/\\s+/).map(x=>parseFloat(x)||1);\n const start=e.clientX,span=Math.max(50,cols[i].getBoundingClientRect().width+cols[i+1].getBoundingClientRect().width);\n resize={id,i,raw,start,span};activate(id);\n });\n handle.addEventListener('pointermove',e=>{\n if(!resize||resize.i!==i)return;\n const v=resize.raw.slice(),total=v[i]+v[i+1];const delta=(e.clientX-resize.start)/resize.span*total;\n v[i]=Math.round(Math.min(4,Math.max(.5,resize.raw[i]+delta))*100)/100;\n v[i+1]=Math.round(Math.min(4,Math.max(.5,total-v[i]))*100)/100;\n if(Math.abs(v[i]+v[i+1]-total)>0.011)return;\n grid.style.setProperty('--sf-layout-cols',v.map(x=>x+'fr').join(' '));place();\n });\n const done=e=>{if(!resize||resize.i!==i)return;const raw=grid.style.getPropertyValue('--sf-layout-cols').trim().split(/\\s+/).map(x=>parseFloat(x)||1);resize=null;handle.classList.remove('sf-resizing');send('resize-columns',id,{widths:raw});};\n handle.addEventListener('pointerup',done);handle.addEventListener('pointercancel',()=>{resize=null;handle.classList.remove('sf-resizing')});\n handle.addEventListener('keydown',e=>{if(e.key!=='ArrowLeft'&&e.key!=='ArrowRight')return;e.preventDefault();const w=grid.style.getPropertyValue('--sf-layout-cols').trim().split(/\\s+/).map(x=>parseFloat(x)||1);const delta=e.key==='ArrowRight'?.1:-.1;const total=w[i]+w[i+1];const first=Math.round(Math.min(4,Math.max(.5,w[i]+delta))*100)/100,second=Math.round((total-first)*100)/100;if(second<.5||second>4)return;w[i]=first;w[i+1]=second;grid.style.setProperty('--sf-layout-cols',w.map(x=>x+'fr').join(' '));place();send('resize-columns',id,{widths:w})});\n new ResizeObserver(place).observe(grid);\n }\n }\n window.addEventListener('message',event=>{\n if(event.source!==parent||event.data?.source!=='siteforge-studio-host')return;\n if(event.data.action==='highlight'&&typeof event.data.blockId==='string')activate(event.data.blockId,false);\n });\n})();\n";
let data=[{id:'b1',type:'hero',title:'连接全球汽车市场',description:'从中国采购,到全球交付。值得信赖的国际汽车贸易伙伴。',columns:null},{id:'b2',type:'features',title:'为什么选择我们',description:'',columns:null},{id:'b3',type:'layout',title:'自由组合布局',description:'',columns:[{width:1},{width:1}]},{id:'b4',type:'cta',title:'准备好开始合作了吗?',description:'联系我们,获取符合您市场需求的采购方案。',columns:null}],selected='b1',insertAfter=null,tab='content',history=[];
const $=s=>document.querySelector(s),esc=s=>String(s??'').replace(/[&<>"']/g,ch=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[ch]));
const id=()=>Math.random().toString(36).slice(2,11);
function snapshot(){history.push(JSON.stringify(data));if(history.length>30)history.shift();$('#status').textContent='未保存修改'}
function section(b){const head='<section class="sf-section" data-block="'+esc(b.id)+'"><div class="sf-container">',end='</div></section>';
if(b.type==='hero')return head+`<div class="hero"><div><p class="kicker">CHINA SOURCING · GLOBAL DELIVERY</p><h1>${esc(b.title)}</h1><p>${esc(b.description)}</p><a href="#">探索全球业务 ↗</a></div><div class="art">🚙</div></div>`+end;
if(b.type==='features')return head+`<div class="center"><small>OUR STRENGTHS</small><h2>${esc(b.title)}</h2></div><div class="cards"><article><b>01</b><h3>专业采购</h3><p>丰富车型供应资源</p></article><article><b>02</b><h3>全球物流</h3><p>多式联运交付保障</p></article><article><b>03</b><h3>海外服务</h3><p>本地化服务协同</p></article></div>`+end;
if(b.type==='layout'){const cols=b.columns.map((c,i)=>`<div class="sf-layout-column"><article class="col-card"><small>模块 ${i+1}</small><h3>${i?'服务与支持':'汽车产品'}</h3><p>在画布上拖动列边界,可以调整两列的占比。</p></article></div>`).join('');return head+`<div class="center"><h2>${esc(b.title)}</h2></div><div class="sf-layout-grid" data-layout="${esc(b.id)}" style="--sf-layout-cols:${b.columns.map(x=>x.width+'fr').join(' ')}">${cols}</div>`+end}
return head+`<div class="cta"><h2>${esc(b.title)}</h2><p>${esc(b.description)}</p><a href="#">联系我们 ↗</a></div>`+end;
}
function render(){const blocks=data.map(section).join('');const css=`<style>*{box-sizing:border-box}body{margin:0;color:#2e3f54;font:15px/1.6 Arial,'Microsoft Yahei',sans-serif}a{display:inline-block;background:#ed843f;border-radius:7px;color:#fff;text-decoration:none;padding:12px 18px;margin-top:8px;font-weight:bold}.site-nav{display:flex;justify-content:space-between;padding:18px 27px;border-bottom:1px solid #ebedf0}.site-nav strong{color:#df7e3f;font-size:18px}.site-nav span{color:#8795a4;font-size:12px}.sf-section{padding:62px 16px;background:white}.sf-section:nth-child(odd){background:#f8fafc}.sf-container{max-width:1050px;margin:auto}.hero{display:grid;grid-template-columns:1fr .8fr;gap:30px;align-items:center;min-height:300px}.kicker,.center small{color:#e27d38;font-weight:bold;font-size:11px;letter-spacing:2px}.hero h1{font-size:40px;line-height:1.2;margin:15px 0}.hero p{color:#617186}.art{display:grid;place-items:center;font-size:115px;background:linear-gradient(135deg,#fff2e4,#f3f7ff);height:280px;border-radius:22px}.center{text-align:center;margin-bottom:25px}.center h2{font-size:28px}.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}.cards article,.col-card{background:#fff;border:1px solid #e7edf3;border-radius:12px;padding:25px}.cards b{color:#eb833b}.cards p,.col-card p{color:#728297}.sf-layout-grid{display:grid;grid-template-columns:var(--sf-layout-cols);gap:16px;position:relative}.sf-layout-column{min-width:0}.col-card{background:#f7f8fb;min-height:190px}.col-card small{color:#e18447}.cta{text-align:center;background:#263b55;padding:60px 15px;border-radius:16px;color:white}.cta p{color:#c4d3e5}footer{text-align:center;padding:35px;font-size:12px;color:#9aa9b7}@media(max-width:800px){.hero{grid-template-columns:1fr}.art{height:170px;font-size:70px}.sf-section{padding:35px 18px}.cards{grid-template-columns:1fr}.sf-layout-grid{grid-template-columns:1fr!important}.hero h1{font-size:26px}.site-nav span{display:none}}</style>`;const content='<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">'+css+'</head><body><div class="site-nav"><strong>HESU AUTO</strong><span>HOME  PRODUCTS  ABOUT  CONTACT</span></div>'+blocks+'<footer>CHINA SOURCING. GLOBAL DELIVERY.</footer><scr'+'ipt>'+CANVAS_BRIDGE+'</scr'+'ipt></body></html>';
$('#preview').onload=()=>$('#preview').contentWindow.postMessage({source:'siteforge-studio-host',action:'highlight',blockId:selected},'*');$('#preview').srcdoc=content;list();fields();}
function list(){$('#blocks').innerHTML=data.map((b,i)=>`<button class="block ${b.id===selected?'sel':''}" data-select="${esc(b.id)}"><span class="shape">${({hero:'▣',features:'▦',layout:'▥',cta:'↗'})[b.type]}</span><span><strong>${esc(b.title||b.type)}</strong><small>${i+1} · 点击选中</small></span></button>`).join('');document.querySelectorAll('[data-select]').forEach(b=>b.onclick=()=>{selected=b.dataset.select;render();});}
function fields(){const b=data.find(x=>x.id===selected);$('#fields').innerHTML= !b?'<p class="muted">点击中间画布中的区块开始。</p>':(tab==='content'?`<div class="prop"><label>标题</label><input id="title" value="${esc(b.title)}"></div><div class="prop"><label>内容描述</label><textarea id="desc">${esc(b.description)}</textarea></div><p class="muted">还可以在画布上双击标题直接编辑。</p>`:tab==='style'?'<p class="muted">本次重点演示布局交互。正式项目可通过属性面板调整颜色和间距。</p>':`<p class="muted">使用顶部设备按钮查看电脑 / 平板 / 手机效果。手机布局独立自适应;桌面列宽通过拖动调整。</p>`);const a=$('#title'),binput=$('#desc');if(a)a.onchange=()=>{snapshot();b.title=a.value;render()};if(binput)binput.onchange=()=>{snapshot();b.description=binput.value;render()};}
window.addEventListener('message',e=>{if(e.source!==$('#preview').contentWindow||e.data?.source!=='siteforge-studio-canvas')return;const m=e.data,i=data.findIndex(b=>b.id===m.blockId);if(i<0)return;const b=data[i];selected=b.id;switch(m.action){case 'select':case 'edit':list();fields();return;case 'up':if(i===0)return;snapshot();[data[i-1],data[i]]=[data[i],data[i-1]];break;case 'down':if(i===data.length-1)return;snapshot();[data[i+1],data[i]]=[data[i],data[i+1]];break;case 'duplicate':snapshot();data.splice(i+1,0,{...structuredClone(b),id:id()});break;case 'delete':if(!confirm('删除该区块?'))return;snapshot();data.splice(i,1);selected=data[Math.max(0,i-1)]?.id||null;break;case 'add-after':insertAfter=b.id;$('#lib').hidden=false;$('#status').textContent='选一种区块插入';list();fields();return;case 'reorder':{const target=data.findIndex(x=>x.id===m.targetId);if(target<0||target===i)return;snapshot();data.splice(target,0,data.splice(i,1)[0]);break;}case 'resize-columns':if(b.type!=='layout'||!Array.isArray(m.widths)||m.widths.length!==b.columns.length||m.widths.some(x=>!Number.isFinite(x)||x<.5||x>4))return;snapshot();b.columns.forEach((x,i)=>x.width=m.widths[i]);break;case 'inline-text':if(!['title','description'].includes(m.field)||typeof m.value!=='string'||m.value.length>500)return;snapshot();b[m.field]=m.value;break;default:return;}render();});
$('#add').onclick=()=>$('#lib').hidden=!$('#lib').hidden;document.querySelectorAll('[data-type]').forEach(btn=>btn.onclick=()=>{snapshot();const type=btn.dataset.type;const b={id:id(),type,title:({hero:'新的横幅',features:'新的优势列表',layout:'新的双列布局',cta:'新的联系区块'})[type],description:'点击修改这里的文字',columns:type==='layout'?[{width:1},{width:1}]:null};const ix=data.findIndex(x=>x.id===insertAfter);data.splice(ix<0?data.length:ix+1,0,b);insertAfter=null;selected=b.id;$('#lib').hidden=true;render();});document.querySelectorAll('[data-device]').forEach(b=>b.onclick=()=>{document.querySelectorAll('[data-device]').forEach(x=>x.classList.remove('active'));b.classList.add('active');$('#device').className='device '+(b.dataset.device==='desktop'?'':b.dataset.device)});document.querySelectorAll('[data-tab]').forEach(b=>b.onclick=()=>{tab=b.dataset.tab;document.querySelectorAll('[data-tab]').forEach(x=>x.classList.toggle('active',x===b));fields()});$('#save').onclick=()=>$('#status').textContent='演示草稿已保存';$('#publish').onclick=()=>alert('这是操作演示,不会发布到任何真实网站。正式流程:保存草稿 → 发布设计到内容库 → 静态构建 → 审批部署。');$('#undo').onclick=()=>{if(!history.length)return;data=JSON.parse(history.pop());selected=data[0]?.id;render();$('#status').textContent='已撤销';};render();
</script></body></html>