Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
812891a205 | ||
|
|
297efaa4a6 | ||
|
|
c08dd355c0 |
No files matched your search
@@ -27,3 +27,11 @@ jobs:
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: "git.schreifuchs.ch/schreifuchs/schreifuchs.ch:${{ github.ref_name }},git.schreifuchs.ch/schreifuchs/schreifuchs.ch:latest"
|
||||
- name: Create Gitea Release
|
||||
uses: https://gitea.com/actions/gitea-release-action@v1
|
||||
with:
|
||||
state: "published"
|
||||
title: "Release ${{ github.ref_name }}"
|
||||
notes: "Automated release for tag ${{ github.ref_name }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -53,13 +53,21 @@ func Path(ctx context.Context, pp ...string) string {
|
||||
}
|
||||
|
||||
func PathForLang(ctx context.Context, lang string, pp ...string) string {
|
||||
slog.Debug("computing path for lang", "pp", pp, "lang", lang)
|
||||
s, ok := ctx.Value(serviceKey).(*Service)
|
||||
if !ok {
|
||||
slog.Error("could not extract translation service from context for translating path", "ctx", ctx, "path", pp)
|
||||
return path.Join(pp...)
|
||||
}
|
||||
|
||||
// remove leading ""
|
||||
for len(pp) > 0 && pp[0] == "" {
|
||||
pp = pp[1:]
|
||||
}
|
||||
|
||||
if len(pp) > 0 {
|
||||
|
||||
slog.Debug("computing path for lang", "pp", pp, "lang", lang, "pp[0]", pp[0], "translations", s.translations)
|
||||
if _, ok := s.translations[pp[0]]; ok {
|
||||
pp = pp[1:]
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func (h *Handler) gallery(w http.ResponseWriter, r *http.Request) {
|
||||
ctx = templer.AppendHeader(ctx, fmt.Sprintf(`<link rel="preload" href="%s?w=800" as="image" />`, image.URL()))
|
||||
}
|
||||
|
||||
h.r.Render(ctx, w, r, pages.GallerySet(imgs))
|
||||
h.r.RenderPage(ctx, w, r, pages.GallerySet(imgs))
|
||||
}
|
||||
|
||||
func (h *Handler) image(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -41,5 +41,5 @@ func (h *Handler) image(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
h.r.Render(r.Context(), w, r, pages.GalleryImage(uid, next, prev))
|
||||
h.r.RenderComponent(r.Context(), w, r, pages.GalleryImage(uid, next, prev))
|
||||
}
|
||||
@@ -40,5 +40,6 @@ type galleryService interface {
|
||||
GetPrevAndNext(ctx context.Context, uid string) (previous *gallery.Image, next *gallery.Image, err error)
|
||||
}
|
||||
type renderer interface {
|
||||
Render(ctx context.Context, w io.Writer, r *http.Request, component templ.Component)
|
||||
RenderPage(ctx context.Context, w io.Writer, r *http.Request, component templ.Component)
|
||||
RenderComponent(ctx context.Context, w io.Writer, r *http.Request, component templ.Component)
|
||||
}
|
||||
@@ -17,7 +17,7 @@ func (h *Handler) home(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
h.r.Render(r.Context(), w, r, pages.Home(pageHeaders))
|
||||
h.r.RenderPage(r.Context(), w, r, pages.Home(pageHeaders))
|
||||
}
|
||||
|
||||
func (h *Handler) page(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -43,5 +43,5 @@ func (h *Handler) page(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
ctx = templer.PageTitle(ctx, page.Title)
|
||||
|
||||
h.r.Render(ctx, w, r, pages.ContentPage(page))
|
||||
h.r.RenderPage(ctx, w, r, pages.ContentPage(page))
|
||||
}
|
||||
@@ -33,5 +33,5 @@ type pageService interface {
|
||||
GetPage(ctx context.Context, uid string) (page.Page, error)
|
||||
}
|
||||
type renderer interface {
|
||||
Render(ctx context.Context, w io.Writer, r *http.Request, component templ.Component)
|
||||
RenderPage(ctx context.Context, w io.Writer, r *http.Request, component templ.Component)
|
||||
}
|
||||
+25
-6
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
templ Head(cfg config.Cfg, title string) {
|
||||
templ head(cfg config.Cfg, title string) {
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
@@ -23,14 +23,35 @@ templ Head(cfg config.Cfg, title string) {
|
||||
@templ.Raw(h)
|
||||
}
|
||||
</head>
|
||||
{ children... }
|
||||
}
|
||||
|
||||
templ Base(cfg config.Cfg, title string) {
|
||||
<!DOCTYPE html>
|
||||
<html lang={ translate.Language(ctx) }>
|
||||
@Head(cfg, title)
|
||||
<body class="bg-black dark" hx-boost="true" hx-target="main" hx-ext="head-support,preload,preload-links">
|
||||
@head(cfg, title)
|
||||
<body class="bg-black dark" hx-boost="true" hx-target="body" hx-ext="head-support,preload,preload-links">
|
||||
@body() {
|
||||
{ children... }
|
||||
}
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
||||
templ Page(cfg config.Cfg, title string) {
|
||||
@head(cfg, title)
|
||||
@body() {
|
||||
{ children... }
|
||||
}
|
||||
}
|
||||
|
||||
templ Component() {
|
||||
for _, h := range templer.GetHeader(ctx) {
|
||||
@templ.Raw(h)
|
||||
}
|
||||
{ children... }
|
||||
}
|
||||
|
||||
templ body() {
|
||||
<header
|
||||
class="fixed z-50 mix-blend-difference p-1 w-full flex justify-between items-start"
|
||||
>
|
||||
@@ -52,6 +73,4 @@ templ Base(cfg config.Cfg, title string) {
|
||||
<main class="text-white">
|
||||
{ children... }
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
+13
-7
@@ -2,7 +2,6 @@ package layouts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
@@ -22,12 +21,9 @@ func New(cfg config.Cfg) *Layouts {
|
||||
}
|
||||
}
|
||||
|
||||
// Render renders a page. If the query paramenter "c" is set
|
||||
// RenderPage renders a page. If the query paramenter HX-Request is set
|
||||
// the component gets rendered without the layout
|
||||
func (l *Layouts) Render(ctx context.Context, w io.Writer, r *http.Request, component templ.Component) {
|
||||
withLayout := !r.URL.Query().Has("c")
|
||||
fmt.Println("layout: ", withLayout)
|
||||
|
||||
func (l *Layouts) RenderPage(ctx context.Context, w io.Writer, r *http.Request, component templ.Component) {
|
||||
title := templer.GetTitle(ctx, "Schreifuchs")
|
||||
|
||||
slog.Debug("HX-Request", "value", r.Header.Get("HX-Request"))
|
||||
@@ -36,10 +32,20 @@ func (l *Layouts) Render(ctx context.Context, w io.Writer, r *http.Request, comp
|
||||
component = Base(l.cfg, title)
|
||||
} else {
|
||||
ctx = templ.WithChildren(ctx, component)
|
||||
component = Head(l.cfg, title)
|
||||
component = Page(l.cfg, title)
|
||||
}
|
||||
|
||||
if err := component.Render(ctx, w); err != nil {
|
||||
slog.Error("error while rendering component", "err", err, "ctx", ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// RenderComponent renders a component alone.
|
||||
func (l *Layouts) RenderComponent(ctx context.Context, w io.Writer, r *http.Request, component templ.Component) {
|
||||
ctx = templ.WithChildren(ctx, component)
|
||||
component = Component()
|
||||
|
||||
if err := component.Render(ctx, w); err != nil {
|
||||
slog.Error("error while rendering component", "err", err, "ctx", ctx)
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,9 @@ templ GallerySet(g gallery.Set) {
|
||||
</div>
|
||||
}
|
||||
|
||||
// Define a templ script to hold complex post-load behavior
|
||||
templ GalleryImage(image string, next *gallery.Image, prev *gallery.Image) {
|
||||
<link rel="preload" href={ "/images/" + image + "?w=800" } as="image"/>
|
||||
<div class="relative w-10/12 h-10/12 flex items-center justify-center overflow-hidden ">
|
||||
<!-- 1. Preloaded Base Image (w=800) -->
|
||||
<img
|
||||
@@ -68,8 +70,8 @@ templ GalleryImage(image string, next *gallery.Image, prev *gallery.Image) {
|
||||
srcset={ "/images/" + image + "?w=400 400w, /images/" + image + "?w=800 800w, /images/" + image + "?w=1200 1200w, /images/" + image + "?w=1600 1600w" }
|
||||
sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
|
||||
alt="Image description"
|
||||
onload="this.classList.remove('opacity-0')"
|
||||
class="absolute inset-0 w-full h-full object-contain transition-opacity duration-300"
|
||||
onload="this.decode().then(() => {this.classList.remove('opacity-0')}).catch(() => {})"
|
||||
class="absolute inset-0 w-full h-full object-contain transition-opacity duration-900 opacity-0"
|
||||
/>
|
||||
<!-- 3. Navigation Controls -->
|
||||
if prev != nil {
|
||||
@@ -77,6 +79,7 @@ templ GalleryImage(image string, next *gallery.Image, prev *gallery.Image) {
|
||||
hx-get={ templer.RelativePath(ctx, "../"+prev.UID) }
|
||||
hx-target={ "#" + detailsContentID }
|
||||
hx-swap="innerHTML"
|
||||
preload
|
||||
class="absolute left-4 top-1/2 -translate-y-1/2 z-10 p-2 text-white"
|
||||
>
|
||||
<
|
||||
@@ -87,6 +90,7 @@ templ GalleryImage(image string, next *gallery.Image, prev *gallery.Image) {
|
||||
hx-get={ templer.RelativePath(ctx, "../"+next.UID) }
|
||||
hx-target={ "#" + detailsContentID }
|
||||
hx-swap="innerHTML"
|
||||
preload="mouseover"
|
||||
class="absolute right-4 top-1/2 -translate-y-1/2 z-10 p-2 text-white"
|
||||
>
|
||||
>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
|
||||
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-text-shadow-color:initial;--tw-text-shadow-alpha:100%}}}@layer theme{:root,:host{--font-sans:"Outfit","outfit",sans-serif;--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-6xl:72rem;--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--font-weight-bold:700;--text-shadow-lg:0px 0px 20px #000;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components{.prose img{max-height:90vh;margin-left:auto;margin-right:auto;display:block}}@layer utilities{.pLine truncated
|
||||
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-text-shadow-color:initial;--tw-text-shadow-alpha:100%}}}@layer theme{:root,:host{--font-sans:"Outfit","outfit",sans-serif;--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-6xl:72rem;--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--font-weight-bold:700;--text-shadow-lg:0px 0px 20px #000;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components{.prose img{max-height:90vh;margin-left:auto;margin-right:auto;display:block}}@layer utilities{.pLine truncated
|
||||
Reference in new issue
Block a user