Compare commits
2 Commits
2d476ea4f6
...
8d398016ac
Author | SHA1 | Date | |
---|---|---|---|
8d398016ac | |||
a313210f71 |
|
@ -1,6 +1,6 @@
|
|||
## wp-go
|
||||
|
||||
一个go写的WordPress的前端,功能比较简单,只有列表页和详情页,rss2,主题只有twentyfifteen和twentyseventeen两套主题,插件的话只有一个简单的列表页的摘要生成和enlighter代码高亮。本身只用于展示文章及评论。因为大量用了泛型功能,所以要求go的版本在1.19及以上,越新越好。。。
|
||||
一个go写的WordPress的前端,功能比较简单,只有列表页和详情页,rss2,主题只有twentyfifteen和twentyseventeen两套主题,插件的话只有一个简单的列表页的摘要生成和enlighter代码高亮。本身只用于展示文章及评论。要求go的版本在1.20以上,越新越好。。。
|
||||
|
||||
#### 特色功能
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ func IsZeros(v any) bool {
|
|||
switch v.(type) {
|
||||
case int64, int, int8, int16, int32, uint64, uint, uint8, uint16, uint32:
|
||||
i := fmt.Sprintf("%d", v)
|
||||
return str.ToInt[int](i) == 0
|
||||
return str.ToInt[int64](i) == 0
|
||||
case float32, float64:
|
||||
f := fmt.Sprintf("%v", v)
|
||||
ff, _ := strconv.ParseFloat(f, 64)
|
||||
|
@ -81,7 +81,7 @@ func IsZeros(v any) bool {
|
|||
s := v.(string)
|
||||
return s == ""
|
||||
}
|
||||
return false
|
||||
return reflect.DeepEqual(v, reflect.Zero(reflect.TypeOf(v)).Interface())
|
||||
}
|
||||
|
||||
func ToBool[T comparable](t T) bool {
|
||||
|
|
|
@ -217,3 +217,21 @@ func TestToBool(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsZeros(t *testing.T) {
|
||||
tt := struct {
|
||||
name string
|
||||
args struct {
|
||||
v struct{ a string }
|
||||
}
|
||||
want bool
|
||||
}{
|
||||
name: "t1",
|
||||
args: struct{ v struct{ a string } }{v: struct{ a string }{a: ""}},
|
||||
}
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := IsZeros(tt.args.v); got != tt.want {
|
||||
t.Errorf("IsZeros() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
3
internal/pkg/cache/cache.go
vendored
3
internal/pkg/cache/cache.go
vendored
|
@ -124,6 +124,9 @@ func (a *Arch) getArchiveCache(ctx context.Context) []models.PostArchive {
|
|||
return a.data
|
||||
}
|
||||
|
||||
// CategoriesTags categories or tags
|
||||
//
|
||||
// t is constraints.Tag or constraints.Category
|
||||
func CategoriesTags(ctx context.Context, t ...int) []models.TermsMy {
|
||||
r, err := categoryAndTagsCaches.GetCache(ctx, time.Second, ctx)
|
||||
logs.ErrPrintln(err, "get category err")
|
||||
|
|
|
@ -5,4 +5,5 @@ const (
|
|||
RecentPostsArgs = "RecentPostsArgs"
|
||||
RecentCommentsArgs = "RecentCommentsArgs"
|
||||
ArchiveArgs = "ArchiveArgs"
|
||||
Categories = "Categories"
|
||||
)
|
||||
|
|
|
@ -32,7 +32,7 @@ var repeat = map[string]string{
|
|||
|
||||
func CalCustomBackGround(h *wp.Handle) (r string) {
|
||||
themeMods := h.CommonThemeMods()
|
||||
if themeMods.BackgroundImage == "" && themeMods.BackgroundColor == themesupport.CustomBackground.DefaultColor {
|
||||
if themeMods.BackgroundImage == "" && (themeMods.BackgroundColor == "" || themeMods.BackgroundColor == themesupport.CustomBackground.DefaultColor) {
|
||||
return
|
||||
}
|
||||
s := str.NewBuilder()
|
||||
|
|
|
@ -1,20 +1,6 @@
|
|||
{{define "layout/sidebar" }}
|
||||
<div id="widget-area" class="widget-area" role="complementary">
|
||||
{{template "common/sidebarWidget" .}}
|
||||
|
||||
<aside id="categories-2" class="widget widget_categories">
|
||||
<h2 class="widget-title">分类</h2>
|
||||
<nav aria-label="分类">
|
||||
<ul>
|
||||
{{range $k,$v := .categories}}
|
||||
<li class="cat-item cat-item-{{$v.Terms.TermId}}">
|
||||
<a href="/p/category/{{$v.Name}}">{{$v.Name}}</a>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
</aside>
|
||||
<aside id="meta-2" class="widget widget_meta"><h2 class="widget-title">其他操作</h2>
|
||||
<nav aria-label="其他操作">
|
||||
<ul>
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/fthvgb1/wp-go/internal/plugins/wphandle"
|
||||
"github.com/fthvgb1/wp-go/internal/theme/wp"
|
||||
"github.com/fthvgb1/wp-go/internal/theme/wp/components"
|
||||
"github.com/fthvgb1/wp-go/internal/theme/wp/components/widget"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -33,7 +34,7 @@ func Init(fs embed.FS) {
|
|||
logs.ErrPrintln(err, "解析colorscheme失败")
|
||||
}
|
||||
|
||||
var pipe = wp.HandlePipe(wp.Render, dispatch)
|
||||
var pipe = wp.HandlePipe(wp.Render, widget.IsCategory, dispatch)
|
||||
|
||||
func Hook(h *wp.Handle) {
|
||||
pipe(h)
|
||||
|
|
185
internal/theme/wp/components/widget/category.go
Normal file
185
internal/theme/wp/components/widget/category.go
Normal file
|
@ -0,0 +1,185 @@
|
|||
package widget
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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/constraints"
|
||||
"github.com/fthvgb1/wp-go/internal/pkg/constraints/widgets"
|
||||
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
||||
"github.com/fthvgb1/wp-go/internal/theme/wp"
|
||||
"github.com/fthvgb1/wp-go/internal/wpconfig"
|
||||
"github.com/fthvgb1/wp-go/safety"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var categoryArgs safety.Var[map[string]string]
|
||||
var categoryConfig = func() safety.Var[map[any]any] {
|
||||
v := safety.Var[map[any]any]{}
|
||||
v.Store(map[any]any{
|
||||
"count": int64(0),
|
||||
"dropdown": int64(0),
|
||||
"hierarchical": int64(0),
|
||||
"title": "分类",
|
||||
})
|
||||
categoryArgs.Store(map[string]string{
|
||||
"{$before_widget}": `<aside id="categories-2" class="widget widget_categories">`,
|
||||
"{$after_widget}": "</aside>",
|
||||
"{$before_title}": `<h2 class="widget-title">`,
|
||||
"{$after_title}": "</h2>",
|
||||
"{$before_sidebar}": "",
|
||||
"{$after_sidebar}": "",
|
||||
"{$class}": "postform",
|
||||
"{$show_option_none}": "选择分类",
|
||||
"{$name}": "cat",
|
||||
"{$id}": "cat",
|
||||
"{$required}": "",
|
||||
"{$nav}": "",
|
||||
"{$navCloser}": "",
|
||||
"{$title}": "",
|
||||
"{$dropdown_id}": "archives-dropdown-2",
|
||||
"{$dropdown_type}": "monthly",
|
||||
"{$dropdown_label}": "选择月份",
|
||||
})
|
||||
return v
|
||||
}()
|
||||
|
||||
var categoryTemplate = `{$before_widget}
|
||||
{$title}
|
||||
{$nav}
|
||||
{$html}
|
||||
{$navCloser}
|
||||
{$after_widget}
|
||||
`
|
||||
|
||||
func Category(h *wp.Handle) string {
|
||||
args := wp.GetComponentsArgs(h, widgets.Categories, categoryArgs.Load())
|
||||
args = maps.FilterZeroMerge(categoryArgs.Load(), args)
|
||||
conf := wpconfig.GetPHPArrayVal("widget_categories", categoryConfig.Load(), int64(2))
|
||||
conf = maps.FilterZeroMerge(categoryConfig.Load(), conf)
|
||||
args["{$title}"] = str.Join(args["{$before_title}"], conf["title"].(string), args["{$after_title}"])
|
||||
t := categoryTemplate
|
||||
dropdown := conf["dropdown"].(int64)
|
||||
categories := cache.CategoriesTags(h.C, constraints.Category)
|
||||
if dropdown == 1 {
|
||||
t = strings.ReplaceAll(t, "{$html}", categoryDropdown(h, args, conf, categories))
|
||||
|
||||
} else {
|
||||
t = strings.ReplaceAll(t, "{$html}", categoryUL(h, args, conf, categories))
|
||||
}
|
||||
return str.Replace(t, args)
|
||||
}
|
||||
|
||||
func categoryUL(h *wp.Handle, args map[string]string, conf map[any]any, categories []models.TermsMy) string {
|
||||
if slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
|
||||
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, args["{title}"])
|
||||
args["{$navCloser}"] = "</nav>"
|
||||
}
|
||||
s := str.NewBuilder()
|
||||
s.WriteString("<ul>\n")
|
||||
isCount := conf["count"].(int64)
|
||||
for _, category := range categories {
|
||||
count := ""
|
||||
if isCount != 0 {
|
||||
count = fmt.Sprintf("(%d)", category.Count)
|
||||
}
|
||||
s.Sprintf(` <li class="cat-item cat-item-%d">
|
||||
<a href="/p/category/%s">%s %s</a>
|
||||
</li>
|
||||
`, category.Terms.TermId, category.Name, category.Name, count)
|
||||
}
|
||||
s.WriteString("</ul>")
|
||||
return s.String()
|
||||
}
|
||||
|
||||
var categoryDropdownJs = `/* <![CDATA[ */
|
||||
(function() {
|
||||
var dropdown = document.getElementById( "%s" );
|
||||
function onCatChange() {
|
||||
if ( dropdown.options[ dropdown.selectedIndex ].value > 0 ) {
|
||||
dropdown.parentNode.submit();
|
||||
}
|
||||
}
|
||||
dropdown.onchange = onCatChange;
|
||||
})();
|
||||
/* ]]> */
|
||||
`
|
||||
|
||||
func categoryDropdown(h *wp.Handle, args map[string]string, conf map[any]any, categories []models.TermsMy) string {
|
||||
s := str.NewBuilder()
|
||||
s.WriteString(`<form action="/" method="get">
|
||||
`)
|
||||
s.Sprintf(` <label class="screen-reader-text" for="%s">%s</label>
|
||||
`, args["{$id}"], args["{$title}"])
|
||||
if len(categories) > 0 {
|
||||
s.Sprintf(` <select %s name="%s" id="%s" class="%s">
|
||||
`, args["{$required}"], args["{$name}"], args["{$id}"], args["{$class}"])
|
||||
s.Sprintf(` <option value="%[1]s">%[1]s</option>
|
||||
`, args["{$show_option_none}"])
|
||||
currentCategory := ""
|
||||
if h.Scene() == constraints.Category {
|
||||
currentCategory = h.Index.Param.Category
|
||||
}
|
||||
showCount := conf["count"].(int64)
|
||||
for _, category := range categories {
|
||||
selected := ""
|
||||
if category.Name == currentCategory {
|
||||
selected = "selected"
|
||||
}
|
||||
count := ""
|
||||
if showCount != 0 {
|
||||
count = fmt.Sprintf("(%d)", category.Count)
|
||||
}
|
||||
s.Sprintf(` <option %s value="%d">%s %s</option>
|
||||
`, selected, category.Terms.TermId, category.Name, count)
|
||||
}
|
||||
s.WriteString(" </select>\n")
|
||||
}
|
||||
s.WriteString("</form>\n")
|
||||
attr := ""
|
||||
if !slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "script") {
|
||||
attr = ` type="text/javascript"`
|
||||
}
|
||||
s.Sprintf(`<script%s>
|
||||
`, attr)
|
||||
s.Sprintf(categoryDropdownJs, args["{$id}"])
|
||||
s.WriteString("</script>\n")
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func IsCategory(next wp.HandleFn[*wp.Handle], h *wp.Handle) {
|
||||
if h.Scene() != constraints.Home {
|
||||
next(h)
|
||||
return
|
||||
}
|
||||
name, ok := parseDropdownCate(h)
|
||||
if !ok {
|
||||
next(h)
|
||||
return
|
||||
}
|
||||
h.C.Redirect(http.StatusMovedPermanently, fmt.Sprintf("/p/category/%s", name))
|
||||
}
|
||||
|
||||
func parseDropdownCate(h *wp.Handle) (cateName string, r bool) {
|
||||
cate := wp.GetComponentsArgs[map[string]string](h, widgets.Categories, categoryArgs.Load())
|
||||
name, ok := cate["{$name}"]
|
||||
if !ok || name == "" {
|
||||
return
|
||||
}
|
||||
cat := h.C.Query(name)
|
||||
if cat == "" {
|
||||
return
|
||||
}
|
||||
cates := slice.SimpleToMap(cache.CategoriesTags(h.C, constraints.Category), func(v models.TermsMy) uint64 {
|
||||
return v.Terms.TermId
|
||||
})
|
||||
cc, r := cates[str.ToInteger[uint64](cat, 0)]
|
||||
if !r {
|
||||
return
|
||||
}
|
||||
cateName = cc.Name
|
||||
return
|
||||
}
|
|
@ -14,6 +14,7 @@ var widgets = map[string]func(*wp.Handle) string{
|
|||
"recent-posts-2": widget.RecentPosts,
|
||||
"recent-comments-2": widget.RecentComments,
|
||||
"archives-2": widget.Archive,
|
||||
"categories-2": widget.Category,
|
||||
}
|
||||
|
||||
func WidgetArea(h *wp.Handle) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user