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" } }