- 赞/踩/赋能/收藏/评论/回顶部移至右下角悬浮操作栏,固定定位 - 回顶部按钮页面顶部隐藏,滚动后显示,平滑滚动 - 评论按钮点击定位到评论区(NAV 下方) - 赋能按钮作者可见但禁止自赋能,点击弹出 toast 提示 - 未登录用户赋能/收藏点击跳转登录页 - postReactions 引用统一改为 postFloatBar
216 lines
11 KiB
HTML
216 lines
11 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">
|
||
{{if .Post.AuthorName}}
|
||
<span>作者:<a href="/space/{{.Post.UserID}}" class="post-meta-author">{{.Post.AuthorName}}</a></span>
|
||
{{else}}
|
||
<span>作者:该用户已注销</span>
|
||
{{end}}
|
||
<span>阅读:{{.Post.ViewsCount}}</span>
|
||
<span>点赞:{{.Post.LikesCount}}</span>
|
||
<span>收藏:{{.Post.FavoritesCount}}</span>
|
||
<span>评论:{{.Post.CommentsCount}}</span>
|
||
<span>发布时间:{{.Post.CreatedAt.Format "2006-01-02 15:04"}}</span>
|
||
{{if and .Post.IsLocked (eq $.Post.UserID $.UID)}}
|
||
<span class="post-status post-status-locked">已锁定{{if .Post.LockReason}}:{{.Post.LockReason}}{{end}}</span>
|
||
{{end}}
|
||
{{if and .Post.PendingBody (eq $.Post.UserID $.UID)}}
|
||
<span class="post-status post-status-revision">修订审核中</span>
|
||
{{end}}
|
||
</div>
|
||
</header>
|
||
|
||
{{if .Post.RejectReason}}
|
||
<div class="post-reject-reason">
|
||
<strong>退回理由:</strong>{{.Post.RejectReason}}
|
||
</div>
|
||
{{end}}
|
||
|
||
<div class="post-detail-body" id="postContent"></div>
|
||
</article>
|
||
|
||
<!-- 右下角悬浮操作栏 -->
|
||
<div class="post-float-bar" id="postFloatBar" data-post-id="{{.Post.ID}}">
|
||
<button class="float-btn float-like-btn" id="likeBtn" title="点赞">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3H14zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"/></svg>
|
||
<span class="float-count" id="likesCount">{{.Post.LikesCount}}</span>
|
||
</button>
|
||
<button class="float-btn float-dislike-btn" id="dislikeBtn" title="踩">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3H10zM17 2h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"/></svg>
|
||
</button>
|
||
{{if .IsLoggedIn}}
|
||
<button class="float-btn float-energize-btn" id="energizeBtn" data-id="{{.Post.ID}}" data-uid="{{$.UID}}" data-author-uid="{{.Post.UserID}}" title="赋能">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
|
||
</button>
|
||
<button class="float-btn float-fav-btn" id="favBtn" title="收藏">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
|
||
<span class="float-count" id="favCount">{{.Post.FavoritesCount}}</span>
|
||
</button>
|
||
{{else}}
|
||
<button class="float-btn float-energize-btn" onclick="location.href='/auth/login?redirect=/posts/{{.Post.ID}}'" title="赋能">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
|
||
</button>
|
||
<button class="float-btn float-fav-btn" onclick="location.href='/auth/login?redirect=/posts/{{.Post.ID}}'" title="收藏">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
|
||
<span class="float-count">0</span>
|
||
</button>
|
||
{{end}}
|
||
<button class="float-btn float-comment-btn" id="floatCommentBtn" title="评论">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
||
</button>
|
||
<button class="float-btn float-top-btn" id="floatTopBtn" title="回顶部" style="display:none">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="18 15 12 9 6 15"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
{{if .IsLoggedIn}}
|
||
<div class="post-actions">
|
||
{{if and $.Post (or (eq $.Post.UserID $.UID) $.CanAccessAdmin) (ne $.Post.Status "pending") (not $.Post.IsLocked)}}
|
||
<a href="/studio/write?id={{$.Post.ID}}" class="btn btn-secondary">编辑</a>
|
||
{{end}}
|
||
{{if and $.Post (eq $.Post.UserID $.UID) (or (eq $.Post.Status "draft") (eq $.Post.Status "rejected")) (not $.Post.IsLocked)}}
|
||
<button class="btn btn-primary" id="submitAuditBtn" data-id="{{$.Post.ID}}">提交审核</button>
|
||
{{end}}
|
||
</div>
|
||
|
||
<!-- 赋能弹窗 -->
|
||
<div class="energize-overlay" id="energizeOverlay" style="display:none">
|
||
<div class="energize-modal">
|
||
<div class="energize-modal-header">
|
||
<h3>为这篇文章注入能量</h3>
|
||
<button class="energize-close" id="energizeClose">×</button>
|
||
</div>
|
||
<div class="energize-modal-body">
|
||
<p class="energize-hint" id="energizeCapHint" style="display:none">
|
||
今日赋能经验奖励已达上限,继续赋能将消耗域能,对方仍会获得激励。
|
||
</p>
|
||
<div class="energize-options">
|
||
<button class="energize-option-btn" id="energizeLight" data-amount="10">
|
||
<span class="energize-option-title">轻赋</span>
|
||
<span class="energize-option-cost">消耗 1 域能</span>
|
||
<span class="energize-option-gain">获得 10 经验</span>
|
||
</button>
|
||
<button class="energize-option-btn" id="energizeHeavy" data-amount="20">
|
||
<span class="energize-option-title">重赋</span>
|
||
<span class="energize-option-cost">消耗 2 域能</span>
|
||
<span class="energize-option-gain">获得 20 经验</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 选择收藏夹弹窗 -->
|
||
<div class="fav-overlay" id="favOverlay" style="display:none">
|
||
<div class="fav-modal">
|
||
<div class="fav-modal-header">
|
||
<h3>选择收藏夹</h3>
|
||
<button class="fav-close" id="favClose">×</button>
|
||
</div>
|
||
<div class="fav-modal-body">
|
||
<div class="fav-folder-list" id="favFolderCheckList">
|
||
<div class="fav-loading">加载中...</div>
|
||
</div>
|
||
<div class="fav-new-folder">
|
||
<input type="text" class="fav-new-input" id="favNewInput" placeholder="新建收藏夹..." maxlength="50">
|
||
<button class="fav-new-btn" id="favNewConfirm">创建并收藏</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
|
||
<!-- 评论区 -->
|
||
{{if .Post.AllowComment}}
|
||
<section class="comments-section" id="comments">
|
||
<h3 class="comments-title">评论 <span class="comments-count" id="commentsTotal">0</span></h3>
|
||
|
||
{{if .IsLoggedIn}}
|
||
<div class="comment-form">
|
||
<textarea class="comment-input" id="commentInput" placeholder="写下你的评论..." rows="3" maxlength="5000"></textarea>
|
||
<div class="comment-form-actions">
|
||
<label class="comment-upload-btn" id="commentUploadLabel">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
||
图片
|
||
</label>
|
||
<input type="file" id="commentImageInput" accept="image/*" style="display:none" />
|
||
<button class="btn btn-primary comment-submit-btn" id="commentSubmitBtn">发表评论</button>
|
||
</div>
|
||
<div class="comment-upload-preview" id="commentUploadPreview"></div>
|
||
</div>
|
||
{{else}}
|
||
<div class="comment-login-hint">
|
||
<a href="/auth/login?redirect=/posts/{{$.Post.ID}}">登录</a> 后参与评论
|
||
</div>
|
||
{{end}}
|
||
|
||
<div class="comments-list" id="commentsList"></div>
|
||
<div class="comments-loading" id="commentsLoading" style="display:none">加载中...</div>
|
||
<button class="btn btn-secondary comments-load-more" id="commentsLoadMore" style="display:none">加载更多</button>
|
||
</section>
|
||
{{end}}
|
||
|
||
<!-- @ 提及下拉 -->
|
||
<div class="mention-dropdown" id="mentionDropdown" style="display:none"></div>
|
||
</div>
|
||
|
||
{{template "layout/footer.html" .}}
|
||
|
||
{{/* MD 内容安全传递给 JS */}}
|
||
<textarea id="postMdContent" style="display:none">{{.Post.Body}}</textarea>
|
||
|
||
<link rel="stylesheet" href="/static/vditor/dist/index.css?v={{assetV "/static/vditor/dist/index.css"}}">
|
||
<script src="/static/vditor/dist/method.min.js?v={{assetV "/static/vditor/dist/method.min.js"}}" nonce="{{.CSPNonce}}"></script>
|
||
<script src="/static/js/shortcode.js?v={{assetV "/static/js/shortcode.js"}}" nonce="{{.CSPNonce}}"></script>
|
||
<script src="/static/js/post-view.js?v={{assetV "/static/js/post-view.js"}}" nonce="{{.CSPNonce}}"></script>
|
||
<script src="/static/js/post-energize.js?v={{assetV "/static/js/post-energize.js"}}" nonce="{{.CSPNonce}}"></script>
|
||
<script src="/static/js/post-reactions.js?v={{assetV "/static/js/post-reactions.js"}}" nonce="{{.CSPNonce}}"></script>
|
||
<script src="/static/js/post-favorite.js?v={{assetV "/static/js/post-favorite.js"}}" nonce="{{.CSPNonce}}"></script>
|
||
<script src="/static/js/post-comments.js?v={{assetV "/static/js/post-comments.js"}}" nonce="{{.CSPNonce}}"></script>
|
||
<script nonce="{{.CSPNonce}}">
|
||
(function() {
|
||
var topBtn = document.getElementById('floatTopBtn');
|
||
var commentBtn = document.getElementById('floatCommentBtn');
|
||
var comments = document.getElementById('comments');
|
||
var nav = document.querySelector('nav');
|
||
var navHeight = nav ? nav.offsetHeight : 60;
|
||
|
||
// 回顶部:页面顶部时隐藏按钮
|
||
function toggleTopBtn() {
|
||
if (!topBtn) return;
|
||
if (window.scrollY > 300) {
|
||
topBtn.style.display = '';
|
||
} else {
|
||
topBtn.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
window.addEventListener('scroll', toggleTopBtn);
|
||
toggleTopBtn();
|
||
|
||
if (topBtn) {
|
||
topBtn.addEventListener('click', function() {
|
||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||
});
|
||
}
|
||
|
||
// 评论按钮:滚动到评论区域顶部(NAV 下方)
|
||
if (commentBtn && comments) {
|
||
commentBtn.addEventListener('click', function() {
|
||
var rect = comments.getBoundingClientRect();
|
||
var scrollTop = window.scrollY + rect.top - navHeight - 12;
|
||
window.scrollTo({ top: scrollTop, behavior: 'smooth' });
|
||
});
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|