Files
mce/templates/MetaLab-2026/html/posts/show.html
Victor_Jay 36b18c0ffe feat: 代码块语法高亮 + 语言选择 + 样式统一
- 引入 @tiptap/extension-code-block-lowlight + lowlight 实现代码语法高亮
- 工具栏新增语言下拉选择器,光标在代码块内时显示,支持 27 种常用语言
- 默认语言 text,高亮主题适配 MetaLab 深蓝背景 (#1a2332)
- 代码块语言标签用 JS 动态注入 DOM 元素(避免 ::before 在 overflow 容器中失效)
- 详情页同步代码块高亮和语言标签显示
- 编辑器与详情页样式统一:代码块暗色背景、引用蓝色边框、链接 accent 蓝
- sanitizePolicy 放行 data-language 属性和 hljs-* class
- 修复 import map 避免 keyed plugin 重复实例
- 修复详情页代码块开头空白行(移除多余的 padding-top)
- 修复语法错误(多余的闭合括号)
2026-05-28 14:34:58 +08:00

88 lines
3.1 KiB
HTML

{{template "layout/header.html" .}}
<body>
{{template "layout/nav.html" .}}
<div class="container post-detail">
<article class="post-article">
<header class="post-detail-header">
<h1 class="post-detail-title">{{.Post.Title}}</h1>
<div class="post-detail-meta">
<span class="post-author">{{if .Post.AuthorName}}{{.Post.AuthorName}}{{else}}UID{{.Post.UserID}}{{end}}</span>
<span class="post-time">{{.Post.CreatedAt.Format "2006-01-02 15:04"}}</span>
{{if ne .Post.Status "approved"}}
<span class="post-status post-status-{{.Post.Status}}">{{index $.StatusNames .Post.Status}}</span>
{{end}}
</div>
</header>
<div class="post-detail-body">
{{.PostBodyHTML}}
{{/* 如果 BodyHTML 为空,直接显示原文 */}}
</div>
{{if not .PostBodyHTML}}
<div class="post-detail-body-raw">{{.Post.Body}}</div>
{{end}}
{{if .Post.RejectReason}}
<div class="post-reject-reason">
<strong>退回理由:</strong>{{.Post.RejectReason}}
</div>
{{end}}
</article>
{{if .IsLoggedIn}}
<div class="post-actions">
{{if and $.Post (or (eq $.Post.UserID $.UID) $.CanAccessAdmin) (ne $.Post.Status "pending") (ne $.Post.Status "locked")}}
<a href="/posts/{{$.Post.ID}}/edit" class="btn btn-secondary">编辑</a>
{{end}}
{{if and $.Post (eq $.Post.UserID $.UID) (or (eq $.Post.Status "draft") (eq $.Post.Status "rejected"))}}
<button class="btn btn-primary" id="submitAuditBtn" data-id="{{$.Post.ID}}">提交审核</button>
{{end}}
</div>
{{end}}
</div>
{{template "layout/footer.html" .}}
<script src="/static/js/common.js"></script>
<script>
// ---- 代码块语言标签注入 ----
(function() {
document.querySelectorAll('.post-detail-body pre').forEach(function(pre) {
var lang = pre.getAttribute('data-language');
if (lang) {
var label = document.createElement('div');
label.className = 'code-lang-label';
label.textContent = lang;
pre.insertBefore(label, pre.firstChild);
pre.style.paddingTop = '32px';
}
});
})();
(function() {
var btn = document.getElementById('submitAuditBtn');
if (!btn) return;
btn.addEventListener('click', function() {
if (!confirm('确认提交审核?审核通过后将公开发布。')) return;
var csrf = document.querySelector('meta[name="csrf-token"]');
fetch('/api/posts/' + btn.dataset.id + '/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrf ? csrf.getAttribute('content') : ''
}
})
.then(function(r) { return r.json(); })
.then(function(d) {
if (d.success) { window.location.reload(); }
else { alert(d.message || '提交失败'); }
})
.catch(function() { alert('请求失败'); });
});
})();
</script>
</body>
</html>