diff options
| author | 2025-08-31 18:12:51 +0700 | |
|---|---|---|
| committer | 2025-08-31 18:12:51 +0700 | |
| commit | 145e7e05f3aa6adbc71a0db5e7da160e626bacd3 (patch) | |
| tree | 6864bf01bbeeeadbf06122b9ab5d993cffaf4062 /internal | |
| parent | 5eb7b64b3da54e769cc6e52fd6918e4b465b8c0a (diff) | |
| download | web-145e7e05f3aa6adbc71a0db5e7da160e626bacd3.tar.gz web-145e7e05f3aa6adbc71a0db5e7da160e626bacd3.zip | |
feat: seamless single page application
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/lightgallery/html_renderer.go | 2 | ||||
| -rw-r--r-- | internal/router/api-v1-general-page-body.go | 8 | ||||
| -rw-r--r-- | internal/router/api-v1-general-page-bottom-embeds.go | 65 | ||||
| -rw-r--r-- | internal/router/api-v1-general-page-footer.go | 5 | ||||
| -rw-r--r-- | internal/router/api-v1-general-page-header.go | 5 | ||||
| -rw-r--r-- | internal/router/api-v1-general-page-top-embeds.go | 64 | ||||
| -rw-r--r-- | internal/router/lang-blog-title.go | 1 | ||||
| -rw-r--r-- | internal/router/lang-blog.go | 1 |
8 files changed, 143 insertions, 8 deletions
diff --git a/internal/lightgallery/html_renderer.go b/internal/lightgallery/html_renderer.go index 21bd049..c8c1cf0 100644 --- a/internal/lightgallery/html_renderer.go +++ b/internal/lightgallery/html_renderer.go @@ -126,7 +126,7 @@ document.addEventListener('htmx:afterRequest', (e) => { if (e.detail.target.id == 'general-page-body') { createLightGallery%s(); } -}); +}, {once: true}); </script>`, galleryID, galleryID, strings.Join(dynamicElements, ","), galleryID, galleryID)) } diff --git a/internal/router/api-v1-general-page-body.go b/internal/router/api-v1-general-page-body.go index 419bad6..4108a4f 100644 --- a/internal/router/api-v1-general-page-body.go +++ b/internal/router/api-v1-general-page-body.go @@ -44,8 +44,9 @@ func Api_V1_GeneralPage_Body(l map[string]*locale.LocaleConfig, langs []string, } values := fiber.Map{ - "L": l[lang], - "Lang": lang, + "L": l[lang], + "Lang": lang, + "QueryString": string(c.Request().URI().QueryString()), } var additionalTemplates []string @@ -117,10 +118,11 @@ func Api_V1_GeneralPage_Body(l map[string]*locale.LocaleConfig, langs []string, areaError = geolocationParts[2] } - values["ParsedMarkdown"] = template.HTML(parsedMarkdown) values["MapLocationX"] = x values["MapLocationY"] = y values["MapLocationAreaMeters"] = areaError + values["Title"] = metadata.Title + values["ParsedMarkdown"] = template.HTML(parsedMarkdown) additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html") } diff --git a/internal/router/api-v1-general-page-bottom-embeds.go b/internal/router/api-v1-general-page-bottom-embeds.go new file mode 100644 index 0000000..f0957f3 --- /dev/null +++ b/internal/router/api-v1-general-page-bottom-embeds.go @@ -0,0 +1,65 @@ +package router + +import ( + "fmt" + "log/slog" + "net/url" + "slices" + "strings" + + "github.com/SayaAndy/saya-today-web/internal/b2" + "github.com/SayaAndy/saya-today-web/locale" + "github.com/gofiber/fiber/v2" +) + +func init() { + tm.Add("general-page-bottom-embeds", "views/partials/general-page-bottom-embeds.html") +} + +func Api_V1_GeneralPage_BottomEmbeds(l map[string]*locale.LocaleConfig, langs []string, b2Client *b2.B2Client) func(c *fiber.Ctx) error { + return func(c *fiber.Ctx) error { + c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8) + + referer := c.Get("Referer", "") + if referer == "" { + return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is empty") + } + urlStruct, err := url.ParseRequestURI(referer) + if err != nil { + return c.Status(fiber.ErrBadRequest.Code).SendString(fmt.Sprintf("'Referer' header is invalid: %s", err.Error())) + } + + path := urlStruct.EscapedPath() + pathParts := strings.Split(strings.Trim(path, "/"), "/") + if len(pathParts) < 2 { + return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'") + } + + lang := pathParts[0] + if !slices.Contains(langs, lang) { + return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language... yet??", lang)) + } + + values := fiber.Map{ + "L": l[lang], + "Lang": lang, + "QueryString": string(c.Request().URI().QueryString()), + } + var additionalTemplates []string + + if len(pathParts) == 2 && pathParts[1] == "blog" { + additionalTemplates = append(additionalTemplates, "views/pages/blog-catalogue.html") + } else if len(pathParts) == 3 && pathParts[1] == "blog" { + additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html") + } + + content, err := tm.Render("general-page-bottom-embeds", values, additionalTemplates...) + 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") + } + + c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8) + return c.Status(fiber.StatusOK).Type("html").Send(content) + } +} diff --git a/internal/router/api-v1-general-page-footer.go b/internal/router/api-v1-general-page-footer.go index 4c3a35e..39b6bea 100644 --- a/internal/router/api-v1-general-page-footer.go +++ b/internal/router/api-v1-general-page-footer.go @@ -40,8 +40,9 @@ func Api_V1_GeneralPage_Footer(l map[string]*locale.LocaleConfig, langs []string } values := fiber.Map{ - "L": l[lang], - "Lang": lang, + "L": l[lang], + "Lang": lang, + "QueryString": string(c.Request().URI().QueryString()), } var additionalTemplates []string diff --git a/internal/router/api-v1-general-page-header.go b/internal/router/api-v1-general-page-header.go index 045ff8b..0529ba6 100644 --- a/internal/router/api-v1-general-page-header.go +++ b/internal/router/api-v1-general-page-header.go @@ -41,8 +41,9 @@ func Api_V1_GeneralPage_Header(l map[string]*locale.LocaleConfig, langs []string } values := fiber.Map{ - "L": l[lang], - "Lang": lang, + "L": l[lang], + "Lang": lang, + "QueryString": string(c.Request().URI().QueryString()), } var additionalTemplates []string diff --git a/internal/router/api-v1-general-page-top-embeds.go b/internal/router/api-v1-general-page-top-embeds.go new file mode 100644 index 0000000..090107b --- /dev/null +++ b/internal/router/api-v1-general-page-top-embeds.go @@ -0,0 +1,64 @@ +package router + +import ( + "fmt" + "log/slog" + "net/url" + "slices" + "strings" + + "github.com/SayaAndy/saya-today-web/locale" + "github.com/gofiber/fiber/v2" +) + +func init() { + tm.Add("general-page-top-embeds", "views/partials/general-page-top-embeds.html") +} + +func Api_V1_GeneralPage_TopEmbeds(l map[string]*locale.LocaleConfig, langs []string) func(c *fiber.Ctx) error { + return func(c *fiber.Ctx) error { + c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8) + + referer := c.Get("Referer", "") + if referer == "" { + return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is empty") + } + urlStruct, err := url.ParseRequestURI(referer) + if err != nil { + return c.Status(fiber.ErrBadRequest.Code).SendString(fmt.Sprintf("'Referer' header is invalid: %s", err.Error())) + } + + path := urlStruct.EscapedPath() + pathParts := strings.Split(strings.Trim(path, "/"), "/") + if len(pathParts) < 2 { + return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'") + } + + lang := pathParts[0] + if !slices.Contains(langs, lang) { + return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language... yet??", lang)) + } + + values := fiber.Map{ + "L": l[lang], + "Lang": lang, + "QueryString": string(c.Request().URI().QueryString()), + } + var additionalTemplates []string + + if len(pathParts) == 2 && pathParts[1] == "blog" { + additionalTemplates = append(additionalTemplates, "views/pages/blog-catalogue.html") + } else if len(pathParts) == 3 && pathParts[1] == "blog" { + additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html") + } + + content, err := tm.Render("general-page-top-embeds", values, additionalTemplates...) + 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") + } + + c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8) + return c.Status(fiber.StatusOK).Type("html").Send(content) + } +} diff --git a/internal/router/lang-blog-title.go b/internal/router/lang-blog-title.go index bafb0d2..d6ca917 100644 --- a/internal/router/lang-blog-title.go +++ b/internal/router/lang-blog-title.go @@ -56,6 +56,7 @@ func Lang_Blog_Title(l map[string]*locale.LocaleConfig, langs []string, b2Client "MapLocationY": y, "MapLocationAreaMeters": areaError, "Lang": lang, + "QueryString": string(c.Request().URI().QueryString()), }) if err != nil { slog.Warn("failed to generate page", slog.String("page", "/"+lang+"/blog/"+c.Params("title")), slog.String("error", err.Error())) diff --git a/internal/router/lang-blog.go b/internal/router/lang-blog.go index dd3f079..38a6597 100644 --- a/internal/router/lang-blog.go +++ b/internal/router/lang-blog.go @@ -76,6 +76,7 @@ func Lang_Blog(l map[string]*locale.LocaleConfig, langs []string, b2Client *b2.B content, err := tm.Render("blog-catalogue", fiber.Map{ "QuerySort": querySort, "QueryTags": strings.Join(queryTags, ","), + "QueryString": string(c.Request().URI().QueryString()), "Tags": tagsArray, "Lang": lang, "L": l[lang], |