背景设置 custom-background

This commit is contained in:
xing 2023-02-16 00:32:02 +08:00
parent 729da0495d
commit bc6b3675ab
17 changed files with 626 additions and 14 deletions

View File

@ -1,7 +1,9 @@
package helper
import (
"net/url"
"reflect"
"strings"
)
func ToAny[T any](v T) any {
@ -24,3 +26,35 @@ func StructColumnToSlice[T any, M any](arr []M, field string) (r []T) {
}
return
}
func UrlScheme(u string, isHttps bool) string {
return Or(isHttps,
strings.Replace(u, "http://", "https://", 1),
strings.Replace(u, "https://", "http://", 1),
)
}
func CutUrlHost(u string) string {
ur, err := url.Parse(u)
if err != nil {
return u
}
ur.Scheme = ""
ur.Host = ""
return ur.String()
}
func Defaults[T comparable](v, defaults T) T {
var zero T
if v == zero {
return defaults
}
return v
}
func DefaultVal[T any](v, defaults T) T {
var zero T
if reflect.DeepEqual(zero, v) {
return defaults
}
return v
}

View File

@ -97,3 +97,50 @@ func TestToAny(t *testing.T) {
})
}
}
func TestCutUrlHost(t *testing.T) {
type args struct {
u string
}
tests := []struct {
name string
args args
want string
}{
{
name: "http",
args: args{"http://xx.yy/xxoo?ss=fff"},
want: "/xxoo?ss=fff",
}, {
name: "https",
args: args{"https://xx.yy/xxoo?ff=fff"},
want: "/xxoo?ff=fff",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := CutUrlHost(tt.args.u); got != tt.want {
t.Errorf("CutUrlHost() = %v, want %v", got, tt.want)
}
})
}
}
func TestDefaults(t *testing.T) {
v := 0
want := 1
t.Run("int", func(t *testing.T) {
if got := Defaults(v, want); !reflect.DeepEqual(got, want) {
t.Errorf("Defaults() = %v, want %v", got, want)
}
})
{
v := ""
want := "a"
t.Run("string", func(t *testing.T) {
if got := Defaults(v, want); !reflect.DeepEqual(got, want) {
t.Errorf("Defaults() = %v, want %v", got, want)
}
})
}
}

View File

@ -108,3 +108,11 @@ func Merge[K comparable, V any](m ...map[K]V) map[K]V {
}
return mm
}
func WithDefaultVal[K comparable, V any](m map[K]V, k K, defaults V) V {
vv, ok := m[k]
if ok {
return vv
}
return defaults
}

View File

@ -11,6 +11,7 @@ import (
"github.com/fthvgb1/wp-go/internal/pkg/logs"
"github.com/fthvgb1/wp-go/internal/plugins"
"github.com/fthvgb1/wp-go/internal/theme"
"github.com/fthvgb1/wp-go/internal/theme/common"
"github.com/fthvgb1/wp-go/internal/wpconfig"
"github.com/fthvgb1/wp-go/model"
"log"
@ -106,6 +107,7 @@ func reload() {
logs.ErrPrintln(err, "获取网站设置WpOption失败")
err = wpconfig.InitTerms()
wpconfig.FlushModes()
common.Reload()
logs.ErrPrintln(err, "获取WpTerms表失败")
if middleWareReloadFn != nil {
middleWareReloadFn()

View File

@ -7,6 +7,7 @@ import (
"github.com/fthvgb1/wp-go/internal/pkg/constraints"
"github.com/fthvgb1/wp-go/internal/static"
"github.com/fthvgb1/wp-go/internal/theme"
"github.com/fthvgb1/wp-go/internal/wpconfig"
"github.com/gin-contrib/gzip"
"github.com/gin-contrib/pprof"
"github.com/gin-contrib/sessions"
@ -28,6 +29,7 @@ func SetupRouter() (*gin.Engine, func()) {
}
r.HTMLRender = theme.GetTemplate()
wpconfig.SetTemplateFs(theme.TemplateFs)
validServerName, reloadValidServerNameFn := middleware.ValidateServerNames()
fl, flReload := middleware.FlowLimit(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime)

View File

@ -0,0 +1,85 @@
package common
import (
"fmt"
"github.com/fthvgb1/wp-go/helper"
"github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/internal/wpconfig"
"github.com/fthvgb1/wp-go/safety"
"strings"
)
var postx = map[string]string{
"left": "left",
"right": "right",
"center": "center",
}
var posty = map[string]string{
"top": "top",
"bottom": "bottom",
"center": "center",
}
var size = map[string]string{
"auto": "auto",
"contain": "contain",
"cover": "cover",
}
var repeat = map[string]string{
"repeat-x": "repeat-x",
"repeat-y": "repeat-y",
"repeat": "repeat",
"no-repeat": "no-repeat",
}
var backgroud = safety.NewVar("")
func (h *Handle) CustomBackGround() {
b := backgroud.Load()
if b == "" {
b = h.CalCustomBackGround()
backgroud.Store(b)
}
h.GinH["customBackground"] = b
}
func (h *Handle) CalCustomBackGround() (r string) {
mods, err := wpconfig.GetThemeMods(h.Theme)
if err != nil {
return
}
if mods.BackgroundImage == "" && mods.BackgroundColor == mods.ThemeSupport.CustomBackground.DefaultColor {
return
}
s := strings.Builder{}
if mods.BackgroundImage != "" {
s.WriteString(` background-image: url("`)
s.WriteString(helper.CutUrlHost(mods.BackgroundImage))
s.WriteString(`");`)
}
backgroundPositionX := helper.Defaults(mods.BackgroundPositionX, mods.ThemeSupport.CustomBackground.DefaultPositionX)
backgroundPositionX = maps.WithDefaultVal(postx, backgroundPositionX, "left")
backgroundPositionY := helper.Defaults(mods.BackgroundPositionY, mods.ThemeSupport.CustomBackground.DefaultPositionY)
backgroundPositionY = maps.WithDefaultVal(posty, backgroundPositionY, "top")
positon := fmt.Sprintf(" background-position: %s %s;", backgroundPositionX, backgroundPositionY)
siz := helper.DefaultVal(mods.BackgroundSize, mods.ThemeSupport.CustomBackground.DefaultSize)
siz = maps.WithDefaultVal(size, siz, "auto")
siz = fmt.Sprintf(" background-size: %s;", siz)
repeats := helper.Defaults(mods.BackgroundRepeat, mods.ThemeSupport.CustomBackground.DefaultRepeat)
repeats = maps.WithDefaultVal(repeat, repeats, "repeat")
repeats = fmt.Sprintf(" background-repeat: %s;", repeats)
attachment := helper.Defaults(mods.BackgroundAttachment, mods.ThemeSupport.CustomBackground.DefaultAttachment)
attachment = helper.Or(attachment == "fixed", "fixed", "scroll")
attachment = fmt.Sprintf(" background-attachment: %s;", attachment)
s.WriteString(positon)
s.WriteString(siz)
s.WriteString(repeats)
s.WriteString(attachment)
r = fmt.Sprintf(`<style id="custom-background-css">
body.custom-background {%s}
</style>`, s.String())
return
}

View File

@ -102,6 +102,7 @@ func (d *DetailHandle) Render() {
if d.Templ == "" {
d.Templ = fmt.Sprintf("%s/posts/detail.gohtml", d.Theme)
}
d.CustomBackGround()
d.C.HTML(d.Code, d.Templ, d.GinH)
}

View File

@ -116,6 +116,7 @@ func (i *IndexHandle) Render() {
if i.Templ == "" {
i.Templ = fmt.Sprintf("%s/posts/index.gohtml", i.Theme)
}
i.CustomBackGround()
i.C.HTML(i.Code, i.Templ, i.GinH)
}

View File

@ -0,0 +1,5 @@
package common
func Reload() {
backgroud.Flush()
}

View File

@ -0,0 +1,68 @@
{
"default": {
"label": "Default",
"colors": [
"#f1f1f1",
"#ffffff",
"#ffffff",
"#333333",
"#333333",
"#f7f7f7"
]
},
"dark": {
"label": "Dark",
"colors": [
"#111111",
"#202020",
"#202020",
"#bebebe",
"#bebebe",
"#1b1b1b"
]
},
"yellow": {
"label": "Yellow",
"colors": [
"#f4ca16",
"#ffdf00",
"#ffffff",
"#111111",
"#111111",
"#f1f1f1"
]
},
"pink": {
"label": "Pink",
"colors": [
"#ffe5d1",
"#e53b51",
"#ffffff",
"#352712",
"#ffffff",
"#f1f1f1"
]
},
"purple": {
"label": "Purple",
"colors": [
"#674970",
"#2e2256",
"#ffffff",
"#2e2256",
"#ffffff",
"#f1f1f1"
]
},
"blue": {
"label": "Blue",
"colors": [
"#e9f2f9",
"#55c3dc",
"#ffffff",
"#22313f",
"#ffffff",
"#f1f1f1"
]
}
}

View File

@ -57,4 +57,8 @@
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="/wp-includes/wlwmanifest.xml" />
<meta name="generator" content="WordPress 6.0.2" />
<style>.recentcomments a{display:inline !important;padding:0 !important;margin:0 !important;}</style>
{{if .customBackground}}
{{.customBackground|unescaped}}
{{end}}
{{end}}

View File

@ -0,0 +1,196 @@
{
"core-block-patterns": true,
"widgets-block-editor": true,
"automatic-feed-links": true,
"title-tag": true,
"post-thumbnails": true,
"menus": true,
"html5": [
"search-form",
"comment-form",
"comment-list",
"gallery",
"caption",
"script",
"style",
"navigation-widgets"
],
"post-formats": [
"aside",
"image",
"video",
"quote",
"link",
"gallery",
"status",
"audio",
"chat"
],
"custom-logo": {
"width": 248,
"height": 248,
"flex-width": false,
"flex-height": true,
"header-text": "",
"unlink-homepage-logo": false
},
"custom-background": {
"default-image": "",
"default-preset": "default",
"default-position-x": "left",
"default-position-y": "top",
"default-size": "auto",
"default-repeat": "repeat",
"default-attachment": "fixed",
"default-color": "f1f1f1",
"wp-head-callback": "_custom_background_cb",
"admin-head-callback": "",
"admin-preview-callback": ""
},
"editor-style": true,
"editor-styles": true,
"wp-block-styles": true,
"responsive-embeds": true,
"editor-color-palette": [
{
"name": "暗灰色",
"slug": "dark-gray",
"color": "#111"
},
{
"name": "亮灰色",
"slug": "light-gray",
"color": "#f1f1f1"
},
{
"name": "白色",
"slug": "white",
"color": "#fff"
},
{
"name": "黄色",
"slug": "yellow",
"color": "#f4ca16"
},
{
"name": "暗棕色",
"slug": "dark-brown",
"color": "#352712"
},
{
"name": "粉色",
"slug": "medium-pink",
"color": "#e53b51"
},
{
"name": "浅粉色",
"slug": "light-pink",
"color": "#ffe5d1"
},
{
"name": "暗紫色",
"slug": "dark-purple",
"color": "#2e2256"
},
{
"name": "紫色",
"slug": "purple",
"color": "#674970"
},
{
"name": "蓝灰色",
"slug": "blue-gray",
"color": "#22313f"
},
{
"name": "亮蓝色",
"slug": "bright-blue",
"color": "#55c3dc"
},
{
"name": "浅蓝色",
"slug": "light-blue",
"color": "#e9f2f9"
}
],
"editor-gradient-presets": [
{
"name": "Dark Gray Gradient",
"slug": "dark-gray-gradient-gradient",
"gradient": "linear-gradient(90deg, rgba(17,17,17,1) 0%, rgba(42,42,42,1) 100%)"
},
{
"name": "Light Gray Gradient",
"slug": "light-gray-gradient",
"gradient": "linear-gradient(90deg, rgba(241,241,241,1) 0%, rgba(215,215,215,1) 100%)"
},
{
"name": "White Gradient",
"slug": "white-gradient",
"gradient": "linear-gradient(90deg, rgba(255,255,255,1) 0%, rgba(230,230,230,1) 100%)"
},
{
"name": "Yellow Gradient",
"slug": "yellow-gradient",
"gradient": "linear-gradient(90deg, rgba(244,202,22,1) 0%, rgba(205,168,10,1) 100%)"
},
{
"name": "Dark Brown Gradient",
"slug": "dark-brown-gradient",
"gradient": "linear-gradient(90deg, rgba(53,39,18,1) 0%, rgba(91,67,31,1) 100%)"
},
{
"name": "Medium Pink Gradient",
"slug": "medium-pink-gradient",
"gradient": "linear-gradient(90deg, rgba(229,59,81,1) 0%, rgba(209,28,51,1) 100%)"
},
{
"name": "Light Pink Gradient",
"slug": "light-pink-gradient",
"gradient": "linear-gradient(90deg, rgba(255,229,209,1) 0%, rgba(255,200,158,1) 100%)"
},
{
"name": "Dark Purple Gradient",
"slug": "dark-purple-gradient",
"gradient": "linear-gradient(90deg, rgba(46,34,86,1) 0%, rgba(66,48,123,1) 100%)"
},
{
"name": "Purple Gradient",
"slug": "purple-gradient",
"gradient": "linear-gradient(90deg, rgba(103,73,112,1) 0%, rgba(131,93,143,1) 100%)"
},
{
"name": "Blue Gray Gradient",
"slug": "blue-gray-gradient",
"gradient": "linear-gradient(90deg, rgba(34,49,63,1) 0%, rgba(52,75,96,1) 100%)"
},
{
"name": "Bright Blue Gradient",
"slug": "bright-blue-gradient",
"gradient": "linear-gradient(90deg, rgba(85,195,220,1) 0%, rgba(43,180,211,1) 100%)"
},
{
"name": "Light Blue Gradient",
"slug": "light-blue-gradient",
"gradient": "linear-gradient(90deg, rgba(233,242,249,1) 0%, rgba(193,218,238,1) 100%)"
}
],
"customize-selective-refresh-widgets": true,
"custom-header": {
"default-image": "",
"random-default": false,
"width": 954,
"height": 1300,
"flex-height": false,
"flex-width": false,
"default-text-color": "333333",
"header-text": true,
"uploads": true,
"wp-head-callback": "twentyfifteen_header_style",
"admin-head-callback": "",
"admin-preview-callback": "",
"video": false,
"video-active-callback": "is_front_page"
},
"widgets": true
}

View File

@ -195,3 +195,12 @@ var class = map[int]string{
constraints.Search: "search ",
constraints.Detail: "post-template-default single single-post single-format-standard ",
}
func ThemeSupport() map[string]struct{} {
return map[string]struct{}{
"custom-header": {},
"wp-custom-logo": {},
"responsive-embeds": {},
"post-formats": {},
}
}

View File

@ -1,34 +1,53 @@
package wpconfig
import (
"embed"
"encoding/json"
"fmt"
"github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/internal/phphelper"
"github.com/fthvgb1/wp-go/internal/pkg/models"
"github.com/fthvgb1/wp-go/safety"
"path/filepath"
"strings"
)
var templateFs embed.FS
func SetTemplateFs(fs embed.FS) {
templateFs = fs
}
type ThemeMods struct {
CustomCssPostId int `json:"custom_css_post_id,omitempty"`
NavMenuLocations []string `json:"nav_menu_locations,omitempty"`
CustomLogo int `json:"custom_logo"`
CustomLogo int `json:"custom_logo,omitempty"`
HeaderImage string `json:"header_image,omitempty"`
BackgroundImage string `json:"background_image"`
BackgroundSize string `json:"background_size"`
BackgroundRepeat string `json:"background_repeat"`
BackgroundColor string `json:"background_color"`
ColorScheme string `json:"color_scheme"`
SidebarTextcolor string `json:"sidebar_textcolor"`
HeaderBackgroundColor string `json:"header_background_color"`
HeaderTextcolor string `json:"header_textcolor"`
BackgroundImage string `json:"background_image,omitempty"`
BackgroundSize string `json:"background_size,omitempty"`
BackgroundRepeat string `json:"background_repeat,omitempty"`
BackgroundColor string `json:"background_color,omitempty"`
BackgroundPreset string `json:"background_preset"`
BackgroundPositionX string `json:"background_position_x,omitempty"`
BackgroundPositionY string `json:"background_position_y"`
BackgroundAttachment string `json:"background_attachment"`
ColorScheme map[string]ColorScheme
SidebarTextcolor string `json:"sidebar_textcolor,omitempty"`
HeaderBackgroundColor string `json:"header_background_color,omitempty"`
HeaderTextcolor string `json:"header_textcolor,omitempty"`
HeaderImagData ImageData `json:"header_image_data,omitempty"`
SidebarsWidgets Sidebars `json:"sidebars_widgets"`
SidebarsWidgets Sidebars `json:"sidebars_widgets,omitempty"`
ThemeSupport ThemeSupport
}
type Sidebars struct {
Time int `json:"time,omitempty"`
Data SidebarsData `json:"data"`
Data SidebarsData `json:"data,omitempty"`
}
type ColorScheme struct {
Label string `json:"label,omitempty"`
Colors []string `json:"colors,omitempty"`
}
type SidebarsData struct {
@ -94,6 +113,7 @@ func GetThemeMods(theme string) (r ThemeMods, err error) {
if err != nil {
return
}
r.setThemeColorScheme(theme)
themeModes.Store(theme, r)
return
}
@ -120,3 +140,28 @@ func IsCustomLogo(theme string) bool {
return false
}
func (m *ThemeMods) setThemeColorScheme(themeName string) {
bytes, err := templateFs.ReadFile(filepath.Join(themeName, "colorscheme.json"))
if err != nil {
return
}
var scheme map[string]ColorScheme
err = json.Unmarshal(bytes, &scheme)
if err != nil {
return
}
m.ColorScheme = scheme
}
func (m *ThemeMods) setThemeSupport(themeName string) {
bytes, err := templateFs.ReadFile(filepath.Join(themeName, "themesupport.json"))
if err != nil {
return
}
var themeSupport ThemeSupport
err = json.Unmarshal(bytes, &themeSupport)
if err != nil {
return
}
m.ThemeSupport = themeSupport
}

View File

@ -0,0 +1,70 @@
package wpconfig
type ThemeSupport struct {
CoreBlockPatterns bool `json:"core-block-patterns"`
WidgetsBlockEditor bool `json:"widgets-block-editor"`
AutomaticFeedLinks bool `json:"automatic-feed-links"`
TitleTag bool `json:"title-tag"`
PostThumbnails bool `json:"post-thumbnails"`
Menus bool `json:"menus"`
HTML5 []string `json:"html5"`
PostFormats []string `json:"post-formats"`
CustomLogo CustomLogo `json:"custom-logo"`
CustomBackground CustomBackground `json:"custom-background"`
EditorStyle bool `json:"editor-style"`
EditorStyles bool `json:"editor-styles"`
WpBlockStyles bool `json:"wp-block-styles"`
ResponsiveEmbeds bool `json:"responsive-embeds"`
EditorColorPalette []EditorColorPalette `json:"editor-color-palette"`
EditorGradientPresets []EditorGradientPresets `json:"editor-gradient-presets"`
CustomizeSelectiveRefreshWidgets bool `json:"customize-selective-refresh-widgets"`
CustomHeader CustomHeader `json:"custom-header"`
Widgets bool `json:"widgets"`
}
type CustomLogo struct {
Width int `json:"width"`
Height int `json:"height"`
FlexWidth bool `json:"flex-width"`
FlexHeight bool `json:"flex-height"`
HeaderText string `json:"header-text"`
UnlinkHomepageLogo bool `json:"unlink-homepage-logo"`
}
type CustomBackground struct {
DefaultImage string `json:"default-image"`
DefaultPreset string `json:"default-preset"`
DefaultPositionX string `json:"default-position-x"`
DefaultPositionY string `json:"default-position-y"`
DefaultSize string `json:"default-size"`
DefaultRepeat string `json:"default-repeat"`
DefaultAttachment string `json:"default-attachment"`
DefaultColor string `json:"default-color"`
WpHeadCallback string `json:"wp-head-callback"`
AdminHeadCallback string `json:"admin-head-callback"`
AdminPreviewCallback string `json:"admin-preview-callback"`
}
type EditorColorPalette struct {
Name string `json:"name"`
Slug string `json:"slug"`
Color string `json:"color"`
}
type EditorGradientPresets struct {
Name string `json:"name"`
Slug string `json:"slug"`
Gradient string `json:"gradient"`
}
type CustomHeader struct {
DefaultImage string `json:"default-image"`
RandomDefault bool `json:"random-default"`
Width int `json:"width"`
Height int `json:"height"`
FlexHeight bool `json:"flex-height"`
FlexWidth bool `json:"flex-width"`
DefaultTextColor string `json:"default-text-color"`
HeaderText bool `json:"header-text"`
Uploads bool `json:"uploads"`
WpHeadCallback string `json:"wp-head-callback"`
AdminHeadCallback string `json:"admin-head-callback"`
AdminPreviewCallback string `json:"admin-preview-callback"`
Video bool `json:"video"`
VideoActiveCallback string `json:"video-active-callback"`
}

View File

@ -35,3 +35,13 @@ func (r *Var[T]) Store(v T) {
}
}
}
func (r *Var[T]) Flush() {
for {
px := atomic.LoadPointer(&r.p)
var v T
if atomic.CompareAndSwapPointer(&r.p, px, unsafe.Pointer(&v)) {
return
}
}
}

View File

@ -1,6 +1,7 @@
package safety
import (
"fmt"
"reflect"
"testing"
"unsafe"
@ -39,3 +40,27 @@ func TestVar_Load(t *testing.T) {
})
}
}
func TestVar_Delete(t *testing.T) {
{
v := NewVar("")
t.Run("string", func(t *testing.T) {
v.Delete()
fmt.Println(v.Load())
v.Store("xx")
fmt.Println(v.Load())
})
}
}
func TestVar_Flush(t *testing.T) {
{
v := NewVar("")
t.Run("string", func(t *testing.T) {
v.Flush()
fmt.Println(v.Load())
v.Store("xx")
fmt.Println(v.Load())
})
}
}