themes-magazine-bold/photo_essay.go
Alex Dunmow fe754f634b initial: theme plugin magazine-bold
Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously
an unversioned directory inside ~/src/blockninja-themes/magazine-bold.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 14:11:38 +08:00

71 lines
1.8 KiB
Go

package main
import (
"bytes"
"context"
"git.dev.alexdunmow.com/block/core/blocks"
)
// PhotoEssayBlockMeta is the numbered photo-essay scaffolding.
var PhotoEssayBlockMeta = blocks.BlockMeta{
Key: "photo_essay",
Title: "Photo Essay",
Description: "Numbered photo-essay with asymmetric frame spans (half / full / tall) and mono captions.",
Source: "magazine-bold",
Category: blocks.CategoryContent,
}
// PhotoFrame is a single image in the photo essay.
type PhotoFrame struct {
Number int
Image string
Caption string
Span string
}
// PhotoEssayData is what the templ component consumes.
type PhotoEssayData struct {
Title string
Frames []PhotoFrame
}
// PhotoEssayBlock renders the photo essay scaffolding.
// content keys: title (text), frames (collection of {image, caption, span}).
func PhotoEssayBlock(ctx context.Context, content map[string]any) string {
rawFrames := getSlice(content, "frames")
frames := make([]PhotoFrame, 0, len(rawFrames))
for i, item := range rawFrames {
img := blocks.ResolveMediaPath(getString(item, "image"))
// Skip frames that have no image (malformed-content safety).
if img == "" {
continue
}
frames = append(frames, PhotoFrame{
Number: i + 1,
Image: img,
Caption: getString(item, "caption"),
Span: normalizeSpan(getString(item, "span")),
})
}
data := PhotoEssayData{
Title: getString(content, "title"),
Frames: frames,
}
var buf bytes.Buffer
_ = photoEssayComponent(data).Render(ctx, &buf)
return buf.String()
}
// photoFrameSpanClass maps a span string to its CSS utility class.
func photoFrameSpanClass(span string) string {
switch span {
case "full":
return "mb-frame-full"
case "tall":
return "mb-frame-tall"
default:
return "mb-frame-half"
}
}