Merge pull request #3 from fthvgb1/dev

Dev
This commit is contained in:
2023-01-26 02:33:40 +08:00 committed by GitHub
commit 68d045157c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 520 additions and 236 deletions

View File

@ -48,3 +48,10 @@ func AnyAnyToStrAny(m map[any]any) (r map[string]any) {
} }
return return
} }
func Reduce[T, V any, K comparable](m map[K]V, fn func(K, V, T) T, r T) T {
for k, v := range m {
r = fn(k, v, r)
}
return r
}

View File

@ -53,6 +53,23 @@ func DiffByFn[T any](a []T, fn func(i, j T) bool, b ...[]T) (r []T) {
return return
} }
func DiffNewByFn[T, V any](a []T, fn func(i, j T) bool, fnV func(T) V, b ...[]T) (r []V) {
for _, t := range a {
f := false
for _, ts := range b {
if IsContainedByFn(ts, t, fn) {
f = true
break
}
}
if f {
continue
}
r = append(r, fnV(t))
}
return
}
func Intersect[T comparable](a []T, b ...[]T) (r []T) { func Intersect[T comparable](a []T, b ...[]T) (r []T) {
for _, t := range a { for _, t := range a {
f := false f := false
@ -87,6 +104,23 @@ func IntersectByFn[T any](a []T, fn func(i, j T) bool, b ...[]T) (r []T) {
return return
} }
func IntersectNewByFn[T, V any](a []T, fn func(i, j T) bool, fnV func(T) V, b ...[]T) (r []V) {
for _, t := range a {
f := false
for _, ts := range b {
if !IsContainedByFn(ts, t, fn) {
f = true
break
}
}
if f {
continue
}
r = append(r, fnV(t))
}
return
}
func Unique[T comparable](a ...[]T) (r []T) { func Unique[T comparable](a ...[]T) (r []T) {
m := map[T]struct{}{} m := map[T]struct{}{}
for _, ts := range a { for _, ts := range a {
@ -112,3 +146,15 @@ func UniqueByFn[T any](fn func(T, T) bool, a ...[]T) (r []T) {
} }
return r return r
} }
func UniqueNewByFn[T, V any](fn func(T, T) bool, fnVal func(T) V, a ...[]T) (r []V) {
var rr []T
for _, ts := range a {
for _, t := range ts {
if !IsContainedByFn(rr, t, fn) {
rr = append(rr, t)
r = append(r, fnVal(t))
}
}
}
return r
}

View File

@ -83,6 +83,46 @@ func TestDiffByFn(t *testing.T) {
} }
} }
func TestDiffNewByFn(t *testing.T) {
type args[T x, V int] struct {
a []T
fn func(i, j T) bool
fnV func(T) V
b [][]T
}
type testCase[T x, V int] struct {
name string
args args[T, V]
wantR []V
}
tests := []testCase[x, int]{
{
name: "t1",
args: args[x, int]{
a: y(number.Range(1, 10, 1)),
fn: func(i, j x) bool {
return i.int == j.int
},
fnV: func(v x) int {
return v.int
},
b: [][]x{
y(number.Range(3, 7, 1)),
y(number.Range(6, 9, 1)),
},
},
wantR: []int{1, 2, 10},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotR := DiffNewByFn(tt.args.a, tt.args.fn, tt.args.fnV, tt.args.b...); !reflect.DeepEqual(gotR, tt.wantR) {
t.Errorf("DiffNewByFn() = %v, want %v", gotR, tt.wantR)
}
})
}
}
func TestIntersect(t *testing.T) { func TestIntersect(t *testing.T) {
type args[T int] struct { type args[T int] struct {
a []T a []T
@ -148,6 +188,46 @@ func TestIntersectByFn(t *testing.T) {
} }
} }
func TestIntersectNewByFn(t *testing.T) {
type args[T x, V int] struct {
a []T
fn func(i, j T) bool
fnV func(T) V
b [][]T
}
type testCase[T x, V int] struct {
name string
args args[T, V]
wantR []V
}
tests := []testCase[x, int]{
{
name: "t1",
args: args[x, int]{
a: y(number.Range(1, 10, 1)),
fn: func(i, j x) bool {
return i.int == j.int
},
fnV: func(v x) int {
return v.int
},
b: [][]x{
y(number.Range(3, 7, 1)),
y(number.Range(6, 9, 1)),
},
},
wantR: []int{6, 7},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotR := IntersectNewByFn(tt.args.a, tt.args.fn, tt.args.fnV, tt.args.b...); !reflect.DeepEqual(gotR, tt.wantR) {
t.Errorf("IntersectNewByFn() = %v, want %v", gotR, tt.wantR)
}
})
}
}
func TestUnique(t *testing.T) { func TestUnique(t *testing.T) {
type args[T int] struct { type args[T int] struct {
a [][]T a [][]T
@ -169,6 +249,15 @@ func TestUnique(t *testing.T) {
}, },
wantR: number.Range(1, 15, 1), wantR: number.Range(1, 15, 1),
}, },
{
name: "t2",
args: args[int]{
a: [][]int{
{1, 1, 1, 2, 2, 2, 3, 3, 4, 5},
},
},
wantR: number.Range(1, 5, 1),
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -209,3 +298,38 @@ func TestUniqueByFn(t *testing.T) {
}) })
} }
} }
func TestUniqueNewByFn(t *testing.T) {
type args[T x, V int] struct {
fn func(T, T) bool
fnVal func(T) V
a [][]T
}
type testCase[T x, V int] struct {
name string
args args[T, V]
wantR []V
}
tests := []testCase[x, int]{
{
name: "t1",
args: args[x, int]{
fn: func(i, j x) bool {
return i.int == j.int
},
fnVal: func(i x) int {
return i.int
},
a: [][]x{y([]int{1, 1, 2, 2, 3, 3}), y([]int{2, 2, 4, 4})},
},
wantR: []int{1, 2, 3, 4},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotR := UniqueNewByFn(tt.args.fn, tt.args.fnVal, tt.args.a...); !reflect.DeepEqual(gotR, tt.wantR) {
t.Errorf("UniqueNewByFn() = %v, want %v", gotR, tt.wantR)
}
})
}
}

View File

@ -108,6 +108,7 @@ func Detail(c *gin.Context) {
ginH["comments"] = hh.formatComment(commentss, 1, d) ginH["comments"] = hh.formatComment(commentss, 1, d)
ginH["next"] = next ginH["next"] = next
ginH["user"] = user ginH["user"] = user
ginH["scene"] = plugins.Detail
} }
type Comment struct { type Comment struct {

View File

@ -312,5 +312,6 @@ func Index(c *gin.Context) {
ginH["totalPage"] = h.getTotalPage(totalRaw) ginH["totalPage"] = h.getTotalPage(totalRaw)
ginH["currentPage"] = h.page ginH["currentPage"] = h.page
ginH["title"] = h.getTitle() ginH["title"] = h.getTitle()
ginH["scene"] = h.scene
ginH["pagination"] = pagination.NewParsePagination(totalRaw, h.pageSize, h.page, h.paginationStep, q, c.Request.URL.Path) ginH["pagination"] = pagination.NewParsePagination(totalRaw, h.pageSize, h.page, h.paginationStep, q, c.Request.URL.Path)
} }

View File

@ -2,14 +2,12 @@ package dao
import ( import (
"context" "context"
"fmt"
"github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/helper/slice" "github.com/fthvgb1/wp-go/helper/slice"
"github.com/fthvgb1/wp-go/internal/pkg/logs" "github.com/fthvgb1/wp-go/internal/pkg/logs"
"github.com/fthvgb1/wp-go/internal/pkg/models" "github.com/fthvgb1/wp-go/internal/pkg/models"
"github.com/fthvgb1/wp-go/internal/plugins"
"github.com/fthvgb1/wp-go/model" "github.com/fthvgb1/wp-go/model"
"strconv" "strconv"
"strings"
) )
func GetPostMetaByPostIds(args ...any) (r map[uint64]map[string]any, err error) { func GetPostMetaByPostIds(args ...any) (r map[uint64]map[string]any, err error) {
@ -64,35 +62,9 @@ func ToPostThumb(c context.Context, meta map[string]any, host string) (r models.
if ok { if ok {
metadata, ok := x.(models.WpAttachmentMetadata) metadata, ok := x.(models.WpAttachmentMetadata)
if ok { if ok {
r = thumbnail(metadata, "post-thumbnail", host) r = plugins.Thumbnail(metadata, "post-thumbnail", host, "thumbnail")
} }
} }
} }
return return
} }
func thumbnail(metadata models.WpAttachmentMetadata, thumbType, host string) (r models.PostThumbnail) {
if _, ok := metadata.Sizes[thumbType]; ok {
r.Path = fmt.Sprintf("%s/wp-content/uploads/%s", host, metadata.File)
r.Width = metadata.Sizes[thumbType].Width
r.Height = metadata.Sizes[thumbType].Height
up := strings.Split(metadata.File, "/")
r.Srcset = strings.Join(maps.FilterToSlice[string](metadata.Sizes, func(s string, size models.MetaDataFileSize) (r string, ok bool) {
up[2] = size.File
if s == "post-thumbnail" {
return
}
r = fmt.Sprintf("%s/wp-content/uploads/%s %dw", host, strings.Join(up, "/"), size.Width)
ok = true
return
}), ", ")
r.Sizes = fmt.Sprintf("(max-width: %dpx) 100vw, %dpx", r.Width, r.Width)
if r.Width >= 740 && r.Width < 767 {
r.Sizes = "(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px"
} else if r.Width >= 767 {
r.Sizes = "(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px"
}
r.OriginAttachmentData = metadata
}
return
}

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"github.com/fthvgb1/wp-go/helper/slice" "github.com/fthvgb1/wp-go/helper/slice"
"github.com/fthvgb1/wp-go/internal/pkg/models" "github.com/fthvgb1/wp-go/internal/pkg/models"
"github.com/fthvgb1/wp-go/internal/plugins"
"github.com/fthvgb1/wp-go/internal/wpconfig" "github.com/fthvgb1/wp-go/internal/wpconfig"
"github.com/fthvgb1/wp-go/model" "github.com/fthvgb1/wp-go/model"
"strings" "strings"
@ -68,7 +69,7 @@ func GetPostsByIds(ids ...any) (m map[uint64]models.Posts, err error) {
pp.Thumbnail = thumb pp.Thumbnail = thumb
} }
} else if pp.PostType == "attachment" && pp.AttachmentMetadata.File != "" { } else if pp.PostType == "attachment" && pp.AttachmentMetadata.File != "" {
thumb := thumbnail(pp.AttachmentMetadata, "thumbnail", host) thumb := plugins.Thumbnail(pp.AttachmentMetadata, "thumbnail", host, "thumbnail", "post-thumbnail")
if thumb.Path != "" { if thumb.Path != "" {
pp.Thumbnail = thumb pp.Thumbnail = thumb
} }

View File

@ -0,0 +1,36 @@
package plugins
import (
"fmt"
"github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/internal/pkg/models"
"strings"
)
func Thumbnail(metadata models.WpAttachmentMetadata, Type, host string, except ...string) (r models.PostThumbnail) {
if _, ok := metadata.Sizes[Type]; ok {
r.Path = fmt.Sprintf("%s/wp-content/uploads/%s", host, metadata.File)
r.Width = metadata.Sizes[Type].Width
r.Height = metadata.Sizes[Type].Height
up := strings.Split(metadata.File, "/")
r.Srcset = strings.Join(maps.FilterToSlice[string](metadata.Sizes, func(s string, size models.MetaDataFileSize) (r string, ok bool) {
up[2] = size.File
for _, s2 := range except {
if s == s2 {
return
}
}
r = fmt.Sprintf("%s/wp-content/uploads/%s %dw", host, strings.Join(up, "/"), size.Width)
ok = true
return
}), ", ")
r.Sizes = fmt.Sprintf("(max-width: %dpx) 100vw, %dpx", r.Width, r.Width)
if r.Width >= 740 && r.Width < 767 {
r.Sizes = "(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px"
} else if r.Width >= 767 {
r.Sizes = "(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px"
}
r.OriginAttachmentData = metadata
}
return
}

View File

@ -6,7 +6,7 @@
{{block "head" .}} {{block "head" .}}
{{end}} {{end}}
</head> </head>
<body class="home blog wp-embed-responsive hfeed has-header-image has-sidebar colors-light"> <body class="{{.bodyClass}} wp-embed-responsive hfeed has-header-image has-sidebar colors-light">
{{template "svg"}} {{template "svg"}}
<div id="page" class="site"> <div id="page" class="site">
<a class="skip-link screen-reader-text" href="#content">跳至内容</a> <a class="skip-link screen-reader-text" href="#content">跳至内容</a>
@ -16,7 +16,7 @@
<div class="custom-header" style="margin-bottom: 0px;"> <div class="custom-header" style="margin-bottom: 0px;">
<div class="custom-header-media"> <div class="custom-header-media">
<div id="wp-custom-header" class="wp-custom-header"> <div id="wp-custom-header" class="wp-custom-header">
<img src="{{.HeaderImage.Path}}" width="{{.HeaderImage.Width}}" height="{{.HeaderImage.Height}}" alt="" {{if .HeaderImage.Srcset}}srcset="{{.HeaderImage.Srcset}}" {{end}} {{if .HeaderImage.Sizes}}sizes="{{.HeaderImage.Srcset}}" {{end}}> <img src="{{.HeaderImage.Path}}" width="{{.HeaderImage.Width}}" height="{{.HeaderImage.Height}}" alt="" {{if .HeaderImage.Srcset}}srcset="{{.HeaderImage.Srcset}}" {{end}} {{if .HeaderImage.Sizes}}sizes="{{.HeaderImage.Sizes}}" {{end}}>
</div> </div>
</div> </div>
@ -44,21 +44,17 @@
</header> </header>
<div class="site-content-contain"> {{block "content" .}}
<div id="content" class="site-content">
{{block "content" .}}
{{end}} {{end}}
</div>
<footer id="colophon" class="site-footer"> <footer id="colophon" class="site-footer">
<div class="wrap"> <div class="wrap">
<div class="site-info"> <div class="site-info">
<a href="https://cn.wordpress.org/" class="imprint">自豪地采用WordPress</a> <a href="https://cn.wordpress.org/" class="imprint">自豪地采用WordPress</a>
</div>
</div> </div>
</footer> </div>
</div> </footer>
</div> </div>

View File

@ -161,4 +161,7 @@
</symbol> </symbol>
</defs> </defs>
</svg> </svg>
{{block "footerx" .}}
{{end}}
{{end}} {{end}}

View File

@ -14,7 +14,6 @@
<link href='https://fonts.gstatic.com' crossorigin rel='preconnect' /> <link href='https://fonts.gstatic.com' crossorigin rel='preconnect' />
<link rel="alternate" type="application/rss+xml" title="{{ .title }} &raquo; Feed" href="/feed" /> <link rel="alternate" type="application/rss+xml" title="{{ .title }} &raquo; Feed" href="/feed" />
<link rel="alternate" type="application/rss+xml" title="{{ .title }} &raquo; 评论Feed" href="/comments/feed" /> <link rel="alternate" type="application/rss+xml" title="{{ .title }} &raquo; 评论Feed" href="/comments/feed" />
<link rel='stylesheet' id='enlighterjs-css' href='/wp-content/plugins/enlighter/cache/enlighterjs.min.css?ver=0A0B0C' media='all' />
<script> <script>
window._wpemojiSettings = {"baseUrl":"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/","ext":".png","svgUrl":"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/svg\/","svgExt":".svg","source":{"concatemoji":"\/wp-includes\/js\/wp-emoji-release.min.js?ver=6.0.2"}}; window._wpemojiSettings = {"baseUrl":"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/","ext":".png","svgUrl":"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/svg\/","svgExt":".svg","source":{"concatemoji":"\/wp-includes\/js\/wp-emoji-release.min.js?ver=6.0.2"}};

View File

@ -2,134 +2,160 @@
{{define "content"}} {{define "content"}}
{{ if .post.PostContent}} {{ if .post.PostContent}}
<div id="primary" class="content-area"> {{if .post.Thumbnail.Path}}
<main id="main" class="site-main"> <div class="single-featured-image-header">
<article id="post-{{.post.Id}}" <img width="{{.post.Thumbnail.OriginAttachmentData.Width}}" height="{{.post.Thumbnail.OriginAttachmentData.Height}}" src="{{.post.Thumbnail.Path}}" class="attachment-twentyseventeen-featured-image size-twentyseventeen-featured-image wp-post-image" alt="{{.post.PostTitle}}" decoding="async" loading="lazy" srcset="{{.post.Thumbnail.Srcset}}" sizes="{{.post.Thumbnail.Sizes}}">
class="post-{{.post.Id}} post type-post status-publish format-standard hentry category-uncategorized"> </div>
{{end}}
<div class="site-content-contain">
<div id="content" class="site-content">
<div class="wrap">
<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 {{if .post.Thumbnail.Path}}has-post-thumbnail{{end}} category-uncategorized">
<header class="entry-header"> <header class="entry-header">
<h1 class="entry-title">{{.post.PostTitle}}</h1></header><!-- .entry-header --> <div class="entry-meta">
<span class="posted-on">
<span class="screen-reader-text">发布于</span>
<a href="/p/{{.post.Id}}" rel="bookmark">
<time class="entry-date published" datetime="{{.post.PostDateGmt}}">{{.post.PostDate|dateCh}}
</time>
<time class="updated" datetime="{{.post.PostModifiedGmt}}">{{.post.PostModified|dateCh}}
</time>
</a>
</span>
<span class="byline">
<span class="author vcard">
<a class="url fn n" href="/p/author/{{.user.UserLogin}}">{{.user.UserLogin}}</a>
</span>
</span>
</div>
<h1 class="entry-title">{{.post.PostTitle}}</h1>
</header><!-- .entry-header -->
<div class="entry-content"> <div class="entry-content">
{{.post.PostContent|unescaped}} {{.post.PostContent|unescaped}}
</div><!-- .entry-content --> </div><!-- .entry-content -->
<footer class="entry-footer"> <footer class="entry-footer">
<span class="posted-on"> <span class="cat-tags-links">
<span class="screen-reader-text">发布于 </span> {{if .post.CategoriesHtml}}
<a href="/p/{{.post.Id}}" rel="bookmark"> <span class="cat-links">
<time class="entry-date published updated" <svg class="icon icon-folder-open" aria-hidden="true" role="img"> <use href="#icon-folder-open" xlink:href="#icon-folder-open"></use> </svg>
datetime="{{.post.PostDateGmt}}">{{.post.PostDate|dateCh}} <span class="screen-reader-text">分类 </span>
</time> {{.post.CategoriesHtml|unescaped}}
</a> </span>
</span> {{end}}
<span class="byline">
<span class="author vcard">
<span class="screen-reader-text">作者 </span>
<a class="url fn n" href="/p/author/{{.user.UserLogin}}">{{.user.UserLogin}}</a>
</span>
</span>
{{if .post.CategoriesHtml}}
<span class="cat-links">
<span class="screen-reader-text">分类 </span>
{{.post.CategoriesHtml|unescaped}}
</span>
{{end}}
{{if .post.TagsHtml}} {{if .post.TagsHtml}}
<span class="tags-links"> <span class="tags-links">
<span class="screen-reader-text">标签 </span> <svg class="icon icon-hashtag" aria-hidden="true" role="img"> <use href="#icon-hashtag" xlink:href="#icon-hashtag"></use> </svg>
{{.post.TagsHtml|unescaped}} <span class="screen-reader-text">标签 </span>
</span> {{.post.TagsHtml|unescaped}}
{{end}} </span>
</footer> {{end}}
<!-- .entry-footer --> </span>
</footer>
<!-- .entry-footer -->
</article><!-- #post-1 --> </article><!-- #post-1 -->
{{ if .showComment}} {{ if .showComment}}
<div id="comments" class="comments-area"> <div id="comments" class="comments-area">
{{ if gt .post.CommentCount 0}} {{ if gt .post.CommentCount 0}}
<h2 class="comments-title">《{{.post.PostTitle}}》上有{{.post.CommentCount}}条评论 </h2> <h2 class="comments-title">《{{.post.PostTitle}}》上有{{.post.CommentCount}}条评论 </h2>
<ol class="comment-list"> <ol class="comment-list">
{{.comments|unescaped}} {{.comments|unescaped}}
</ol> </ol>
{{end}} {{end}}
{{if eq .post.CommentStatus "open"}} {{if eq .post.CommentStatus "open"}}
<div id="respond" class="comment-respond"> <div id="respond" class="comment-respond">
<h3 id="reply-title" class="comment-reply-title">发表回复 <h3 id="reply-title" class="comment-reply-title">发表回复
<small> <small>
<a rel="nofollow" id="cancel-comment-reply-link" href="/p/{{.post.Id}}#respond" style="display:none;">取消回复</a> <a rel="nofollow" id="cancel-comment-reply-link" href="/p/{{.post.Id}}#respond" style="display:none;">取消回复</a>
</small> </small>
</h3> </h3>
<form action="/comment" method="post" id="commentform" class="comment-form" <form action="/comment" method="post" id="commentform" class="comment-form"
novalidate=""> novalidate="">
<p class="comment-notes"> <p class="comment-notes">
<span id="email-notes">您的电子邮箱地址不会被公开。</span> <span id="email-notes">您的电子邮箱地址不会被公开。</span>
<span class="required-field-message" aria-hidden="true">必填项已用<span class="required" aria-hidden="true">*</span>标注</span> <span class="required-field-message" aria-hidden="true">必填项已用<span class="required" aria-hidden="true">*</span>标注</span>
</p> </p>
<p class="comment-form-comment"> <p class="comment-form-comment">
<label for="comment">评论 <span class="required" aria-hidden="true">*</span></label> <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> <textarea id="comment" name="comment" cols="45" rows="8" maxlength="65525" required=""></textarea></p>
<p class="comment-form-author"> <p class="comment-form-author">
<label for="author">显示名称 <span class="required" aria-hidden="true">*</span></label> <label for="author">显示名称 <span class="required" aria-hidden="true">*</span></label>
<input id="author" name="author" type="text" value="" size="30" maxlength="245" <input id="author" name="author" type="text" value="" size="30" maxlength="245"
required=""></p> required=""></p>
<p class="comment-form-email"> <p class="comment-form-email">
<label for="email">电子邮箱地址 <span class="required" aria-hidden="true">*</span></label> <label for="email">电子邮箱地址 <span class="required" aria-hidden="true">*</span></label>
<input id="email" name="email" type="email" value="" size="30" maxlength="100" <input id="email" name="email" type="email" value="" size="30" maxlength="100"
aria-describedby="email-notes" required=""> aria-describedby="email-notes" required="">
</p> </p>
<p class="comment-form-url"><label for="url">网站地址</label> <p class="comment-form-url"><label for="url">网站地址</label>
<input id="url" name="url" type="url" value="" size="30" maxlength="200"></p> <input id="url" name="url" type="url" value="" size="30" maxlength="200"></p>
<p class="comment-form-cookies-consent"> <p class="comment-form-cookies-consent">
<input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes"> <input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes">
<label for="wp-comment-cookies-consent">在此浏览器中保存我的显示名称、邮箱地址和网站地址,以便下次评论时使用。</label> <label for="wp-comment-cookies-consent">在此浏览器中保存我的显示名称、邮箱地址和网站地址,以便下次评论时使用。</label>
</p> </p>
<p class="form-submit"> <p class="form-submit">
<input name="submit" type="submit" id="submit" class="submit" value="发表评论"> <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_post_ID" value="{{.post.Id}}" id="comment_post_ID">
<input type="hidden" name="comment_parent" id="comment_parent" value="0"> <input type="hidden" name="comment_parent" id="comment_parent" value="0">
</p> </p>
</form> </form>
</div><!-- #respond --> </div><!-- #respond -->
{{else}} {{else}}
<p class="no-comments">评论已关闭。</p> <p class="no-comments">评论已关闭。</p>
{{end}} {{end}}
</div><!-- .comments-area --> </div><!-- .comments-area -->
{{end}} {{end}}
<nav class="navigation post-navigation" aria-label="文章"> <nav class="navigation post-navigation" aria-label="文章">
<h2 class="screen-reader-text">文章导航</h2> <h2 class="screen-reader-text">文章导航</h2>
<div class="nav-links"> <div class="nav-links">
{{if gt .prev.Id 0}} {{if gt .prev.Id 0}}
<div class="nav-previous"> <div class="nav-previous">
<a href="/p/{{.prev.Id}}" rel="prev"> <a href="/p/{{.prev.Id}}" rel="prev">
<span class="meta-nav" aria-hidden="true">上一篇</span> <span class="meta-nav" aria-hidden="true">上一篇</span>
<span class="screen-reader-text">上篇文章:</span> <span class="screen-reader-text">上篇文章:</span>
<span class="post-title">{{.prev.PostTitle}}</span></a> <span class="post-title">{{.prev.PostTitle}}</span></a>
</div> </div>
{{end}} {{end}}
{{if gt .next.Id 0}} {{if gt .next.Id 0}}
<div class="nav-next"> <div class="nav-next">
<a href="/p/{{.next.Id}}" rel="next"> <a href="/p/{{.next.Id}}" rel="next">
<span class="meta-nav" aria-hidden="true">下一篇</span> <span class="meta-nav" aria-hidden="true">下一篇</span>
<span class="screen-reader-text">下篇文章:</span> <span class="screen-reader-text">下篇文章:</span>
<span class="post-title">{{.next.PostTitle}}</span></a> <span class="post-title">{{.next.PostTitle}}</span></a>
</div> </div>
{{end}} {{end}}
</div>
</nav>
</main><!-- .site-main -->
</div> </div>
</nav>
</main><!-- .site-main --> <aside id="secondary" class="widget-area" aria-label="博客边栏">
{{template "layout/sidebar" .}}
</aside>
</div>
</div>
</div> </div>
{{else}} {{else}}
{{template "layout/empty"}} {{template "layout/empty"}}
{{end }} {{end }}
{{end}} {{end}}
{{ define "footer"}}
{{ define "footerx"}}
<script src='/wp-includes/js/comment-reply.min.js?ver=6.0.2' id='comment-reply-js'></script> <script src='/wp-includes/js/comment-reply.min.js?ver=6.0.2' id='comment-reply-js'></script>
{{end}} {{end}}

View File

@ -1,81 +1,86 @@
{{template "layout/base" .}} {{template "layout/base" .}}
{{define "content" }} {{define "content" }}
{{if .posts}} <div class="site-content-contain">
<div id="content" class="site-content">
{{if .posts}}
<div class="wrap"> <div class="wrap">
<header class="page-header"> <header class="page-header">
<h2 class="page-title">文章</h2> <h2 class="page-title">文章</h2>
</header> </header>
<div id="primary" class="content-area"> <div id="primary" class="content-area">
<main id="main" class="site-main"> <main id="main" class="site-main">
{{if .header}} {{if .header}}
<header class="page-header"> <header class="page-header">
<h1 class="page-title"> <h1 class="page-title">
{{if .search}} {{if .search}}
{{.header}} {{.header}}
{{else}} {{else}}
{{.header |unescaped}} {{.header |unescaped}}
{{end}} {{end}}
</h1> </h1>
</header> </header>
{{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 {{if $v.Thumbnail.Path}}has-post-thumbnail{{end}} type-post status-publish format-standard hentry category"> class="post-{{$v.Id}} post {{if $v.Thumbnail.Path}}has-post-thumbnail{{end}} type-post status-publish format-standard hentry category">
<header class="entry-header"> <header class="entry-header">
<div class="entry-meta"> <div class="entry-meta">
<span class="screen-reader-text">发布于 </span> <span class="screen-reader-text">发布于 </span>
<a href="/p/{{$v.Id}}" rel="bookmark"> <a href="/p/{{$v.Id}}" rel="bookmark">
<time class="entry-date published" datetime="{{$v.PostDateGmt}}">{{$v.PostDate|dateCh}} <time class="entry-date published" datetime="{{$v.PostDateGmt}}">{{$v.PostDate|dateCh}}
</time><time class="updated" datetime="{{$v.PostModifiedGmt}}">{{$v.PostModified|dateCh}} </time><time class="updated" datetime="{{$v.PostModifiedGmt}}">{{$v.PostModified|dateCh}}
</time> </time>
</a> </a>
</div> </div>
<h3 class="entry-title"> <h3 class="entry-title">
<a href="/p/{{$v.Id}}" rel="bookmark">{{$v.PostTitle}}</a> <a href="/p/{{$v.Id}}" rel="bookmark">{{$v.PostTitle}}</a>
</h3> </h3>
</header> </header>
{{if $v.Thumbnail.Path}} {{if $v.Thumbnail.Path}}
<div class="post-thumbnail"> <div class="post-thumbnail">
<a href="/p/{{$v.Id}}" > <a href="/p/{{$v.Id}}" >
<img width="{{$v.Thumbnail.Width}}" height="{{$v.Thumbnail.Height}}" src="{{$v.Thumbnail.Path}}" class="attachment-twentyseventeen-featured-image size-twentyseventeen-featured-image wp-post-image" alt="{{$v.PostTitle}}" decoding="async" loading="lazy" srcset="{{$v.Thumbnail.Srcset}}" sizes="{{$v.Thumbnail.Sizes}}"> <img width="{{$v.Thumbnail.Width}}" height="{{$v.Thumbnail.Height}}" src="{{$v.Thumbnail.Path}}" class="attachment-twentyseventeen-featured-image size-twentyseventeen-featured-image wp-post-image" alt="{{$v.PostTitle}}" decoding="async" loading="lazy" srcset="{{$v.Thumbnail.Srcset}}" sizes="{{$v.Thumbnail.Sizes}}">
</a> </a>
</div> </div>
{{end}}
<!-- .entry-header -->
<div class="entry-content">
{{$v.PostContent|unescaped}}
</div>
<!-- .entry-content -->
</article>
<!-- #post-{{$v.Id}} -->
{{end}} {{end}}
{{template "layout/page" .}}
</main>
<!-- .site-main -->
<!-- .entry-header --> </div>
<div class="entry-content"> <aside id="secondary" class="widget-area" aria-label="博客边栏">
{{$v.PostContent|unescaped}} {{template "layout/sidebar" .}}
</div> </aside>
</div>
<!-- .entry-content --> {{else }}
{{template "layout/empty" .}}
{{end}}
{{end}}
</article>
<!-- #post-{{$v.Id}} -->
{{end}}
{{template "layout/page" .}}
</main>
<!-- .site-main -->
</div>
<aside id="secondary" class="widget-area" aria-label="博客边栏">
{{template "layout/sidebar" .}}
</aside>
</div> </div>
</div>
{{else }}
{{template "layout/empty" .}}
{{end}}
{{end}}

View File

@ -1,8 +1,11 @@
package twentyseventeen package twentyseventeen
import ( import (
"fmt"
"github.com/elliotchance/phpserialize" "github.com/elliotchance/phpserialize"
"github.com/fthvgb1/wp-go/helper/maps" "github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/helper/slice"
str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/internal/pkg/cache" "github.com/fthvgb1/wp-go/internal/pkg/cache"
"github.com/fthvgb1/wp-go/internal/pkg/logs" "github.com/fthvgb1/wp-go/internal/pkg/logs"
"github.com/fthvgb1/wp-go/internal/pkg/models" "github.com/fthvgb1/wp-go/internal/pkg/models"
@ -44,6 +47,7 @@ func Hook(status int, c *gin.Context, h gin.H, scene, stats int) {
templ := "twentyseventeen/posts/index.gohtml" templ := "twentyseventeen/posts/index.gohtml"
if _, ok := plugins.IndexSceneMap[scene]; ok { if _, ok := plugins.IndexSceneMap[scene]; ok {
h["HeaderImage"] = getHeaderImage(c) h["HeaderImage"] = getHeaderImage(c)
posts := h["posts"].([]models.Posts)
p, ok := h["pagination"] p, ok := h["pagination"]
if ok { if ok {
pp, ok := p.(pagination.ParsePagination) pp, ok := p.(pagination.ParsePagination)
@ -51,18 +55,58 @@ func Hook(status int, c *gin.Context, h gin.H, scene, stats int) {
h["pagination"] = pagination.Paginate(paginate, pp) h["pagination"] = pagination.Paginate(paginate, pp)
} }
} }
d := 0
s := ""
if scene == plugins.Search {
if len(posts) > 0 {
d = 1
} else {
d = 0
}
} else if scene == plugins.Category {
cate := slice.Filter(cache.Categories(c), func(my models.TermsMy) bool {
return my.Name == c.Param("category")
})[0]
d = int(cate.Terms.TermId)
if cate.Slug[0] != '%' {
s = cate.Slug
}
}
h["bodyClass"] = bodyClass(scene, d, s)
h["posts"] = postThumbnail(posts, scene)
} else if scene == plugins.Detail { } else if scene == plugins.Detail {
h["HeaderImage"] = getHeaderImage(c) h["HeaderImage"] = getHeaderImage(c)
post := h["post"].(models.Posts)
h["bodyClass"] = bodyClass(scene, int(post.Id))
host, _ := wpconfig.Options.Load("siteurl")
img := plugins.Thumbnail(post.Thumbnail.OriginAttachmentData, "thumbnail", host, "thumbnail", "post-thumbnail")
img.Width = img.OriginAttachmentData.Width
img.Height = img.OriginAttachmentData.Height
img.Sizes = "100vw"
img.Srcset = fmt.Sprintf("%s %dw, %s", img.Path, img.Width, img.Srcset)
post.Thumbnail = img
h["post"] = post
templ = "twentyseventeen/posts/detail.gohtml" templ = "twentyseventeen/posts/detail.gohtml"
} }
c.HTML(status, templ, h) c.HTML(status, templ, h)
return return
} }
func postThumbnail(posts []models.Posts, scene int) []models.Posts {
return slice.Map(posts, func(t models.Posts) models.Posts {
if t.Thumbnail.Path != "" {
if slice.IsContained(scene, []int{plugins.Home, plugins.Archive, plugins.Search}) {
t.Thumbnail.Sizes = "(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px"
} else {
t.Thumbnail.Sizes = "100vw"
}
}
return t
})
}
func getHeaderImage(c *gin.Context) (r models.PostThumbnail) { func getHeaderImage(c *gin.Context) (r models.PostThumbnail) {
r.Path = "/wp-content/themes/twentyseventeen/assets/images/header.jpg" r.Path = "/wp-content/themes/twentyseventeen/assets/images/header.jpg"
r.Width = 2000
r.Height = 1200
meta, err := getHeaderMarkup() meta, err := getHeaderMarkup()
if err != nil { if err != nil {
logs.ErrPrintln(err, "解析主题背景图设置错误") logs.ErrPrintln(err, "解析主题背景图设置错误")
@ -74,10 +118,18 @@ func getHeaderImage(c *gin.Context) (r models.PostThumbnail) {
logs.ErrPrintln(err, "获取主题背景图信息错误") logs.ErrPrintln(err, "获取主题背景图信息错误")
return return
} }
host, _ := wpconfig.Options.Load("siteurl")
m.Thumbnail = plugins.Thumbnail(m.AttachmentMetadata, "thumbnail", host, "thumbnail", "post-thumbnail", "twentyseventeen-thumbnail-avatar")
if m.Thumbnail.Path != "" { if m.Thumbnail.Path != "" {
r = m.Thumbnail r = m.Thumbnail
if len(m.AttachmentMetadata.Sizes) > 0 {
r.Srcset = str.Join(r.Path, " 2000vw, ", r.Srcset)
}
} }
} }
r.Width = 2000
r.Height = 1200
r.Sizes = "100vw"
return return
} }
@ -93,3 +145,25 @@ func getHeaderMarkup() (r HeaderImageMeta, err error) {
} }
return return
} }
func bodyClass(scene, d int, a ...any) string {
s := ""
if scene == plugins.Search {
if d > 0 {
s = "search-results"
} else {
s = "search-no-results"
}
} else if scene == plugins.Category {
s = fmt.Sprintf("category-%d %v", d, a[0])
} else if scene == plugins.Detail {
s = fmt.Sprintf("postid-%d", d)
}
return map[int]string{
plugins.Home: "home blog ",
plugins.Archive: "archive date page-two-column",
plugins.Category: str.Join("archive category page-two-column ", s),
plugins.Search: str.Join("search ", s),
plugins.Detail: str.Join("post-template-default single single-post single-format-standard ", s),
}[scene]
}

View File

@ -1,7 +1,7 @@
package stream package stream
import ( import (
"github.com/fthvgb1/wp-go/safety" "github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/taskPools" "github.com/fthvgb1/wp-go/taskPools"
"sync" "sync"
) )
@ -24,15 +24,8 @@ func newMapX[K comparable, V any]() mapX[K, V] {
} }
} }
func SimpleMapFilterAndMapToSlice[R any, K comparable, V any](mm SimpleMapStream[K, V], fn func(K, V) (R, bool), c int) SimpleSliceStream[R] { func SimpleMapFilterAndMapToSlice[R any, K comparable, V any](mm SimpleMapStream[K, V], fn func(K, V) (R, bool)) SimpleSliceStream[R] {
rr := safety.NewSlice([]R{}) return NewSimpleSliceStream(maps.FilterToSlice(mm.m, fn))
mm.ParallelForEach(func(k K, v V) {
vv, ok := fn(k, v)
if ok {
rr.Append(vv)
}
}, c)
return NewSimpleSliceStream(rr.Load())
} }
func SimpleMapParallelFilterAndMapToMap[K comparable, V any, KK comparable, VV any](mm SimpleMapStream[KK, VV], fn func(KK, VV) (K, V, bool), c int) SimpleMapStream[K, V] { func SimpleMapParallelFilterAndMapToMap[K comparable, V any, KK comparable, VV any](mm SimpleMapStream[KK, VV], fn func(KK, VV) (K, V, bool), c int) SimpleMapStream[K, V] {