8884e100f9
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>
21 lines
25 KiB
HTML
21 lines
25 KiB
HTML
<!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=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[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> |