diff options
| author | 2026-03-29 02:05:06 +0700 | |
|---|---|---|
| committer | 2026-03-29 02:05:06 +0700 | |
| commit | 0a9de353b2456505b0b8214fab4a7c844d31735c (patch) | |
| tree | ae130f4617bab4b05f13521b1e701cd88f48d69f | |
| parent | 610341bc9d59f9724e8e71f663b28df1904cb038 (diff) | |
| download | web-0a9de353b2456505b0b8214fab4a7c844d31735c.tar.gz web-0a9de353b2456505b0b8214fab4a7c844d31735c.zip | |
fix: add page metadata correctly
feat: link marker fill saturation and brightness in the global map to the publication date
| -rw-r--r-- | internal/frontmatter/parser.go | 19 | ||||
| -rw-r--r-- | internal/router/basic-handler.go | 6 | ||||
| -rw-r--r-- | internal/router/handlers/lang-blog-title.go | 14 | ||||
| -rw-r--r-- | internal/router/handlers/lang-map.go | 8 | ||||
| -rw-r--r-- | internal/router/handlers/lang-user.go | 7 | ||||
| -rw-r--r-- | internal/router/handlers/lang.go | 8 | ||||
| -rw-r--r-- | internal/router/handlers/root.go | 7 | ||||
| -rw-r--r-- | internal/router/router.go | 12 | ||||
| -rw-r--r-- | internal/templatemanager/templatemanager.go | 3 | ||||
| -rw-r--r-- | locale/localization.en.yaml | 2 | ||||
| -rw-r--r-- | locale/localization.go | 4 | ||||
| -rw-r--r-- | locale/localization.ru.yaml | 2 | ||||
| -rw-r--r-- | views/layouts/general-page.html | 4 | ||||
| -rw-r--r-- | views/pages/blog-catalogue.html | 5 | ||||
| -rw-r--r-- | views/pages/blog-page.html | 7 | ||||
| -rw-r--r-- | views/pages/global-map.html | 27 | ||||
| -rw-r--r-- | views/pages/home-page.html | 6 | ||||
| -rw-r--r-- | views/pages/language-pick.html | 5 | ||||
| -rw-r--r-- | views/pages/user-page.html | 5 |
19 files changed, 94 insertions, 57 deletions
diff --git a/internal/frontmatter/parser.go b/internal/frontmatter/parser.go index 83312dc..6062113 100644 --- a/internal/frontmatter/parser.go +++ b/internal/frontmatter/parser.go @@ -9,15 +9,16 @@ import ( ) type Metadata struct { - Title string `yaml:"title"` - ShortDescription string `yaml:"shortDescription"` - ActionDate string `yaml:"actionDate"` - PublishedTime time.Time `yaml:"publishedTime"` - Thumbnail string `yaml:"thumbnail"` - Tags []string `yaml:"tags"` - Geolocation string `yaml:"geolocation"` - Medley string `yaml:"medley"` - MedleyPart int `yaml:"medleyPart"` + Title string `yaml:"title"` + ShortDescription string `yaml:"shortDescription"` + ActionDate string `yaml:"actionDate"` + PublishedTime time.Time `yaml:"publishedTime"` + Thumbnail string `yaml:"thumbnail"` + Tags []string `yaml:"tags"` + Geolocation string `yaml:"geolocation"` + Medley string `yaml:"medley"` + MedleyPart int `yaml:"medleyPart"` + ContentSettings map[string]string `yaml:"contentSettings"` } func ParseFrontmatter(content []byte) (metadata *Metadata, markdown []byte, err error) { diff --git a/internal/router/basic-handler.go b/internal/router/basic-handler.go index a859d10..4a94a48 100644 --- a/internal/router/basic-handler.go +++ b/internal/router/basic-handler.go @@ -41,6 +41,12 @@ 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) 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 0f4f564..97de089 100644 --- a/internal/router/handlers/lang-blog-title.go +++ b/internal/router/handlers/lang-blog-title.go @@ -46,6 +46,20 @@ func (r *BlogPageHandler) ToValidateLang() router.LangSetting { return router.InPath } +func (r *BlogPageHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta map[string]string, 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", + }, 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/handlers/lang-map.go b/internal/router/handlers/lang-map.go index dbf1437..7df6104 100644 --- a/internal/router/handlers/lang-map.go +++ b/internal/router/handlers/lang-map.go @@ -3,6 +3,7 @@ package handlers import ( "fmt" "log/slog" + "slices" "strconv" "strings" @@ -41,6 +42,9 @@ func (r *MapHandler) ToValidateLang() router.LangSetting { func (r *MapHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) { pages, err := supplements.B2Client.Scan(lang + "/") + slices.SortFunc(pages, func(a *b2.BlogPage, b *b2.BlogPage) int { + return a.Metadata.PublishedTime.Compare(b.Metadata.PublishedTime) + }) status := fiber.StatusOK if err != nil { slog.Error("received an error while scanning b2 pages", @@ -52,6 +56,7 @@ func (r *MapHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang } type MapMarker struct { + Index int `json:"Index"` Title string `json:"Title"` PageLink string `json:"PageLink"` Lat float64 `json:"Lat"` @@ -61,7 +66,7 @@ func (r *MapHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang } mapMarkers := make([]*MapMarker, 0, len(pages)) - for _, page := range pages { + for i, page := range pages { geolocationParts := strings.Split(page.Metadata.Geolocation, " ") if len(geolocationParts) < 2 { continue @@ -78,6 +83,7 @@ func (r *MapHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang } mapMarkers = append(mapMarkers, &MapMarker{ + Index: i, Title: page.Metadata.Title, PageLink: fmt.Sprintf("/%s/blog/%s", lang, page.FileName), Lat: x, diff --git a/internal/router/handlers/lang-user.go b/internal/router/handlers/lang-user.go index db566fe..c22bcac 100644 --- a/internal/router/handlers/lang-user.go +++ b/internal/router/handlers/lang-user.go @@ -37,6 +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, + }, nil +} + func (r *UserHandler) RenderBody(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) { templateMap["Title"] = supplements.Localization[lang].UserProfile.Header diff --git a/internal/router/handlers/lang.go b/internal/router/handlers/lang.go index fc4deb6..74166ae 100644 --- a/internal/router/handlers/lang.go +++ b/internal/router/handlers/lang.go @@ -41,6 +41,14 @@ func (r *HomeHandler) ToValidateLang() router.LangSetting { return router.InPath } +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), + }, nil +} + func (r *HomeHandler) RenderBody(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) { templateMap["Title"] = supplements.Localization[lang].HomePage.Header templateMap["FilledHeartCount"] = uint(40) diff --git a/internal/router/handlers/root.go b/internal/router/handlers/root.go index c8c4cd4..9f15782 100644 --- a/internal/router/handlers/root.go +++ b/internal/router/handlers/root.go @@ -35,6 +35,13 @@ func (r *RootHandler) CacheDuration() time.Duration { return 24 * time.Hour } +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-летки, странствующего по ебеням, зато не мейнстрим", + }, nil +} + func (r *RootHandler) RenderBody(c *fiber.Ctx, supplements *router.Supplements, _ string, templateMap fiber.Map) (statusCode int, err error) { templateMap["Title"] = "Choose Your Language" templateMap["AvailableLanguages"] = supplements.AvailableLanguages diff --git a/internal/router/router.go b/internal/router/router.go index c0556f0..f28add2 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -60,6 +60,7 @@ type Route interface { ToValidateLang() LangSetting TemplatesToInject() []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) 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) @@ -382,11 +383,18 @@ func (r *Router) generalPage(c *fiber.Ctx, route Route, lang string) error { return c.Status(fiber.StatusOK).Type("html").Send(val) } - content, err := r.supplements.TemplateManager.Render("general-page", fiber.Map{ + valueMap := fiber.Map{ "L": r.supplements.Localization[lang], "Lang": lang, "QueryString": queryString, - }) + } + + var err error + if valueMap["Meta"], err = route.AddMeta(c, r.supplements, lang, valueMap); err != nil { + slog.Warn("failed to receive meta", slog.String("path", path), slog.String("error", err.Error())) + } + + 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())) return c.Status(fiber.ErrInternalServerError.Code).SendString("failed to generate div") diff --git a/internal/templatemanager/templatemanager.go b/internal/templatemanager/templatemanager.go index 75309e4..b23e2e8 100644 --- a/internal/templatemanager/templatemanager.go +++ b/internal/templatemanager/templatemanager.go @@ -32,6 +32,9 @@ var templateFuncMap = template.FuncMap{ return items }, "replace": strings.ReplaceAll, + "fdiv": func(a, b int) float64 { + return float64(a) / float64(b) + }, } func NewTemplateManager(templates ...TemplateManagerTemplates) (*TemplateManager, error) { diff --git a/locale/localization.en.yaml b/locale/localization.en.yaml index c7f2df8..e165866 100644 --- a/locale/localization.en.yaml +++ b/locale/localization.en.yaml @@ -1,6 +1,7 @@ TagsLabel: 'Tags:' BlogSearch: Header: 'Blog Search' + Description: "The Saya Blog posts' list" TagsHeader: 'Tags' OrderByHeader: 'Order by...' TitleOrdered: 'Title' @@ -9,6 +10,7 @@ BlogSearch: ChooseAllTags: 'Choose All' GlobalMap: Header: 'Global Map' + Description: "Global map with all the tags of places I've been to" HomePage: Header: 'Home Page' Contacts: 'Contacts' diff --git a/locale/localization.go b/locale/localization.go index c6467c4..a4f36f1 100644 --- a/locale/localization.go +++ b/locale/localization.go @@ -20,6 +20,7 @@ type LocaleConfig struct { type BlogSearchConfig struct { Header string `yaml:"Header" json:"Header"` + Description string `yaml:"Description" json:"Description"` TagsHeader string `yaml:"TagsHeader" json:"TagsHeader"` OrderByHeader string `yaml:"OrderByHeader" json:"OrderByHeader"` TitleOrdered string `yaml:"TitleOrdered" json:"TitleOrdered"` @@ -29,7 +30,8 @@ type BlogSearchConfig struct { } type GlobalMapConfig struct { - Header string `yaml:"Header" json:"Header"` + Header string `yaml:"Header" json:"Header"` + Description string `yaml:"Description" json:"Description"` } type HomePageConfig struct { diff --git a/locale/localization.ru.yaml b/locale/localization.ru.yaml index 5df82da..e65848a 100644 --- a/locale/localization.ru.yaml +++ b/locale/localization.ru.yaml @@ -1,6 +1,7 @@ TagsLabel: 'Тэги:' BlogSearch: Header: 'Поиск по блогу' + Description: 'Каталог записей Saya Blog' TagsHeader: 'Тэги' OrderByHeader: 'Упорядочить по...' TitleOrdered: 'названию' @@ -9,6 +10,7 @@ BlogSearch: ChooseAllTags: 'Выбрать все' GlobalMap: Header: 'Глобальная карта' + Description: 'Глобальная карта с метками мест, где я побывал' HomePage: Header: 'Домашняя страница' Contacts: 'Контакты' diff --git a/views/layouts/general-page.html b/views/layouts/general-page.html index 2bf548f..3f5bcfd 100644 --- a/views/layouts/general-page.html +++ b/views/layouts/general-page.html @@ -3,7 +3,9 @@ <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - {{ block "meta" . }}{{ end }} + {{- range $k, $v := .Meta }} + <meta name="{{ $k }}" content="{{ $v }}"> + {{- end }} <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"> <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.css"> <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/glightbox/3.3.0/css/glightbox.min.css"> diff --git a/views/pages/blog-catalogue.html b/views/pages/blog-catalogue.html index 349e58f..d2c74ae 100644 --- a/views/pages/blog-catalogue.html +++ b/views/pages/blog-catalogue.html @@ -1,8 +1,3 @@ -{{ define "meta" }} -<meta name="og:title" content="{{ .L.BlogSearch.Header }}"> -<meta name="og:description" content="{{ .L.BlogSearch.Description }}"> -{{ end }} - {{ define "body" }} <div class="flex flex-row ar-lt-0.8:flex-col text-base h-full"> <div class="relative flex shrink-0 ar-gt-0.8:min-w-[10dvh] ar-gt-0.8:max-w-[20dvh] ar-gt-0.8:w-fit ar-lt-0.8:w-full ar-lt-0.8:max-h-[30%] ar-gt-0.8:mr-6"> diff --git a/views/pages/blog-page.html b/views/pages/blog-page.html index 241ef43..c81406f 100644 --- a/views/pages/blog-page.html +++ b/views/pages/blog-page.html @@ -1,10 +1,3 @@ -{{ define "meta" }} -<meta name="og:title" content="{{ .Title }}"> -<meta name="og:description" content="{{ .ShortDescription }} [{{ .ActionDate }}]"> -<meta name="og:image" content="{{ .Thumbnail }}"> -<meta name="twitter:card" content="summary_large_image"> -{{ end }} - {{ define "body" }} <div class="absolute w-full h-full inset-0 inset-shadow-[0_0_0.4rem_black] pointer-events-none z-20"></div> <div class="relative bg-background-light flex flex-col px-8 py-4 overflow-y-auto"> diff --git a/views/pages/global-map.html b/views/pages/global-map.html index a19f3fa..4b07bd2 100644 --- a/views/pages/global-map.html +++ b/views/pages/global-map.html @@ -245,35 +245,32 @@ map.addLayer(markers); } - function stringToColor(str) { + function markerToHsl(str, newCoef) { let hash = 0; - for (let i = 0; i < str.length; i++) { + for (let i = 0; i < str.length / 2; i++) { hash = str.charCodeAt(i) + ((hash << 5) - hash); + hash = str.charCodeAt(str.length - i - 1) + ((hash << 5) - hash); + hash %= 360; } - let color = '#'; - for (let i = 0; i < 3; i++) { - const value = (hash >> (i * 8)) & 0xFF; - color += ('00' + value.toString(16)).substr(-2); - } - - return color; + return [hash, (20 + newCoef * 80).toFixed(0), (20 + newCoef * 75).toFixed(0)]; } - function mapAddMarker(x, y, relativeErrorMeters = 0, title = "", link = "", thumbnail = "") { - const titleColor = stringToColor(title); + function mapAddMarker(x, y, relativeErrorMeters = 0, title = "", link = "", thumbnail = "", newCoef = 1) { + const [h, s, l] = markerToHsl(title, newCoef); + const color = `hsl(${h} ${s}% ${l}%)`; if (relativeErrorMeters != 0) { var circle = L.circle([x, y], { - color: titleColor, - fillColor: titleColor, + color: color, + fillColor: color, fillOpacity: 0.15, radius: relativeErrorMeters }).addTo(map); } var marker = L.marker([x, y], { - icon: createCustomIcon(titleColor), + icon: createCustomIcon(color), title: title, }).bindPopup(` <div class="flex flex-row justify-center justify-items-center"> @@ -287,7 +284,7 @@ document.addEventListener('DOMContentLoaded', () => { initLocationMap(); {{- range .MapMarkers }} - mapAddMarker({{ .Lat }}, {{ .Long }}, {{ .AccuracyMeters }}, {{ .Title }}, {{ .PageLink }}, {{ .Thumbnail }}); + mapAddMarker({{ .Lat }}, {{ .Long }}, {{ .AccuracyMeters }}, {{ .Title }}, {{ .PageLink }}, {{ .Thumbnail }}, {{ fdiv .Index (len $.MapMarkers) }}); {{- end }} }); diff --git a/views/pages/home-page.html b/views/pages/home-page.html index 4ba6b8e..6d397fa 100644 --- a/views/pages/home-page.html +++ b/views/pages/home-page.html @@ -1,9 +1,3 @@ -{{ define "meta" }} -<meta name="og:title" content="{{ .Title }}"> -<meta name="og:description" content="{{ .L.HomePage.Description }}"> -<meta name="og:image" content="https://f003.backblazeb2.com/file/sayana-static/home-page-gifs/{{ .GifName }}"> -{{ end }} - {{ define "body" }} <div class="absolute w-full h-full inset-0 inset-shadow-[0_0_0.4rem_black] pointer-events-none z-20"></div> <div class="relative bg-background-light flex flex-row ar-lt-0.6:flex-col w-full h-full overflow-y-auto text-base/loose tracking-wide z-10"> diff --git a/views/pages/language-pick.html b/views/pages/language-pick.html index 3f6f672..775c18e 100644 --- a/views/pages/language-pick.html +++ b/views/pages/language-pick.html @@ -1,8 +1,3 @@ -{{ define "meta" }} -<meta name="og:title" content="{{ .Root.Header }}"> -<meta name="og:description" content="{{ .Root.Description }}"> -{{ end }} - {{ define "body" }} <div class="flex flex-col justify-center text-3xl h-full"> {{- range .AvailableLanguages }} diff --git a/views/pages/user-page.html b/views/pages/user-page.html index c9f7373..fda7e66 100644 --- a/views/pages/user-page.html +++ b/views/pages/user-page.html @@ -1,8 +1,3 @@ -{{ define "meta" }} -<meta name="og:title" content="{{ .L.BlogSearch.Header }}"> -<meta name="og:description" content="{{ .L.BlogSearch.Description }}"> -{{ end }} - {{ define "body" }} <div class="absolute w-full h-full inset-0 inset-shadow-[0_0_0.4rem_black] pointer-events-none z-20"></div> <div class="relative bg-background-light flex flex-col px-8 py-4"> |