From 44fe2478478225450becb77ad5d273462c9b400a Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Thu, 16 Oct 2025 12:23:00 +0700 Subject: feat: implement new prototype gallery --- internal/glightbox/html_renderer.go | 134 ++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 internal/glightbox/html_renderer.go (limited to 'internal/glightbox/html_renderer.go') diff --git a/internal/glightbox/html_renderer.go b/internal/glightbox/html_renderer.go new file mode 100644 index 0000000..3b6a533 --- /dev/null +++ b/internal/glightbox/html_renderer.go @@ -0,0 +1,134 @@ +package glightbox + +import ( + "bytes" + "fmt" + "math/rand" + "strings" + "time" + + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/util" +) + +type GLightboxHTMLRenderer struct { + html.Config + md goldmark.Markdown +} + +func NewGLightboxHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { + r := &GLightboxHTMLRenderer{ + Config: html.NewConfig(), + md: goldmark.New( + goldmark.WithRendererOptions( + html.WithHardWraps(), + html.WithXHTML(), + ), + ), + } + for _, opt := range opts { + opt.SetHTMLOption(&r.Config) + } + return r +} + +func (r *GLightboxHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + reg.Register(KindGLightboxBlock, r.renderGLightbox) +} + +func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + gallery := n.(*GLightboxBlock) + + if len(gallery.Images) == 0 { + return ast.WalkContinue, nil + } + + galleryID := generateDivId(8) + + var elements []string + for i, img := range gallery.Images { + imageUrlSegments := strings.Split(img.URL, ".") + imageUrlWithoutExt := strings.Join(imageUrlSegments[:len(imageUrlSegments)-1], ".") + imageUrlParts := strings.Split(imageUrlWithoutExt, "/") + imageNameParts := strings.Split(imageUrlParts[len(imageUrlParts)-1], "-") + + var captionBuf bytes.Buffer + captionHTML := img.Caption + if err := r.md.Convert(img.Caption, &captionBuf); err == nil { + captionHTML = captionBuf.Bytes() + captionHTML = bytes.TrimPrefix(captionHTML, []byte("

")) + captionHTML = bytes.TrimSuffix(captionHTML, []byte("

\n")) + captionHTML = bytes.TrimSuffix(captionHTML, []byte("

")) + } + + dayDate, _ := time.Parse("20060102 150405", imageNameParts[len(imageNameParts)-2]+" "+imageNameParts[len(imageNameParts)-1]) + dayDate = dayDate.In(gallery.Location) + + glightboxDescId := "" + if len(captionHTML) != 0 { + glightboxDescId = fmt.Sprintf("glightbox-desc-%s-%d", galleryID, i) + } + + dataDescriptionAttribute := "" + if glightboxDescId != "" { + dataDescriptionAttribute = fmt.Sprintf("data-description=\".%s\"", glightboxDescId) + } + + elements = append(elements, fmt.Sprintf(` + + webp thumbnail + `, img.URL, galleryID, galleryID, galleryID, dayDate.Format("2006-01-02 15:04:05 -07:00"), dataDescriptionAttribute, imageUrlWithoutExt)) + + if glightboxDescId != "" { + elements = append(elements, fmt.Sprintf(` +
+

%s

+
`, glightboxDescId, captionHTML)) + } + } + + w.WriteString(fmt.Sprintf(` +
+
+
+
+ %s +
+
+
`, galleryID, galleryID, strings.Join(elements, "\n"))) + + w.WriteString(fmt.Sprintf(` +`, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID)) + } + + return ast.WalkContinue, nil +} + +func generateDivId(length int) string { + const charset = "abcdefghijklmnopqrstuvwxyz" + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) // Seed with current time + b := make([]byte, length) + for i := range b { + b[i] = charset[seededRand.Intn(len(charset))] + } + return string(b) +} -- cgit v1.3.1+13 From db174993127a8b2faf863a670fd6ce8ca8d7c1af Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Fri, 17 Oct 2025 01:16:18 +0700 Subject: feat: add onclick links in blog post links feat: add href for any onclick links/icons chore: rm any remains of old lightgallery fix: show borders between post rows fix: map redefining --- internal/glightbox/html_renderer.go | 2 +- internal/tailwind/link_renderer.go | 49 +++++++++++++++++++++ internal/tailwind/transformer.go | 7 +++ internal/templatemanager/templatemanager.go | 4 +- main.go | 14 ++++-- static/input.css | 31 ++++---------- views/layouts/general-page.html | 27 +++++++++--- views/pages/blog-page.html | 66 +++++------------------------ views/pages/global-map.html | 16 ++++--- views/partials/catalogue-blog-cards.html | 8 ++-- views/partials/general-page-header.html | 6 ++- 11 files changed, 131 insertions(+), 99 deletions(-) create mode 100644 internal/tailwind/link_renderer.go (limited to 'internal/glightbox/html_renderer.go') diff --git a/internal/glightbox/html_renderer.go b/internal/glightbox/html_renderer.go index 3b6a533..43d4790 100644 --- a/internal/glightbox/html_renderer.go +++ b/internal/glightbox/html_renderer.go @@ -81,7 +81,7 @@ func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, elements = append(elements, fmt.Sprintf(` - webp thumbnail + webp thumbnail `, img.URL, galleryID, galleryID, galleryID, dayDate.Format("2006-01-02 15:04:05 -07:00"), dataDescriptionAttribute, imageUrlWithoutExt)) if glightboxDescId != "" { diff --git a/internal/tailwind/link_renderer.go b/internal/tailwind/link_renderer.go new file mode 100644 index 0000000..ff3d437 --- /dev/null +++ b/internal/tailwind/link_renderer.go @@ -0,0 +1,49 @@ +package tailwind + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/util" +) + +type CustomLinkRenderer struct { + html.Config +} + +func NewCustomLinkRenderer(opts ...html.Option) renderer.NodeRenderer { + r := &CustomLinkRenderer{ + Config: html.NewConfig(), + } + for _, opt := range opts { + opt.SetHTMLOption(&r.Config) + } + return r +} + +func (r *CustomLinkRenderer) renderLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.Link) + if entering { + _, _ = w.WriteString("") + } else { + _, _ = w.WriteString("") + } + return ast.WalkContinue, nil +} + +func (r *CustomLinkRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + reg.Register(ast.KindLink, r.renderLink) +} diff --git a/internal/tailwind/transformer.go b/internal/tailwind/transformer.go index f932533..23ba1a3 100644 --- a/internal/tailwind/transformer.go +++ b/internal/tailwind/transformer.go @@ -1,6 +1,9 @@ package tailwind import ( + "bytes" + "fmt" + "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/text" @@ -51,6 +54,10 @@ func (t *TailwindTransformer) Transform(node *ast.Document, reader text.Reader, node.SetAttribute([]byte("class"), []byte("bg-background-dark p-1 rounded-lg overflow-x-auto mb-4")) case *ast.Link: + if bytes.HasPrefix(node.Destination, []byte{'.', '/'}) { + onclickAttr := fmt.Appendf(make([]byte, 0, 21+len(node.Destination)), "return changeUrl('%s');", node.Destination) + node.SetAttribute([]byte("onclick"), onclickAttr) + } node.SetAttribute([]byte("class"), []byte("text-secondary hover:text-main-dark underline")) case *ast.Image: diff --git a/internal/templatemanager/templatemanager.go b/internal/templatemanager/templatemanager.go index 4bf9a49..eebc297 100644 --- a/internal/templatemanager/templatemanager.go +++ b/internal/templatemanager/templatemanager.go @@ -37,7 +37,7 @@ func NewTemplateManager(templates ...TemplateManagerTemplates) (*TemplateManager templateMap := make(map[string]templateManagerRender) for _, tmplStruct := range templates { - tmpl := template.New("").Funcs(templateFuncMap) + tmpl := template.New(tmplStruct.Name).Funcs(templateFuncMap) tmpl, err := tmpl.ParseFiles(tmplStruct.Files...) if err != nil { return nil, err @@ -84,7 +84,7 @@ func (tm *TemplateManager) Add(name string, files ...string) error { return fmt.Errorf("you can't add template without any files") } - tmpl := template.New("").Funcs(templateFuncMap) + tmpl := template.New(name).Funcs(templateFuncMap) tmpl, err := tmpl.ParseFiles(files...) if err != nil { diff --git a/main.go b/main.go index 53dbb74..a6a30b0 100644 --- a/main.go +++ b/main.go @@ -23,7 +23,9 @@ import ( "github.com/golang-migrate/migrate/v4/database/sqlite3" "github.com/yuin/goldmark" "github.com/yuin/goldmark/parser" - gmhtml "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/util" _ "github.com/golang-migrate/migrate/v4/source/file" _ "github.com/mattn/go-sqlite3" @@ -37,9 +39,15 @@ var ( ), goldmark.WithParserOptions( parser.WithAutoHeadingID(), + parser.WithAttribute(), ), - goldmark.WithRendererOptions( - gmhtml.WithXHTML(), + goldmark.WithRenderer( + renderer.NewRenderer( + renderer.WithNodeRenderers( + util.Prioritized(tailwind.NewCustomLinkRenderer(html.WithUnsafe(), html.WithXHTML()), 50), + util.Prioritized(html.NewRenderer(html.WithXHTML()), 100), + ), + ), ), ) b2Client *b2.B2Client diff --git a/static/input.css b/static/input.css index 36d17b2..1e7f9fc 100644 --- a/static/input.css +++ b/static/input.css @@ -236,37 +236,22 @@ a:hover { border-style: outset; } -.desktop-sidebar-custom { - width: 5vw; - background-size: calc(var(--squares-and-triangles-background-size) * 1vw); -} - .bg-sidebar { background-image: var(--squares-and-triangles-background); background-repeat: var(--squares-and-triangles-background-repeat); - background-size: calc(var(--squares-and-triangles-background-width-coef) * 1vw) calc(var(--squares-and-triangles-background-height-coef) * 1vw); + background-size: calc(var(--squares-and-triangles-background-width-coef) * 1dvw) calc(var(--squares-and-triangles-background-height-coef) * 1dvw); } .logo-custom { - width: 3.5vw; - height: 20vw; - font-size: 2.5vw; - -webkit-text-stroke: 0.1vw var(--sidebar-stroke-color); + width: 3.5dvw; + height: 20dvw; + font-size: 2.5dvw; + -webkit-text-stroke: 0.1dvw var(--sidebar-stroke-color); writing-mode: sideways-lr; text-orientation: mixed; display: block; } -.border-left-custom { - width: 0.5vw; - border-right: 0.3vh dashed var(--main-dark-color); -} - -.border-right-custom { - width: 0.5vw; - border-left: 0.5vh dotted var(--main-dark-color); -} - .inset-shadow { box-shadow: inset 0vh 1vh 1vh -1vh rgba(75, 81, 58, 0.5), inset 1vh 0vh 1vh -1vh rgba(75, 81, 58, 0.5), @@ -278,8 +263,8 @@ a:hover { -webkit-text-stroke-color: var(--sidebar-stroke-color); } -.text-stroke-\[0\.1vw\] { - -webkit-text-stroke-width: 0.1vw; +.text-stroke-\[0\.1dvw\] { + -webkit-text-stroke-width: 0.1dvw; } .theme-wheel { @@ -411,7 +396,7 @@ body[data-theme~="ram"] .leaflet-tile { @media (max-aspect-ratio: 0.8/1) { .bg-sidebar { - background-size: calc(var(--squares-and-triangles-background-width-coef) * 1.6vh) calc(var(--squares-and-triangles-background-height-coef) * 1.6vh); + background-size: calc(var(--squares-and-triangles-background-width-coef) * 1.6dvh) calc(var(--squares-and-triangles-background-height-coef) * 1.6dvh); } .ar-lt-0\.8\:bg-background-light { diff --git a/views/layouts/general-page.html b/views/layouts/general-page.html index 88c5de5..b163387 100644 --- a/views/layouts/general-page.html +++ b/views/layouts/general-page.html @@ -14,13 +14,22 @@ + + @@ -165,12 +174,20 @@
saya.today
-
- - - +
diff --git a/views/pages/blog-page.html b/views/pages/blog-page.html index aadebac..9704502 100644 --- a/views/pages/blog-page.html +++ b/views/pages/blog-page.html @@ -1,20 +1,3 @@ -{{ define "top-embeds" }} - -{{ end }} - {{ define "body" }}

{{ .Title }}

@@ -52,16 +35,17 @@ .openPopup(); } - document.addEventListener('htmx:afterRequest', (e) => { - if (e.detail.target.id == 'general-page-body') { - initLocationMap( - 'map-container', - {{ .MapLocationX }}, - {{ .MapLocationY }}, - {{ .MapLocationAreaMeters }} - ); - } - }, {once: true}); + if (map) { + map.remove(); + map = null; + } + + setTimeout(() => initLocationMap( + 'map-container', + {{ .MapLocationX }}, + {{ .MapLocationY }}, + {{ .MapLocationAreaMeters }} + ), 1000); {{- end }}
@@ -70,31 +54,3 @@ {{ define "footer" }}
{{ end }} - -{{ define "bottom-embeds" }} - -{{ end }} diff --git a/views/pages/global-map.html b/views/pages/global-map.html index 4c6fb5e..27c8a73 100644 --- a/views/pages/global-map.html +++ b/views/pages/global-map.html @@ -44,11 +44,17 @@
saya.today
-
- - - - +
diff --git a/views/partials/catalogue-blog-cards.html b/views/partials/catalogue-blog-cards.html index 041f3c8..5c3bb95 100644 --- a/views/partials/catalogue-blog-cards.html +++ b/views/partials/catalogue-blog-cards.html @@ -1,10 +1,12 @@ {{- range .BlogPages }} -
+
- + + +
- + {{ .Title }} // {{ .ActionDate }} diff --git a/views/partials/general-page-header.html b/views/partials/general-page-header.html index 7f6ab8a..e5488b4 100644 --- a/views/partials/general-page-header.html +++ b/views/partials/general-page-header.html @@ -1,7 +1,9 @@
- -

//

+
+ + +

//

{{ .Title }}

{{ .PublishedDate }}

-- cgit v1.3.1+13 From c9a2858279d3d3bf48d752d5ad250303368f9ebd Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Fri, 17 Oct 2025 04:17:06 +0700 Subject: feat: add support for tags in gallery images feat: add 2x tag for an image in gallery feat: update layout of galleries while loading images (not just after) --- internal/glightbox/block.go | 1 + internal/glightbox/html_renderer.go | 31 +++++++++++++++++++++++++------ internal/glightbox/parser.go | 16 ++++++++++++++-- static/input.css | 16 ++++++++++++++++ views/pages/global-map.html | 2 +- 5 files changed, 57 insertions(+), 9 deletions(-) (limited to 'internal/glightbox/html_renderer.go') diff --git a/internal/glightbox/block.go b/internal/glightbox/block.go index 696f328..e53e67b 100644 --- a/internal/glightbox/block.go +++ b/internal/glightbox/block.go @@ -15,6 +15,7 @@ type GLightboxBlock struct { type GLightboxImage struct { URL string + Tags []string Caption []byte } diff --git a/internal/glightbox/html_renderer.go b/internal/glightbox/html_renderer.go index 43d4790..3da98eb 100644 --- a/internal/glightbox/html_renderer.go +++ b/internal/glightbox/html_renderer.go @@ -78,11 +78,26 @@ func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, dataDescriptionAttribute = fmt.Sprintf("data-description=\".%s\"", glightboxDescId) } + tagClassList := make([]string, 0, len(img.Tags)) + for _, tag := range img.Tags { + switch tag { + case "2x": + tagClassList = append(tagClassList, "grid-item-2x") + } + } + elements = append(elements, fmt.Sprintf(` - - webp thumbnail - `, img.URL, galleryID, galleryID, galleryID, dayDate.Format("2006-01-02 15:04:05 -07:00"), dataDescriptionAttribute, imageUrlWithoutExt)) + + + + + + + + + `, img.URL, galleryID, strings.Join(tagClassList, " "), galleryID, galleryID, dayDate.Format("2006-01-02 15:04:05 -07:00"), dataDescriptionAttribute, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt)) if glightboxDescId != "" { elements = append(elements, fmt.Sprintf(` @@ -114,10 +129,14 @@ func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, percentPosition: true }); - imagesLoaded('.masonry-grid-%s', function() { - msnry_%s.layout(); + var imgLoad_%s_timer; + var imgLoad_%s = imagesLoaded('.masonry-grid-%s', () => msnry_%s.layout()); + + imgLoad_%s.on('progress', function() { + clearTimeout(imgLoad_%s_timer); + imgLoad_%s_timer = setTimeout(() => msnry_%s.layout(), 500); }); -`, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID)) +`, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID)) } return ast.WalkContinue, nil diff --git a/internal/glightbox/parser.go b/internal/glightbox/parser.go index ba3f22e..6780090 100644 --- a/internal/glightbox/parser.go +++ b/internal/glightbox/parser.go @@ -4,6 +4,7 @@ import ( "bytes" "log/slog" "regexp" + "strings" "time" "github.com/yuin/goldmark/ast" @@ -60,16 +61,27 @@ func (p *GLightboxParser) Continue(node ast.Node, reader text.Reader, pc parser. gallery := node.(*GLightboxBlock) - parts := bytes.SplitN(trimmed, []byte{'|'}, 2) + parts := bytes.SplitN(trimmed, []byte{'|'}, 3) url := bytes.TrimSpace(parts[0]) caption := make([]byte, 0) - if len(parts) > 1 { + tagsRaw := "" + if len(parts) == 2 { caption = bytes.TrimSpace(parts[1]) } + if len(parts) >= 3 { + tagsRaw = string(parts[1]) + caption = bytes.TrimSpace(parts[2]) + } + + tags := strings.Split(tagsRaw, ",") + for i := range tags { + tags[i] = strings.TrimSpace(tags[i]) + } gallery.Images = append(gallery.Images, GLightboxImage{ URL: string(url), + Tags: tags, Caption: caption, }) diff --git a/static/input.css b/static/input.css index d766049..8080d13 100644 --- a/static/input.css +++ b/static/input.css @@ -331,22 +331,38 @@ a:hover { width: 50%; } +.grid-item-2x { + width: 100%; +} + @media (width >= 32rem) { .grid-item, .grid-sizer { width: 33%; } + + .grid-item-2x { + width: 66%; + } } @media (width >= 40rem) { .grid-item, .grid-sizer { width: 25%; } + + .grid-item-2x { + width: 50%; + } } @media (width >= 48rem) { .grid-item, .grid-sizer { width: 20%; } + + .grid-item-2x { + width: 40%; + } } .map-container .leaflet-container { diff --git a/views/pages/global-map.html b/views/pages/global-map.html index d595e07..9b67514 100644 --- a/views/pages/global-map.html +++ b/views/pages/global-map.html @@ -3,7 +3,7 @@ - {{ .L.GlobalMap.Header }} // SAYA TODAY + {{ .L.GlobalMap.Header }} // SAYA TODAY -- cgit v1.3.1+13 From 7526d3c1dbb5564fb4156da4510a92038a6fdac8 Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Fri, 17 Oct 2025 05:09:02 +0700 Subject: feat: add tooltip for images in a gallery feat: add image index inside a gallery fix: return gap inside a gallery --- internal/glightbox/html_renderer.go | 10 ++++-- static/input.css | 64 +++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) (limited to 'internal/glightbox/html_renderer.go') diff --git a/internal/glightbox/html_renderer.go b/internal/glightbox/html_renderer.go index 3da98eb..5514b6d 100644 --- a/internal/glightbox/html_renderer.go +++ b/internal/glightbox/html_renderer.go @@ -86,8 +86,12 @@ func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, } } + if len(img.Caption) > 0 { + tagClassList = append(tagClassList, "grid-tooltip") + } + elements = append(elements, fmt.Sprintf(` - @@ -97,7 +101,9 @@ func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, - `, img.URL, galleryID, strings.Join(tagClassList, " "), galleryID, galleryID, dayDate.Format("2006-01-02 15:04:05 -07:00"), dataDescriptionAttribute, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt)) + %s + %d + `, img.URL, galleryID, strings.Join(tagClassList, " "), galleryID, galleryID, dayDate.Format("2006-01-02 15:04:05 -07:00"), dataDescriptionAttribute, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, captionHTML, i+1)) if glightboxDescId != "" { elements = append(elements, fmt.Sprintf(` diff --git a/static/input.css b/static/input.css index 8080d13..cfefa0d 100644 --- a/static/input.css +++ b/static/input.css @@ -327,10 +327,74 @@ a:hover { transform: scale(1.1); } +.grid-tooltip { + position: relative; + display: inline-block; + box-shadow: inset 0rem 0rem 0.5rem var(--main-light-color); + transition: box-shadow 0.5s ease-in-out; +} + +.grid-tooltip:hover { + box-shadow: none; +} + +.grid-tooltip-text { + visibility: hidden; + opacity: 0; + transition: opacity 0.5s; + width: 100%; + top: 100%; + background-color: var(--background-dark-color); + color: var(--main-dark-color); + text-align: center; + padding: 0.25rem 0.25rem; + margin-top: 0.25rem; + border-radius: 0.5rem; + position: absolute; + z-index: 15; +} + +.grid-tooltip:hover .grid-tooltip-text { + visibility: visible; + opacity: 1; +} + +.grid-tooltip-text::after { + content: " "; + position: absolute; + bottom: 100%; + left: 50%; + margin-left: -0.25rem; + border-width: 0.25rem; + border-style: solid; + border-color: transparent transparent black transparent; +} + .grid-item, .grid-sizer { + position: relative; + display: inline-block; width: 50%; } +.grid-item-index { + visibility: visible; + opacity: 1; + transition: opacity 0.5s; + top: 0%; + left: 0%; + background-color: var(--main-light-color); + color: var(--background-dark-color); + text-align: center; + padding: 0.25rem 0.25rem; + position: absolute; + z-index: 14; +} + +.grid-item:hover .grid-item-index { + visibility: hidden; + opacity: 0; +} + .grid-item-2x { width: 100%; } -- cgit v1.3.1+13 From ecda238c01a4e6bb837f9a2fb0714648dea08d03 Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Fri, 17 Oct 2025 18:39:21 +0700 Subject: feat: allow links to appear in tooltips in gallery --- internal/glightbox/html_renderer.go | 50 +++++++++++++++++++++++++++++-------- static/input.css | 4 +-- 2 files changed, 41 insertions(+), 13 deletions(-) (limited to 'internal/glightbox/html_renderer.go') diff --git a/internal/glightbox/html_renderer.go b/internal/glightbox/html_renderer.go index 5514b6d..a9d066d 100644 --- a/internal/glightbox/html_renderer.go +++ b/internal/glightbox/html_renderer.go @@ -4,11 +4,14 @@ import ( "bytes" "fmt" "math/rand" + "regexp" "strings" "time" + "github.com/SayaAndy/saya-today-web/internal/tailwind" "github.com/yuin/goldmark" "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/renderer" "github.com/yuin/goldmark/renderer/html" "github.com/yuin/goldmark/util" @@ -16,22 +19,36 @@ import ( type GLightboxHTMLRenderer struct { html.Config - md goldmark.Markdown + md goldmark.Markdown + anchorMatchRe *regexp.Regexp } func NewGLightboxHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { r := &GLightboxHTMLRenderer{ Config: html.NewConfig(), md: goldmark.New( - goldmark.WithRendererOptions( - html.WithHardWraps(), - html.WithXHTML(), + goldmark.WithParserOptions( + parser.WithAutoHeadingID(), + parser.WithAttribute(), + ), + goldmark.WithRenderer( + renderer.NewRenderer( + renderer.WithNodeRenderers( + util.Prioritized(tailwind.NewCustomLinkRenderer( + html.WithUnsafe(), html.WithHardWraps(), html.WithXHTML(), + ), 50), + util.Prioritized(html.NewRenderer( + html.WithUnsafe(), html.WithHardWraps(), html.WithXHTML(), + ), 100), + ), + ), ), ), } for _, opt := range opts { opt.SetHTMLOption(&r.Config) } + r.anchorMatchRe = regexp.MustCompile(`(?s)<\s*a(\s+[^<]*)(href\s*=\s*["'].*?["'])\s*([^<]*)>(.*?)<\s*\/\s*a\s*>`) return r } @@ -90,6 +107,8 @@ func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, tagClassList = append(tagClassList, "grid-tooltip") } + anchorlessCaptionHTML := r.anchorMatchRe.ReplaceAll(captionHTML, []byte("$4")) + elements = append(elements, fmt.Sprintf(` @@ -101,9 +120,9 @@ func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, - %s +

%s

%d -
`, img.URL, galleryID, strings.Join(tagClassList, " "), galleryID, galleryID, dayDate.Format("2006-01-02 15:04:05 -07:00"), dataDescriptionAttribute, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, captionHTML, i+1)) + `, img.URL, galleryID, strings.Join(tagClassList, " "), galleryID, galleryID, dayDate.Format("2006-01-02 15:04:05 -07:00"), dataDescriptionAttribute, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, anchorlessCaptionHTML, i+1)) if glightboxDescId != "" { elements = append(elements, fmt.Sprintf(` @@ -116,7 +135,7 @@ func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, w.WriteString(fmt.Sprintf(`

-
+
%s
@@ -132,17 +151,26 @@ func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, var msnry_%s = new Masonry('.masonry-grid-%s', { itemSelector: '.grid-item-%s', columnWidth: '.grid-sizer-%s', - percentPosition: true + percentPosition: true, + horizontalOrder: true }); var imgLoad_%s_timer; - var imgLoad_%s = imagesLoaded('.masonry-grid-%s', () => msnry_%s.layout()); + var imgLoad_%s = imagesLoaded('.masonry-grid-%s'); - imgLoad_%s.on('progress', function() { + function initMasonryLayout_%s() { clearTimeout(imgLoad_%s_timer); imgLoad_%s_timer = setTimeout(() => msnry_%s.layout(), 500); + } + + imgLoad_%s.on('progress', initMasonryLayout_%s); + + document.addEventListener('popout', (e) => { + imgLoad_%s.off('progress', initMasonryLayout_%s); + initMasonryLayout_%s = null; + imgLoad_%s = null; }); -`, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID)) +`, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID, galleryID)) } return ast.WalkContinue, nil diff --git a/static/input.css b/static/input.css index 01a747e..910149a 100644 --- a/static/input.css +++ b/static/input.css @@ -122,12 +122,12 @@ html { --squares-and-triangles-background-height-coef: 15; } -a { +a, .linklike { color: var(--main-medium-color) !important; text-decoration: underline; } -a:hover { +a:hover, .linklike:hover { color: var(--main-light-color) !important; } -- cgit v1.3.1+13 From 152bbebe8d2d0a07ab6958a74b5f53159c79e45f Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Fri, 17 Oct 2025 19:20:06 +0700 Subject: feat(glightbox): don't hide text in mobile devices --- internal/glightbox/html_renderer.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'internal/glightbox/html_renderer.go') diff --git a/internal/glightbox/html_renderer.go b/internal/glightbox/html_renderer.go index a9d066d..44fbd4c 100644 --- a/internal/glightbox/html_renderer.go +++ b/internal/glightbox/html_renderer.go @@ -145,7 +145,8 @@ func (r *GLightboxHTMLRenderer) renderGLightbox(w util.BufWriter, source []byte, w.WriteString(fmt.Sprintf(`