Files
cms-SiteForge/examples/Studio_V8_21_1_交互预览.html
T
浅念 601451f22b upgrade: adopt V8.21.3 (V8.13→8.21.3: P5 SFTP/S3, P6 multilingual, editor overhaul, enterprise hardening)
Overlay ~150 upstream items onto our V8.12 base, preserving trade-pro
theme, registry tests, and design docs. Re-applied our patch set
(discovery/env_for/blocks.css/type-mapping/theme_color/frontend entries,
test_theme_pro_v3 mods) — all anchors survived upstream evolution.

New platform enhancement (fixes upgrade-introduced regression):
multilingual.site_locale now honors settings_json.locale, plus
PUT /api/i18n/sites/{id}/locale — standalone English sites get
<html lang='en'> under the V8.15 locale-rewrite pipeline.

compose: adopt V8.21.3 (image 8.21.3-dev.1, /api/ready probes, MySQL/S3
env) with project name pinned to siteforge-v8-10 (data volumes).

Tests: 356 passed / 11 failed — all 11 confirmed pre-existing in
pristine V8.21.3 on this host (10 upstream Windows env + our build test
now green after locale fix). Patch registry updated in plan doc.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-23 12:31:03 +08:00

14 lines
12 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 Studio UX · 离线演示</title>
<style>
*{box-sizing:border-box}body{margin:0;font:13px 'Segoe UI','Microsoft YaHei',Arial,sans-serif;color:#344255;background:#edf1f5}button,input{font:inherit}button{cursor:pointer}.top{height:68px;background:white;border-bottom:1px solid #e1e5ec;display:flex;align-items:center;gap:13px;padding:0 18px}.logo{font-weight:800;font-size:18px;color:#dc762d}.tag{font-size:11px;background:#f8f1e8;padding:6px 9px;border-radius:8px;color:#af662b}.page{font-weight:700}.sp{flex:1}.btn{padding:10px 12px;border-radius:8px;border:1px solid #e2e7ed;background:#fff;color:#465973}.btn.primary{background:#dc702e;color:#fff;border-color:#dc702e}.btn.active{background:#fdf1e8;border-color:#efc19c;color:#a65425}.layout{display:grid;grid-template-columns:270px minmax(0,1fr) 320px;height:calc(100vh - 68px);min-height:650px}.pane{background:#fff;overflow:auto}.left{border-right:1px solid #e2e8f0}.right{border-left:1px solid #e2e8f0}.panehead{display:flex;align-items:center;justify-content:space-between;padding:23px 20px 10px}.panehead b{font-size:16px}.muted{color:#8a98a9;font-size:11px}.field{padding:9px 16px}.field label{display:block;font-size:11px;font-weight:700;color:#69798d;margin:0 0 7px}.field select,.field input{width:100%;border:1px solid #dce3ec;border-radius:8px;padding:10px;background:#fff}.sec{padding:20px 17px 12px;font-weight:750;font-size:11px;color:#77879a}.search{margin:0 15px 12px;width:calc(100% - 30px);padding:11px;border:1px solid #dde6ed;border-radius:8px;background:#f7f9fb;outline-color:#e9a979}.list{padding:0 12px}.item{display:flex;gap:8px;align-items:center;border:1px solid #e6ebf1;padding:10px 8px;border-radius:9px;margin-bottom:7px;cursor:pointer}.item.active{background:#fff6ed;border-color:#efa56e}.item.hidden{opacity:.48}.symbol{width:29px;height:29px;display:grid;place-items:center;background:#fff0e1;border-radius:8px;color:#c46f31}.iteminfo{flex:1;min-width:0}.iteminfo b,.iteminfo small{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.iteminfo small{color:#8d9bab;margin-top:4px;font-size:10px}.act{border:0;background:none;color:#9ba7b7;padding:3px}.add{padding:0 15px 24px;display:grid;grid-template-columns:1fr 1fr;gap:8px}.add button{padding:12px 8px;border:1px dashed #d3dce5;background:#fcfdff;border-radius:8px;text-align:left;color:#64748b}.preview{display:flex;flex-direction:column;min-width:0}.previewbar{height:46px;display:flex;align-items:center;gap:9px;padding:0 16px;color:#7a899d;font-size:11px}.dot{width:8px;height:8px;background:#3ab28a;border-radius:50%}.stage{flex:1;min-height:0;overflow:auto;padding:22px 15px;display:flex;justify-content:center;align-items:flex-start;background:radial-gradient(#dbe3eb 1px,transparent 1px);background-size:19px 19px}.frame{max-width:100%;width:100%;background:white;min-height:580px;box-shadow:0 19px 50px #1b344418;transition:width .2s;border:1px solid #e4e6ea;border-radius:5px;overflow:hidden}.frame.tablet{width:780px}.frame.phone{width:390px;flex-shrink:0}.webnav{display:flex;align-items:center;justify-content:space-between;padding:21px 7%;border-bottom:1px solid #edf0f3}.webnav strong{font-size:18px;color:#dd7933}.weblinks{display:flex;gap:18px;color:#768395;font-size:11px}.hero{background:linear-gradient(122deg,#f8ede0,#f1f6f8);padding:65px 8%;display:flex;gap:20px;align-items:center}.hero h1{font-size:clamp(24px,3vw,43px);line-height:1.14;margin:10px 0;color:#24364c}.hero p{color:#788898;line-height:1.65;max-width:480px}.hero .eyebrow{font-size:11px;letter-spacing:2px;color:#d07934}.hero .cta{display:inline-block;background:#de792f;color:white;padding:12px 17px;border-radius:6px;font-size:11px;margin-top:10px}.abstract{min-height:160px;min-width:28%;background:linear-gradient(45deg,#9dabb3,#f4d7b6);border-radius:18px;transform:skew(-8deg);box-shadow:18px 15px #e7d1ba}.features{display:grid;grid-template-columns:repeat(3,1fr);gap:13px;padding:25px 7%}.feature{padding:20px;border:1px solid #e6e9ee;border-radius:10px}.feature b{display:block;margin:0 0 8px}.feature p{font-size:11px;line-height:1.6;color:#8895a4}.tabs{display:flex;gap:4px;padding:4px;background:#f1f4f7;border-radius:9px;margin:6px 17px 20px}.tabs button{flex:1;border:0;padding:10px 6px;background:transparent;border-radius:6px;color:#79879a}.tabs button.active{background:white;color:#bf6831;font-weight:750;box-shadow:0 1px 7px #263c5814}.properties{padding:2px 19px}.properties h3{font-size:15px}.properties label{font-size:11px;color:#78879c;display:block;margin:14px 0 7px}.properties input,.properties textarea{width:100%;padding:10px 12px;border:1px solid #e0e6ed;border-radius:7px}.properties textarea{height:98px}.footer{padding:15px;border-top:1px solid #e1e5ed;color:#8797a7;font-size:11px;display:flex;justify-content:space-between}.hide{display:none!important}@media(max-width:1100px){.layout{grid-template-columns:235px minmax(0,1fr) 275px}.webnav{padding:15px}.hero{padding:38px 7%}.top .page,.top .tag{display:none}}@media(max-width:850px){.layout{grid-template-columns:1fr}.left,.right{position:fixed;top:68px;bottom:0;z-index:8;width:280px;box-shadow:4px 0 20px #0002;display:none}.left{left:0}.right{right:0}.left.open,.right.open{display:block}.weblinks{display:none}}
</style></head><body>
<header class="top"><span class="logo">◈ SiteForge</span><span class="tag">Visual Studio · V8.21.1</span><span class="page">首页 / 版式编辑</span><div class="sp"></div><button class="btn" onclick="toggle('left')">区块</button><button class="btn" onclick="toggle('right')">属性</button><button class="btn device active" data-device="desktop" onclick="device('desktop')">PC</button><button class="btn device" data-device="tablet" onclick="device('tablet')">平板</button><button class="btn device" data-device="phone" onclick="device('phone')">手机</button><button class="btn" onclick="alert('演示模式:实际系统支持保存草稿、版本历史和正式发布审批。')">保存草稿</button><button class="btn primary" onclick="alert('交互演示不会发布任何真实网站。')">发布设计 ↗</button></header>
<main class="layout"><aside class="pane left" id="left"><div class="panehead"><b>页面结构</b><span class="muted" id="count"></span></div><div class="field"><label>当前页面</label><select><option>首页 /</option><option>关于我们(演示)</option></select></div><div class="sec">区块排序 / 筛选</div><input class="search" id="search" placeholder="搜索区块..." oninput="draw()"><div class="list" id="blocks"></div><div class="sec">添加内容区块</div><div class="add"><button onclick="add('hero')">✦ 封面横幅</button><button onclick="add('features')">▦ 核心优势</button><button onclick="add('cta')">↗ 联系引导</button><button onclick="add('stats')"># 数字指标</button></div></aside>
<section class="preview"><div class="previewbar"><i class="dot"></i> 实时预览 / <span id="previewDevice">桌面端</span><div class="sp"></div><span class="muted">演示数据 · 不连接网站</span></div><div class="stage"><div class="frame" id="frame"><div class="webnav"><strong>HESU AUTO</strong><span class="weblinks">HOME PRODUCTS  GLOBAL NETWORK  ABOUT CONTACT</span></div><div class="hero"><div><span class="eyebrow">CHINA SOURCING · GLOBAL DELIVERY</span><h1 id="heroTitle">Your Global Automotive Partner</h1><p id="heroText">Connecting vehicle sourcing, global logistics and local delivery through one integrated solution.</p><span class="cta">EXPLORE SOLUTIONS →</span></div><div class="abstract"></div></div><div class="features" id="features"><div class="feature"><b>Global Sourcing</b><p>Discover a wide range of automotive solutions.</p></div><div class="feature"><b>Reliable Delivery</b><p>International logistics and export expertise.</p></div><div class="feature"><b>Local Support</b><p>After-sales and overseas delivery network.</p></div></div></div></div><div class="footer"><span>预览不等于发布</span><span>PC / Tablet / Mobile</span></div></section>
<aside class="pane right" id="right"><div class="panehead"><b>属性设置</b><span class="muted" id="chosen">封面横幅</span></div><div class="tabs"><button class="active" data-tab="content" onclick="tab('content')">内容</button><button data-tab="style" onclick="tab('style')">样式</button><button data-tab="responsive" onclick="tab('responsive')">响应式</button></div><div class="properties" id="inspector"></div></aside></main>
<script>
let rows=[{type:'hero',title:'首页形象横幅',visible:true},{type:'features',title:'核心优势',visible:true},{type:'stats',title:'业务规模数据',visible:true},{type:'cta',title:'全球合作邀请',visible:true}],selected=0,tabName='content';const names={hero:'封面横幅',features:'核心优势',stats:'数字指标',cta:'行动号召'};const esc=x=>String(x).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
function draw(){const q=document.querySelector('#search').value.toLowerCase();document.querySelector('#count').textContent=rows.length+' 个区块';document.querySelector('#blocks').innerHTML=rows.map((r,i)=>({r,i})).filter(({r})=>(r.title+names[r.type]).toLowerCase().includes(q)).map(({r,i})=>`<div class="item ${i===selected?'active':''} ${r.visible?'':'hidden'}" onclick="select(${i})"><span class="symbol">${{hero:'✦',features:'▦',stats:'#',cta:'↗'}[r.type]}</span><div class="iteminfo"><b>${esc(names[r.type])}</b><small>${esc(r.title)}</small></div><button class="act" title="上移" onclick="event.stopPropagation();move(${i},-1)">↑</button><button class="act" title="下移" onclick="event.stopPropagation();move(${i},1)">↓</button><button class="act" title="显隐" onclick="event.stopPropagation();rows[${i}].visible=!rows[${i}].visible;draw();updatePreview()">◉</button></div>`).join('')||'<div class="muted">未找到匹配的区块</div>';inspect()}
function select(i){selected=i;draw()};function add(type){rows.push({type,title:names[type],visible:true});selected=rows.length-1;draw()};function move(i,offset){const to=i+offset;if(to<0||to>=rows.length)return;rows.splice(to,0,rows.splice(i,1)[0]);selected=to;draw()};function device(d){document.querySelector('#frame').className='frame '+(d==='desktop'?'':d);document.querySelector('#previewDevice').textContent={desktop:'桌面端',tablet:'平板端',phone:'手机端'}[d];document.querySelectorAll('.device').forEach(b=>b.classList.toggle('active',b.dataset.device===d))};function tab(t){tabName=t;document.querySelectorAll('[data-tab]').forEach(b=>b.classList.toggle('active',b.dataset.tab===t));inspect()};function toggle(side){document.querySelector('#'+(side==='left'?'right':'left')).classList.remove('open');document.querySelector('#'+side).classList.toggle('open')};function inspect(){let r=rows[selected];if(!r)return;document.querySelector('#chosen').textContent=names[r.type];document.querySelector('#inspector').innerHTML=tabName==='content'?`<h3>${esc(names[r.type])}</h3><label>区块标题</label><input id="propTitle" value="${esc(r.title)}" oninput="rows[selected].title=this.value;updatePreview()"><label>内容文本</label><textarea placeholder="此处编辑内容,实时预览不会修改正式站点">${esc(r.description||'展示企业内容和品牌价值。')}</textarea>`:tabName==='style'?'<h3>外观设置</h3><label>背景颜色</label><input type="color" value="#f8ede0"><label>上下留白</label><input type="range" min="0" max="120" value="65">':'<h3>不同设备布局</h3><label>手机端隐藏</label><input type="checkbox" onchange="rows[selected].visible=!this.checked;draw();updatePreview()"><label>平板间距(px)</label><input type="number" value="50"><label>手机间距(px)</label><input type="number" value="28">'};function updatePreview(){const t=rows.find(r=>r.type==='hero');if(t)document.querySelector('#heroTitle').textContent=t.title||'Welcome';document.querySelector('#features').style.opacity=rows.some(r=>r.type==='features'&&!r.visible)?'.17':'1';const label=document.querySelector('#blocks .item.active .iteminfo small');if(label)label.textContent=rows[selected]?.title||''};draw();
</script></body></html>