2026-10-23 12:31:03 +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-helpers.js" ></ script >< script defer src = "/ui/editor.js" ></ script >< link rel = "stylesheet" href = "/ui/professional-ui.css" >< script defer src = "/ui/professional-ui.js" ></ script ></ head >
2026-10-22 17:02:45 +08:00
< body data-sf-page = "editor" >
2026-10-22 16:49:25 +08:00
< div class = "studio" >
2026-10-23 12:31:03 +08:00
< header class = "studio-top sf-easy-top" >
< div class = "brand" >< a href = "/" title = "返回网站管理" > ◈</ a >< div >< b > SiteForge</ b >< small > 页面编辑</ small ></ div ></ div >
< div class = "file-name sf-easy-file" >< small id = "siteName" > 加载中</ small >< strong id = "pageName" > 页面编辑器</ strong ></ div >
< div class = "sf-pane-controls" >< button type = "button" onclick = "Studio.togglePane('left')" > ☰ 内容</ button >< button type = "button" onclick = "Studio.togglePane('right')" > ⚙ 编辑</ button ></ div >
< div class = "top-center sf-easy-device" role = "group" aria-label = "预览设备" >
< button id = "deviceDesktop" class = "icon-btn on" onclick = "Studio.device('desktop')" title = "电脑预览" aria-label = "电脑预览" > 电脑</ button >
< button id = "deviceTablet" class = "icon-btn" onclick = "Studio.device('tablet')" title = "平板预览" aria-label = "平板预览" > 平板</ button >
< button id = "devicePhone" class = "icon-btn" onclick = "Studio.device('phone')" title = "手机预览" aria-label = "手机预览" > 手机</ button >
</ div >
< span id = "saveStatus" class = "save-status sf-easy-save-status" role = "status" aria-live = "polite" > 读取中…</ span >
< button id = "saveDraftButton" type = "button" class = "ui-btn ghost sf-save-btn" onclick = "Studio.save()" > 保存草稿</ button >
< button id = "publishDesignButton" type = "button" class = "ui-btn primary sf-publish-btn" onclick = "Studio.publishDesign()" > 发布设计</ button >
< details class = "studio-actions" >< summary title = "其他功能" > 更多 ▾</ summary >< div class = "studio-actions-menu" >
< button id = "studioUndo" class = "ui-btn ghost" onclick = "Studio.undo()" disabled > ↶ 撤销</ button >
< button id = "studioRedo" class = "ui-btn ghost" onclick = "Studio.redo()" disabled > ↷ 重做</ button >
< button class = "ui-btn ghost" onclick = "Studio.showHistory()" > 版本历史</ button >
< button class = "ui-btn ghost" onclick = "Studio.showSiteDesign()" > 全站页眉与页脚</ button >
< button class = "ui-btn ghost" onclick = "Studio.showTokens()" > 全站设计规范</ button >
< 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 >
</ div ></ details >
2026-10-22 16:49:25 +08:00
</ header >
2026-10-23 12:31:03 +08:00
< div class = "sf-steps" aria-label = "编辑操作指引" >< div class = "sf-steps-label" > 只需 3 步</ div >< span class = "sf-step" id = "sfStep1" > ① 选择或添加区块</ span >< span class = "sf-step-separator" > →</ span >< span class = "sf-step" id = "sfStep2" > ② 修改右侧内容</ span >< span class = "sf-step-separator" > →</ span >< span class = "sf-step" id = "sfStep3" > ③ 保存并发布</ span >< button type = "button" class = "sf-guide-link" onclick = "Studio.showHelp()" > 新手使用指南 ?</ button ></ div >
2026-10-22 16:49:25 +08:00
< div class = "studio-body" >
2026-10-23 12:31:03 +08:00
< aside class = "left-pane" aria-label = "页面内容和区块" >
< div class = "pane-heading" >< div >< span class = "overline" > 页面内容</ span >< h3 > 编辑页面</ h3 ></ div >< span class = "chip" id = "blockCount" > 0 个区块</ span ></ div >
< div class = "field sf-page-picker" >< label for = "pageSelect" > 当前编辑的页面</ label >< select id = "pageSelect" onchange = "Studio.choosePage(this.value)" ></ select ></ div >
< div class = "sf-add-area" >< button type = "button" id = "sfAddBlock" class = "sf-add-button" aria-expanded = "false" aria-controls = "sfLibraryPanel" onclick = "Studio.toggleLibrary()" > + 添加内容区块</ button >< p > 例如图片横幅、公司简介、产品列表等</ p ></ div >
< section id = "sfLibraryPanel" class = "sf-library-panel" hidden aria-label = "添加区块" >< div class = "sf-panel-caption" > 点击类型即可添加到当前页面 < button type = "button" onclick = "Studio.toggleLibrary(false)" aria-label = "收起添加面板" > 收起 × </ button ></ div >< div class = "palette" id = "palette" ></ div >< details class = "sf-subsection" >< summary > 从我的组件库添加</ summary >< div class = "palette" id = "reusablePalette" ></ div ></ details ></ section >
< div class = "section-label" > 当前页面的内容 < span class = "section-caption" > 点击一项进行编辑</ span ></ div >
< div class = "structure-filter" >< label for = "blockSearch" class = "sr-only" > 搜索页面内容</ label >< input id = "blockSearch" type = "search" placeholder = "查找横幅、文字、产品…" autocomplete = "off" oninput = "Studio.filter(this.value)" >< button type = "button" onclick = "Studio.clearFilter()" aria-label = "清除搜索" > × </ button ></ div >
< div id = "blockList" class = "block-list" role = "list" aria-label = "当前页面区块" ></ div >
< p class = "structure-hint" > 点击区块进入右侧编辑;拖动 ⠿ 或使用 ↑ ↓ 调整顺序。</ p >
< details class = "sf-advanced" >< summary > 高级页面设置 < span > 模板、布局和组件保存</ span ></ summary >
< div class = "field" >< label for = "pageTemplate" > 页面模板</ label >< select id = "pageTemplate" onchange = "Studio.changeTemplateKind(this.value)" ></ select ></ div >
< div class = "field" >< label for = "layoutMode" > 排版方式</ label >< select id = "layoutMode" onchange = "Studio.setLayoutMode(this.value)" >< option value = "append" > 保留原页面,追加区块</ option >< option value = "replace" > 用这些区块重新排版页面</ option ></ select ></ div >
< div class = "sf-advanced-buttons" >< button type = "button" class = "ui-btn ghost" onclick = "Studio.resetPreset()" > 使用模板预设布局</ button >< button type = "button" class = "ui-btn ghost" onclick = "Studio.saveReusable()" > 将所选区块存为组件</ button ></ div >
< p class = "sf-advanced-note" > 更换模板预设可能替换当前草稿,请先保存;不会直接改变在线网站。</ p >
</ details >
2026-10-22 16:49:25 +08:00
</ aside >
2026-10-23 12:31:03 +08:00
< section class = "preview-workspace" >< div class = "preview-head" >< span class = "live-dot" id = "previewDot" ></ span >< span id = "previewState" role = "status" aria-live = "polite" > 实时预览</ 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 >
< div class = "stage-footer" >< span id = "deviceDetails" > 桌面端 · 自适应宽度</ span >< span > 当前是草稿预览,不是线上网站</ span ></ div ></ section >
< aside class = "right-pane" >< div class = "pane-heading" >< div >< span class = "overline" > 步骤 2 · 修改内容</ span >< h3 > 编辑选中的区块</ h3 ></ div >< span class = "chip" id = "blockTypeLabel" > 页面</ span ></ div >
< div class = "inspector-nav" role = "tablist" aria-label = "属性编辑分类" >< button type = "button" role = "tab" id = "tabContent" aria-selected = "true" onclick = "Studio.changeInspectorTab('content')" > 内容</ button >< button type = "button" role = "tab" id = "tabStyle" aria-selected = "false" onclick = "Studio.changeInspectorTab('style')" > 样式</ button >< button type = "button" role = "tab" id = "tabResponsive" aria-selected = "false" onclick = "Studio.changeInspectorTab('responsive')" > 手机/平板</ button ></ div >
< div class = "inspector" id = "inspector" >< div class = "no-selection" > 先从左侧点击一个内容区块,或者点击“添加内容区块”。</ div ></ div >
< details class = "right-foot sf-advanced-foot" >< summary > 高级:动态数据变量</ summary >< p > 支持 < code > {{site.name}}</ code > 、< code > {{page.title}}</ code > 等变量;动态内容列表可以按网站内容类型绑定。</ p ></ details >
2026-10-22 16:49:25 +08:00
</ aside >
</ div >
2026-10-23 12:31:03 +08:00
< dialog id = "sfGuideDialog" class = "sf-help-dialog" aria-labelledby = "sfGuideTitle" >
< div class = "sf-help-head" >< div >< span class = "overline" > 新手指南</ span >< h2 id = "sfGuideTitle" > 3 分钟学会编辑页面</ h2 ></ div >< button type = "button" class = "ui-btn ghost" onclick = "document.querySelector('#sfGuideDialog').close()" > 关闭 × </ button ></ div >
< ol class = "sf-help-steps" >< li >< b > 先选页面</ b >< p > 左侧顶部切换要编辑的页面;选择现有内容区块,或点击橙色的“添加内容区块”。</ p ></ li >< li >< b > 修改内容</ b >< p > 在右侧“内容”里改标题、文案和图片;切换“样式”或“手机/平板”调整外观。中间自动展示效果。</ p ></ li >< li >< b > 保存草稿,再发布</ b >< p > 点击右上角“保存草稿”可以保留工作。核对后点击“发布设计”,它会更新内容库;正式网站还需要执行静态构建和部署。</ p ></ li ></ ol >
< div class = "sf-guide-note" > 撤销、版本历史、全站页眉、静态构建等低频功能在右上角「更多」。</ div >
< button type = "button" class = "ui-btn primary sf-guide-done" onclick = "document.querySelector('#sfGuideDialog').close()" > 知道了,开始编辑</ button >
</ dialog >
2026-10-22 16:49:25 +08:00
< 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 >
2026-10-23 12:31:03 +08:00
< fieldset style = "border:1px solid #e2e8f0;border-radius:10px;padding:15px;display:grid;gap:12px" >< legend > 手机底部快捷导航 Tabs(可选)</ legend >
< p style = "margin:0;color:#64748b;font-size:13px" > 默认关闭。需要时开启后添加 1–5 个按钮。它们只显示在手机上,平板和电脑不显示。</ p >
< label >< input name = "mobile_tabs_enabled" type = "checkbox" onchange = "Studio.toggleMobileTabsForm()" > 开启手机底部 Tabs</ label >
< div id = "mobileTabsEditor" hidden style = "display:grid;gap:10px" >
< div id = "mobileTabsRows" style = "display:grid;gap:9px" ></ div >
< button class = "ui-btn ghost" type = "button" onclick = "Studio.addMobileTab()" > + 添加一个 Tab(最多 5 个)</ button >
< small style = "color:#64748b" > 标题建议不超过 4 个字;链接使用站内路径(如 /products/)。菜单按钮会打开右侧导航抽屉。</ small >
</ div >
</ fieldset >
2026-10-22 16:49:25 +08:00
< 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 >
2026-10-23 12:31:03 +08:00
< dialog id = "studioHistoryModal" aria-labelledby = "studioHistoryTitle" style = "border:1px solid #dce5f1;border-radius:14px;padding:24px;width:min(680px,95vw);max-height:82vh;overflow:auto" >
< h2 id = "studioHistoryTitle" > 页面设计版本历史</ h2 >
< p style = "color:#64748b" > 保存草稿、发布设计都会创建不可变快照。恢复只写入新草稿,不会直接修改已发布站点。</ p >
< div id = "studioHistoryItems" aria-live = "polite" ></ div >
< button class = "ui-btn ghost" type = "button" onclick = "document.querySelector('#studioHistoryModal').close()" > 关闭</ button >
</ dialog >
< div id = "toast" class = "toast" role = "status" aria-live = "polite" ></ div >
2026-10-22 16:49:25 +08:00
</ div ></ body ></ html >