2026-10-22 17:02:45 +08:00
<!doctype html> < html lang = "zh-CN" >< head >< meta charset = "utf-8" >< meta name = "viewport" content = "width=device-width,initial-scale=1" >< title > SiteForge Studio · 可视化建站</ title >< link rel = "stylesheet" href = "/ui/editor.css" >< script defer src = "/ui/editor.js" ></ script >< link rel = "stylesheet" href = "/ui/professional-ui.css" >< script defer src = "/ui/professional-ui.js" ></ script ></ head >
< body data-sf-page = "editor" >
2026-10-22 16:49:25 +08:00
< div class = "studio" >
< header class = "studio-top" >
< div class = "brand" >< a href = "/" title = "返回网站管理" > ◈</ a >< div >< b > SiteForge</ b >< small > VISUAL STUDIO</ small ></ div ></ div >
< span class = "divide" ></ span >< div class = "file-name" >< span id = "siteName" > 加载中</ span >< small > / </ small >< strong id = "pageName" > 页面编辑器</ strong ></ div >
< div class = "top-center" >< button id = "deviceDesktop" class = "icon-btn on" onclick = "Studio.device('desktop')" title = "PC预览" > ▣</ button >< button id = "deviceTablet" class = "icon-btn" onclick = "Studio.device('tablet')" title = "平板预览" > ▤</ button >< button id = "devicePhone" class = "icon-btn" onclick = "Studio.device('phone')" title = "手机预览" > ▯</ button ></ div >
< button class = "ui-btn ghost" onclick = "Studio.undo()" title = "撤销 Ctrl+Z" > ↶ 撤销</ button >< button class = "ui-btn ghost" onclick = "Studio.redo()" title = "重做 Ctrl+Y" > ↷ 重做</ button >< button class = "ui-btn ghost" onclick = "Studio.showTokens()" > 设计规范</ button >< button class = "ui-btn ghost" onclick = "Studio.showSiteDesign()" > 全站页眉与页脚</ button >< span id = "saveStatus" class = "save-status" > 未修改</ span >< button class = "ui-btn ghost" onclick = "Studio.refreshPreview()" > ↻ 刷新预览</ button >< button class = "ui-btn ghost" onclick = "Studio.buildSite()" > 构建静态站</ button >< button class = "ui-btn ghost" onclick = "Studio.discardDraft()" > 放弃草稿</ button >< button class = "ui-btn ghost" onclick = "Studio.save()" > 保存草稿</ button >< button class = "ui-btn primary" onclick = "Studio.publishDesign()" > 发布设计 ↗</ button >
</ header >
< div class = "studio-body" >
< aside class = "left-pane" >< div class = "pane-heading" >< div >< span class = "overline" > STRUCTURE</ span >< h3 > 页面结构</ h3 ></ div >< span class = "chip" id = "blockCount" > 0 区块</ span ></ div >
< div class = "field" >< label > 页面</ label >< select id = "pageSelect" onchange = "Studio.choosePage(this.value)" ></ select ></ div >
< div class = "field" >< label > 页面模板</ label >< select id = "pageTemplate" onchange = "Studio.changeTemplateKind(this.value)" ></ select ></ div >
< div style = "padding:0 19px 7px" >< button class = "ui-btn ghost" style = "width:100%" onclick = "Studio.resetPreset()" > ◈ 应用此页面模板的预设区块</ button ></ div >
< div class = "field" >< label > 页面布局模式</ label >< select id = "layoutMode" onchange = "Studio.setLayoutMode(this.value)" >< option value = "append" > 保留主题原页面 + 追加区块</ option >< option value = "replace" > 全页自由排版(保留导航与页脚)</ option ></ select ></ div >< div class = "section-label" > 内容区块 · 拖拽可调整排序</ div >< div id = "blockList" class = "block-list" ></ div >
< div class = "section-label" > 添加功能区块</ div >< div class = "palette" id = "palette" ></ div >< div class = "section-label" > 可复用组件库</ div >< button class = "ui-btn ghost" style = "margin:10px" onclick = "Studio.saveReusable()" > 将当前区块存为组件</ button >< div class = "palette" id = "reusablePalette" ></ div >
< div class = "sidebar-foot" > 页面由区块驱动,所见预览使用服务端与正式构建相同的数据绑定引擎。</ div >
</ aside >
< section class = "preview-workspace" >< div class = "preview-head" >< span class = "live-dot" ></ span >< span > 实时预览</ span >< code id = "routeDisplay" > /</ code >< span class = "preview-note" > 正在展示正式主题中的完整页面,草稿不会影响正式构建,发布设计后才会参与下次构建</ span ></ div >< div class = "stage" >< div class = "device-frame" id = "deviceFrame" >< iframe id = "sitePreview" title = "页面预览" sandbox = "allow-scripts" referrerpolicy = "no-referrer" ></ iframe ></ div ></ div ></ section >
< aside class = "right-pane" >< div class = "pane-heading" >< div >< span class = "overline" > PROPERTIES</ span >< h3 > 属性设置</ h3 ></ div >< span class = "chip" id = "blockTypeLabel" > 页面</ span ></ div >
< div class = "inspector" id = "inspector" >< div class = "no-selection" > 在左侧选择一个区块,在这里编辑它的文字、图片、布局及数据来源。</ div ></ div >
< div class = "right-foot" >< div > 动态数据绑定</ div >< p > 支持 < code > {{site.name}}</ code > 、< code > {{page.title}}</ code > 等变量;“动态内容列表”按类型自动查询当前网站的数据。</ p ></ div >
</ aside >
</ div >
< dialog id = "designModal" style = "border:1px solid #e2e8f0;border-radius:14px;padding:24px;width:min(460px,90vw);box-shadow:0 16px 52px #142a492f" >< h2 > 全站设计规范</ h2 >< p > 调整后保存并刷新预览,发布构建自动采用该规范。</ p >< form id = "designForm" method = "dialog" style = "display:grid;gap:12px" >< label > 标题缩放 < input name = "heading_scale" type = "number" min = "0.8" max = "1.5" step = "0.1" ></ label >< label > 圆角 < input name = "radius" type = "number" min = "0" max = "32" ></ label >< label > 版心宽度 < input name = "container_width" type = "number" min = "880" max = "1600" ></ label >< label > 板块间距 < input name = "section_spacing" type = "number" min = "20" max = "140" ></ label >< label > 字体 < select name = "font" >< option value = "system" > 系统字体</ option >< option value = "serif" > 衬线字体</ option >< option value = "modern" > 现代字体</ option ></ select ></ label >< label > 按钮风格 < select name = "button_style" >< option value = "rounded" > 圆角</ option >< option value = "square" > 直角</ option >< option value = "pill" > 胶囊</ option ></ select ></ label >< label > 导航风格 < select name = "header_style" >< option value = "standard" > 标准</ option >< option value = "compact" > 紧凑</ option ></ select ></ label >< div style = "display:flex;gap:12px" >< button class = "ui-btn primary" type = "button" onclick = "Studio.saveTokens()" > 保存全站规范</ button >< button class = "ui-btn ghost" value = "cancel" > 取消</ button ></ div ></ form ></ dialog >
< dialog id = "siteDesignModal" style = "border:1px solid #e2e8f0;border-radius:14px;padding:22px;width:min(750px,96vw);max-height:88vh;overflow:auto;box-shadow:0 18px 56px #142a492f" >
< h2 > 全站设计 · 页眉、导航、页脚与响应式</ h2 >
< p style = "color:#64748b" > 先保存独立草稿;预览只显示在编辑器内。发布后,所有页面的下次静态构建才会使用新设计。</ p >
< div id = "siteDesignStatus" role = "status" style = "font-weight:600;margin-bottom:12px" > 读取中...</ div >
< form id = "siteDesignForm" method = "dialog" style = "display:grid;gap:12px" >
< fieldset style = "display:grid;gap:9px;border:1px solid #e2e8f0;border-radius:8px" >< legend > 页眉与导航</ legend >
< label >< input type = "checkbox" name = "show_announcement" > 显示顶部提示栏</ label >
< label > 提示栏文字 < input name = "announcement" maxlength = "140" style = "width:100%" ></ label >
< label >< input type = "checkbox" name = "show_search" > 显示站内搜索</ label >
< label >< input type = "checkbox" name = "show_cta" > 显示联系按钮</ label >
< label > 按钮文字 < input name = "cta_text" maxlength = "40" ></ label >
< label > 按钮路径 < input name = "cta_href" placeholder = "/contact/" ></ label >
< label > 导航结构(JSON,每项含 title、route、可选 children)
< textarea name = "nav" rows = "6" style = "display:block;width:100%;font-family:monospace" spellcheck = "false" ></ textarea >
</ label >
</ fieldset >
< fieldset style = "display:grid;gap:9px;border:1px solid #e2e8f0;border-radius:8px" >< legend > 全站页脚</ legend >
< label > 企业名称或页脚标题 < input name = "footer_title" maxlength = "120" style = "width:100%" ></ label >
< label > 页脚简介 < textarea name = "footer_description" rows = "2" maxlength = "650" style = "display:block;width:100%" ></ textarea ></ label >
< label > 联系邮箱 < input name = "footer_email" type = "email" maxlength = "150" ></ label >
< label >< input name = "footer_show_nav" type = "checkbox" > 页脚显示导航链接</ label >
</ fieldset >
< fieldset style = "display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;border:1px solid #e2e8f0;border-radius:8px" >< legend > 不同设备布局</ legend >
< label > 平板板块间距 < input name = "tablet_gap" type = "number" min = "20" max = "120" ></ label >
< label > 手机板块间距 < input name = "mobile_gap" type = "number" min = "16" max = "100" ></ label >
< label > 手机内容边距 < input name = "mobile_container_padding" type = "number" min = "8" max = "48" ></ label >
< label >< input name = "mobile_hide_announcement" type = "checkbox" > 手机隐藏提示栏</ label >
< label >< input name = "mobile_hide_footer_links" type = "checkbox" > 手机隐藏页脚导航</ label >
</ fieldset >
< div style = "display:flex;flex-wrap:wrap;gap:8px" >
< button class = "ui-btn ghost" type = "button" onclick = "Studio.previewSiteDesign()" > 预览草稿</ button >
< button class = "ui-btn ghost" type = "button" onclick = "Studio.discardSiteDesign()" > 放弃全站草稿</ button >
< button class = "ui-btn ghost" type = "button" onclick = "Studio.saveSiteDesign()" > 保存全站草稿</ button >
< button class = "ui-btn primary" type = "button" onclick = "Studio.publishSiteDesign()" > 发布全站设计</ button >
< button class = "ui-btn ghost" value = "cancel" > 关闭</ button >
</ div >
</ form >
</ dialog >
< dialog id = "siteMediaModal" style = "border:1px solid #dce5f1;border-radius:14px;padding:24px;width:min(720px,94vw);max-height:85vh;overflow:auto" >
< h2 > 本站图片素材库</ h2 >< p style = "font-size:13px;color:#66758a" > 选择图片后更新当前组件;保存草稿、发布设计后才会参与静态构建。</ p >
< div id = "siteMediaGrid" style = "display:grid;grid-template-columns:repeat(auto-fill,minmax(135px,1fr));gap:12px" ></ div >
< button type = "button" class = "ui-btn ghost" onclick = "document.querySelector('#siteMediaModal').close()" style = "margin-top:15px" > 关闭</ button >
</ dialog >
< div id = "toast" class = "toast" ></ div >
</ div ></ body ></ html >