chore(tui): visual polish — detail sections, column headers, alert detail #37

Merged
lerko merged 20 commits from chore/ux-polish into main 2026-05-28 20:40:29 +00:00
Showing only changes of commit 82d7b2942b - Show all commits
+92 -13
View File
@@ -334,15 +334,50 @@ func fmtDuration(d time.Duration) string {
return fmt.Sprintf("%dd", days)
}
func (m Model) dynamicWidths() (nameW, sparkW int) {
fixed := 6 + 10 + 10 + 8 + 8 + 7 + 9 // #, TYPE, STATUS, LATENCY, UPTIME, SSL, RETRY
overhead := 30 // cell padding + borders
avail := m.termWidth - chromePadH - 2 - fixed - overhead
if avail < 30 {
avail = 30
type tableLayout struct {
nameW, sparkW int
headers []string
colWidths []int
}
func (m Model) computeLayout() tableLayout {
type colDef struct {
short string
full string
minWidth int
maxWidth int
}
nameW = avail / 2
sparkW = avail - nameW - 2 // -2 for spark column padding
cols := []colDef{
{"#", "#", 4, 6},
{"", "", 0, 0}, // NAME (dynamic)
{"TYPE", "TYPE", 8, 10},
{"STATUS", "STATUS", 8, 10},
{"LAT", "LATENCY", 5, 10},
{"UP%", "UPTIME", 5, 8},
{"", "", 0, 0}, // HISTORY (dynamic)
{"SSL", "SSL", 5, 7},
{"RT", "RETRIES", 5, 9},
}
overhead := 30
usable := m.termWidth - chromePadH - 2 - overhead
if usable < 80 {
usable = 80
}
fixedMin := 0
for i, c := range cols {
if i == 1 || i == 6 {
continue
}
fixedMin += c.minWidth
}
avail := usable - fixedMin
nameW := avail / 2
sparkW := avail - nameW - 2
if nameW < 13 {
nameW = 13
}
@@ -355,7 +390,50 @@ func (m Model) dynamicWidths() (nameW, sparkW int) {
if sparkW > 60 {
sparkW = 60
}
return
surplus := usable - fixedMin - nameW - sparkW - 2
if surplus < 0 {
surplus = 0
}
headers := make([]string, len(cols))
widths := make([]int, len(cols))
for i, c := range cols {
if i == 1 {
headers[i] = "NAME"
widths[i] = 0
continue
}
if i == 6 {
headers[i] = "HISTORY"
widths[i] = sparkW + 2
continue
}
w := c.minWidth
expand := c.maxWidth - c.minWidth
if surplus >= expand {
w = c.maxWidth
surplus -= expand
} else if surplus > 0 {
w += surplus
surplus = 0
}
if w >= len(c.full)+2 {
headers[i] = c.full
} else {
headers[i] = c.short
}
widths[i] = w
}
return tableLayout{
nameW: nameW,
sparkW: sparkW,
headers: headers,
colWidths: widths,
}
}
func (m Model) viewSitesTab() string {
@@ -373,12 +451,13 @@ func (m Model) viewSitesTab() string {
return "\n" + welcome
}
nameW, sparkWidth := m.dynamicWidths()
colWidths := []int{6, 0, 10, 10, 8, 8, sparkWidth + 2, 7, 9}
layout := m.computeLayout()
nameW := layout.nameW
sparkWidth := layout.sparkW
var groupRows map[int]bool
return m.renderTable(
[]string{"#", "NAME", "TYPE", "STATUS", "LAT", "UPTIME", "HISTORY", "SSL", "RETRY"},
layout.headers,
len(m.sites),
func(start, end int) [][]string {
groupRows = make(map[int]bool)
@@ -444,7 +523,7 @@ func (m Model) viewSitesTab() string {
}
return rows
},
colWidths,
layout.colWidths,
func(row, col int) *lipgloss.Style {
if groupRows[row] {
s := siteGroupStyle