refactor: ByteMD 迁移至 Tiptap WYSIWYG 编辑器 + Token 刷新优化
- 移除 ByteMD CDN 资源和 goldmark 依赖,替换为 Tiptap ESM 模块 - 编辑器从源码编辑模式改为 WYSIWYG 所见即所得 - 移除 /api/posts/preview 预览接口(Tiptap 直接输出 HTML 无需后端渲染) - 保留 UploadImage 图片上传接口和 bluemonday HTML 消毒 - 工具栏支持加粗、斜体、删除线、代码、标题、列表、引用、代码块、分割线、撤销/重做 - 支持图片粘贴/拖拽上传,Ctrl+S 快捷提交,F11 全屏,字数统计 - 优化 common.js:自动 401 拦截 Token 刷新,修复刷新死循环 - 草稿 localStorage 键名更新为 draft_post_body_html
This commit is contained in:
@ -1,16 +1,114 @@
|
||||
{{template "layout/header.html" .}}
|
||||
<link rel="stylesheet" href="https://esm.sh/bytemd@1.22.0/dist/index.css">
|
||||
<link rel="stylesheet" href="https://esm.sh/highlight.js@11.9.0/styles/github.css">
|
||||
<style>
|
||||
/* ByteMD 编辑器容器适配全高布局 */
|
||||
/* Tiptap 编辑器容器适配全高布局 */
|
||||
#editor-container {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
}
|
||||
#editor-container .bytemd {
|
||||
height: 100%;
|
||||
|
||||
/* Tiptap 编辑器核心样式 */
|
||||
.tiptap {
|
||||
padding: 16px 24px;
|
||||
outline: none;
|
||||
min-height: 100%;
|
||||
font-size: 15px;
|
||||
line-height: 1.7;
|
||||
color: #24292f;
|
||||
}
|
||||
|
||||
/* 段落间距 */
|
||||
.tiptap p { margin: 0.5em 0; }
|
||||
|
||||
/* 标题 */
|
||||
.tiptap h1 { margin: 1em 0 0.5em; font-size: 2em; font-weight: 700; }
|
||||
.tiptap h2 { margin: 0.8em 0 0.4em; font-size: 1.5em; font-weight: 700; }
|
||||
.tiptap h3 { margin: 0.6em 0 0.3em; font-size: 1.17em; font-weight: 700; }
|
||||
|
||||
/* 列表 */
|
||||
.tiptap ul, .tiptap ol { padding-left: 1.5em; margin: 0.5em 0; }
|
||||
.tiptap li { margin: 0.2em 0; }
|
||||
.tiptap ul[data-type="taskList"] { list-style: none; padding-left: 0; }
|
||||
.tiptap ul[data-type="taskList"] li { display: flex; align-items: flex-start; gap: 0.4em; }
|
||||
.tiptap ul[data-type="taskList"] li > label { flex-shrink: 0; margin-top: 0.15em; }
|
||||
|
||||
/* 引用 */
|
||||
.tiptap blockquote {
|
||||
border-left: 3px solid #e5e7eb;
|
||||
padding-left: 1em;
|
||||
margin: 0.5em 0;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
/* 代码块 */
|
||||
.tiptap pre {
|
||||
background: #1f2937;
|
||||
color: #f3f4f6;
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
overflow-x: auto;
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
.tiptap pre code { background: transparent; padding: 0; color: inherit; font-size: inherit; }
|
||||
.tiptap code {
|
||||
background: #f3f4f6;
|
||||
padding: 2px 5px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9em;
|
||||
font-family: 'SF Mono', 'Menlo', 'Monaco', monospace;
|
||||
}
|
||||
|
||||
/* 水平线 */
|
||||
.tiptap hr { border: none; border-top: 1px solid #e5e7eb; margin: 1em 0; }
|
||||
|
||||
/* 图片 */
|
||||
.tiptap img { max-width: 100%; height: auto; border-radius: 6px; }
|
||||
|
||||
/* 链接 */
|
||||
.tiptap a { color: #6366f1; text-decoration: underline; }
|
||||
|
||||
/* Placeholder */
|
||||
.tiptap p.is-editor-empty:first-child::before {
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
color: #c4c4c4;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/* 工具栏 */
|
||||
.editor-toolbar {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
padding: 6px 12px;
|
||||
background: #fafafa;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.editor-toolbar button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 30px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: #374151;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.editor-toolbar button:hover { background: #e5e7eb; }
|
||||
.editor-toolbar button.is-active { background: #1f2937; color: #fff; }
|
||||
.editor-toolbar .toolbar-divider {
|
||||
width: 1px;
|
||||
background: #e5e7eb;
|
||||
margin: 3px 4px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
@ -29,10 +127,33 @@
|
||||
maxlength="200" required autofocus>
|
||||
</div>
|
||||
|
||||
{{/* 工具栏 */}}
|
||||
<div class="editor-toolbar" id="toolbar">
|
||||
<button type="button" data-action="bold" title="加粗 (Ctrl+B)"><strong>B</strong></button>
|
||||
<button type="button" data-action="italic" title="斜体 (Ctrl+I)"><em>I</em></button>
|
||||
<button type="button" data-action="strike" title="删除线"><s>S</s></button>
|
||||
<button type="button" data-action="code" title="行内代码"></></button>
|
||||
<span class="toolbar-divider"></span>
|
||||
<button type="button" data-action="h1" title="标题 1">H1</button>
|
||||
<button type="button" data-action="h2" title="标题 2">H2</button>
|
||||
<button type="button" data-action="h3" title="标题 3">H3</button>
|
||||
<span class="toolbar-divider"></span>
|
||||
<button type="button" data-action="bulletList" title="无序列表">•</button>
|
||||
<button type="button" data-action="orderedList" title="有序列表">1.</button>
|
||||
<button type="button" data-action="blockquote" title="引用">"</button>
|
||||
<span class="toolbar-divider"></span>
|
||||
<button type="button" data-action="codeBlock" title="代码块">{ }</button>
|
||||
<button type="button" data-action="horizontalRule" title="分隔线">—</button>
|
||||
<span class="toolbar-divider"></span>
|
||||
<button type="button" data-action="undo" title="撤销">↩</button>
|
||||
<button type="button" data-action="redo" title="重做">↪</button>
|
||||
</div>
|
||||
|
||||
{{/* 编辑器主体 */}}
|
||||
<div class="editor-main">
|
||||
<div class="editor-pane" id="editorPane">
|
||||
<div id="editor-container" data-value="{{if .Post}}{{.Post.Body}}{{end}}"></div>
|
||||
<div id="editor-container"
|
||||
data-content="{{if .Post}}{{.Post.BodyHTML}}{{end}}"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -49,4 +170,6 @@
|
||||
|
||||
{{template "layout/footer.html" .}}
|
||||
|
||||
<script src="/static/js/common.js"></script>
|
||||
<script type="module" src="/static/js/editor.js"></script>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user