fix(ui): remove borders from agent messages, move user border to left with Primary color

Agent messages now render borderless. User messages use a left border
with theme.Primary (Mauve) instead of a right border with Secondary.
This commit is contained in:
Ed Zynda
2026-02-26 12:51:44 +03:00
parent faea00795e
commit ee5f41764b
2 changed files with 53 additions and 36 deletions
+49 -31
View File
@@ -11,6 +11,7 @@ type blockRenderer struct {
align *lipgloss.Position
borderColor *color.Color
fullWidth bool
noBorder bool
paddingTop int
paddingBottom int
paddingLeft int
@@ -32,6 +33,14 @@ func WithFullWidth() renderingOption {
}
}
// WithNoBorder returns a renderingOption that disables all borders on the
// block, rendering content with only padding.
func WithNoBorder() renderingOption {
return func(c *blockRenderer) {
c.noBorder = true
}
}
// WithAlign returns a renderingOption that sets the horizontal alignment
// of the block content within its container. The align parameter accepts
// lipgloss.Left, lipgloss.Center, or lipgloss.Right positions.
@@ -134,44 +143,53 @@ func renderContentBlock(content string, containerWidth int, options ...rendering
PaddingBottom(renderer.paddingBottom).
PaddingLeft(renderer.paddingLeft).
PaddingRight(renderer.paddingRight).
Foreground(theme.Text).
BorderStyle(lipgloss.ThickBorder())
Foreground(theme.Text)
align := lipgloss.Left
if renderer.align != nil {
align = *renderer.align
}
// Border width used for full-width calculation.
borderChars := 0
// Default to transparent/no border color
var borderColor color.Color = lipgloss.NoColor{}
if renderer.borderColor != nil {
borderColor = *renderer.borderColor
}
if renderer.noBorder {
// No borders — just padding.
} else {
style = style.BorderStyle(lipgloss.ThickBorder())
// Very muted color for the opposite border
mutedOppositeBorder := AdaptiveColor("#F3F4F6", "#1F2937")
align := lipgloss.Left
if renderer.align != nil {
align = *renderer.align
}
// Align determines which border gets the accent color.
// All blocks span full width — no horizontal floating.
switch align {
case lipgloss.Right:
style = style.
BorderRight(true).
BorderLeft(true).
BorderRightForeground(borderColor).
BorderLeftForeground(mutedOppositeBorder)
default: // Left (and fallback)
style = style.
BorderLeft(true).
BorderRight(true).
BorderLeftForeground(borderColor).
BorderRightForeground(mutedOppositeBorder)
// Default to transparent/no border color
var borderColor color.Color = lipgloss.NoColor{}
if renderer.borderColor != nil {
borderColor = *renderer.borderColor
}
// Very muted color for the opposite border
mutedOppositeBorder := AdaptiveColor("#F3F4F6", "#1F2937")
// Align determines which border gets the accent color.
switch align {
case lipgloss.Right:
style = style.
BorderRight(true).
BorderLeft(true).
BorderRightForeground(borderColor).
BorderLeftForeground(mutedOppositeBorder)
borderChars = 2
default: // Left (and fallback)
style = style.
BorderLeft(true).
BorderRight(true).
BorderLeftForeground(borderColor).
BorderRightForeground(mutedOppositeBorder)
borderChars = 2
}
}
if renderer.fullWidth {
// Subtract 2 for left + right border characters so the total
// rendered width equals containerWidth exactly.
style = style.Width(renderer.width - 2)
// Subtract border characters so the total rendered width
// equals containerWidth exactly.
style = style.Width(renderer.width - borderChars)
}
content = style.Render(content)
+4 -5
View File
@@ -107,8 +107,8 @@ func (r *MessageRenderer) RenderUserMessage(content string, timestamp time.Time)
rendered := renderContentBlock(
fullContent,
r.width,
WithAlign(lipgloss.Right),
WithBorderColor(theme.Secondary),
WithAlign(lipgloss.Left),
WithBorderColor(theme.Primary),
WithMarginBottom(1),
)
@@ -151,12 +151,11 @@ func (r *MessageRenderer) RenderAssistantMessage(content string, timestamp time.
fullContent := strings.TrimSuffix(messageContent, "\n") + "\n" +
lipgloss.NewStyle().Foreground(theme.VeryMuted).Render(info)
// Use the new block renderer
// Use the new block renderer — no borders for agent messages.
rendered := renderContentBlock(
fullContent,
r.width,
WithAlign(lipgloss.Left),
WithBorderColor(theme.Primary),
WithNoBorder(),
WithMarginBottom(1),
)