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"`
|
||||
Contact *configContact `mapstructure:"contact"`
|
||||
Announcement *configAnnouncement `mapstructure:"announcement"`
|
||||
name string
|
||||
// Configs read from database
|
||||
hideOldContentWarning bool
|
||||
hideShareButton bool
|
||||
|
@ -429,6 +430,10 @@ func (a *goBlog) initConfig(logging bool) error {
|
|||
if a.cfg.Blogs[a.cfg.DefaultBlog] == nil {
|
||||
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
|
||||
if ms := a.cfg.Micropub.MediaStorage; ms != nil && 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
|
||||
|
||||
`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
|
||||
}
|
||||
|
||||
// Blog
|
||||
type Blog interface {
|
||||
GetBlog() string
|
||||
}
|
||||
|
||||
// RenderType
|
||||
type RenderType string
|
||||
|
||||
|
@ -46,3 +51,12 @@ type PostRenderData interface {
|
|||
RenderData
|
||||
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() {
|
||||
Symbols["go.goblog.app/app/pkgs/plugintypes/plugintypes"] = map[string]reflect.Value{
|
||||
// function, constant and variable definitions
|
||||
"BlogFooterRenderType": reflect.ValueOf(plugintypes.BlogFooterRenderType),
|
||||
"PostMainElementRenderType": reflect.ValueOf(plugintypes.PostMainElementRenderType),
|
||||
|
||||
// type definitions
|
||||
"App": reflect.ValueOf((*plugintypes.App)(nil)),
|
||||
"Blog": reflect.ValueOf((*plugintypes.Blog)(nil)),
|
||||
"BlogRenderData": reflect.ValueOf((*plugintypes.BlogRenderData)(nil)),
|
||||
"Database": reflect.ValueOf((*plugintypes.Database)(nil)),
|
||||
"Exec": reflect.ValueOf((*plugintypes.Exec)(nil)),
|
||||
"Middleware": reflect.ValueOf((*plugintypes.Middleware)(nil)),
|
||||
|
@ -54,6 +57,8 @@ func init() {
|
|||
|
||||
// interface wrapper definitions
|
||||
"_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)),
|
||||
"_Exec": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Exec)(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()
|
||||
}
|
||||
|
||||
// _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
|
||||
type _go_goblog_app_app_pkgs_plugintypes_Database struct {
|
||||
IValue interface{}
|
||||
|
|
16
plugins.go
16
plugins.go
|
@ -72,3 +72,19 @@ func (d *pluginPostRenderData) GetPost() plugintypes.Post {
|
|||
func (p *post) pluginRenderData() plugintypes.PostRenderData {
|
||||
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
|
||||
hb.WriteElementOpen("footer")
|
||||
// Footer menu
|
||||
if fm, ok := rd.Blog.Menus["footer"]; ok {
|
||||
hb.WriteElementOpen("nav")
|
||||
for i, item := range fm.Items {
|
||||
if i > 0 {
|
||||
hb.WriteUnescaped(" • ")
|
||||
a.renderWithPlugins(hb, plugintypes.BlogFooterRenderType, rd.Blog.pluginRenderData(), func(hb *htmlbuilder.HtmlBuilder) {
|
||||
// Footer menu
|
||||
if fm, ok := rd.Blog.Menus["footer"]; ok {
|
||||
hb.WriteElementOpen("nav")
|
||||
for i, item := range fm.Items {
|
||||
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.WriteEscaped(a.renderMdTitle(item.Title))
|
||||
hb.WriteElementClose("a")
|
||||
hb.WriteElementClose("nav")
|
||||
}
|
||||
hb.WriteElementClose("nav")
|
||||
}
|
||||
// Copyright
|
||||
hb.WriteElementOpen("p", "translate", "no")
|
||||
hb.WriteUnescaped("© ")
|
||||
hb.WriteEscaped(time.Now().Format("2006"))
|
||||
hb.WriteUnescaped(" ")
|
||||
if user != nil && user.Name != "" {
|
||||
hb.WriteEscaped(user.Name)
|
||||
} else {
|
||||
hb.WriteEscaped(renderedBlogTitle)
|
||||
}
|
||||
hb.WriteElementClose("p")
|
||||
// Tor
|
||||
a.renderTorNotice(hb, rd)
|
||||
// Copyright
|
||||
hb.WriteElementOpen("p", "translate", "no")
|
||||
hb.WriteUnescaped("© ")
|
||||
hb.WriteEscaped(time.Now().Format("2006"))
|
||||
hb.WriteUnescaped(" ")
|
||||
if user != nil && user.Name != "" {
|
||||
hb.WriteEscaped(user.Name)
|
||||
} else {
|
||||
hb.WriteEscaped(renderedBlogTitle)
|
||||
}
|
||||
hb.WriteElementClose("p")
|
||||
// Tor
|
||||
a.renderTorNotice(hb, rd)
|
||||
})
|
||||
hb.WriteElementClose("footer")
|
||||
// Easter egg
|
||||
if rd.EasterEgg {
|
||||
|
|
Loading…
Reference in New Issue