Diffstat (limited to 'internal')
| -rw-r--r-- | internal/glightbox/block.go | 31 | ||||
| -rw-r--r-- | internal/glightbox/html_renderer.go | 134 | ||||
| -rw-r--r-- | internal/lightgallery/block.go | 31 | ||||
| -rw-r--r-- | internal/lightgallery/extension.go (renamed from internal/glightbox/extension.go) | 14 | ||||
| -rw-r--r-- | internal/lightgallery/html_renderer.go | 145 | ||||
| -rw-r--r-- | internal/lightgallery/parser.go (renamed from internal/glightbox/parser.go) | 26 |
6 files changed, 196 insertions, 185 deletions
diff --git a/internal/glightbox/block.go b/internal/glightbox/block.go deleted file mode 100644 index 696f328..0000000 --- a/internal/glightbox/block.go +++ /dev/null @@ -1,31 +0,0 @@ -package glightbox - -import ( - "time" - - "github.com/yuin/goldmark/ast" -) - -// GLightboxBlock represents a light gallery block in the AST -type GLightboxBlock struct { - ast.BaseBlock - Images []GLightboxImage - Location *time.Location -} - -type GLightboxImage struct { - URL string - Caption []byte -} - -var KindGLightboxBlock = ast.NewNodeKind("GLightboxBlock") - -// Dump implements ast.Node.Dump -func (n *GLightboxBlock) Dump(source []byte, level int) { - ast.DumpHelper(n, source, level, nil, nil) -} - -// Kind implements ast.Node.Kind -func (n *GLightboxBlock) Kind() ast.NodeKind { - return KindGLightboxBlock -} diff --git a/internal/glightbox/html_renderer.go b/internal/glightbox/html_renderer.go deleted file mode 100644 index 3b6a533..0000000 --- a/internal/glightbox/html_renderer.go +++ /dev/null @@ -1,134 +0,0 @@ -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("<p>")) - captionHTML = bytes.TrimSuffix(captionHTML, []byte("</p>\n")) - captionHTML = bytes.TrimSuffix(captionHTML, []byte("</p>")) - } - - 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(` - <a href="https://f003.backblazeb2.com/file/sayana-photos/full/%s" class="glightbox-%s grid-item grid-item-%s" - data-gallery="gallery-%s" data-title="%s" %s> - <img src="https://f003.backblazeb2.com/file/sayana-photos/webp-320p/%s.webp" class="rounded-md p-0.5" alt="webp thumbnail" /> - </a>`, img.URL, galleryID, galleryID, galleryID, dayDate.Format("2006-01-02 15:04:05 -07:00"), dataDescriptionAttribute, imageUrlWithoutExt)) - - if glightboxDescId != "" { - elements = append(elements, fmt.Sprintf(` - <div class="glightbox-desc rounded-4 %s"> - <p>%s</p> - </div>`, glightboxDescId, captionHTML)) - } - } - - w.WriteString(fmt.Sprintf(` -<div class="justify-content-center display-block m-1"> - <hr class="border-t-3 border-dotted border-main-dark mt-1 mb-2 w-[80%%] ml-auto mr-auto"> - <div class="grid masonry-grid-%s"> - <div class="grid-sizer grid-sizer-%s"></div> - %s - </div> - <hr class="border-t-3 border-dotted border-main-dark mt-1 mb-2 w-[80%%] ml-auto mr-auto"> -</div>`, galleryID, galleryID, strings.Join(elements, "\n"))) - - w.WriteString(fmt.Sprintf(` -<script> - var lightbox_%s = GLightbox({ - selector: '.glightbox-%s' - }); - - var msnry_%s = new Masonry('.masonry-grid-%s', { - itemSelector: '.grid-item-%s', - columnWidth: '.grid-sizer-%s', - percentPosition: true - }); - - imagesLoaded('.masonry-grid-%s', function() { - msnry_%s.layout(); - }); -</script>`, 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) -} diff --git a/internal/lightgallery/block.go b/internal/lightgallery/block.go new file mode 100644 index 0000000..8eb7c9e --- /dev/null +++ b/internal/lightgallery/block.go @@ -0,0 +1,31 @@ +package lightgallery + +import ( + "time" + + "github.com/yuin/goldmark/ast" +) + +// LightGalleryBlock represents a light gallery block in the AST +type LightGalleryBlock struct { + ast.BaseBlock + Images []LightGalleryImage + Location *time.Location +} + +type LightGalleryImage struct { + URL string + Caption []byte +} + +var KindLightGalleryBlock = ast.NewNodeKind("LightGalleryBlock") + +// Dump implements ast.Node.Dump +func (n *LightGalleryBlock) Dump(source []byte, level int) { + ast.DumpHelper(n, source, level, nil, nil) +} + +// Kind implements ast.Node.Kind +func (n *LightGalleryBlock) Kind() ast.NodeKind { + return KindLightGalleryBlock +} diff --git a/internal/glightbox/extension.go b/internal/lightgallery/extension.go index 7fd17b1..761dc05 100644 --- a/internal/glightbox/extension.go +++ b/internal/lightgallery/extension.go @@ -1,4 +1,4 @@ -package glightbox +package lightgallery import ( "github.com/yuin/goldmark" @@ -8,21 +8,21 @@ import ( ) // Extension that combines parser and renderer -type GLightboxExtension struct{} +type LightGalleryExtension struct{} -func NewGLightboxExtension() goldmark.Extender { - return &GLightboxExtension{} +func NewLightGalleryExtension() goldmark.Extender { + return &LightGalleryExtension{} } -func (e *GLightboxExtension) Extend(m goldmark.Markdown) { +func (e *LightGalleryExtension) Extend(m goldmark.Markdown) { m.Parser().AddOptions( parser.WithBlockParsers( - util.Prioritized(NewGLightboxParser(), 500), + util.Prioritized(NewLightGalleryParser(), 500), ), ) m.Renderer().AddOptions( renderer.WithNodeRenderers( - util.Prioritized(NewGLightboxHTMLRenderer(), 500), + util.Prioritized(NewLightGalleryHTMLRenderer(), 500), ), ) } diff --git a/internal/lightgallery/html_renderer.go b/internal/lightgallery/html_renderer.go new file mode 100644 index 0000000..c2f785e --- /dev/null +++ b/internal/lightgallery/html_renderer.go @@ -0,0 +1,145 @@ +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" + "github.com/yuin/goldmark/util" +) + +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) + } + return r +} + +func (r *LightGalleryHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + reg.Register(KindLightGalleryBlock, r.renderLightGallery) +} + +func (r *LightGalleryHTMLRenderer) renderLightGallery(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + gallery := n.(*LightGalleryBlock) + + if len(gallery.Images) == 0 { + return ast.WalkContinue, nil + } + + galleryID := generateDivId(8) + + w.WriteString(fmt.Sprintf(` +<div class="justify-content-center display-block m-1"> + <hr class="border-t-3 border-dotted border-main-dark mt-1 mb-2 w-[80%%] ml-auto mr-auto"> + <div id="lg-%s" class="inline-gallery-container relative ml-auto mr-auto"></div> + <hr class="border-t-3 border-dotted border-main-dark mt-1 mb-2 w-[80%%] ml-auto mr-auto"> +</div>`, galleryID)) + + var dynamicElements []string + for _, 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("<p>")) + captionHTML = bytes.TrimSuffix(captionHTML, []byte("</p>\n")) + captionHTML = bytes.TrimSuffix(captionHTML, []byte("</p>")) + } + + dayDate, _ := time.Parse("20060102 150405", imageNameParts[len(imageNameParts)-2]+" "+imageNameParts[len(imageNameParts)-1]) + dayDate = dayDate.In(gallery.Location) + dynamicElements = append(dynamicElements, fmt.Sprintf(`{ + src: + "https://f003.backblazeb2.com/file/sayana-photos/full/%s", + downloadUrl: + "https://f003.backblazeb2.com/file/sayana-photos/full/%s", + alt: "%s", + responsive: "https://f003.backblazeb2.com/file/sayana-photos/webp-320p/%s.webp 384, https://f003.backblazeb2.com/file/sayana-photos/webp-560p/%s.webp 672, https://f003.backblazeb2.com/file/sayana-photos/webp-800p/%s.webp 960, https://f003.backblazeb2.com/file/sayana-photos/webp-1200p/%s.webp 1440, https://f003.backblazeb2.com/file/sayana-photos/webp-1600p/%s.webp 1920", + thumb: + "https://f003.backblazeb2.com/file/sayana-photos/webp-320p/%s.webp", + subHtml: `+"`"+`<div class="flex flex-row light-gallery-captions"> + <p class="grow !text-base/[1] text-left font-spectral text-main-dark">%s</p> + <p class="!text-base/[1] text-right font-spectral text-secondary">%s</p> + </div>`+"`"+` + }`, img.URL, img.URL, util.EscapeHTML(captionHTML), imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, imageUrlWithoutExt, captionHTML, dayDate.Format("2006-01-02 15:04:05 -07:00"))) + } + + w.WriteString(fmt.Sprintf(` +<script> +function createLightGallery%s() { + const $lgContainer = document.getElementById('lg-%s'); + const config = { + container: $lgContainer, + dynamic: true, + dynamicEl: [%s], + width: "100%%", + height: "50vmin", + hash: false, + closable: false, + showMaximizeIcon: true, + appendSubHtmlTo: ".lg-sub-html", + isMobile: () => false, + slideDelay: 0, + plugins: [lgZoom, lgThumbnail], + thumbWidth: calculateVmin(10), + thumbHeight: "10vmin", + thumbMargin: 4 + }; + const inlineGallery = lightGallery($lgContainer, config); + + setTimeout(() => { + inlineGallery.openGallery(); + }, 200); + + galleryMap.set(inlineGallery, createLightGallery%s); +} + +document.addEventListener('htmx:afterRequest', (e) => { + if (e.detail.xhr.status == 404 || e.detail.successful != true) { + return console.error(e); + } + if (e.detail.target.id == 'general-page-body') { + createLightGallery%s(); + } +}, {once: true}); +</script>`, galleryID, galleryID, strings.Join(dynamicElements, ","), 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) +} diff --git a/internal/glightbox/parser.go b/internal/lightgallery/parser.go index ba3f22e..daec797 100644 --- a/internal/glightbox/parser.go +++ b/internal/lightgallery/parser.go @@ -1,4 +1,4 @@ -package glightbox +package lightgallery import ( "bytes" @@ -11,17 +11,17 @@ import ( "github.com/yuin/goldmark/text" ) -type GLightboxParser struct{} +type LightGalleryParser struct{} -func NewGLightboxParser() parser.BlockParser { - return &GLightboxParser{} +func NewLightGalleryParser() parser.BlockParser { + return &LightGalleryParser{} } -func (p *GLightboxParser) Trigger() []byte { +func (p *LightGalleryParser) Trigger() []byte { return []byte{'{'} } -func (p *GLightboxParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) { +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:")) { @@ -43,10 +43,10 @@ func (p *GLightboxParser) Open(parent ast.Node, reader text.Reader, pc parser.Co return nil, parser.NoChildren } - return &GLightboxBlock{Location: loc}, parser.NoChildren + return &LightGalleryBlock{Location: loc}, parser.NoChildren } -func (p *GLightboxParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State { +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.Continue | parser.NoChildren @@ -58,7 +58,7 @@ func (p *GLightboxParser) Continue(node ast.Node, reader text.Reader, pc parser. return parser.Close } - gallery := node.(*GLightboxBlock) + gallery := node.(*LightGalleryBlock) parts := bytes.SplitN(trimmed, []byte{'|'}, 2) url := bytes.TrimSpace(parts[0]) @@ -68,7 +68,7 @@ func (p *GLightboxParser) Continue(node ast.Node, reader text.Reader, pc parser. caption = bytes.TrimSpace(parts[1]) } - gallery.Images = append(gallery.Images, GLightboxImage{ + gallery.Images = append(gallery.Images, LightGalleryImage{ URL: string(url), Caption: caption, }) @@ -76,13 +76,13 @@ func (p *GLightboxParser) Continue(node ast.Node, reader text.Reader, pc parser. return parser.Continue | parser.NoChildren } -func (p *GLightboxParser) Close(node ast.Node, reader text.Reader, pc parser.Context) { +func (p *LightGalleryParser) Close(node ast.Node, reader text.Reader, pc parser.Context) { } -func (p *GLightboxParser) CanInterruptParagraph() bool { +func (p *LightGalleryParser) CanInterruptParagraph() bool { return true } -func (p *GLightboxParser) CanAcceptIndentedLine() bool { +func (p *LightGalleryParser) CanAcceptIndentedLine() bool { return false } |