From 85d4a9799ce2ce663af25be8c7e8f59f8d43761d Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Thu, 14 Aug 2025 04:18:31 +0700 Subject: feat: parse gallery caption as an inline markdown feat: stylize href links for themes feat: adapt map palette for dark themes like night and ram feat: add popup for markers on maps feat: dump z-index from 13 to 8 for zoom on region level feat: show timezone in catalogue with colon fix: ignore empty lines inside gallery block fix: enable closing tag for gallery block with slash fix: on filter reset in catalogue default to publication date desc sort --- internal/lightgallery/block.go | 2 +- internal/lightgallery/html_renderer.go | 29 +++++++++++++++++++---------- internal/lightgallery/parser.go | 18 ++++++++---------- main.go | 10 +++++----- saya-today-web | Bin 0 -> 19752119 bytes static/input.css | 14 ++++++++++++++ views/pages/blog-catalogue.html | 2 +- views/pages/blog-page.html | 10 +++++++--- 8 files changed, 55 insertions(+), 30 deletions(-) create mode 100755 saya-today-web diff --git a/internal/lightgallery/block.go b/internal/lightgallery/block.go index 072aa3c..8eb7c9e 100644 --- a/internal/lightgallery/block.go +++ b/internal/lightgallery/block.go @@ -15,7 +15,7 @@ type LightGalleryBlock struct { type LightGalleryImage struct { URL string - Caption string + Caption []byte } var KindLightGalleryBlock = ast.NewNodeKind("LightGalleryBlock") diff --git a/internal/lightgallery/html_renderer.go b/internal/lightgallery/html_renderer.go index 77b9785..850cd95 100644 --- a/internal/lightgallery/html_renderer.go +++ b/internal/lightgallery/html_renderer.go @@ -1,11 +1,13 @@ package lightgallery 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" @@ -14,11 +16,18 @@ import ( type LightGalleryHTMLRenderer struct { html.Config + md goldmark.Markdown } func NewLightGalleryHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { r := &LightGalleryHTMLRenderer{ Config: html.NewConfig(), + md: goldmark.New( + goldmark.WithRendererOptions( + html.WithHardWraps(), + html.WithXHTML(), + ), + ), } for _, opt := range opts { opt.SetHTMLOption(&r.Config) @@ -53,6 +62,15 @@ func (r *LightGalleryHTMLRenderer) renderLightGallery(w util.BufWriter, source [ imageUrlWithoutExt := strings.Join(imageUrlSegments[:len(imageUrlSegments)-1], ".") imageNameParts := strings.Split(imageUrlWithoutExt, "-") + 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) dynamicElements = append(dynamicElements, fmt.Sprintf(`{ @@ -71,7 +89,7 @@ func (r *LightGalleryHTMLRenderer) renderLightGallery(w util.BufWriter, source [

%s

%s

`+"`"+` - }`, img.URL, img.URL, escapeHTML(img.Caption), imageUrlWithoutExt, imageUrlWithoutExt, escapeHTML(img.Caption), dayDate.Format("2006-01-02 15:04:05 -07:00"))) + }`, img.URL, img.URL, util.EscapeHTML(captionHTML), imageUrlWithoutExt, imageUrlWithoutExt, captionHTML, dayDate.Format("2006-01-02 15:04:05 -07:00"))) } w.WriteString(fmt.Sprintf(` @@ -118,15 +136,6 @@ window.addEventListener("resize", () => { return ast.WalkContinue, nil } -func escapeHTML(s string) string { - s = strings.ReplaceAll(s, "&", "&") - s = strings.ReplaceAll(s, "<", "<") - s = strings.ReplaceAll(s, ">", ">") - s = strings.ReplaceAll(s, "\"", """) - s = strings.ReplaceAll(s, "'", "'") - return s -} - func generateDivId(length int) string { const charset = "abcdefghijklmnopqrstuvwxyz" seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) // Seed with current time diff --git a/internal/lightgallery/parser.go b/internal/lightgallery/parser.go index bd7483a..daec797 100644 --- a/internal/lightgallery/parser.go +++ b/internal/lightgallery/parser.go @@ -4,7 +4,6 @@ import ( "bytes" "log/slog" "regexp" - "strings" "time" "github.com/yuin/goldmark/ast" @@ -25,7 +24,7 @@ func (p *LightGalleryParser) Trigger() []byte { func (p *LightGalleryParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) { line, _ := reader.PeekLine() - if !bytes.HasPrefix(line, []byte("{Gallery")) { + if !bytes.HasPrefix(line, []byte("{Gallery:")) { return nil, parser.NoChildren } @@ -50,28 +49,27 @@ func (p *LightGalleryParser) Open(parent ast.Node, reader text.Reader, pc parser func (p *LightGalleryParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State { line, segment := reader.PeekLine() if len(line) == 0 || segment.Len() == 0 { - return parser.Close + return parser.Continue | parser.NoChildren } trimmed := bytes.TrimSpace(line) - if bytes.Equal(trimmed, []byte("{Gallery}")) { + if bytes.Equal(trimmed, []byte("{Gallery}")) || bytes.Equal(trimmed, []byte("{/Gallery}")) { reader.AdvanceLine() return parser.Close } gallery := node.(*LightGalleryBlock) - lineStr := string(trimmed) - parts := strings.SplitN(lineStr, "|", 2) - url := strings.TrimSpace(parts[0]) - caption := "" + parts := bytes.SplitN(trimmed, []byte{'|'}, 2) + url := bytes.TrimSpace(parts[0]) + caption := make([]byte, 0) if len(parts) > 1 { - caption = strings.TrimSpace(parts[1]) + caption = bytes.TrimSpace(parts[1]) } gallery.Images = append(gallery.Images, LightGalleryImage{ - URL: url, + URL: string(url), Caption: caption, }) diff --git a/main.go b/main.go index a53cc8b..4dc9619 100644 --- a/main.go +++ b/main.go @@ -265,7 +265,7 @@ func main() { "Link": page.Link, "ArticleLink": "/" + lang + "/blog/" + page.FileName, "Title": page.Metadata.Title, - "PublishedTime": page.Metadata.PublishedTime.Format("2006-01-02 15:04:05 -0700"), + "PublishedTime": page.Metadata.PublishedTime.Format("2006-01-02 15:04:05 -07:00"), "ActionDate": page.Metadata.ActionDate, "ShortDescription": page.Metadata.ShortDescription, "Thumbnail": page.Metadata.Thumbnail, @@ -287,12 +287,12 @@ func main() { case "actionDateDesc": return strings.Compare(b["ActionDate"], a["ActionDate"]) case "publicationDateAsc": - publishedTimeA, _ := time.Parse("2006-01-02 15:04:05 -0700", a["PublishedTime"]) - publishedTimeB, _ := time.Parse("2006-01-02 15:04:05 -0700", b["PublishedTime"]) + publishedTimeA, _ := time.Parse("2006-01-02 15:04:05 -07:00", a["PublishedTime"]) + publishedTimeB, _ := time.Parse("2006-01-02 15:04:05 -07:00", b["PublishedTime"]) return publishedTimeA.Compare(publishedTimeB) case "publicationDateDesc": - publishedTimeA, _ := time.Parse("2006-01-02 15:04:05 -0700", a["PublishedTime"]) - publishedTimeB, _ := time.Parse("2006-01-02 15:04:05 -0700", b["PublishedTime"]) + publishedTimeA, _ := time.Parse("2006-01-02 15:04:05 -07:00", a["PublishedTime"]) + publishedTimeB, _ := time.Parse("2006-01-02 15:04:05 -07:00", b["PublishedTime"]) return publishedTimeB.Compare(publishedTimeA) } return 0 diff --git a/saya-today-web b/saya-today-web new file mode 100755 index 0000000..b6522e8 Binary files /dev/null and b/saya-today-web differ diff --git a/static/input.css b/static/input.css index aef2d8f..cfc7391 100644 --- a/static/input.css +++ b/static/input.css @@ -88,6 +88,15 @@ --squares-and-triangles-background-height-coef: 15; } +a { + color: var(--main-medium-color) !important; + text-decoration: underline; +} + +a:hover { + color: var(--main-light-color) !important; +} + .bg-interlocked-hexagons { background-image: var(--interlocked-hexagons-background); background-repeat: var(--interlocked-hexagons-background-repeat); @@ -332,6 +341,11 @@ body:has(.lg-container:not([class~="lg-inline"])) #sidebar { } } +body[data-theme~="night"] .leaflet-tile, +body[data-theme~="ram"] .leaflet-tile { + filter: invert(1) hue-rotate(190deg) contrast(1.1) brightness(1.2) !important; +} + @media (min-aspect-ratio: 0.8/1) { .ar-gt-0\.8\:mr-\[1\.2vmin\] { margin-right: 1.2vmin; diff --git a/views/pages/blog-catalogue.html b/views/pages/blog-catalogue.html index 0da8d26..6c0f629 100644 --- a/views/pages/blog-catalogue.html +++ b/views/pages/blog-catalogue.html @@ -91,7 +91,7 @@ checkboxes.forEach(checkbox => { checkbox.checked = true; }); - const sortRadio = tagsContainer.querySelector('#sortTitleAsc'); + const sortRadio = tagsContainer.querySelector('#sortPublicationDateDesc'); sortRadio.checked = true; }); } diff --git a/views/pages/blog-page.html b/views/pages/blog-page.html index feb63ef..330a1ac 100644 --- a/views/pages/blog-page.html +++ b/views/pages/blog-page.html @@ -34,10 +34,10 @@