diff --git a/internal/tui/tab_sites.go b/internal/tui/tab_sites.go index c35cafe..36d490e 100644 --- a/internal/tui/tab_sites.go +++ b/internal/tui/tab_sites.go @@ -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