601451f22b
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>
14 lines
12 KiB
HTML
14 lines
12 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 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=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[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>
|