Files
mce/templates/MetaLab-2026/html/posts/new.html
Victor_Jay 799ac3c95c fix: 放宽 CSP 允许 esm.sh CDN 加载 CodeMirror 6 ESM 模块
- script-src 添加 https://esm.sh,允许 CodeMirror 6 的 ESM import 加载
- connect-src 显式设为 self,确保 Markdown 预览 fetch 请求正常
- img-src 添加 blob:,支持粘贴图片场景
2026-05-27 19:44:59 +08:00

130 lines
8.6 KiB
HTML

{{template "layout/header.html" .}}
<body>
{{template "layout/nav.html" .}}
<div class="editor-layout">
<form id="postForm" class="editor-form">
<input type="hidden" id="postId" value="{{if .Post}}{{.Post.ID}}{{end}}">
{{/* 标题区域 */}}
<div class="editor-header">
<input type="text" id="postTitle" class="editor-title-input"
value="{{if .Post}}{{.Post.Title}}{{end}}"
placeholder="输入文章标题..."
maxlength="200" required autofocus>
</div>
{{/* 工具栏 */}}
<div class="editor-toolbar" id="toolbar">
<div class="tb-group">
<button type="button" class="tb-btn" data-action="bold" title="加粗 (Ctrl+B)">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z"/></svg>
</button>
<button type="button" class="tb-btn" data-action="italic" title="斜体 (Ctrl+I)">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z"/></svg>
</button>
<button type="button" class="tb-btn" data-action="strikethrough" title="删除线">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M6.85 7.08C6.85 4.37 9.45 3 12.24 3c1.64 0 3 .49 3.9 1.28.77.65 1.46 1.73 1.46 3.24h-3.01c0-.31-.05-.59-.15-.85-.29-.86-1.2-1.28-2.25-1.28-1.86 0-2.34 1.02-2.34 1.7 0 .48.25.88.74 1.21.38.25.77.48 1.41.7H7.39c-.21-.34-.54-.89-.54-1.92zM21 12v-2H3v2h9.62c1.15.45 1.96.75 1.96 1.97 0 1-.81 1.67-2.28 1.67-1.54 0-2.93-.54-2.93-2.51H6.4c0 2.21 1.79 4.21 4.4 4.21 3.61 0 5.2-2.48 5.2-4.3 0-1.43-.84-2.46-2.37-3.04H21z"/></svg>
</button>
<button type="button" class="tb-btn" data-action="code" title="行内代码 (Ctrl+`)">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M9.4 16.6 4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0 4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/></svg>
</button>
</div>
<span class="tb-sep"></span>
<div class="tb-group">
<button type="button" class="tb-btn" data-action="h1" title="一级标题">H1</button>
<button type="button" class="tb-btn" data-action="h2" title="二级标题">H2</button>
<button type="button" class="tb-btn" data-action="h3" title="三级标题">H3</button>
<button type="button" class="tb-btn" data-action="h4" title="四级标题">H4</button>
</div>
<span class="tb-sep"></span>
<div class="tb-group">
<button type="button" class="tb-btn" data-action="link" title="插入链接 (Ctrl+K)">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/></svg>
</button>
<button type="button" class="tb-btn" data-action="image" title="插入图片 (Ctrl+Shift+I)">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>
</button>
</div>
<span class="tb-sep"></span>
<div class="tb-group">
<button type="button" class="tb-btn" data-action="quote" title="引用块">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z"/></svg>
</button>
<button type="button" class="tb-btn" data-action="pre" title="代码块">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3 3h18v18H3V3zm2 2v14h14V5H5zm4 2h6v2H9V7zm0 4h6v2H9v-2z"/></svg>
</button>
</div>
<span class="tb-sep"></span>
<div class="tb-group">
<button type="button" class="tb-btn" data-action="ul" title="无序列表">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z"/></svg>
</button>
<button type="button" class="tb-btn" data-action="ol" title="有序列表">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z"/></svg>
</button>
<button type="button" class="tb-btn" data-action="task" title="任务列表">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>
</button>
<button type="button" class="tb-btn" data-action="table" title="插入表格">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M4 4h16a2 2 0 012 2v12a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2zm0 4v3h4V8H4zm6 0v3h4V8h-4zm6 0v3h4V8h-4zm-12 5v3h4v-3H4zm6 0v3h4v-3h-4zm6 0v3h4v-3h-4zM4 6h16V6H4v.01z"/></svg>
</button>
</div>
<span class="tb-sep"></span>
<button type="button" class="tb-btn" data-action="hr" title="分割线">&mdash;</button>
<div class="tb-spacer"></div>
{{/* 右侧:预览切换 + 全屏 */}}
<div class="tb-group tb-right">
<button type="button" class="tb-btn tb-toggle" id="btnTogglePreview" title="切换预览 (Ctrl+Shift+P)">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></svg>
</button>
<button type="button" class="tb-btn" id="btnFullscreen" title="全屏编辑 (F11)">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>
</button>
</div>
</div>
{{/* 代码块语言选择器(下拉菜单) */}}
<div class="lang-picker" id="langPicker" style="display:none">
<div class="lang-picker-search">
<input type="text" id="langSearch" placeholder="搜索语言...">
</div>
<div class="lang-picker-list" id="langList"></div>
</div>
{{/* 编辑器主体:编辑区 + 预览区 */}}
<div class="editor-main">
<div class="editor-pane" id="editorPane">
<textarea id="postBody" style="display:none;">{{if .Post}}{{.Post.Body}}{{end}}</textarea>
</div>
<div class="preview-pane" id="previewPane">
<div class="preview-content post-detail-body" id="previewContent">
<em style="color:#9ca3af">预览将在此处显示...</em>
</div>
</div>
</div>
{{/* 状态栏 */}}
<div class="editor-statusbar">
<span class="status-item" id="wordCount">0 字</span>
<span class="status-item" id="lineCount">0 行</span>
<span class="status-item" id="readTime">约 1 分钟</span>
<span class="status-spacer"></span>
<span class="status-item status-draft" id="draftStatus" style="display:none">草稿已保存</span>
<button type="submit" class="btn btn-primary btn-submit">{{if .Post}}保存修改{{else}}发布帖子{{end}}</button>
</div>
</form>
{{/* 隐藏的图片上传控件 */}}
<input type="file" id="imageFileInput" accept="image/jpeg,image/png,image/gif,image/webp" style="display:none;">
</div>
{{template "layout/footer.html" .}}
{{/* CodeMirror 6 (MIT License, via esm.sh bundle) */}}
<script src="/static/js/common.js"></script>
<script type="module" src="/static/js/editor.js"></script>