diff --git a/renderer/fencedcodeblock.go b/renderer/fencedcodeblock.go index 064b099..3763d35 100644 --- a/renderer/fencedcodeblock.go +++ b/renderer/fencedcodeblock.go @@ -141,22 +141,30 @@ func (r *ConfluenceFencedCodeBlockRenderer) renderFencedCodeBlock(writer util.Bu r.Attachments.Attach(attachment) effectiveAlign := calculateAlign(r.MarkConfig.ImageAlign, attachment.Width) + effectiveLayout := calculateLayout(effectiveAlign, attachment.Width) + displayWidth := calculateDisplayWidth(attachment.Width, effectiveLayout) err = r.Stdlib.Templates.ExecuteTemplate( writer, "ac:image", struct { - Align string - Width string - Height string - Title string - Alt string - Attachment string - Url string + Align string + Layout string + OriginalWidth string + OriginalHeight string + Width string + Height string + Title string + Alt string + Attachment string + Url string }{ effectiveAlign, + effectiveLayout, attachment.Width, attachment.Height, + displayWidth, + attachment.Height, attachment.Name, "", attachment.Filename, @@ -177,22 +185,30 @@ func (r *ConfluenceFencedCodeBlockRenderer) renderFencedCodeBlock(writer util.Bu r.Attachments.Attach(attachment) effectiveAlign := calculateAlign(r.MarkConfig.ImageAlign, attachment.Width) + effectiveLayout := calculateLayout(effectiveAlign, attachment.Width) + displayWidth := calculateDisplayWidth(attachment.Width, effectiveLayout) err = r.Stdlib.Templates.ExecuteTemplate( writer, "ac:image", struct { - Align string - Width string - Height string - Title string - Alt string - Attachment string - Url string + Align string + Layout string + OriginalWidth string + OriginalHeight string + Width string + Height string + Title string + Alt string + Attachment string + Url string }{ effectiveAlign, + effectiveLayout, attachment.Width, attachment.Height, + displayWidth, + attachment.Height, attachment.Name, "", attachment.Filename, diff --git a/renderer/image.go b/renderer/image.go index 52d08a2..6eb0799 100644 --- a/renderer/image.go +++ b/renderer/image.go @@ -40,6 +40,43 @@ func calculateAlign(configuredAlign string, width string) string { return configuredAlign } +// calculateLayout determines the appropriate ac:layout value based on alignment and width +// Images >= 1800px use "full-width", otherwise based on alignment +func calculateLayout(align string, width string) string { + // Check if full-width should be used + if width != "" { + widthInt, err := strconv.Atoi(width) + if err == nil && widthInt >= 1800 { + return "full-width" + } + } + + // Otherwise use layout based on alignment + switch align { + case "left": + return "align-start" + case "center": + return "center" + case "right": + return "align-end" + case "wide": + return "center" + default: + return "" + } +} + +// calculateDisplayWidth determines the display width +// Full-width layout uses 1800px, otherwise uses original width +func calculateDisplayWidth(originalWidth string, layout string) string { + if layout == "full-width" { + return "1800" + } + return originalWidth +} + + + type ConfluenceImageRenderer struct { html.Config Stdlib *stdlib.Lib @@ -82,15 +119,21 @@ func (r *ConfluenceImageRenderer) renderImage(writer util.BufWriter, source []by writer, "ac:image", struct { - Align string - Width string - Height string - Title string - Alt string - Attachment string - Url string + Align string + Layout string + OriginalWidth string + OriginalHeight string + Width string + Height string + Title string + Alt string + Attachment string + Url string }{ r.ImageAlign, + calculateLayout(r.ImageAlign, ""), + "", + "", "", "", string(n.Title), @@ -104,22 +147,30 @@ func (r *ConfluenceImageRenderer) renderImage(writer util.BufWriter, source []by r.Attachments.Attach(attachments[0]) effectiveAlign := calculateAlign(r.ImageAlign, attachments[0].Width) + effectiveLayout := calculateLayout(effectiveAlign, attachments[0].Width) + displayWidth := calculateDisplayWidth(attachments[0].Width, effectiveLayout) err = r.Stdlib.Templates.ExecuteTemplate( writer, "ac:image", struct { - Align string - Width string - Height string - Title string - Alt string - Attachment string - Url string + Align string + Layout string + OriginalWidth string + OriginalHeight string + Width string + Height string + Title string + Alt string + Attachment string + Url string }{ effectiveAlign, + effectiveLayout, attachments[0].Width, attachments[0].Height, + displayWidth, + attachments[0].Height, string(n.Title), string(nodeToHTMLText(n, source)), attachments[0].Filename, diff --git a/renderer/image_test.go b/renderer/image_test.go new file mode 100644 index 0000000..168ffc5 --- /dev/null +++ b/renderer/image_test.go @@ -0,0 +1,84 @@ +package renderer + +import "testing" + +func TestCalculateAlign(t *testing.T) { + tests := []struct { + name string + configuredAlign string + width string + expectedAlign string + }{ + {"No alignment configured", "", "1000", ""}, + {"No width available", "center", "", "center"}, + {"Below threshold", "center", "500", "center"}, + {"At threshold", "center", "760", "wide"}, + {"Above threshold", "center", "1000", "wide"}, + {"Left below threshold", "left", "700", "left"}, + {"Left at threshold", "left", "760", "wide"}, + {"Invalid width", "center", "abc", "center"}, + {"Large image", "center", "2000", "wide"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := calculateAlign(tt.configuredAlign, tt.width) + if result != tt.expectedAlign { + t.Errorf("calculateAlign(%q, %q) = %q, want %q", tt.configuredAlign, tt.width, result, tt.expectedAlign) + } + }) + } +} + +func TestCalculateLayout(t *testing.T) { + tests := []struct { + name string + align string + width string + expectedLayout string + }{ + {"Left alignment", "left", "500", "align-start"}, + {"Center alignment", "center", "500", "center"}, + {"Right alignment", "right", "500", "align-end"}, + {"Wide alignment", "wide", "1000", "center"}, + {"Full-width threshold", "center", "1800", "full-width"}, + {"Above full-width", "left", "2000", "full-width"}, + {"Below full-width", "center", "1799", "center"}, + {"No alignment", "", "1000", ""}, + {"Unknown alignment", "justify", "500", ""}, + {"Invalid width", "center", "abc", "center"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := calculateLayout(tt.align, tt.width) + if result != tt.expectedLayout { + t.Errorf("calculateLayout(%q, %q) = %q, want %q", tt.align, tt.width, result, tt.expectedLayout) + } + }) + } +} + +func TestCalculateDisplayWidth(t *testing.T) { + tests := []struct { + name string + originalWidth string + layout string + expectedWidth string + }{ + {"Full-width layout", "2000", "full-width", "1800"}, + {"Center layout keeps original", "1000", "center", "1000"}, + {"Align-start keeps original", "800", "align-start", "800"}, + {"Empty original", "", "center", ""}, + {"Empty layout", "1000", "", "1000"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := calculateDisplayWidth(tt.originalWidth, tt.layout) + if result != tt.expectedWidth { + t.Errorf("calculateDisplayWidth(%q, %q) = %q, want %q", tt.originalWidth, tt.layout, result, tt.expectedWidth) + } + }) + } +} diff --git a/stdlib/stdlib.go b/stdlib/stdlib.go index a22665b..fbe1327 100644 --- a/stdlib/stdlib.go +++ b/stdlib/stdlib.go @@ -212,7 +212,10 @@ func templates(api *confluence.API) (*template.Template, error) { `ac:image`: text( `Use

Use

Use

-

+