Files

73 lines
2.4 KiB
Go

package style
import (
"strings"
"charm.land/lipgloss/v2"
)
// borderTypes maps the `border:` config value to a lipgloss.Border. Only the
// symmetric, general-purpose border kinds are exposed here; MarkdownBorder,
// BlockBorder and the half-block variants are content-specific rather than a
// theming choice.
var borderTypes = map[string]lipgloss.Border{
"rounded": lipgloss.RoundedBorder(),
"normal": lipgloss.NormalBorder(),
"thick": lipgloss.ThickBorder(),
"double": lipgloss.DoubleBorder(),
"hidden": lipgloss.HiddenBorder(),
"ascii": lipgloss.ASCIIBorder(),
}
// resolveBorderType maps a `border:` config value to a lipgloss.Border,
// falling back to RoundedBorder for an empty or unrecognized name.
func resolveBorderType(name string) lipgloss.Border {
if b, ok := borderTypes[strings.ToLower(strings.TrimSpace(name))]; ok {
return b
}
return lipgloss.RoundedBorder()
}
// ContentHeight returns the usable inner height for a bordered panel of totalH rows.
func ContentHeight(totalH int) int {
h := totalH - 2
if h < 0 {
return 0
}
return h
}
// RenderWithTitle renders a bordered box with a title embedded in the top border.
// title may contain ANSI color codes. width and height are the total outer dimensions.
//
// Example:
//
// box := style.RenderWithTitle(style.S.PanelFocused, "Header", content, w, h)
func RenderWithTitle(border lipgloss.Style, title, content string, width, height int) string {
boxH := height - 1
if contentH := boxH - 1; contentH > 0 {
lines := strings.Split(content, "\n")
if len(lines) > contentH {
content = strings.Join(lines[:contentH], "\n")
}
}
box := border.BorderTop(false).Width(width).Height(boxH).Render(content)
boxWidth := lipgloss.Width(strings.SplitN(box, "\n", 2)[0])
titleW := lipgloss.Width(title)
// Pull the corner/fill glyphs from the style's own border spec instead of
// hardcoding rounded-border characters, so this respects style.S.BorderType.
b, _, _, _, _ := border.GetBorder()
topLeft, top, topRight := b.TopLeft, b.Top, b.TopRight
fillW := boxWidth - titleW - lipgloss.Width(topLeft) - lipgloss.Width(topRight) - 2 // 2 = the spaces around the title
if fillW < 0 {
fillW = 0
}
bc := lipgloss.NewStyle().Foreground(border.GetBorderTopForeground())
topLine := bc.Render(topLeft+" ") + bc.Render(title) + bc.Render(" "+strings.Repeat(top, fillW)+topRight)
return lipgloss.JoinVertical(lipgloss.Left, topLine, box)
}