Files
jiang13-forum/embed_static/templates/post.html
freefire e1c1708715 初始提交:姜十三论坛 Jiang13 Forum
轻量自用论坛,Go 单二进制 + React SPA 内嵌 + SQLite。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 21:08:52 +08:00

73 lines
5.1 KiB
HTML

{{define "post.html"}}{{template "layout" .}}{{end}}
{{define "content"}}
<nav aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="/">首页</a></li><li class="breadcrumb-item"><a href="/board/{{.Post.BoardID}}">{{.Post.Board.Name}}</a></li><li class="breadcrumb-item active">帖子</li></ol></nav>
<div class="card mb-4">
<div class="card-body">
<h3>{{if .Post.Pinned}}<span class="badge badge-pin me-1">置顶</span>{{end}}{{.Post.Title}}</h3>
<div class="small text-muted mb-3">
<a href="/user/{{.Post.UserID}}">{{.Post.User.Nickname}}</a> · {{.Post.CreatedAt.Format "2006-01-02 15:04"}} · 👁 {{.Post.ViewCount}}
{{if .Post.Tags}}· 标签:{{.Post.Tags}}{{end}}
</div>
<div class="post-content">{{safeHTML .Post.Content}}</div>
<div class="mt-3 d-flex gap-2 flex-wrap">
{{if .CurrentUser}}
<button class="btn btn-outline-primary btn-sm" id="likeBtn" onclick="toggleLike()">{{if .Liked}}已点赞{{else}}点赞{{end}}</button>
<button class="btn btn-outline-warning btn-sm" id="favBtn" onclick="toggleFav()">{{if .Favorited}}已收藏{{else}}收藏{{end}}</button>
{{if or (eq .CurrentUserID .Post.UserID) .IsAdmin}}
<a href="/post/{{.Post.ID}}/edit" class="btn btn-outline-secondary btn-sm">编辑</a>
<button class="btn btn-outline-danger btn-sm" onclick="deletePost()">删除</button>
{{end}}
{{if .IsAdmin}}
<button class="btn btn-outline-dark btn-sm" onclick="pinPost()">{{if .Post.Pinned}}取消置顶{{else}}置顶{{end}}</button>
{{end}}
{{else}}<a href="/login" class="btn btn-outline-primary btn-sm">登录后互动</a>{{end}}
</div>
</div>
</div>
<h5>评论 ({{len .Comments}})</h5>
{{range .Comments}}
<div class="card mb-2 comment-floor">
<div class="card-body py-2">
<div class="d-flex justify-content-between">
<strong>#{{.Floor}} {{.User.Nickname}}</strong>
<small class="text-muted">{{.CreatedAt.Format "01-02 15:04"}}</small>
</div>
{{if .ReplyUser}}<div class="small text-muted">回复 #{{.ReplyUser.Floor}} {{.ReplyUser.User.Nickname}}</div>{{end}}
<div class="mt-1">{{.Content}}</div>
{{if $.CurrentUser}}
<button class="btn btn-link btn-sm p-0" onclick="replyTo({{.ID}},{{.Floor}},'{{.User.Nickname}}')">回复</button>
{{if or (eq $.CurrentUserID .UserID) $.IsAdmin}}
<button class="btn btn-link btn-sm p-0 text-danger" onclick="deleteComment({{.ID}})">删除</button>
{{end}}
{{end}}
</div>
</div>
{{end}}
{{if .CurrentUser}}
<div class="card mt-3">
<div class="card-body">
<form id="commentForm">
<div id="replyHint" class="small text-muted mb-2" style="display:none"></div>
<input type="hidden" name="reply_to" id="replyTo">
<textarea name="content" class="form-control mb-2" rows="3" placeholder="写下你的评论..." required></textarea>
<button type="submit" class="btn btn-success btn-sm">发表评论</button>
<button type="button" class="btn btn-secondary btn-sm" onclick="cancelReply()" id="cancelReplyBtn" style="display:none">取消回复</button>
</form>
</div>
</div>
{{end}}
{{end}}
{{define "scripts"}}
<script>
const postId={{.Post.ID}};
function toggleLike(){ fetch('/api/posts/'+postId+'/like',{method:'POST',credentials:'same-origin'}).then(r=>r.json()).then(d=>{ if(d.error){showToast(d.error,'danger');return;} document.getElementById('likeBtn').textContent=d.liked?'已点赞':'点赞'; }); }
function toggleFav(){ fetch('/api/posts/'+postId+'/favorite',{method:'POST',credentials:'same-origin'}).then(r=>r.json()).then(d=>{ if(d.error){showToast(d.error,'danger');return;} document.getElementById('favBtn').textContent=d.favorited?'已收藏':'收藏'; }); }
function deletePost(){ confirmAction('确定删除此帖?',()=>{ fetch('/api/posts/'+postId,{method:'DELETE',credentials:'same-origin'}).then(r=>r.json()).then(d=>{ if(d.error){showToast(d.error,'danger');return;} location.href='/board/{{.Post.BoardID}}'; }); }); }
function pinPost(){ fetch('/admin/api/posts/'+postId+'/pin',{method:'POST',credentials:'same-origin',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'pinned={{if .Post.Pinned}}false{{else}}true{{end}}'}).then(r=>r.json()).then(()=>location.reload()); }
function replyTo(id,floor,name){ document.getElementById('replyTo').value=id; document.getElementById('replyHint').style.display='block'; document.getElementById('replyHint').textContent='回复 #'+floor+' '+name; document.getElementById('cancelReplyBtn').style.display='inline-block'; }
function cancelReply(){ document.getElementById('replyTo').value=''; document.getElementById('replyHint').style.display='none'; document.getElementById('cancelReplyBtn').style.display='none'; }
function deleteComment(id){ confirmAction('确定删除?',()=>{ fetch('/api/comments/'+id,{method:'DELETE',credentials:'same-origin'}).then(()=>location.reload()); }); }
document.getElementById('commentForm')?.addEventListener('submit',function(e){ e.preventDefault(); apiPost('/api/posts/'+postId+'/comments',this,true).then(d=>{ if(d.error){showToast(d.error,'danger');return;} location.reload(); }); });
</script>
{{end}}