package main import ( "bytes" "context" "strconv" "git.dev.alexdunmow.com/block/core/blocks" ) // DiagramCaptionBlockMeta defines metadata for the diagram-caption block. var DiagramCaptionBlockMeta = blocks.BlockMeta{ Key: "diagram_caption", Title: "Diagram Caption", Description: "Annotated technical figure with a Fig. NN. heading and optional callout pins.", Source: "scifi-clean", Category: blocks.CategoryContent, } // DiagramCalloutPin is a percent-positioned overlay pin. type DiagramCalloutPin struct { X float64 Y float64 Label string } // DiagramCaptionData drives the templ render. type DiagramCaptionData struct { Image string FigureNumber string Title string Body string CalloutPins []DiagramCalloutPin } // DiagramCaptionBlock renders the diagram-caption block. // Content shape: {"image": "media:...", "figureNumber": "...", "title": "...", "body": "...", // "calloutPins": [{"x": 12, "y": 50, "label": "..."}]} func DiagramCaptionBlock(ctx context.Context, content map[string]any) string { data := DiagramCaptionData{ Image: blocks.ResolveMediaPath(getString(content, "image")), FigureNumber: getString(content, "figureNumber"), Title: getString(content, "title"), Body: getString(content, "body"), } for _, raw := range getSlice(content, "calloutPins") { data.CalloutPins = append(data.CalloutPins, DiagramCalloutPin{ X: getFloat(raw, "x", 0), Y: getFloat(raw, "y", 0), Label: getString(raw, "label"), }) } var buf bytes.Buffer _ = diagramCaptionComponent(data).Render(ctx, &buf) return buf.String() } // percentStyle returns a tiny inline style string positioning the pin in percent. func percentStyle(x, y float64) string { return "left: " + strconv.FormatFloat(x, 'f', 2, 64) + "%; top: " + strconv.FormatFloat(y, 'f', 2, 64) + "%;" }