feat: opaque session、安装/发帖 SSR 与最小 Admin 后台
浏览器登录改为 DB sessions(可吊销);敏感词与 OIDC PEM 入 settings; 落地安装向导、注册发帖与 /admin 仪表盘/板块/审核/设置。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
47
templates/admin/boards.tmpl
Normal file
47
templates/admin/boards.tmpl
Normal file
@@ -0,0 +1,47 @@
|
||||
{{define "admin/boards"}}
|
||||
{{template "base/head" .}}
|
||||
{{template "base/navbar" .}}
|
||||
<main class="j13-main j13-admin">
|
||||
<h1>板块管理</h1>
|
||||
{{template "admin/nav" .}}
|
||||
{{template "base/alert" .}}
|
||||
|
||||
<h2>新建板块</h2>
|
||||
<form method="post" action="/admin/boards" class="j13-form j13-admin-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<label>名称 <input name="name" required value="{{.Form.Name}}"/></label>
|
||||
<label>简介 <input name="description" value="{{.Form.Description}}"/></label>
|
||||
<label>图标(可选) <input name="icon" value="{{.Form.Icon}}"/></label>
|
||||
<label>色号 <input name="color_index" type="number" value="{{.Form.ColorIndex}}"/></label>
|
||||
<label>排序 <input name="sort_order" type="number" value="{{.Form.SortOrder}}"/></label>
|
||||
<button type="submit">创建</button>
|
||||
</form>
|
||||
|
||||
<h2>已有板块</h2>
|
||||
{{if .Boards}}
|
||||
<ul class="j13-admin-list">
|
||||
{{range .Boards}}
|
||||
<li class="j13-admin-card">
|
||||
<form method="post" action="/admin/boards/{{.ID}}" class="j13-form j13-admin-form">
|
||||
<input type="hidden" name="_csrf" value="{{$.CSRF}}"/>
|
||||
<label>名称 <input name="name" required value="{{.Name}}"/></label>
|
||||
<label>简介 <input name="description" value="{{.Description}}"/></label>
|
||||
<label>图标 <input name="icon" value="{{.Icon}}"/></label>
|
||||
<label>色号 <input name="color_index" type="number" value="{{.ColorIndex}}"/></label>
|
||||
<label>排序 <input name="sort_order" type="number" value="{{.SortOrder}}"/></label>
|
||||
<p class="j13-muted">已发布帖 {{.PostCount}}</p>
|
||||
<button type="submit">保存</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/boards/{{.ID}}/delete" class="j13-inline-form" onsubmit="return confirm('确认删除该板块?');">
|
||||
<input type="hidden" name="_csrf" value="{{$.CSRF}}"/>
|
||||
<button type="submit" class="j13-linkbtn">删除</button>
|
||||
</form>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p class="j13-empty">暂无板块</p>
|
||||
{{end}}
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
18
templates/admin/dashboard.tmpl
Normal file
18
templates/admin/dashboard.tmpl
Normal file
@@ -0,0 +1,18 @@
|
||||
{{define "admin/dashboard"}}
|
||||
{{template "base/head" .}}
|
||||
{{template "base/navbar" .}}
|
||||
<main class="j13-main j13-admin">
|
||||
<h1>管理后台</h1>
|
||||
{{template "admin/nav" .}}
|
||||
{{template "base/alert" .}}
|
||||
<ul class="j13-admin-stats">
|
||||
<li><strong>{{.UserCount}}</strong><span>用户</span></li>
|
||||
<li><strong>{{.PostCount}}</strong><span>已发布帖</span></li>
|
||||
<li><strong>{{.BoardCount}}</strong><span>板块</span></li>
|
||||
<li><strong>{{.PendingPosts}}</strong><span>待审帖</span></li>
|
||||
<li><strong>{{.PendingComments}}</strong><span>待审评</span></li>
|
||||
</ul>
|
||||
<p class="j13-muted">有待审内容时请前往 <a href="/admin/moderation">内容审核</a>。</p>
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
60
templates/admin/moderation.tmpl
Normal file
60
templates/admin/moderation.tmpl
Normal file
@@ -0,0 +1,60 @@
|
||||
{{define "admin/moderation"}}
|
||||
{{template "base/head" .}}
|
||||
{{template "base/navbar" .}}
|
||||
<main class="j13-main j13-admin">
|
||||
<h1>内容审核</h1>
|
||||
{{template "admin/nav" .}}
|
||||
{{template "base/alert" .}}
|
||||
|
||||
<h2>待审帖子({{len .Posts}})</h2>
|
||||
{{if .Posts}}
|
||||
<ul class="j13-admin-list">
|
||||
{{range .Posts}}
|
||||
<li class="j13-admin-card">
|
||||
<p><a href="/post/{{.ID}}">{{.Title}}</a></p>
|
||||
<p class="j13-muted">{{.AuthorName}} · {{.BoardName}} · {{.CreatedAt}}</p>
|
||||
<div class="j13-admin-actions">
|
||||
<form method="post" action="/admin/posts/{{.ID}}/approve" class="j13-inline-form">
|
||||
<input type="hidden" name="_csrf" value="{{$.CSRF}}"/>
|
||||
<button type="submit">通过</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/posts/{{.ID}}/reject" class="j13-form j13-admin-reject">
|
||||
<input type="hidden" name="_csrf" value="{{$.CSRF}}"/>
|
||||
<input name="reason" required placeholder="拒绝原因" />
|
||||
<button type="submit" class="j13-btn-secondary">拒绝</button>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p class="j13-empty">无待审帖子</p>
|
||||
{{end}}
|
||||
|
||||
<h2>待审评论({{len .Comments}})</h2>
|
||||
{{if .Comments}}
|
||||
<ul class="j13-admin-list">
|
||||
{{range .Comments}}
|
||||
<li class="j13-admin-card">
|
||||
<p class="j13-muted">#{{.Floor}} · {{.AuthorName}} · {{.CreatedAt}} · <a href="/post/{{.PostID}}">{{.PostTitle}}</a></p>
|
||||
<p>{{.Excerpt}}</p>
|
||||
<div class="j13-admin-actions">
|
||||
<form method="post" action="/admin/comments/{{.ID}}/approve" class="j13-inline-form">
|
||||
<input type="hidden" name="_csrf" value="{{$.CSRF}}"/>
|
||||
<button type="submit">通过</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/comments/{{.ID}}/reject" class="j13-form j13-admin-reject">
|
||||
<input type="hidden" name="_csrf" value="{{$.CSRF}}"/>
|
||||
<input name="reason" required placeholder="拒绝原因" />
|
||||
<button type="submit" class="j13-btn-secondary">拒绝</button>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p class="j13-empty">无待审评论</p>
|
||||
{{end}}
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
9
templates/admin/nav.tmpl
Normal file
9
templates/admin/nav.tmpl
Normal file
@@ -0,0 +1,9 @@
|
||||
{{define "admin/nav"}}
|
||||
<nav class="j13-admin-nav">
|
||||
<a href="/admin/dashboard"{{if eq .NavActive "dashboard"}} class="is-active"{{end}}>仪表盘</a>
|
||||
<a href="/admin/boards"{{if eq .NavActive "boards"}} class="is-active"{{end}}>板块</a>
|
||||
<a href="/admin/moderation"{{if eq .NavActive "moderation"}} class="is-active"{{end}}>审核</a>
|
||||
<a href="/admin/settings"{{if eq .NavActive "settings"}} class="is-active"{{end}}>设置</a>
|
||||
<a href="/">返回前台</a>
|
||||
</nav>
|
||||
{{end}}
|
||||
43
templates/admin/settings.tmpl
Normal file
43
templates/admin/settings.tmpl
Normal file
@@ -0,0 +1,43 @@
|
||||
{{define "admin/settings"}}
|
||||
{{template "base/head" .}}
|
||||
{{template "base/navbar" .}}
|
||||
<main class="j13-main j13-admin">
|
||||
<h1>站点设置</h1>
|
||||
{{template "admin/nav" .}}
|
||||
{{template "base/alert" .}}
|
||||
|
||||
<h2>品牌</h2>
|
||||
<form method="post" action="/admin/settings/brand" class="j13-form j13-admin-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<label>站点名称 <input name="name" required value="{{.Brand.Name}}"/></label>
|
||||
<label>标语 <input name="slogan" value="{{.Brand.Slogan}}"/></label>
|
||||
<label>简介 <textarea name="description" rows="3">{{.Brand.Description}}</textarea></label>
|
||||
<label>关键词 <input name="keywords" value="{{.Brand.Keywords}}"/></label>
|
||||
<label>Logo 字标(单字) <input name="logo_mark" maxlength="4" value="{{.Brand.LogoMark}}"/></label>
|
||||
<label>ICP 备案号 <input name="icp_beian" value="{{.Brand.ICPBeian}}"/></label>
|
||||
<label>ICP 链接 <input name="icp_beian_url" value="{{.Brand.ICPBeianURL}}"/></label>
|
||||
<button type="submit">保存品牌</button>
|
||||
</form>
|
||||
|
||||
<h2>基础限流</h2>
|
||||
<p class="j13-muted">窗口内允许的操作次数(秒)。</p>
|
||||
<form method="post" action="/admin/settings/limits" class="j13-form j13-admin-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<label>发帖 <input name="rate_limit_post" type="number" min="1" value="{{.RatePost}}"/></label>
|
||||
<label>评论 <input name="rate_limit_comment" type="number" min="1" value="{{.RateComment}}"/></label>
|
||||
<label>注册 <input name="rate_limit_register" type="number" min="1" value="{{.RateReg}}"/></label>
|
||||
<label>登录 <input name="rate_limit_login" type="number" min="1" value="{{.RateLogin}}"/></label>
|
||||
<label>窗口秒数 <input name="rate_limit_window_sec" type="number" min="10" value="{{.RateWindow}}"/></label>
|
||||
<button type="submit">保存限流</button>
|
||||
</form>
|
||||
|
||||
<h2>敏感词(有效 {{.FilterCount}} 个)</h2>
|
||||
<p class="j13-muted">每行一个词,# 开头为注释。保存后立即热更新。</p>
|
||||
<form method="post" action="/admin/settings/filter-words" class="j13-form j13-admin-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<label>词表 <textarea name="filter_words" rows="12">{{.FilterWords}}</textarea></label>
|
||||
<button type="submit">保存敏感词</button>
|
||||
</form>
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
20
templates/auth/login.tmpl
Normal file
20
templates/auth/login.tmpl
Normal file
@@ -0,0 +1,20 @@
|
||||
{{define "auth/login"}}
|
||||
{{template "base/head" .}}
|
||||
<main class="j13-main j13-main--solo j13-auth">
|
||||
<h1>登录</h1>
|
||||
{{template "base/alert" .}}
|
||||
<form method="post" action="/login" class="j13-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<input type="hidden" name="redirect" value="{{.Redirect}}"/>
|
||||
<label>用户名
|
||||
<input name="username" required autocomplete="username" value="{{.Username}}"/>
|
||||
</label>
|
||||
<label>密码
|
||||
<input type="password" name="password" required autocomplete="current-password"/>
|
||||
</label>
|
||||
<button type="submit">登录</button>
|
||||
</form>
|
||||
<p><a href="/register">没有账号?注册</a> · <a href="/">返回首页</a></p>
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
39
templates/auth/register.tmpl
Normal file
39
templates/auth/register.tmpl
Normal file
@@ -0,0 +1,39 @@
|
||||
{{define "auth/register"}}
|
||||
{{template "base/head" .}}
|
||||
<main class="j13-main j13-main--solo j13-auth">
|
||||
<h1>注册</h1>
|
||||
{{template "base/alert" .}}
|
||||
<form method="post" action="/register" class="j13-form" id="register-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<label>用户名
|
||||
<input name="username" required autocomplete="username" value="{{.Username}}" maxlength="32"/>
|
||||
</label>
|
||||
<label>昵称
|
||||
<input name="nickname" autocomplete="nickname" value="{{.Nickname}}" maxlength="32" placeholder="可选,默认与用户名相同"/>
|
||||
</label>
|
||||
<label>邮箱
|
||||
<input type="email" name="email" required autocomplete="email" value="{{.Email}}"/>
|
||||
</label>
|
||||
{{if .RequireEmailCode}}
|
||||
<label>邮箱验证码
|
||||
<div class="j13-form__row">
|
||||
<input name="email_code" required inputmode="numeric" autocomplete="one-time-code" maxlength="8"/>
|
||||
<button type="submit" formaction="/register/send-code" formnovalidate class="j13-btn-secondary">发送验证码</button>
|
||||
</div>
|
||||
</label>
|
||||
<p class="j13-muted">邮件服务已启用,注册需验证邮箱。</p>
|
||||
{{else}}
|
||||
<p class="j13-muted">邮件服务未配置,可直接注册(管理员可稍后在后台启用 SMTP)。</p>
|
||||
{{end}}
|
||||
<label>密码
|
||||
<input type="password" name="password" required autocomplete="new-password" minlength="6"/>
|
||||
</label>
|
||||
<label>确认密码
|
||||
<input type="password" name="password2" required autocomplete="new-password" minlength="6"/>
|
||||
</label>
|
||||
<button type="submit">注册</button>
|
||||
</form>
|
||||
<p><a href="/login">已有账号?登录</a> · <a href="/">返回首页</a></p>
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
@@ -1,51 +0,0 @@
|
||||
{{define "base"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>{{.Title}}</title>
|
||||
{{if .Description}}<meta name="description" content="{{.Description}}"/>{{end}}
|
||||
<link rel="stylesheet" href="/ssr-assets/site.css"/>
|
||||
</head>
|
||||
<body class="j13-body">
|
||||
<header class="j13-header">
|
||||
<div class="j13-header__inner">
|
||||
<a class="j13-brand" href="/">
|
||||
<span class="j13-brand__mark">{{.LogoMark}}</span>
|
||||
<span class="j13-brand__text">
|
||||
<strong>{{.SiteName}}</strong>
|
||||
{{if .Slogan}}<span class="j13-brand__slogan">{{.Slogan}}</span>{{end}}
|
||||
</span>
|
||||
</a>
|
||||
<nav class="j13-nav">
|
||||
{{if .LoggedIn}}
|
||||
<a href="/compose">发帖</a>
|
||||
<a href="/messages">消息</a>
|
||||
<a href="/profile">{{.ViewerName}}</a>
|
||||
{{if .IsAdmin}}<a href="/admin/dashboard">后台</a>{{end}}
|
||||
{{else}}
|
||||
<a href="/login">登录</a>
|
||||
<a href="/register">注册</a>
|
||||
{{end}}
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<div class="j13-layout">
|
||||
<aside class="j13-aside j13-aside--left">
|
||||
<a class="j13-aside__link{{if eq .ActiveBoard 0}} is-active{{end}}" href="/">全部帖子</a>
|
||||
{{range .Boards}}
|
||||
<a class="j13-aside__link{{if eq $.ActiveBoard .ID}} is-active{{end}}" href="/board/{{.ID}}">{{.Name}}</a>
|
||||
{{end}}
|
||||
</aside>
|
||||
<main class="j13-main">
|
||||
{{template "content" .}}
|
||||
</main>
|
||||
</div>
|
||||
<footer class="j13-footer">
|
||||
<p>{{.SiteName}} · Gitea 式 SSR 骨架</p>
|
||||
</footer>
|
||||
<script src="/ssr-assets/site.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
4
templates/base/alert.tmpl
Normal file
4
templates/base/alert.tmpl
Normal file
@@ -0,0 +1,4 @@
|
||||
{{define "base/alert"}}
|
||||
{{if .Error}}<div class="j13-alert j13-alert--error" role="alert">{{.Error}}</div>{{end}}
|
||||
{{if .Flash}}<div class="j13-flash" role="status">{{.Flash}}</div>{{end}}
|
||||
{{end}}
|
||||
8
templates/base/footer.tmpl
Normal file
8
templates/base/footer.tmpl
Normal file
@@ -0,0 +1,8 @@
|
||||
{{define "base/footer"}}
|
||||
<footer class="j13-footer">
|
||||
<p>{{.SiteName}}</p>
|
||||
</footer>
|
||||
<script src="/ssr-assets/site.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
12
templates/base/head.tmpl
Normal file
12
templates/base/head.tmpl
Normal file
@@ -0,0 +1,12 @@
|
||||
{{define "base/head"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>{{.Title}}</title>
|
||||
{{if .Description}}<meta name="description" content="{{.Description}}"/>{{end}}
|
||||
<link rel="stylesheet" href="/ssr-assets/site.css"/>
|
||||
</head>
|
||||
<body class="j13-body">
|
||||
{{end}}
|
||||
27
templates/base/navbar.tmpl
Normal file
27
templates/base/navbar.tmpl
Normal file
@@ -0,0 +1,27 @@
|
||||
{{define "base/navbar"}}
|
||||
<header class="j13-header">
|
||||
<div class="j13-header__inner">
|
||||
<a class="j13-brand" href="/">
|
||||
<span class="j13-brand__mark">{{.LogoMark}}</span>
|
||||
<span class="j13-brand__text">
|
||||
<strong>{{.SiteName}}</strong>
|
||||
{{if .Slogan}}<span class="j13-brand__slogan">{{.Slogan}}</span>{{end}}
|
||||
</span>
|
||||
</a>
|
||||
<nav class="j13-nav">
|
||||
{{if .LoggedIn}}
|
||||
<a href="/compose">发帖</a>
|
||||
<a href="/profile">{{.ViewerName}}</a>
|
||||
{{if .IsAdmin}}<a href="/admin/dashboard">后台</a>{{end}}
|
||||
<form class="j13-inline-form" method="post" action="/logout">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<button type="submit" class="j13-linkbtn">退出</button>
|
||||
</form>
|
||||
{{else}}
|
||||
<a href="/register">注册</a>
|
||||
<a href="/login">登录</a>
|
||||
{{end}}
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
{{end}}
|
||||
39
templates/compose.tmpl
Normal file
39
templates/compose.tmpl
Normal file
@@ -0,0 +1,39 @@
|
||||
{{define "compose"}}
|
||||
{{template "base/head" .}}
|
||||
{{template "base/navbar" .}}
|
||||
{{if .Flash}}<div class="j13-flash" role="status">{{.Flash}}</div>{{end}}
|
||||
<main class="j13-main j13-main--solo j13-compose">
|
||||
<h1>{{if .IsEdit}}编辑帖子{{else}}发帖{{end}}</h1>
|
||||
{{template "base/alert" .}}
|
||||
<form method="post" action="{{.FormAction}}" class="j13-form" id="compose-form" data-csrf="{{.CSRF}}" data-upload="/compose/upload">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<label>板块
|
||||
<select name="board_id" required>
|
||||
<option value="">请选择</option>
|
||||
{{range .Boards}}
|
||||
<option value="{{.ID}}" {{if eq $.BoardID .ID}}selected{{end}}>{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</label>
|
||||
<label>标题
|
||||
<input name="title" required maxlength="{{.TitleMax}}" value="{{.Title}}"/>
|
||||
</label>
|
||||
<label>标签
|
||||
<input name="tags" maxlength="{{.TagsMax}}" value="{{.Tags}}" placeholder="逗号分隔,可选"/>
|
||||
</label>
|
||||
<label>正文
|
||||
<textarea name="content" id="compose-content" rows="16" required maxlength="{{.ContentMax}}" placeholder="支持纯文本;图片上传后插入 Markdown 图片语法">{{.Content}}</textarea>
|
||||
</label>
|
||||
<div class="j13-compose__tools">
|
||||
<label class="j13-btn-secondary j13-filebtn">
|
||||
插入图片
|
||||
<input type="file" id="compose-image" accept="image/*" hidden/>
|
||||
</label>
|
||||
<span class="j13-muted" id="compose-upload-status"></span>
|
||||
</div>
|
||||
<p class="j13-muted">本版仅发普通讨论帖;投票 / 悬赏 / 抽奖后续迭代。</p>
|
||||
<button type="submit">{{if .IsEdit}}保存{{else}}发布{{end}}</button>
|
||||
</form>
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
@@ -2,5 +2,5 @@ package templates
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed *.tmpl
|
||||
//go:embed *.tmpl base/*.tmpl home/*.tmpl post/*.tmpl shared/*.tmpl status/*.tmpl auth/*.tmpl admin/*.tmpl
|
||||
var FS embed.FS
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
{{define "home"}}{{template "base" .}}{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
{{define "home/feed"}}
|
||||
<section class="j13-feed">
|
||||
<header class="j13-feed__header">
|
||||
<h1 class="j13-feed__title">{{if .BoardName}}{{.BoardName}}{{else}}全部帖子{{end}}</h1>
|
||||
@@ -10,14 +8,13 @@
|
||||
<a class="{{if eq .Sort "hot"}}is-active{{end}}" href="{{sortURL .ActiveBoard "hot"}}">热门讨论</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{if not .Posts}}
|
||||
<p class="j13-empty">暂无帖子。登录后可以发第一帖。</p>
|
||||
<p class="j13-empty">暂无帖子。</p>
|
||||
{{else}}
|
||||
<ul class="j13-post-list">
|
||||
{{range .Posts}}
|
||||
<li class="j13-post-item">
|
||||
<a class="j13-post-item__title" href="/post/{{.ID}}">{{.Title}}</a>
|
||||
<a class="j13-post-item__title" href="{{postURL .ID}}">{{.Title}}</a>
|
||||
<div class="j13-post-item__meta">
|
||||
{{if .Pinned}}<span class="j13-tag j13-tag--pin">置顶</span>{{end}}
|
||||
{{if .Featured}}<span class="j13-tag j13-tag--feat">精华</span>{{end}}
|
||||
@@ -30,7 +27,6 @@
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
|
||||
{{if or .HasPrev .HasMore}}
|
||||
<nav class="j13-pager">
|
||||
{{if .HasPrev}}<a href="{{pageURL .ActiveBoard .Sort .PrevPage}}">上一页</a>{{end}}
|
||||
12
templates/home/home.tmpl
Normal file
12
templates/home/home.tmpl
Normal file
@@ -0,0 +1,12 @@
|
||||
{{define "home"}}
|
||||
{{template "base/head" .}}
|
||||
{{template "base/navbar" .}}
|
||||
{{if .Flash}}<div class="j13-flash" role="status">{{.Flash}}</div>{{end}}
|
||||
<div class="j13-layout">
|
||||
{{template "shared/board_aside" .}}
|
||||
<main class="j13-main">
|
||||
{{template "home/feed" .}}
|
||||
</main>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
37
templates/install.tmpl
Normal file
37
templates/install.tmpl
Normal file
@@ -0,0 +1,37 @@
|
||||
{{define "install"}}
|
||||
{{template "base/head" .}}
|
||||
<main class="j13-main j13-main--solo j13-install">
|
||||
<h1>安装姜十三论坛</h1>
|
||||
<p class="j13-muted">首次运行配置站点与管理员账号。</p>
|
||||
{{template "base/alert" .}}
|
||||
<form method="post" action="/install" class="j13-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<fieldset>
|
||||
<legend>站点</legend>
|
||||
<label>站点名称
|
||||
<input name="site_name" required value="{{.SiteName}}" maxlength="64"/>
|
||||
</label>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>管理员</legend>
|
||||
<label>用户名
|
||||
<input name="admin_username" required autocomplete="username" value="{{.AdminUsername}}" pattern="[a-zA-Z0-9_]{3,32}"/>
|
||||
</label>
|
||||
<label>邮箱
|
||||
<input type="email" name="admin_email" required autocomplete="email" value="{{.AdminEmail}}"/>
|
||||
</label>
|
||||
<label>昵称
|
||||
<input name="admin_nickname" value="{{.AdminNickname}}" maxlength="32"/>
|
||||
</label>
|
||||
<label>密码
|
||||
<input type="password" name="admin_password" required autocomplete="new-password" minlength="6"/>
|
||||
</label>
|
||||
<label>确认密码
|
||||
<input type="password" name="admin_password2" required autocomplete="new-password" minlength="6"/>
|
||||
</label>
|
||||
</fieldset>
|
||||
<button type="submit">安装</button>
|
||||
</form>
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
10
templates/post-install.tmpl
Normal file
10
templates/post-install.tmpl
Normal file
@@ -0,0 +1,10 @@
|
||||
{{define "post-install"}}
|
||||
{{template "base/head" .}}
|
||||
<main class="j13-main j13-main--solo j13-install">
|
||||
<h1>安装完成</h1>
|
||||
<p>站点已就绪,正在进入论坛…</p>
|
||||
<p><a href="/">立即进入</a></p>
|
||||
<meta http-equiv="refresh" content="2;url=/"/>
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
69
templates/post/body.tmpl
Normal file
69
templates/post/body.tmpl
Normal file
@@ -0,0 +1,69 @@
|
||||
{{define "post/body"}}
|
||||
<article class="j13-post">
|
||||
<header class="j13-post__header">
|
||||
<h1 class="j13-post__title">{{.PostTitle}}</h1>
|
||||
<div class="j13-post__meta">
|
||||
{{if .Pinned}}<span class="j13-tag j13-tag--pin">置顶</span>{{end}}
|
||||
{{if .Featured}}<span class="j13-tag j13-tag--feat">精华</span>{{end}}
|
||||
{{if .PostTypeLabel}}<span class="j13-tag">{{.PostTypeLabel}}</span>{{end}}
|
||||
{{if .BoardName}}<a class="j13-tag" href="/board/{{.BoardID}}">{{.BoardName}}</a>{{end}}
|
||||
<span>{{.AuthorName}}</span>
|
||||
<span>{{.CreatedLabel}}</span>
|
||||
<span>{{.ViewCount}} 阅读</span>
|
||||
</div>
|
||||
{{if .LoggedIn}}
|
||||
<div class="j13-post__actions">
|
||||
<form method="post" action="/post/{{.PostID}}/like" class="j13-inline-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<button type="submit">{{if .Liked}}取消赞{{else}}赞{{end}} ({{.LikeCount}})</button>
|
||||
</form>
|
||||
<form method="post" action="/post/{{.PostID}}/favorite" class="j13-inline-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<button type="submit">{{if .Favorited}}取消收藏{{else}}收藏{{end}}</button>
|
||||
</form>
|
||||
{{if .CanEdit}}<a class="j13-linkbtn" href="/post/{{.PostID}}/edit">编辑</a>{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</header>
|
||||
<div class="j13-post__content post-detail-content">{{safeHTML .BodyHTML}}</div>
|
||||
</article>
|
||||
|
||||
<section class="j13-comments" id="comments">
|
||||
<h2>评论 ({{.CommentCount}})</h2>
|
||||
{{if not .Comments}}
|
||||
<p class="j13-empty">暂无评论。</p>
|
||||
{{else}}
|
||||
<ul class="j13-comment-list">
|
||||
{{range .Comments}}
|
||||
<li class="j13-comment" id="floor-{{.Floor}}">
|
||||
<div class="j13-comment__meta">
|
||||
<span class="j13-comment__floor">#{{.Floor}}</span>
|
||||
<span>{{.AuthorName}}</span>
|
||||
<span>{{.CreatedLabel}}</span>
|
||||
</div>
|
||||
{{if .ContentHidden}}
|
||||
<p class="j13-muted">(私密评论不可见)</p>
|
||||
{{else}}
|
||||
<div class="j13-comment__body">{{safeHTML .Content}}</div>
|
||||
{{end}}
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
|
||||
{{if .LoggedIn}}
|
||||
{{if .CommentsLocked}}
|
||||
<p class="j13-muted">评论已锁定。</p>
|
||||
{{else}}
|
||||
<form class="j13-comment-form" method="post" action="/post/{{.PostID}}/comments">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<label for="comment-content">发表评论</label>
|
||||
<textarea id="comment-content" name="content" rows="4" required maxlength="8000"></textarea>
|
||||
<button type="submit">提交</button>
|
||||
</form>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<p><a href="/login?redirect={{.PostPath}}">登录</a> 后回复。</p>
|
||||
{{end}}
|
||||
</section>
|
||||
{{end}}
|
||||
12
templates/post/view.tmpl
Normal file
12
templates/post/view.tmpl
Normal file
@@ -0,0 +1,12 @@
|
||||
{{define "post"}}
|
||||
{{template "base/head" .}}
|
||||
{{template "base/navbar" .}}
|
||||
{{if .Flash}}<div class="j13-flash" role="status">{{.Flash}}</div>{{end}}
|
||||
<div class="j13-layout">
|
||||
{{template "shared/board_aside" .}}
|
||||
<main class="j13-main">
|
||||
{{template "post/body" .}}
|
||||
</main>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
8
templates/shared/board_aside.tmpl
Normal file
8
templates/shared/board_aside.tmpl
Normal file
@@ -0,0 +1,8 @@
|
||||
{{define "shared/board_aside"}}
|
||||
<aside class="j13-aside j13-aside--left">
|
||||
<a class="j13-aside__link{{if eq .ActiveBoard 0}} is-active{{end}}" href="/">全部帖子</a>
|
||||
{{range .Boards}}
|
||||
<a class="j13-aside__link{{if eq $.ActiveBoard .ID}} is-active{{end}}" href="/board/{{.ID}}">{{.Name}}</a>
|
||||
{{end}}
|
||||
</aside>
|
||||
{{end}}
|
||||
21
templates/status/404.tmpl
Normal file
21
templates/status/404.tmpl
Normal file
@@ -0,0 +1,21 @@
|
||||
{{define "status/404"}}
|
||||
{{template "base/head" .}}
|
||||
{{template "base/navbar" .}}
|
||||
<main class="j13-main j13-main--solo">
|
||||
<h1>页面不存在</h1>
|
||||
<p>您访问的页面不存在或已删除。</p>
|
||||
<p><a href="/">返回首页</a></p>
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
|
||||
{{define "status/pending"}}
|
||||
{{template "base/head" .}}
|
||||
{{template "base/navbar" .}}
|
||||
<main class="j13-main j13-main--solo">
|
||||
<h1>{{.Heading}}</h1>
|
||||
<p>{{.Message}}</p>
|
||||
<p><a href="/">返回首页</a></p>
|
||||
</main>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user