详情 模板
This commit is contained in:
parent
dce85a16be
commit
78a9262e06
@ -3,8 +3,77 @@ package common
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github/fthvgb1/wp-go/models"
|
"github/fthvgb1/wp-go/models"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var PostsCache sync.Map
|
||||||
|
|
||||||
|
func GetPostFromCache(Id uint64) (r models.WpPosts) {
|
||||||
|
p, ok := PostsCache.Load(Id)
|
||||||
|
if ok {
|
||||||
|
r = *p.(*models.WpPosts)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func QueryAndSetPostCache(postIds []models.WpPosts) (err error) {
|
||||||
|
var all []uint64
|
||||||
|
var needQuery []interface{}
|
||||||
|
for _, wpPosts := range postIds {
|
||||||
|
all = append(all, wpPosts.Id)
|
||||||
|
if _, ok := PostsCache.Load(wpPosts.Id); !ok {
|
||||||
|
needQuery = append(needQuery, wpPosts.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(needQuery) > 0 {
|
||||||
|
rawPosts, er := models.Find[models.WpPosts](models.SqlBuilder{{
|
||||||
|
"Id", "in", "",
|
||||||
|
}}, "a.*,ifnull(d.name,'') category_name,ifnull(taxonomy,'') `taxonomy`", "", nil, models.SqlBuilder{{
|
||||||
|
"a", "left join", "wp_term_relationships b", "a.Id=b.object_id",
|
||||||
|
}, {
|
||||||
|
"left join", "wp_term_taxonomy c", "b.term_taxonomy_id=c.term_taxonomy_id",
|
||||||
|
}, {
|
||||||
|
"left join", "wp_terms d", "c.term_id=d.term_id",
|
||||||
|
}}, 0, needQuery)
|
||||||
|
if er != nil {
|
||||||
|
err = er
|
||||||
|
return
|
||||||
|
}
|
||||||
|
postsMap := make(map[uint64]*models.WpPosts)
|
||||||
|
for i, post := range rawPosts {
|
||||||
|
v, ok := postsMap[post.Id]
|
||||||
|
if !ok {
|
||||||
|
v = &rawPosts[i]
|
||||||
|
}
|
||||||
|
if post.Taxonomy == "category" {
|
||||||
|
v.Categories = append(v.Categories, post.CategoryName)
|
||||||
|
} else if post.Taxonomy == "post_tag" {
|
||||||
|
v.Tags = append(v.Tags, post.CategoryName)
|
||||||
|
}
|
||||||
|
postsMap[post.Id] = v
|
||||||
|
}
|
||||||
|
for _, pp := range postsMap {
|
||||||
|
if len(pp.Categories) > 0 {
|
||||||
|
t := make([]string, 0, len(pp.Categories))
|
||||||
|
for _, cat := range pp.Categories {
|
||||||
|
t = append(t, fmt.Sprintf(`<a href="/p/category/%s" rel="category tag">%s</a>`, cat, cat))
|
||||||
|
}
|
||||||
|
pp.CategoriesHtml = strings.Join(t, "、")
|
||||||
|
}
|
||||||
|
if len(pp.Tags) > 0 {
|
||||||
|
t := make([]string, 0, len(pp.Tags))
|
||||||
|
for _, cat := range pp.Tags {
|
||||||
|
t = append(t, fmt.Sprintf(`<a href="/p/tag/%s" rel="tag">%s</a>`, cat, cat))
|
||||||
|
}
|
||||||
|
pp.TagsHtml = strings.Join(t, "、")
|
||||||
|
}
|
||||||
|
PostsCache.Store(pp.Id, pp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func Archives() (r []models.PostArchive, err error) {
|
func Archives() (r []models.PostArchive, err error) {
|
||||||
r, err = models.Find[models.PostArchive](models.SqlBuilder{
|
r, err = models.Find[models.PostArchive](models.SqlBuilder{
|
||||||
{"post_type", "post"}, {"post_status", "publish"},
|
{"post_type", "post"}, {"post_status", "publish"},
|
||||||
@ -37,13 +106,21 @@ func RecentPosts() (r []models.WpPosts, err error) {
|
|||||||
r, err = models.Find[models.WpPosts](models.SqlBuilder{{
|
r, err = models.Find[models.WpPosts](models.SqlBuilder{{
|
||||||
"post_type", "post",
|
"post_type", "post",
|
||||||
}, {"post_status", "publish"}}, "ID,post_title,post_password", "", models.SqlBuilder{{"post_date", "desc"}}, nil, 5)
|
}, {"post_status", "publish"}}, "ID,post_title,post_password", "", models.SqlBuilder{{"post_date", "desc"}}, nil, 5)
|
||||||
|
for i, post := range r {
|
||||||
|
if post.PostPassword != "" {
|
||||||
|
PasswordProjectTitle(&r[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func PasswdProject(post *models.WpPosts) {
|
func PasswordProjectTitle(post *models.WpPosts) {
|
||||||
if post.PostTitle != "" {
|
if post.PostPassword != "" {
|
||||||
post.PostTitle = fmt.Sprintf("密码保护:%s", post.PostTitle)
|
post.PostTitle = fmt.Sprintf("密码保护:%s", post.PostTitle)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PasswdProjectContent(post *models.WpPosts) {
|
||||||
if post.PostContent != "" {
|
if post.PostContent != "" {
|
||||||
format := `
|
format := `
|
||||||
<form action="/login" class="post-password-form" method="post">
|
<form action="/login" class="post-password-form" method="post">
|
||||||
|
@ -1,7 +1,90 @@
|
|||||||
package actions
|
package actions
|
||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-contrib/sessions"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github/fthvgb1/wp-go/actions/common"
|
||||||
|
"github/fthvgb1/wp-go/models"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
func Detail(c *gin.Context) {
|
func Detail(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
var h = gin.H{}
|
||||||
|
var err error
|
||||||
|
defer func() {
|
||||||
|
c.HTML(http.StatusOK, "detail", h)
|
||||||
|
if err != nil {
|
||||||
|
c.Error(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
Id := 0
|
||||||
|
if id != "" {
|
||||||
|
Id, err = strconv.Atoi(id)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ID := uint64(Id)
|
||||||
|
post := common.GetPostFromCache(ID)
|
||||||
|
if post.Id == 0 {
|
||||||
|
er := common.QueryAndSetPostCache([]models.WpPosts{{Id: ID}})
|
||||||
|
if er != nil {
|
||||||
|
err = er
|
||||||
|
return
|
||||||
|
}
|
||||||
|
post = common.GetPostFromCache(ID)
|
||||||
|
if post.Id == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pw := sessions.Default(c).Get("post_password")
|
||||||
|
showComment := true
|
||||||
|
common.PasswordProjectTitle(&post)
|
||||||
|
if post.PostPassword != "" && pw != post.PostPassword {
|
||||||
|
common.PasswdProjectContent(&post)
|
||||||
|
showComment = false
|
||||||
|
}
|
||||||
|
recent, err := common.RecentPosts()
|
||||||
|
archive, err := common.Archives()
|
||||||
|
categoryItems, err := common.Categories()
|
||||||
|
canComment := false
|
||||||
|
if post.CommentStatus == "open" {
|
||||||
|
canComment = true
|
||||||
|
}
|
||||||
|
prev, err := models.FirstOne[models.WpPosts](models.SqlBuilder{
|
||||||
|
{"post_date", "<", post.PostDate.Format("2006-01-02 15:04:05")},
|
||||||
|
{"post_status", "publish"},
|
||||||
|
{"post_type", "post"},
|
||||||
|
}, "ID,post_title")
|
||||||
|
if prev.Id > 0 {
|
||||||
|
if _, ok := common.PostsCache.Load(prev.Id); !ok {
|
||||||
|
common.QueryAndSetPostCache([]models.WpPosts{prev})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next, err := models.FirstOne[models.WpPosts](models.SqlBuilder{
|
||||||
|
{"post_date", ">", post.PostDate.Format("2006-01-02 15:04:05")},
|
||||||
|
{"post_status", "publish"},
|
||||||
|
{"post_type", "post"},
|
||||||
|
}, "ID,post_title,post_password")
|
||||||
|
if prev.Id > 0 {
|
||||||
|
if _, ok := common.PostsCache.Load(next.Id); !ok {
|
||||||
|
common.QueryAndSetPostCache([]models.WpPosts{next})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h = gin.H{
|
||||||
|
"title": fmt.Sprintf("%s-%s", post.PostTitle, models.Options["blogname"]),
|
||||||
|
"post": post,
|
||||||
|
"options": models.Options,
|
||||||
|
"recentPosts": recent,
|
||||||
|
"archives": archive,
|
||||||
|
"categories": categoryItems,
|
||||||
|
"comment": showComment,
|
||||||
|
"canComment": canComment,
|
||||||
|
"prev": prev,
|
||||||
|
"next": next,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,9 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var PostsCache sync.Map
|
type indexHandle struct {
|
||||||
|
|
||||||
type IndexHandle struct {
|
|
||||||
c *gin.Context
|
c *gin.Context
|
||||||
session sessions.Session
|
session sessions.Session
|
||||||
page int
|
page int
|
||||||
@ -39,8 +36,8 @@ type IndexHandle struct {
|
|||||||
paginationStep int
|
paginationStep int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIndexHandle(ctx *gin.Context) *IndexHandle {
|
func newIndexHandle(ctx *gin.Context) *indexHandle {
|
||||||
return &IndexHandle{
|
return &indexHandle{
|
||||||
c: ctx,
|
c: ctx,
|
||||||
session: sessions.Default(ctx),
|
session: sessions.Default(ctx),
|
||||||
page: 1,
|
page: 1,
|
||||||
@ -58,17 +55,17 @@ func NewIndexHandle(ctx *gin.Context) *IndexHandle {
|
|||||||
status: []interface{}{"publish"},
|
status: []interface{}{"publish"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (h *IndexHandle) setTitleLR(l, r string) {
|
func (h *indexHandle) setTitleLR(l, r string) {
|
||||||
h.titleL = l
|
h.titleL = l
|
||||||
h.titleR = r
|
h.titleR = r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *IndexHandle) getTitle() string {
|
func (h *indexHandle) getTitle() string {
|
||||||
h.title = fmt.Sprintf("%s-%s", h.titleL, h.titleR)
|
h.title = fmt.Sprintf("%s-%s", h.titleL, h.titleR)
|
||||||
return h.title
|
return h.title
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *IndexHandle) parseParams() {
|
func (h *indexHandle) parseParams() {
|
||||||
h.order = h.c.Query("order")
|
h.order = h.c.Query("order")
|
||||||
if !helper.IsContainInArr(h.order, []string{"asc", "desc"}) {
|
if !helper.IsContainInArr(h.order, []string{"asc", "desc"}) {
|
||||||
h.order = "asc"
|
h.order = "asc"
|
||||||
@ -143,73 +140,18 @@ func (h *IndexHandle) parseParams() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *IndexHandle) getTotalPage(totalRaws int) int {
|
func (h *indexHandle) getTotalPage(totalRaws int) int {
|
||||||
h.totalPage = int(math.Ceil(float64(totalRaws) / float64(h.pageSize)))
|
h.totalPage = int(math.Ceil(float64(totalRaws) / float64(h.pageSize)))
|
||||||
return h.totalPage
|
return h.totalPage
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *IndexHandle) queryAndSetPostCache(postIds []models.WpPosts) (err error) {
|
|
||||||
var all []uint64
|
|
||||||
var needQuery []interface{}
|
|
||||||
for _, wpPosts := range postIds {
|
|
||||||
all = append(all, wpPosts.Id)
|
|
||||||
if _, ok := PostsCache.Load(wpPosts.Id); !ok {
|
|
||||||
needQuery = append(needQuery, wpPosts.Id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(needQuery) > 0 {
|
|
||||||
rawPosts, er := models.Find[models.WpPosts](models.SqlBuilder{{
|
|
||||||
"Id", "in", "",
|
|
||||||
}}, "a.*,ifnull(d.name,'') category_name,ifnull(taxonomy,'') `taxonomy`", "", nil, models.SqlBuilder{{
|
|
||||||
"a", "left join", "wp_term_relationships b", "a.Id=b.object_id",
|
|
||||||
}, {
|
|
||||||
"left join", "wp_term_taxonomy c", "b.term_taxonomy_id=c.term_taxonomy_id",
|
|
||||||
}, {
|
|
||||||
"left join", "wp_terms d", "c.term_id=d.term_id",
|
|
||||||
}}, 0, needQuery)
|
|
||||||
if er != nil {
|
|
||||||
err = er
|
|
||||||
return
|
|
||||||
}
|
|
||||||
postsMap := make(map[uint64]*models.WpPosts)
|
|
||||||
for i, post := range rawPosts {
|
|
||||||
v, ok := postsMap[post.Id]
|
|
||||||
if !ok {
|
|
||||||
v = &rawPosts[i]
|
|
||||||
}
|
|
||||||
if post.Taxonomy == "category" {
|
|
||||||
v.Categories = append(v.Categories, post.CategoryName)
|
|
||||||
} else if post.Taxonomy == "post_tag" {
|
|
||||||
v.Tags = append(v.Tags, post.CategoryName)
|
|
||||||
}
|
|
||||||
postsMap[post.Id] = v
|
|
||||||
}
|
|
||||||
for _, pp := range postsMap {
|
|
||||||
if len(pp.Categories) > 0 {
|
|
||||||
t := make([]string, 0, len(pp.Categories))
|
|
||||||
for _, cat := range pp.Categories {
|
|
||||||
t = append(t, fmt.Sprintf(`<a href="/p/category/%s" rel="category tag">%s</a>`, cat, cat))
|
|
||||||
}
|
|
||||||
pp.CategoriesHtml = strings.Join(t, "、")
|
|
||||||
}
|
|
||||||
if len(pp.Tags) > 0 {
|
|
||||||
t := make([]string, 0, len(pp.Tags))
|
|
||||||
for _, cat := range pp.Tags {
|
|
||||||
t = append(t, fmt.Sprintf(`<a href="/p/tag/%s" rel="tag">%s</a>`, cat, cat))
|
|
||||||
}
|
|
||||||
pp.TagsHtml = strings.Join(t, "、")
|
|
||||||
}
|
|
||||||
PostsCache.Store(pp.Id, pp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func Index(c *gin.Context) {
|
func Index(c *gin.Context) {
|
||||||
h := NewIndexHandle(c)
|
h := newIndexHandle(c)
|
||||||
h.parseParams()
|
h.parseParams()
|
||||||
|
ginH := gin.H{}
|
||||||
postIds, totalRaw, err := models.SimplePagination[models.WpPosts](h.where, "ID", "", h.page, h.pageSize, h.orderBy, h.join, h.postType, h.status)
|
postIds, totalRaw, err := models.SimplePagination[models.WpPosts](h.where, "ID", "", h.page, h.pageSize, h.orderBy, h.join, h.postType, h.status)
|
||||||
defer func() {
|
defer func() {
|
||||||
|
c.HTML(http.StatusOK, "index", ginH)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(err)
|
c.Error(err)
|
||||||
}
|
}
|
||||||
@ -220,27 +162,28 @@ func Index(c *gin.Context) {
|
|||||||
if len(postIds) < 1 && h.category != "" {
|
if len(postIds) < 1 && h.category != "" {
|
||||||
h.titleL = "未找到页面"
|
h.titleL = "未找到页面"
|
||||||
}
|
}
|
||||||
err = h.queryAndSetPostCache(postIds)
|
err = common.QueryAndSetPostCache(postIds)
|
||||||
pw := h.session.Get("post_password")
|
pw := h.session.Get("post_password")
|
||||||
for i, v := range postIds {
|
for i, v := range postIds {
|
||||||
post, _ := PostsCache.Load(v.Id)
|
post, _ := common.PostsCache.Load(v.Id)
|
||||||
pp := post.(*models.WpPosts)
|
pp := post.(*models.WpPosts)
|
||||||
px := *pp
|
px := *pp
|
||||||
|
common.PasswordProjectTitle(&px)
|
||||||
if px.PostPassword != "" && pw != px.PostPassword {
|
if px.PostPassword != "" && pw != px.PostPassword {
|
||||||
common.PasswdProject(&px)
|
common.PasswdProjectContent(&px)
|
||||||
}
|
}
|
||||||
postIds[i] = px
|
postIds[i] = px
|
||||||
}
|
}
|
||||||
recent, err := common.RecentPosts()
|
recent, err := common.RecentPosts()
|
||||||
for i, post := range recent {
|
for i, post := range recent {
|
||||||
if post.PostPassword != "" && pw != post.PostPassword {
|
if post.PostPassword != "" && pw != post.PostPassword {
|
||||||
common.PasswdProject(&recent[i])
|
common.PasswdProjectContent(&recent[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
archive, err := common.Archives()
|
archive, err := common.Archives()
|
||||||
categoryItems, err := common.Categories()
|
categoryItems, err := common.Categories()
|
||||||
q := c.Request.URL.Query().Encode()
|
q := c.Request.URL.Query().Encode()
|
||||||
c.HTML(http.StatusOK, "index.html", gin.H{
|
ginH = gin.H{
|
||||||
"posts": postIds,
|
"posts": postIds,
|
||||||
"options": models.Options,
|
"options": models.Options,
|
||||||
"recentPosts": recent,
|
"recentPosts": recent,
|
||||||
@ -251,7 +194,7 @@ func Index(c *gin.Context) {
|
|||||||
"search": h.search,
|
"search": h.search,
|
||||||
"header": h.header,
|
"header": h.header,
|
||||||
"title": h.getTitle(),
|
"title": h.getTitle(),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pagination(currentPage, totalPage, step int, path, query string) (html string) {
|
func pagination(currentPage, totalPage, step int, path, query string) (html string) {
|
||||||
|
2
go.mod
2
go.mod
@ -3,6 +3,7 @@ module github/fthvgb1/wp-go
|
|||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/gin-contrib/sessions v0.0.5
|
||||||
github.com/gin-gonic/gin v1.8.1
|
github.com/gin-gonic/gin v1.8.1
|
||||||
github.com/go-sql-driver/mysql v1.6.0
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
github.com/jmoiron/sqlx v1.3.5
|
github.com/jmoiron/sqlx v1.3.5
|
||||||
@ -10,7 +11,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-contrib/sessions v0.0.5 // indirect
|
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.0 // indirect
|
github.com/go-playground/locales v0.14.0 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||||
|
@ -25,7 +25,10 @@ func SetupRouter() *gin.Engine {
|
|||||||
return t.Format("2006年 01月 02日")
|
return t.Format("2006年 01月 02日")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
loadTemplates(r, "**/*")
|
reader := templates.NewFsTemplate(r.FuncMap)
|
||||||
|
reader.AddTemplate("index", "posts/index.html", "layout/*.html")
|
||||||
|
reader.AddTemplate("detail", "posts/detail.html", "layout/*.html")
|
||||||
|
r.HTMLRender = reader
|
||||||
r.Use(middleware.SetStaticFileCache)
|
r.Use(middleware.SetStaticFileCache)
|
||||||
//gzip 因为一般会用nginx做反代时自动使用gzip,所以go这边本身可以不用
|
//gzip 因为一般会用nginx做反代时自动使用gzip,所以go这边本身可以不用
|
||||||
/*r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{
|
/*r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{
|
||||||
@ -53,9 +56,3 @@ func SetupRouter() *gin.Engine {
|
|||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadTemplates(engine *gin.Engine, pattern string) {
|
|
||||||
templ := template.New("").Funcs(engine.FuncMap).Delims("{{", "}}")
|
|
||||||
templ = template.Must(templ.ParseFS(templates.TemplateFs, pattern))
|
|
||||||
engine.SetHTMLTemplate(templ)
|
|
||||||
}
|
|
||||||
|
133
templates/posts/detail.html
Normal file
133
templates/posts/detail.html
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
{{template "layout/base" .}}
|
||||||
|
{{define "content"}}
|
||||||
|
<div id="primary" class="content-area">
|
||||||
|
<main id="main" class="site-main">
|
||||||
|
|
||||||
|
|
||||||
|
<article id="post-{{.post.Id}}" class="post-{{.post.Id}} post type-post status-publish format-standard hentry category-uncategorized">
|
||||||
|
|
||||||
|
<header class="entry-header">
|
||||||
|
<h1 class="entry-title">{{.post.PostTitle}}</h1> </header><!-- .entry-header -->
|
||||||
|
|
||||||
|
<div class="entry-content">
|
||||||
|
{{.post.PostContent|unescaped}}
|
||||||
|
</div><!-- .entry-content -->
|
||||||
|
|
||||||
|
|
||||||
|
<footer class="entry-footer">
|
||||||
|
<span class="posted-on">
|
||||||
|
<span class="screen-reader-text">发布于 </span>
|
||||||
|
<a href="/p/{{.post.Id}}" rel="bookmark">
|
||||||
|
<time class="entry-date published updated" datetime="{{.post.PostDateGmt}}">{{.post.PostDate|dateCh}}
|
||||||
|
</time>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
{{if .post.CategoriesHtml}}
|
||||||
|
<span class="cat-links">
|
||||||
|
<span class="screen-reader-text">分类 </span>
|
||||||
|
{{.post.CategoriesHtml|unescaped}}
|
||||||
|
</span>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .post.TagsHtml}}
|
||||||
|
<span class="tags-links">
|
||||||
|
<span class="screen-reader-text">标签 </span>
|
||||||
|
{{.post.TagsHtml|unescaped}}
|
||||||
|
</span>
|
||||||
|
{{end}}
|
||||||
|
</footer>
|
||||||
|
<!-- .entry-footer -->
|
||||||
|
|
||||||
|
</article><!-- #post-1 -->
|
||||||
|
|
||||||
|
<div id="comments" class="comments-area">
|
||||||
|
|
||||||
|
<h2 class="comments-title">
|
||||||
|
《{{.post.PostTitle}}》上有1条评论 </h2>
|
||||||
|
|
||||||
|
|
||||||
|
<ol class="comment-list">
|
||||||
|
<li id="comment-1" class="comment even thread-even depth-1">
|
||||||
|
<article id="div-comment-1" class="comment-body">
|
||||||
|
<footer class="comment-meta">
|
||||||
|
<div class="comment-author vcard">
|
||||||
|
<img alt="" src="http://1.gravatar.com/avatar/d7a973c7dab26985da5f961be7b74480?s=56&d=mm&r=g" srcset="http://1.gravatar.com/avatar/d7a973c7dab26985da5f961be7b74480?s=112&d=mm&r=g 2x" class="avatar avatar-56 photo" height="56" width="56" loading="lazy"> <b class="fn"><a href="https://cn.wordpress.org/" rel="external nofollow ugc" class="url">一位WordPress评论者</a></b><span class="says">说道:</span> </div><!-- .comment-author -->
|
||||||
|
|
||||||
|
<div class="comment-metadata">
|
||||||
|
<a href="/p/1#comment-1"><time datetime="2022-08-19T09:26:37+08:00">2022年 8月 19日 上午9:26</time></a> </div><!-- .comment-metadata -->
|
||||||
|
|
||||||
|
</footer><!-- .comment-meta -->
|
||||||
|
|
||||||
|
<div class="comment-content">
|
||||||
|
<p>您好,这是一条评论。若需要审核、编辑或删除评论,请访问仪表盘的评论界面。评论者头像来自 <a href="https://cn.gravatar.com/">Gravatar</a>。</p>
|
||||||
|
</div><!-- .comment-content -->
|
||||||
|
|
||||||
|
<div class="reply"><a rel="nofollow" class="comment-reply-link" href="/p/1?replytocom=1#respond" data-commentid="1" data-postid="1" data-belowelement="div-comment-1" data-respondelement="respond" data-replyto="回复给一位WordPress评论者" aria-label="回复给一位WordPress评论者">回复</a></div> </article><!-- .comment-body -->
|
||||||
|
</li><!-- #comment-## -->
|
||||||
|
</ol><!-- .comment-list -->
|
||||||
|
|
||||||
|
{{if .canComment}}
|
||||||
|
<div id="respond" class="comment-respond">
|
||||||
|
<h3 id="reply-title" class="comment-reply-title">发表回复
|
||||||
|
<small>
|
||||||
|
<a rel="nofollow"
|
||||||
|
id="cancel-comment-reply-link" href="/p/{{.post.Id}}#respond"
|
||||||
|
style="display:none;">取消回复</a>
|
||||||
|
</small>
|
||||||
|
</h3>
|
||||||
|
<form action="/wp-comments-post.php" method="post" id="commentform" class="comment-form" novalidate="">
|
||||||
|
<p class="comment-notes"><span id="email-notes">您的电子邮箱地址不会被公开。</span> <span
|
||||||
|
class="required-field-message" aria-hidden="true">必填项已用<span class="required"
|
||||||
|
aria-hidden="true">*</span>标注</span>
|
||||||
|
</p>
|
||||||
|
<p class="comment-form-comment"><label for="comment">评论 <span class="required" aria-hidden="true">*</span></label>
|
||||||
|
<textarea id="comment" name="comment" cols="45" rows="8" maxlength="65525"
|
||||||
|
required=""></textarea></p>
|
||||||
|
<p class="comment-form-author"><label for="author">显示名称 <span class="required"
|
||||||
|
aria-hidden="true">*</span></label>
|
||||||
|
<input id="author" name="author" type="text" value="" size="30" maxlength="245" required=""></p>
|
||||||
|
<p class="comment-form-email"><label for="email">电子邮箱地址 <span class="required"
|
||||||
|
aria-hidden="true">*</span></label>
|
||||||
|
<input id="email" name="email" type="email" value="" size="30" maxlength="100"
|
||||||
|
aria-describedby="email-notes" required=""></p>
|
||||||
|
<p class="comment-form-url"><label for="url">网站地址</label>
|
||||||
|
<input id="url" name="url" type="url" value="" size="30" maxlength="200"></p>
|
||||||
|
<p class="comment-form-cookies-consent">
|
||||||
|
<input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes">
|
||||||
|
<label for="wp-comment-cookies-consent">在此浏览器中保存我的显示名称、邮箱地址和网站地址,以便下次评论时使用。</label>
|
||||||
|
</p>
|
||||||
|
<p class="form-submit"><input name="submit" type="submit" id="submit" class="submit" value="发表评论">
|
||||||
|
<input type="hidden" name="comment_post_ID" value="{{.post.Id}}" id="comment_post_ID">
|
||||||
|
<input type="hidden" name="comment_parent" id="comment_parent" value="0">
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div><!-- #respond -->
|
||||||
|
{{end}}
|
||||||
|
</div><!-- .comments-area -->
|
||||||
|
|
||||||
|
<nav class="navigation post-navigation" aria-label="文章">
|
||||||
|
<h2 class="screen-reader-text">文章导航</h2>
|
||||||
|
|
||||||
|
<div class="nav-links">
|
||||||
|
{{if gt .prev.Id 0}}
|
||||||
|
<div class="nav-previous">
|
||||||
|
<a href="/p/{{.prev.Id}}" rel="prev">
|
||||||
|
<span class="meta-nav" aria-hidden="true">上一篇</span>
|
||||||
|
<span class="screen-reader-text">上篇文章:</span>
|
||||||
|
<span class="post-title">{{.prev.PostTitle}}</span></a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{if gt .next.Id 0}}
|
||||||
|
<div class="nav-next">
|
||||||
|
<a href="/p/{{.next.Id}}" rel="next">
|
||||||
|
<span class="meta-nav" aria-hidden="true">下一篇</span>
|
||||||
|
<span class="screen-reader-text">下篇文章:</span>
|
||||||
|
<span class="post-title">{{.next.PostTitle}}</span></a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</main><!-- .site-main -->
|
||||||
|
</div>
|
||||||
|
{{end}}
|
@ -16,7 +16,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{ range $k,$v:=.posts}}
|
{{ range $k,$v:=.posts}}
|
||||||
<article id="post-{{$v.Id}}"
|
<article id="post-{{$v.Id}}"
|
||||||
class="post-{{$v.Id}} post type-post status-publish format-standard hentry category-uncategorized">
|
class="post-{{$v.Id}} post type-post status-publish format-standard hentry category">
|
||||||
|
|
||||||
<header class="entry-header">
|
<header class="entry-header">
|
||||||
<h2 class="entry-title">
|
<h2 class="entry-title">
|
||||||
@ -25,7 +25,7 @@
|
|||||||
</header><!-- .entry-header -->
|
</header><!-- .entry-header -->
|
||||||
|
|
||||||
<div class="entry-content">
|
<div class="entry-content">
|
||||||
<p>{{$v.PostContent|unescaped}}</p>
|
{{$v.PostContent|unescaped}}
|
||||||
</div><!-- .entry-content -->
|
</div><!-- .entry-content -->
|
||||||
|
|
||||||
<footer class="entry-footer">
|
<footer class="entry-footer">
|
||||||
|
@ -1,6 +1,34 @@
|
|||||||
package templates
|
package templates
|
||||||
|
|
||||||
import "embed"
|
import (
|
||||||
|
"embed"
|
||||||
|
"github.com/gin-gonic/gin/render"
|
||||||
|
"html/template"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
//go:embed posts layout
|
//go:embed posts layout
|
||||||
var TemplateFs embed.FS
|
var TemplateFs embed.FS
|
||||||
|
|
||||||
|
type FsTemplate struct {
|
||||||
|
Templates map[string]*template.Template
|
||||||
|
FuncMap template.FuncMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFsTemplate(funcMap template.FuncMap) *FsTemplate {
|
||||||
|
return &FsTemplate{FuncMap: funcMap, Templates: make(map[string]*template.Template)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *FsTemplate) AddTemplate(name, main string, sub ...string) {
|
||||||
|
tmp := []string{main}
|
||||||
|
tmp = append(tmp, sub...)
|
||||||
|
t.Templates[name] = template.Must(template.New(filepath.Base(main)).Funcs(t.FuncMap).ParseFS(TemplateFs, tmp...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t FsTemplate) Instance(name string, data any) render.Render {
|
||||||
|
r := t.Templates[name]
|
||||||
|
return render.HTML{
|
||||||
|
Template: r,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user