diff options
| author | 2026-05-10 00:00:54 +0700 | |
|---|---|---|
| committer | 2026-05-10 00:00:54 +0700 | |
| commit | 978e9aa66d15a503cb7dd6f547ceba1d7918d1bf (patch) | |
| tree | 9ef9d447ac142849efea26af7998ad55b9aa3fee | |
| parent | d5e3be1753086c7688a403cb06ca611bba304a74 (diff) | |
| parent | 19b9ff9ab13094fc51caecd0ca32fbbf6bdf4db3 (diff) | |
| download | web-978e9aa66d15a503cb7dd6f547ceba1d7918d1bf.tar.gz web-978e9aa66d15a503cb7dd6f547ceba1d7918d1bf.zip | |
v0.15.7 (#38)v0.15.7
* [feat: render full page completely in one
request](https://github.com/SayaAndy/saya-today-web/commit/19b9ff9ab13094fc51caecd0ca32fbbf6bdf4db3)
| -rw-r--r-- | internal/router/router.go | 49 | ||||
| -rw-r--r-- | views/layouts/general-page.html | 122 |
2 files changed, 94 insertions, 77 deletions
diff --git a/internal/router/router.go b/internal/router/router.go index 964a953..7f3511a 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -451,8 +451,8 @@ func (r *Router) generalPage(c *fiber.Ctx, route Route, lang string) error { path := c.Path() method := c.Method() trimmedPath := strings.Trim(path, "/") - cacheKey := "" queryString := c.Request().URI().QueryString() + cacheKey := "" switch route.ToCache() { case ByUrlOnly: @@ -469,6 +469,7 @@ func (r *Router) generalPage(c *fiber.Ctx, route Route, lang string) error { valueMap := fiber.Map{ "L": r.supplements.Localization[lang], "Lang": lang, + "Path": trimmedPath, "QueryString": queryString, "CanonicalEndpoint": r.canonicalEndpoint, "StaticStorageBaseUrl": r.supplements.StaticStorage.BaseUrl, @@ -489,10 +490,52 @@ func (r *Router) generalPage(c *fiber.Ctx, route Route, lang string) error { valueMap["LinkedData"] = template.JS(ldBytes) } + syntheticReferer := path + if len(queryString) > 0 { + syntheticReferer += "?" + string(queryString) + } + c.Request().Header.Set("Referer", syntheticReferer) + + parts := []struct { + name string + key string + render func(c *fiber.Ctx, supplements *Supplements, lang string, templateMap fiber.Map) (int, error) + }{ + {"top-embeds", "RenderedTopEmbeds", route.RenderTopEmbeds}, + {"header", "RenderedHeader", route.RenderHeader}, + {"body", "RenderedBody", route.RenderBody}, + {"footer", "RenderedFooter", route.RenderFooter}, + {"bottom-embeds", "RenderedBottomEmbeds", route.RenderBottomEmbeds}, + } + + for _, p := range parts { + statusCode, err := p.render(c, r.supplements, lang, valueMap) + if err != nil { + slog.Error("failed to render segment for full page", + slog.String("path", path), + slog.String("segment", p.name), + slog.String("error", err.Error()), + ) + c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8) + return c.Status(statusCode).SendString(err.Error()) + } + segContent, err := r.supplements.TemplateManager.Render("general-page-"+p.name, valueMap, route.TemplatesToInject()...) + if err != nil { + slog.Error("failed to render segment template for full page", + slog.String("path", path), + slog.String("segment", p.name), + slog.String("error", err.Error()), + ) + c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8) + return c.Status(fiber.ErrInternalServerError.Code).SendString("failed to generate segment") + } + valueMap[p.key] = template.HTML(segContent) + } + 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") + slog.Warn("failed to generate full page", slog.String("path", path), slog.String("error", err.Error())) + return c.Status(fiber.ErrInternalServerError.Code).SendString("failed to generate full page") } go r.supplements.PageCache.SetWithTTL(cacheKey, content, int64(len(content)), route.CacheDuration()) diff --git a/views/layouts/general-page.html b/views/layouts/general-page.html index 5cf870f..d787c16 100644 --- a/views/layouts/general-page.html +++ b/views/layouts/general-page.html @@ -311,14 +311,50 @@ switchTheme(savedTheme); </script> - <div - id="general-page-top-embeds" - class="flex" - hx-get="/api/v1/general-page/top-embeds{{ if .QueryString }}?{{ .QueryString }}{{ end }}" - hx-trigger="load" - hx-target="this" - hx-swap="innerHTML" - ></div> + <script src="{{ .StaticStorageBaseUrl }}/libs/htmx/2.0.6/htmx.min.js"></script> + <script src="{{ .StaticStorageBaseUrl }}/libs/leaflet/1.9.4/leaflet.js"></script> + <script src="{{ .StaticStorageBaseUrl }}/libs/imagesloaded/5.0.0/imagesloaded.pkgd.min.js"></script> + <script src="{{ .StaticStorageBaseUrl }}/libs/packery/3.0.0/dist/packery.pkgd.min.js"></script> + + <script> + // Enable fitWidth-like attribute for Packery. Source: https://codepen.io/desandro/pen/kVmLYz + var __resetLayout = Packery.prototype._resetLayout; + Packery.prototype._resetLayout = function () { + __resetLayout.call(this); + var parentSize = getSize(this.element.parentNode); + var colW = this.columnWidth + this.gutter; + this.fitWidth = + Math.floor((parentSize.innerWidth + this.gutter) / colW) * + colW; + this.packer.width = this.fitWidth; + this.packer.height = Number.POSITIVE_INFINITY; + this.packer.reset(); + }; + + Packery.prototype._getContainerSize = function () { + var emptyWidth = 0; + for (var i = 0, len = this.packer.spaces.length; i < len; i++) { + var space = this.packer.spaces[i]; + if ( + space.y === 0 && + space.height === Number.POSITIVE_INFINITY + ) { + emptyWidth += space.width; + } + } + + return { + width: this.fitWidth - this.gutter - emptyWidth, + height: this.maxY - this.gutter, + }; + }; + + Packery.prototype.needsResizeLayout = function () { + return true; + }; + </script> + + <div id="general-page-top-embeds" class="flex">{{ .RenderedTopEmbeds }}</div> <div id="general-page-top-embeds-trigger" hx-get="/api/v1/general-page/top-embeds{{ if .QueryString }}?{{ .QueryString }}{{ end }}" @@ -492,11 +528,7 @@ <header id="general-page-header" class="max-xs:hidden [@media(max-height:32rem)]:hidden flex flex-col ml-8 basis-8" - hx-get="/api/v1/general-page/header{{ if .QueryString }}?{{ .QueryString }}{{ end }}" - hx-trigger="load" - hx-target="this" - hx-swap="innerHTML" - ></header> + >{{ .RenderedHeader }}</header> <div id="general-page-header-trigger" hx-get="/api/v1/general-page/header{{ if .QueryString }}?{{ .QueryString }}{{ end }}" @@ -512,11 +544,7 @@ <main id="general-page-body" class="relative flex-1 overflow-y-auto" - hx-get="/api/v1/general-page/body{{ if .QueryString }}?{{ .QueryString }}{{ end }}" - hx-trigger="load" - hx-target="this" - hx-swap="innerHTML" - ></main> + >{{ .RenderedBody }}</main> <div id="general-page-body-trigger" hx-get="/api/v1/general-page/body{{ if .QueryString }}?{{ .QueryString }}{{ end }}" @@ -528,11 +556,7 @@ <footer id="general-page-footer" class="flex flex-row basis-4 my-1" - hx-get="/api/v1/general-page/footer{{ if .QueryString }}?{{ .QueryString }}{{ end }}" - hx-trigger="load" - hx-target="this" - hx-swap="innerHTML" - ></footer> + >{{ .RenderedFooter }}</footer> <div id="general-page-footer-trigger" hx-get="/api/v1/general-page/footer{{ if .QueryString }}?{{ .QueryString }}{{ end }}" @@ -554,57 +578,7 @@ <div class="grow bg-split-right"></div> - <script src="{{ .StaticStorageBaseUrl }}/libs/htmx/2.0.6/htmx.min.js"></script> - <script src="{{ .StaticStorageBaseUrl }}/libs/leaflet/1.9.4/leaflet.js"></script> - <script src="{{ .StaticStorageBaseUrl }}/libs/imagesloaded/5.0.0/imagesloaded.pkgd.min.js"></script> - <script src="{{ .StaticStorageBaseUrl }}/libs/packery/3.0.0/dist/packery.pkgd.min.js"></script> - - <script> - // Enable fitWidth-like attribute for Packery. Source: https://codepen.io/desandro/pen/kVmLYz - var __resetLayout = Packery.prototype._resetLayout; - Packery.prototype._resetLayout = function () { - __resetLayout.call(this); - var parentSize = getSize(this.element.parentNode); - var colW = this.columnWidth + this.gutter; - this.fitWidth = - Math.floor((parentSize.innerWidth + this.gutter) / colW) * - colW; - this.packer.width = this.fitWidth; - this.packer.height = Number.POSITIVE_INFINITY; - this.packer.reset(); - }; - - Packery.prototype._getContainerSize = function () { - var emptyWidth = 0; - for (var i = 0, len = this.packer.spaces.length; i < len; i++) { - var space = this.packer.spaces[i]; - if ( - space.y === 0 && - space.height === Number.POSITIVE_INFINITY - ) { - emptyWidth += space.width; - } - } - - return { - width: this.fitWidth - this.gutter - emptyWidth, - height: this.maxY - this.gutter, - }; - }; - - Packery.prototype.needsResizeLayout = function () { - return true; - }; - </script> - - <div - id="general-page-bottom-embeds" - class="flex" - hx-get="/api/v1/general-page/bottom-embeds{{ if .QueryString }}?{{ .QueryString }}{{ end }}" - hx-trigger="load" - hx-target="this" - hx-swap="innerHTML" - ></div> + <div id="general-page-bottom-embeds" class="flex">{{ .RenderedBottomEmbeds }}</div> <div id="general-page-bottom-embeds-trigger" hx-get="/api/v1/general-page/bottom-embeds{{ if .QueryString }}?{{ .QueryString }}{{ end }}" |