Added better compatibility for the TUI in smaller terminals
This commit is contained in:
+54
-11
@@ -137,10 +137,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
m.statusErr = msg.err.Error()
|
m.statusErr = msg.err.Error()
|
||||||
} else {
|
} else {
|
||||||
m.statusErr = ""
|
m.statusErr = ""
|
||||||
|
wasLoaded := m.statusLoaded
|
||||||
m.status = msg.st
|
m.status = msg.st
|
||||||
m.statusLoaded = true
|
m.statusLoaded = true
|
||||||
m.peers.Refresh(msg.st, msg.st.NodeID)
|
m.peers.Refresh(msg.st, msg.st.NodeID)
|
||||||
m.checks.Refresh(msg.st)
|
m.checks.Refresh(msg.st)
|
||||||
|
// First load may change header height on narrow terminals;
|
||||||
|
// re-run the layout so the body shrinks to compensate.
|
||||||
|
if !wasLoaded {
|
||||||
|
m.resizeTabs()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
|
|
||||||
@@ -261,12 +267,22 @@ func (m model) View() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m model) renderHeader() string {
|
func (m model) renderHeader() string {
|
||||||
|
outerW := m.width - 2
|
||||||
|
if outerW < 20 {
|
||||||
|
outerW = 20
|
||||||
|
}
|
||||||
|
// headerStyle has Padding(0,1), so the usable content width is outerW-2.
|
||||||
|
innerW := outerW - 2
|
||||||
|
if innerW < 1 {
|
||||||
|
innerW = 1
|
||||||
|
}
|
||||||
|
|
||||||
if !m.statusLoaded {
|
if !m.statusLoaded {
|
||||||
msg := "connecting to daemon…"
|
msg := "connecting to daemon…"
|
||||||
if m.statusErr != "" {
|
if m.statusErr != "" {
|
||||||
msg = "daemon: " + m.statusErr
|
msg = "daemon: " + m.statusErr
|
||||||
}
|
}
|
||||||
return headerStyle.Width(m.width - 2).Render(titleStyle.Render("QUptime") + " " + helpStyle.Render(msg))
|
return headerStyle.Width(outerW).Render(titleStyle.Render("QUptime") + " " + helpStyle.Render(msg))
|
||||||
}
|
}
|
||||||
st := m.status
|
st := m.status
|
||||||
quorum := stateDownStyle.Render("● no quorum")
|
quorum := stateDownStyle.Render("● no quorum")
|
||||||
@@ -297,16 +313,40 @@ func (m model) renderHeader() string {
|
|||||||
" ",
|
" ",
|
||||||
subtleStyle.Render(fmt.Sprintf("term %d ver %d", st.Term, st.Version)),
|
subtleStyle.Render(fmt.Sprintf("term %d ver %d", st.Term, st.Version)),
|
||||||
)
|
)
|
||||||
width := m.width - 2
|
leftW := lipgloss.Width(left)
|
||||||
if width < 20 {
|
rightW := lipgloss.Width(right)
|
||||||
width = 20
|
|
||||||
}
|
// Single row when both halves fit with at least one space between them.
|
||||||
gap := width - lipgloss.Width(left) - lipgloss.Width(right)
|
if leftW+rightW+1 <= innerW {
|
||||||
if gap < 1 {
|
gap := innerW - leftW - rightW
|
||||||
gap = 1
|
|
||||||
}
|
|
||||||
row := left + strings.Repeat(" ", gap) + right
|
row := left + strings.Repeat(" ", gap) + right
|
||||||
return headerStyle.Width(width).Render(row)
|
return headerStyle.Width(outerW).Render(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise stack vertically so nothing gets clipped on narrow terminals.
|
||||||
|
rows := lipgloss.JoinVertical(lipgloss.Left, left, right)
|
||||||
|
return headerStyle.Width(outerW).Render(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
// headerHeight is the number of terminal rows renderHeader will produce,
|
||||||
|
// including the rounded border. Used to compute the body area in resizeTabs.
|
||||||
|
func (m model) headerHeight() int {
|
||||||
|
// border(2) + content lines. The status-not-loaded variant is always 1
|
||||||
|
// content line; once loaded we stack when content doesn't fit.
|
||||||
|
contentLines := 1
|
||||||
|
if m.statusLoaded && m.width > 0 {
|
||||||
|
innerW := m.width - 4
|
||||||
|
if innerW < 1 {
|
||||||
|
innerW = 1
|
||||||
|
}
|
||||||
|
// Worst-case content widths roughly track these constants, so use
|
||||||
|
// a heuristic threshold instead of re-rendering: title+node+master+
|
||||||
|
// role is ~60 chars, quorum+term/ver is ~30 chars, plus the gap.
|
||||||
|
if 60+30+1 > innerW {
|
||||||
|
contentLines = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return contentLines + 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) renderTabs() string {
|
func (m model) renderTabs() string {
|
||||||
@@ -513,7 +553,10 @@ func (m *model) setFlash(s string, level flashLevel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *model) resizeTabs() {
|
func (m *model) resizeTabs() {
|
||||||
bodyH := m.height - 8
|
// Rows consumed outside the body: header (variable), tabs (1),
|
||||||
|
// body's own rounded border (2), flash (1), help (1).
|
||||||
|
reserved := m.headerHeight() + 5
|
||||||
|
bodyH := m.height - reserved
|
||||||
if bodyH < 5 {
|
if bodyH < 5 {
|
||||||
bodyH = 5
|
bodyH = 5
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user