mirror of https://github.com/jlelse/GoBlog
Add webrings plugin
This commit is contained in:
parent
1f2510ac53
commit
e1edd5c18c
|
@ -95,6 +95,7 @@ type configBlog struct {
|
||||||
Map *configGeoMap `mapstructure:"map"`
|
Map *configGeoMap `mapstructure:"map"`
|
||||||
Contact *configContact `mapstructure:"contact"`
|
Contact *configContact `mapstructure:"contact"`
|
||||||
Announcement *configAnnouncement `mapstructure:"announcement"`
|
Announcement *configAnnouncement `mapstructure:"announcement"`
|
||||||
|
name string
|
||||||
// Configs read from database
|
// Configs read from database
|
||||||
hideOldContentWarning bool
|
hideOldContentWarning bool
|
||||||
hideShareButton bool
|
hideShareButton bool
|
||||||
|
@ -429,6 +430,10 @@ func (a *goBlog) initConfig(logging bool) error {
|
||||||
if a.cfg.Blogs[a.cfg.DefaultBlog] == nil {
|
if a.cfg.Blogs[a.cfg.DefaultBlog] == nil {
|
||||||
return errors.New("default blog does not exist")
|
return errors.New("default blog does not exist")
|
||||||
}
|
}
|
||||||
|
// Set name attribute for every blog
|
||||||
|
for name, blog := range a.cfg.Blogs {
|
||||||
|
blog.name = name
|
||||||
|
}
|
||||||
// Check media storage config
|
// Check media storage config
|
||||||
if ms := a.cfg.Micropub.MediaStorage; ms != nil && ms.MediaURL != "" {
|
if ms := a.cfg.Micropub.MediaStorage; ms != nil && ms.MediaURL != "" {
|
||||||
ms.MediaURL = strings.TrimSuffix(ms.MediaURL, "/")
|
ms.MediaURL = strings.TrimSuffix(ms.MediaURL, "/")
|
||||||
|
|
|
@ -41,4 +41,20 @@ Adds hidden `u-syndication` `data` elements to post page when the configured pos
|
||||||
|
|
||||||
#### Config
|
#### Config
|
||||||
|
|
||||||
`parameter` (string): Name for the post parameter containing the syndication links.
|
`parameter` (string): Name for the post parameter containing the syndication links.
|
||||||
|
|
||||||
|
### Webrings (plugins/webrings)
|
||||||
|
|
||||||
|
Adds webring links to the bottom of the blog footer to easily participate in webrings.
|
||||||
|
|
||||||
|
#### Config
|
||||||
|
|
||||||
|
You can add webring links like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
config:
|
||||||
|
default: # Name of the blog
|
||||||
|
- title: Webring # Title to show for the webring
|
||||||
|
prev: https://example.com/ # Link to previous webring site
|
||||||
|
next: https://example.net/ # Link to next webring site
|
||||||
|
```
|
|
@ -27,6 +27,11 @@ type Post interface {
|
||||||
GetParameters() map[string][]string
|
GetParameters() map[string][]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Blog
|
||||||
|
type Blog interface {
|
||||||
|
GetBlog() string
|
||||||
|
}
|
||||||
|
|
||||||
// RenderType
|
// RenderType
|
||||||
type RenderType string
|
type RenderType string
|
||||||
|
|
||||||
|
@ -46,3 +51,12 @@ type PostRenderData interface {
|
||||||
RenderData
|
RenderData
|
||||||
GetPost() Post
|
GetPost() Post
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render footer element on every blog page, data = BlogRenderData
|
||||||
|
const BlogFooterRenderType RenderType = "blog-footer"
|
||||||
|
|
||||||
|
// BlogRenderData is RenderData containing a Blog
|
||||||
|
type BlogRenderData interface {
|
||||||
|
RenderData
|
||||||
|
GetBlog() Blog
|
||||||
|
}
|
||||||
|
|
|
@ -36,10 +36,13 @@ import (
|
||||||
func init() {
|
func init() {
|
||||||
Symbols["go.goblog.app/app/pkgs/plugintypes/plugintypes"] = map[string]reflect.Value{
|
Symbols["go.goblog.app/app/pkgs/plugintypes/plugintypes"] = map[string]reflect.Value{
|
||||||
// function, constant and variable definitions
|
// function, constant and variable definitions
|
||||||
|
"BlogFooterRenderType": reflect.ValueOf(plugintypes.BlogFooterRenderType),
|
||||||
"PostMainElementRenderType": reflect.ValueOf(plugintypes.PostMainElementRenderType),
|
"PostMainElementRenderType": reflect.ValueOf(plugintypes.PostMainElementRenderType),
|
||||||
|
|
||||||
// type definitions
|
// type definitions
|
||||||
"App": reflect.ValueOf((*plugintypes.App)(nil)),
|
"App": reflect.ValueOf((*plugintypes.App)(nil)),
|
||||||
|
"Blog": reflect.ValueOf((*plugintypes.Blog)(nil)),
|
||||||
|
"BlogRenderData": reflect.ValueOf((*plugintypes.BlogRenderData)(nil)),
|
||||||
"Database": reflect.ValueOf((*plugintypes.Database)(nil)),
|
"Database": reflect.ValueOf((*plugintypes.Database)(nil)),
|
||||||
"Exec": reflect.ValueOf((*plugintypes.Exec)(nil)),
|
"Exec": reflect.ValueOf((*plugintypes.Exec)(nil)),
|
||||||
"Middleware": reflect.ValueOf((*plugintypes.Middleware)(nil)),
|
"Middleware": reflect.ValueOf((*plugintypes.Middleware)(nil)),
|
||||||
|
@ -54,6 +57,8 @@ func init() {
|
||||||
|
|
||||||
// interface wrapper definitions
|
// interface wrapper definitions
|
||||||
"_App": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_App)(nil)),
|
"_App": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_App)(nil)),
|
||||||
|
"_Blog": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Blog)(nil)),
|
||||||
|
"_BlogRenderData": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_BlogRenderData)(nil)),
|
||||||
"_Database": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Database)(nil)),
|
"_Database": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Database)(nil)),
|
||||||
"_Exec": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Exec)(nil)),
|
"_Exec": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Exec)(nil)),
|
||||||
"_Middleware": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Middleware)(nil)),
|
"_Middleware": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Middleware)(nil)),
|
||||||
|
@ -76,6 +81,26 @@ func (W _go_goblog_app_app_pkgs_plugintypes_App) GetDatabase() plugintypes.Datab
|
||||||
return W.WGetDatabase()
|
return W.WGetDatabase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// _go_goblog_app_app_pkgs_plugintypes_Blog is an interface wrapper for Blog type
|
||||||
|
type _go_goblog_app_app_pkgs_plugintypes_Blog struct {
|
||||||
|
IValue interface{}
|
||||||
|
WGetBlog func() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_Blog) GetBlog() string {
|
||||||
|
return W.WGetBlog()
|
||||||
|
}
|
||||||
|
|
||||||
|
// _go_goblog_app_app_pkgs_plugintypes_BlogRenderData is an interface wrapper for BlogRenderData type
|
||||||
|
type _go_goblog_app_app_pkgs_plugintypes_BlogRenderData struct {
|
||||||
|
IValue interface{}
|
||||||
|
WGetBlog func() plugintypes.Blog
|
||||||
|
}
|
||||||
|
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_BlogRenderData) GetBlog() plugintypes.Blog {
|
||||||
|
return W.WGetBlog()
|
||||||
|
}
|
||||||
|
|
||||||
// _go_goblog_app_app_pkgs_plugintypes_Database is an interface wrapper for Database type
|
// _go_goblog_app_app_pkgs_plugintypes_Database is an interface wrapper for Database type
|
||||||
type _go_goblog_app_app_pkgs_plugintypes_Database struct {
|
type _go_goblog_app_app_pkgs_plugintypes_Database struct {
|
||||||
IValue interface{}
|
IValue interface{}
|
||||||
|
|
16
plugins.go
16
plugins.go
|
@ -72,3 +72,19 @@ func (d *pluginPostRenderData) GetPost() plugintypes.Post {
|
||||||
func (p *post) pluginRenderData() plugintypes.PostRenderData {
|
func (p *post) pluginRenderData() plugintypes.PostRenderData {
|
||||||
return &pluginPostRenderData{p: p}
|
return &pluginPostRenderData{p: p}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *configBlog) GetBlog() string {
|
||||||
|
return b.name
|
||||||
|
}
|
||||||
|
|
||||||
|
type pluginBlogRenderData struct {
|
||||||
|
b *configBlog
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *pluginBlogRenderData) GetBlog() plugintypes.Blog {
|
||||||
|
return d.b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *configBlog) pluginRenderData() plugintypes.BlogRenderData {
|
||||||
|
return &pluginBlogRenderData{b: b}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package webrings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"go.goblog.app/app/pkgs/htmlbuilder"
|
||||||
|
"go.goblog.app/app/pkgs/plugintypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetPlugin() plugintypes.UI {
|
||||||
|
return &plugin{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type plugin struct {
|
||||||
|
config map[string]any
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*plugin) SetApp(_ plugintypes.App) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) SetConfig(config map[string]any) {
|
||||||
|
p.config = config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) Render(hb *htmlbuilder.HtmlBuilder, t plugintypes.RenderType, data plugintypes.RenderData, render plugintypes.RenderNextFunc) {
|
||||||
|
render(hb)
|
||||||
|
if t == plugintypes.BlogFooterRenderType {
|
||||||
|
bd, ok := data.(plugintypes.BlogRenderData)
|
||||||
|
if !ok {
|
||||||
|
fmt.Println("webrings plugin: data is not BlogRenderData!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
blogData := bd.GetBlog()
|
||||||
|
if blogData == nil {
|
||||||
|
fmt.Println("webrings plugin: blog is nil!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
blog := blogData.GetBlog()
|
||||||
|
if blog == "" {
|
||||||
|
fmt.Println("webrings plugin: blog is empty!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if blogWebringsAny, ok := p.config[blog]; ok {
|
||||||
|
if blogWebrings, ok := blogWebringsAny.([]any); ok {
|
||||||
|
for _, webringAny := range blogWebrings {
|
||||||
|
if webring, ok := webringAny.(map[string]any); ok {
|
||||||
|
title, titleOk := unwrapToString(webring["title"])
|
||||||
|
prev, prevOk := unwrapToString(webring["prev"])
|
||||||
|
next, nextOk := unwrapToString(webring["next"])
|
||||||
|
if titleOk && (prevOk || nextOk) {
|
||||||
|
hb.WriteElementOpen("p")
|
||||||
|
if prevOk {
|
||||||
|
hb.WriteElementOpen("a", "href", prev)
|
||||||
|
hb.WriteEscaped("←")
|
||||||
|
hb.WriteElementClose("a")
|
||||||
|
}
|
||||||
|
hb.WriteEscaped(" " + title + " ")
|
||||||
|
if nextOk {
|
||||||
|
hb.WriteElementOpen("a", "href", next)
|
||||||
|
hb.WriteEscaped("→")
|
||||||
|
hb.WriteElementClose("a")
|
||||||
|
}
|
||||||
|
hb.WriteElementClose("p")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unwrapToString(o any) (string, bool) {
|
||||||
|
if o == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
s, ok := o.(string)
|
||||||
|
return s, ok && s != ""
|
||||||
|
}
|
50
ui.go
50
ui.go
|
@ -162,32 +162,34 @@ func (a *goBlog) renderBase(hb *htmlbuilder.HtmlBuilder, rd *renderData, title,
|
||||||
}
|
}
|
||||||
// Footer
|
// Footer
|
||||||
hb.WriteElementOpen("footer")
|
hb.WriteElementOpen("footer")
|
||||||
// Footer menu
|
a.renderWithPlugins(hb, plugintypes.BlogFooterRenderType, rd.Blog.pluginRenderData(), func(hb *htmlbuilder.HtmlBuilder) {
|
||||||
if fm, ok := rd.Blog.Menus["footer"]; ok {
|
// Footer menu
|
||||||
hb.WriteElementOpen("nav")
|
if fm, ok := rd.Blog.Menus["footer"]; ok {
|
||||||
for i, item := range fm.Items {
|
hb.WriteElementOpen("nav")
|
||||||
if i > 0 {
|
for i, item := range fm.Items {
|
||||||
hb.WriteUnescaped(" • ")
|
if i > 0 {
|
||||||
|
hb.WriteUnescaped(" • ")
|
||||||
|
}
|
||||||
|
hb.WriteElementOpen("a", "href", item.Link)
|
||||||
|
hb.WriteEscaped(a.renderMdTitle(item.Title))
|
||||||
|
hb.WriteElementClose("a")
|
||||||
}
|
}
|
||||||
hb.WriteElementOpen("a", "href", item.Link)
|
hb.WriteElementClose("nav")
|
||||||
hb.WriteEscaped(a.renderMdTitle(item.Title))
|
|
||||||
hb.WriteElementClose("a")
|
|
||||||
}
|
}
|
||||||
hb.WriteElementClose("nav")
|
// Copyright
|
||||||
}
|
hb.WriteElementOpen("p", "translate", "no")
|
||||||
// Copyright
|
hb.WriteUnescaped("© ")
|
||||||
hb.WriteElementOpen("p", "translate", "no")
|
hb.WriteEscaped(time.Now().Format("2006"))
|
||||||
hb.WriteUnescaped("© ")
|
hb.WriteUnescaped(" ")
|
||||||
hb.WriteEscaped(time.Now().Format("2006"))
|
if user != nil && user.Name != "" {
|
||||||
hb.WriteUnescaped(" ")
|
hb.WriteEscaped(user.Name)
|
||||||
if user != nil && user.Name != "" {
|
} else {
|
||||||
hb.WriteEscaped(user.Name)
|
hb.WriteEscaped(renderedBlogTitle)
|
||||||
} else {
|
}
|
||||||
hb.WriteEscaped(renderedBlogTitle)
|
hb.WriteElementClose("p")
|
||||||
}
|
// Tor
|
||||||
hb.WriteElementClose("p")
|
a.renderTorNotice(hb, rd)
|
||||||
// Tor
|
})
|
||||||
a.renderTorNotice(hb, rd)
|
|
||||||
hb.WriteElementClose("footer")
|
hb.WriteElementClose("footer")
|
||||||
// Easter egg
|
// Easter egg
|
||||||
if rd.EasterEgg {
|
if rd.EasterEgg {
|
||||||
|
|
Loading…
Reference in New Issue