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/handlers/root.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'internal/router/handlers/root.go') diff --git a/internal/router/handlers/root.go b/internal/router/handlers/root.go index 9f15782..89b9c63 100644 --- a/internal/router/handlers/root.go +++ b/internal/router/handlers/root.go @@ -35,6 +35,10 @@ func (r *RootHandler) CacheDuration() time.Duration { return 24 * time.Hour } +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", -- 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/handlers/root.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/handlers/root.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