From 7a40c01dd14f04787f5052d0c89e0d6fb9ce597f Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Mon, 30 Mar 2026 23:25:59 +0700 Subject: feat: build sitemap.xml --- internal/router/router.go | 59 +++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 23 deletions(-) (limited to 'internal/router/router.go') diff --git a/internal/router/router.go b/internal/router/router.go index f28add2..56313ff 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -52,6 +52,13 @@ var ( Routes = make([]Route, 0) ) +type SitemapInfo struct { + Loc string + LastModified time.Time + ChangeFreq string + Priority float32 +} + type Route interface { Filter() (method string, path string) IsTemplated() bool @@ -59,6 +66,8 @@ type Route interface { CacheDuration() time.Duration ToValidateLang() LangSetting TemplatesToInject() []string + SitemapInfo(supplements *Supplements) []SitemapInfo + ContentType() string Render(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) AddMeta(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (meta map[string]string, err error) RenderHeader(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) @@ -87,6 +96,7 @@ type Router struct { app *fiber.App templatedRoutes map[string]map[string]Route templatedPathMatcher *PathMatcher + canonicalEndpoint string } func NewRouter(cfg *config.Config) (*Router, error) { @@ -213,7 +223,7 @@ func NewRouter(cfg *config.Config) (*Router, error) { templatedRoutes := make(map[string]map[string]Route) templatedPathMatcher := NewPathMatcher() - return &Router{supplements, app, templatedRoutes, templatedPathMatcher}, nil + return &Router{supplements, app, templatedRoutes, templatedPathMatcher, cfg.CanonicalEndpoint}, nil } func (r *Router) InitRoutes() (err error) { @@ -261,10 +271,11 @@ func (r *Router) InitRoutes() (err error) { } defaultMap := fiber.Map{ - "L": r.supplements.Localization[lang], - "Lang": lang, - "Path": trimmedPath, - "QueryString": queryString, + "L": r.supplements.Localization[lang], + "Lang": lang, + "Path": trimmedPath, + "QueryString": queryString, + "CanonicalEndpoint": r.canonicalEndpoint, } statusCode, err := currentRoute.Render(c, r.supplements, lang, defaultMap) @@ -303,8 +314,8 @@ func (r *Router) InitRoutes() (err error) { go r.supplements.PageCache.SetWithTTL(cacheKey, content, int64(len(content)), route.CacheDuration()) } - c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8) - return c.Status(statusCode).Type("html").Send(content) + c.Set(fiber.HeaderContentType, route.ContentType()) + return c.Status(statusCode).Send(content) }) } } @@ -327,7 +338,7 @@ func (r *Router) InitRoutes() (err error) { r.app.Static("/", "./static") - Routes = make([]Route, 0) + // Routes = make([]Route, 0) return nil } @@ -379,14 +390,15 @@ func (r *Router) generalPage(c *fiber.Ctx, route Route, lang string) error { } if val, ok := r.supplements.PageCache.Get(cacheKey); val != nil && ok { - c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8) - return c.Status(fiber.StatusOK).Type("html").Send(val) + c.Set(fiber.HeaderContentType, route.ContentType()) + return c.Status(fiber.StatusOK).Send(val) } valueMap := fiber.Map{ - "L": r.supplements.Localization[lang], - "Lang": lang, - "QueryString": queryString, + "L": r.supplements.Localization[lang], + "Lang": lang, + "QueryString": queryString, + "CanonicalEndpoint": r.canonicalEndpoint, } var err error @@ -401,8 +413,8 @@ func (r *Router) generalPage(c *fiber.Ctx, route Route, lang string) error { } go r.supplements.PageCache.SetWithTTL(cacheKey, content, int64(len(content)), route.CacheDuration()) - c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8) - return c.Status(fiber.StatusOK).Type("html").Send(content) + c.Set(fiber.HeaderContentType, route.ContentType()) + return c.Status(fiber.StatusOK).Send(content) } func (r *Router) generalPageSegment(c *fiber.Ctx, part string) error { @@ -447,17 +459,18 @@ func (r *Router) generalPageSegment(c *fiber.Ctx, part string) error { if route.ToCache() != Disabled { if val, ok := r.supplements.PageCache.Get(cacheKey); val != nil && ok { - c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8) - return c.Status(fiber.StatusOK).Type("html").Send(val) + c.Set(fiber.HeaderContentType, route.ContentType()) + return c.Status(fiber.StatusOK).Send(val) } } var statusCode int defaultMap := fiber.Map{ - "L": r.supplements.Localization[lang], - "Lang": lang, - "Path": strings.Trim(path, "/"), - "QueryString": queryString, + "L": r.supplements.Localization[lang], + "Lang": lang, + "Path": strings.Trim(path, "/"), + "QueryString": queryString, + "CanonicalEndpoint": r.canonicalEndpoint, } switch part { @@ -505,8 +518,8 @@ func (r *Router) generalPageSegment(c *fiber.Ctx, part string) error { go r.supplements.PageCache.SetWithTTL(cacheKey, content, int64(len(content)), route.CacheDuration()) } - c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8) - return c.Status(statusCode).Type("html").Send(content) + c.Set(fiber.HeaderContentType, route.ContentType()) + return c.Status(statusCode).Send(content) } func (r *Router) getAndValidateLang(c *fiber.Ctx, langSetting LangSetting, defaultLang ...string) (string, error) { -- cgit v1.3.1+13 From a0ace41ad3b0f4661e98d8fa8ef254369cc80d1e Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Tue, 31 Mar 2026 00:06:46 +0700 Subject: feat: specify canonical hrefs for each page feat: specify more meta properties for search engines fix: correct user and catalogue meta format: specify og property names in property field feat: user profile description --- internal/router/basic-handler.go | 6 ++---- internal/router/handlers/lang-blog-title.go | 14 ++++++++------ internal/router/handlers/lang-blog.go | 9 +++++++++ internal/router/handlers/lang-user.go | 11 +++++++---- internal/router/handlers/lang.go | 12 +++++++----- internal/router/handlers/root.go | 11 +++++++---- internal/router/router.go | 8 +++++++- locale/localization.en.yaml | 1 + locale/localization.go | 1 + locale/localization.ru.yaml | 1 + views/layouts/general-page.html | 10 ++++++++-- views/pages/global-map.html | 8 ++++++-- 12 files changed, 64 insertions(+), 28 deletions(-) (limited to 'internal/router/router.go') diff --git a/internal/router/basic-handler.go b/internal/router/basic-handler.go index 98a7d84..96d0f77 100644 --- a/internal/router/basic-handler.go +++ b/internal/router/basic-handler.go @@ -49,10 +49,8 @@ func (r *BasicHandler) Render(c *fiber.Ctx, supplements *Supplements, lang strin return fiber.StatusNoContent, nil } -func (r *BasicHandler) AddMeta(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (meta map[string]string, err error) { - return map[string]string{ - "robots": "noindex,nofollow", - }, nil +func (r *BasicHandler) AddMeta(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (meta []MetaField, err error) { + return []MetaField{{Name: "robots", Content: "noindex,nofollow"}}, nil } func (r *BasicHandler) RenderHeader(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) { diff --git a/internal/router/handlers/lang-blog-title.go b/internal/router/handlers/lang-blog-title.go index 9eac084..a9acdbb 100644 --- a/internal/router/handlers/lang-blog-title.go +++ b/internal/router/handlers/lang-blog-title.go @@ -65,17 +65,19 @@ func (r *BlogPageHandler) SitemapInfo(supplements *router.Supplements) []router. return sitemapInfo } -func (r *BlogPageHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta map[string]string, err error) { +func (r *BlogPageHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta []router.MetaField, err error) { metadata, _, err := supplements.B2Client.ReadFrontmatter(lang + "/" + c.Params("title") + ".md") if err != nil { return nil, fmt.Errorf("failed to read frontmatter of the desired blog post: %w", err) } - return map[string]string{ - "og:title": metadata.Title, - "og:description": fmt.Sprintf("%s [%s]", metadata.ShortDescription, metadata.ActionDate), - "og:image": fmt.Sprintf("https://f003.backblazeb2.com/file/sayana-photos/webp-320p/%s.webp", metadata.Thumbnail), - "twitter:card": "summary_large_image", + return []router.MetaField{ + {Property: "og:title", Content: metadata.Title}, + {Property: "og:description", Content: fmt.Sprintf("%s [%s]", metadata.ShortDescription, metadata.ActionDate)}, + {Property: "og:image", Content: fmt.Sprintf("https://f003.backblazeb2.com/file/sayana-photos/webp-320p/%s.webp", metadata.Thumbnail)}, + {Property: "og:url", Content: fmt.Sprintf("%s/%s/blog/%s", templateMap["CanonicalEndpoint"], lang, c.Params("title"))}, + {Property: "og:type", Content: "website"}, + {Name: "twitter:card", Content: "summary_large_image"}, }, nil } diff --git a/internal/router/handlers/lang-blog.go b/internal/router/handlers/lang-blog.go index ffac77e..709d3dc 100644 --- a/internal/router/handlers/lang-blog.go +++ b/internal/router/handlers/lang-blog.go @@ -55,6 +55,15 @@ func (r *CatalogueHandler) SitemapInfo(supplements *router.Supplements) []router return sitemapInfo } +func (r *CatalogueHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta []router.MetaField, err error) { + return []router.MetaField{ + {Property: "og:title", Content: supplements.Localization[lang].BlogSearch.Header}, + {Property: "og:description", Content: supplements.Localization[lang].BlogSearch.Description}, + {Property: "og:url", Content: fmt.Sprintf("%s/%s/blog", templateMap["CanonicalEndpoint"], lang)}, + {Property: "og:type", Content: "website"}, + }, nil +} + func (r *CatalogueHandler) RenderBody(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) { querySort := c.Query("sort") if querySort == "" { diff --git a/internal/router/handlers/lang-user.go b/internal/router/handlers/lang-user.go index c22bcac..eae1685 100644 --- a/internal/router/handlers/lang-user.go +++ b/internal/router/handlers/lang-user.go @@ -37,10 +37,13 @@ func (r *UserHandler) ToValidateLang() router.LangSetting { return router.InPath } -func (r *UserHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta map[string]string, err error) { - return map[string]string{ - "og:title": supplements.Localization[lang].BlogSearch.Header, - "og:description": supplements.Localization[lang].BlogSearch.Description, +func (r *UserHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta []router.MetaField, err error) { + return []router.MetaField{ + {Name: "robots", Content: "noindex,nofollow"}, + {Property: "og:title", Content: supplements.Localization[lang].UserProfile.Header}, + {Property: "og:description", Content: supplements.Localization[lang].UserProfile.Description}, + {Property: "og:url", Content: fmt.Sprintf("%s/%s/user", templateMap["CanonicalEndpoint"], lang)}, + {Property: "og:type", Content: "website"}, }, nil } diff --git a/internal/router/handlers/lang.go b/internal/router/handlers/lang.go index 5430773..c618353 100644 --- a/internal/router/handlers/lang.go +++ b/internal/router/handlers/lang.go @@ -49,11 +49,13 @@ func (r *HomeHandler) SitemapInfo(supplements *router.Supplements) []router.Site return sitemapInfo } -func (r *HomeHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta map[string]string, err error) { - return map[string]string{ - "og:title": supplements.Localization[lang].HomePage.Header, - "og:description": supplements.Localization[lang].HomePage.HomePageDescription, - "og:image": "https://f003.backblazeb2.com/file/sayana-static/home-page-gifs/" + fmt.Sprintf("otter-%d.gif", rand.Int()%3+1), +func (r *HomeHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta []router.MetaField, err error) { + return []router.MetaField{ + {Property: "og:title", Content: supplements.Localization[lang].HomePage.Header}, + {Property: "og:description", Content: supplements.Localization[lang].HomePage.HomePageDescription}, + {Property: "og:image", Content: fmt.Sprintf("https://f003.backblazeb2.com/file/sayana-static/home-page-gifs/otter-%d.gif", rand.Int()%3+1)}, + {Property: "og:url", Content: fmt.Sprintf("%s/%s", templateMap["CanonicalEndpoint"], lang)}, + {Property: "og:type", Content: "website"}, }, nil } diff --git a/internal/router/handlers/root.go b/internal/router/handlers/root.go index 89b9c63..f188a61 100644 --- a/internal/router/handlers/root.go +++ b/internal/router/handlers/root.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "time" "github.com/SayaAndy/saya-today-web/internal/router" @@ -39,10 +40,12 @@ func (r *RootHandler) SitemapInfo(_ *router.Supplements) []router.SitemapInfo { return []router.SitemapInfo{{Loc: "", Priority: 0.7}} } -func (r *RootHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta map[string]string, err error) { - return map[string]string{ - "og:title": "Saya Blog", - "og:description": "The blog of a 25 years old, travelling God knows where, proud to be not mainstream // Личный блог 25-летки, странствующего по ебеням, зато не мейнстрим", +func (r *RootHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta []router.MetaField, err error) { + return []router.MetaField{ + {Property: "og:title", Content: "Saya Blog"}, + {Property: "og:description", Content: "The blog of a 25 years old, travelling God knows where, proud to be not mainstream // Личный блог 25-летки, странствующего по ебеням, зато не мейнстрим"}, + {Property: "og:url", Content: fmt.Sprint(templateMap["CanonicalEndpoint"])}, + {Property: "og:type", Content: "website"}, }, nil } diff --git a/internal/router/router.go b/internal/router/router.go index 56313ff..1b490d8 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -59,6 +59,12 @@ type SitemapInfo struct { Priority float32 } +type MetaField struct { + Name string + Property string + Content string +} + type Route interface { Filter() (method string, path string) IsTemplated() bool @@ -69,7 +75,7 @@ type Route interface { SitemapInfo(supplements *Supplements) []SitemapInfo ContentType() string Render(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) - AddMeta(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (meta map[string]string, err error) + AddMeta(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (meta []MetaField, err error) RenderHeader(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) RenderBody(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) RenderFooter(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) diff --git a/locale/localization.en.yaml b/locale/localization.en.yaml index e165866..9923881 100644 --- a/locale/localization.en.yaml +++ b/locale/localization.en.yaml @@ -48,6 +48,7 @@ Mail: CapturedOn: 'Captured on' UserProfile: Header: 'Personal Settings' + Description: 'Set and verify your e-mail here, as well as subscribe to favorite blog tags' EmailHeader: 'E-Mail' VerificationCodeHeader: 'Verification Code' TypeEmail: 'Please type your email' diff --git a/locale/localization.go b/locale/localization.go index a4f36f1..7080355 100644 --- a/locale/localization.go +++ b/locale/localization.go @@ -85,6 +85,7 @@ type NewPostConfig struct { type UserProfileConfig struct { Header string `yaml:"Header" json:"Header"` + Description string `yaml:"Description" json:"Description"` EmailHeader string `yaml:"EmailHeader" json:"EmailHeader"` VerificationCodeHeader string `yaml:"VerificationCodeHeader" json:"VerificationCodeHeader"` TypeEmail string `yaml:"TypeEmail" json:"TypeEmail"` diff --git a/locale/localization.ru.yaml b/locale/localization.ru.yaml index e65848a..34e5387 100644 --- a/locale/localization.ru.yaml +++ b/locale/localization.ru.yaml @@ -48,6 +48,7 @@ Mail: CapturedOn: 'Снималось' UserProfile: Header: 'Личные настройки' + Description: 'Здесь можно настроить и верифицировать свою электронную почту, а также подписаться на избранные темы блога' EmailHeader: 'E-Mail' VerificationCodeHeader: 'Код верификации' TypeEmail: 'Пожалуйста, введите свою почту' diff --git a/views/layouts/general-page.html b/views/layouts/general-page.html index 3f5bcfd..2114b1c 100644 --- a/views/layouts/general-page.html +++ b/views/layouts/general-page.html @@ -3,8 +3,14 @@ - {{- range $k, $v := .Meta }} - + {{- range .Meta }} + + {{- if eq .Property "og:description" }} + + {{- end }} + {{- if eq .Property "og:url" }} + + {{- end }} {{- end }} diff --git a/views/pages/global-map.html b/views/pages/global-map.html index 4b07bd2..604b52e 100644 --- a/views/pages/global-map.html +++ b/views/pages/global-map.html @@ -3,9 +3,13 @@ - - + + + + + {{ .L.GlobalMap.Header }} // SAYA TODAY + {{ block "header" . }}{{ end }} -- cgit v1.3.1+13 From c7742b341a46360d16dd9035c046f004d0fe760c Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Tue, 31 Mar 2026 00:13:10 +0700 Subject: feat: enable etag middleware feat: enable compress middleware feat: trim end slash of each request url (except for root) --- internal/router/handlers/root.go | 4 ++-- internal/router/router.go | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'internal/router/router.go') diff --git a/internal/router/handlers/root.go b/internal/router/handlers/root.go index f188a61..cd01fcd 100644 --- a/internal/router/handlers/root.go +++ b/internal/router/handlers/root.go @@ -37,14 +37,14 @@ func (r *RootHandler) CacheDuration() time.Duration { } func (r *RootHandler) SitemapInfo(_ *router.Supplements) []router.SitemapInfo { - return []router.SitemapInfo{{Loc: "", Priority: 0.7}} + return []router.SitemapInfo{{Loc: "/", Priority: 0.7}} } func (r *RootHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta []router.MetaField, err error) { return []router.MetaField{ {Property: "og:title", Content: "Saya Blog"}, {Property: "og:description", Content: "The blog of a 25 years old, travelling God knows where, proud to be not mainstream // Личный блог 25-летки, странствующего по ебеням, зато не мейнстрим"}, - {Property: "og:url", Content: fmt.Sprint(templateMap["CanonicalEndpoint"])}, + {Property: "og:url", Content: fmt.Sprint(templateMap["CanonicalEndpoint"]) + "/"}, {Property: "og:type", Content: "website"}, }, nil } diff --git a/internal/router/router.go b/internal/router/router.go index 1b490d8..3ce7e3b 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -21,7 +21,9 @@ import ( "github.com/SayaAndy/saya-today-web/locale" "github.com/dgraph-io/ristretto/v2" "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/compress" "github.com/gofiber/fiber/v2/middleware/cors" + "github.com/gofiber/fiber/v2/middleware/etag" "github.com/golang-migrate/migrate/v4" "github.com/golang-migrate/migrate/v4/database/sqlite3" "github.com/yuin/goldmark" @@ -226,6 +228,20 @@ func NewRouter(cfg *config.Config) (*Router, error) { AllowHeaders: "Origin, Content-Type, Accept", })) + app.Use(compress.New(compress.Config{ + Level: compress.LevelBestSpeed, + })) + + app.Use(etag.New()) + + app.Use(func(c *fiber.Ctx) error { + path := c.Path() + if len(path) > 1 && path[len(path)-1] == '/' { + return c.Redirect(strings.TrimRight(path, "/"), fiber.StatusMovedPermanently) + } + return c.Next() + }) + templatedRoutes := make(map[string]map[string]Route) templatedPathMatcher := NewPathMatcher() -- cgit v1.3.1+13 From a8f566cbeb8358aca7fb4532d8b69c513ef197f3 Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Tue, 31 Mar 2026 00:49:07 +0700 Subject: feat: add linked data --- internal/router/basic-handler.go | 4 ++++ internal/router/handlers/lang-blog-title.go | 16 ++++++++++++++++ internal/router/router.go | 12 ++++++++++++ views/layouts/general-page.html | 5 +++++ 4 files changed, 37 insertions(+) (limited to 'internal/router/router.go') diff --git a/internal/router/basic-handler.go b/internal/router/basic-handler.go index 96d0f77..b973d01 100644 --- a/internal/router/basic-handler.go +++ b/internal/router/basic-handler.go @@ -53,6 +53,10 @@ func (r *BasicHandler) AddMeta(c *fiber.Ctx, supplements *Supplements, lang stri return []MetaField{{Name: "robots", Content: "noindex,nofollow"}}, nil } +func (r *BasicHandler) AddLinkedData(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (ld map[string]any, err error) { + return nil, nil +} + func (r *BasicHandler) RenderHeader(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) { return fiber.StatusNoContent, nil } diff --git a/internal/router/handlers/lang-blog-title.go b/internal/router/handlers/lang-blog-title.go index a9acdbb..5bfc6e7 100644 --- a/internal/router/handlers/lang-blog-title.go +++ b/internal/router/handlers/lang-blog-title.go @@ -81,6 +81,22 @@ func (r *BlogPageHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, }, nil } +func (r *BlogPageHandler) AddLinkedData(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (ld map[string]any, err error) { + metadata, _, err := supplements.B2Client.ReadFrontmatter(lang + "/" + c.Params("title") + ".md") + if err != nil { + return nil, fmt.Errorf("failed to read frontmatter of the desired blog post: %w", err) + } + + return map[string]any{ + "@context": "https://schema.org", + "@type": "Article", + "headline": metadata.Title, + "description": fmt.Sprintf("%s [%s]", metadata.ShortDescription, metadata.ActionDate), + "author": map[string]string{"@type": "Person", "name": "Saya Andy"}, + "datePublished": metadata.PublishedTime.UTC().Format(time.RFC3339), + }, nil +} + func (r *BlogPageHandler) RenderBody(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) { _, pathParts, _, err := router.GetPathFromReferer(c) if err != nil { diff --git a/internal/router/router.go b/internal/router/router.go index 3ce7e3b..0d0ce8c 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -2,8 +2,10 @@ package router import ( "database/sql" + "encoding/json" "errors" "fmt" + "html/template" "log/slog" "net/url" "slices" @@ -78,6 +80,7 @@ type Route interface { ContentType() string Render(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) AddMeta(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (meta []MetaField, err error) + AddLinkedData(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (ld map[string]any, err error) RenderHeader(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) RenderBody(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) RenderFooter(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) @@ -428,6 +431,15 @@ func (r *Router) generalPage(c *fiber.Ctx, route Route, lang string) error { slog.Warn("failed to receive meta", slog.String("path", path), slog.String("error", err.Error())) } + var ld map[string]any + if ld, err = route.AddLinkedData(c, r.supplements, lang, valueMap); err != nil { + slog.Warn("failed to receive linked data", slog.String("path", path), slog.String("error", err.Error())) + } + if ld != nil { + ldBytes, _ := json.Marshal(ld) + valueMap["LinkedData"] = template.JS(ldBytes) + } + content, err := r.supplements.TemplateManager.Render("general-page", valueMap) if err != nil { slog.Warn("failed to generate div", slog.String("path", path), slog.String("error", err.Error())) diff --git a/views/layouts/general-page.html b/views/layouts/general-page.html index d7d11a3..7167d12 100644 --- a/views/layouts/general-page.html +++ b/views/layouts/general-page.html @@ -16,6 +16,11 @@ + {{- with .LinkedData }} + + {{- end }} -- cgit v1.3.1+13