Monorepo for Tangled tangled.org
5

Configure Feed

Select the types of activity you want to include in your feed.

appview/pipelines/ssh: nicer step dividers

make it independent of colorscheme

Signed-off-by: oppiliappan <me@oppi.li>

author
oppiliappan
date (May 26, 2026, 4:05 PM +0100) commit c051797a parent c8599677 change-id olxzxpsw
+16 -13
+16 -13
appview/pipelines/ssh/tui.go
··· 19 19 ) 20 20 21 21 var ( 22 - colorWhite lipgloss.ANSIColor = 7 22 + colorFg lipgloss.NoColor = lipgloss.NoColor{} 23 23 colorBlue lipgloss.ANSIColor = 4 24 24 colorBrightBlack lipgloss.ANSIColor = 8 25 - colorDarkGrey lipgloss.ANSIColor = 0 26 25 ) 27 26 28 27 type tickMsg time.Time ··· 126 125 } 127 126 128 127 func (m *pipelineModel) vpHeight() int { 129 - return max(m.height-2, 1) // topbar + divider take 2 lines 128 + return max(m.height-2, 1) // topbar + empty line take 2 lines 130 129 } 131 130 132 131 // resizeViewports updates all viewport dimensions and re-renders their content after a terminal resize. ··· 301 300 302 301 // renderLogs builds the full log content string for a workflow, used as viewport content. 303 302 func renderLogs(r *lipgloss.Renderer, wl *workflowLogs, width int) string { 304 - headerStyle := r.NewStyle().Foreground(colorWhite).Background(colorBrightBlack).Bold(true) 303 + headerStyle := r.NewStyle().Foreground(colorFg).Bold(true) 305 304 cmdStyle := r.NewStyle().Foreground(colorBlue).Width(width) 305 + dimStyle := r.NewStyle().Faint(true) 306 306 now := time.Now() 307 307 var sb strings.Builder 308 308 for i := range wl.steps { ··· 313 313 } else if !st.startTime.IsZero() { 314 314 dur = now.Sub(st.startTime).Round(time.Second).String() 315 315 } 316 - durRendered := headerStyle.Render(dur) 317 - nameWidth := max(width-lipgloss.Width(dur)-1, 1) 318 - header := fmt.Sprintf("%-*s ", nameWidth, st.name) + durRendered 319 - sb.WriteString(headerStyle.Width(width).Render(header) + "\n") 316 + // build overlay: "── name ──...── dur ──" 317 + nameStr := headerStyle.Render(st.name + " ") 318 + durStr := headerStyle.Render(" " + dur + " ") 319 + nameW := lipgloss.Width(nameStr) 320 + durW := lipgloss.Width(durStr) 321 + fillW := max(width-nameW-durW, 0) 322 + fill := dimStyle.Render(strings.Repeat("─", fillW)) 323 + header := nameStr + fill + durStr 324 + sb.WriteString(header + "\n") 320 325 if st.command != "" { 321 326 sb.WriteString(cmdStyle.Render(st.command) + "\n") 322 327 } ··· 332 337 } 333 338 334 339 func (m *pipelineModel) View() string { 335 - r := m.renderer 336 - divider := r.NewStyle().Foreground(colorBrightBlack).Render(strings.Repeat("─", m.width)) 337 340 body := "" 338 341 if wl := m.selectedLogs(); wl != nil && wl.ready { 339 342 body = wl.vp.View() 340 343 } 341 - return lipgloss.JoinVertical(lipgloss.Left, m.topbarView(), divider, body) 344 + return lipgloss.JoinVertical(lipgloss.Left, m.topbarView(), "", body) 342 345 } 343 346 344 347 // topbarView renders the single-line tab bar with workflow tabs left and trigger info + help right. 345 348 func (m *pipelineModel) topbarView() string { 346 349 r := m.renderer 347 - activeStyle := r.NewStyle().Background(colorBlue).Foreground(colorWhite) 350 + activeStyle := r.NewStyle().Background(colorBlue).Foreground(colorFg).Bold(true) 348 351 349 352 now := time.Now() 350 353 ··· 388 391 } 389 392 390 393 func helpText(r *lipgloss.Renderer) string { 391 - key := r.NewStyle().Foreground(colorWhite) 394 + key := r.NewStyle().Foreground(colorFg) 392 395 action := r.NewStyle().Faint(true) 393 396 sep := action.Render(" · ") 394 397