Documentation
¶
Overview ¶
Package ui holds what every hoist screen shares: one Styles palette built from a light/dark flag, the frame and pane chrome every screen is drawn in (frame.go), the dialog compositor (dialog.go), relative-time wording (time.go) and the status-bar line helper. It imports Lip Gloss and x/ansi (cell width and ANSI stripping) — no Bubbles components, no screen state — so any screen package can depend on it without a cycle.
Index ¶
- func Ago(now, t time.Time) string
- func BodyHeight(height, sections int) int
- func Box(st Styles, title string, sections []string, width int) string
- func Columns(st Styles, left, right string, leftWidth int) string
- func Dialog(st Styles, under, title, body string, width, height int) string
- func Span(d time.Duration) string
- func StatusBar(width int, left, right string) string
- func Until(now, t time.Time) string
- type Frame
- type Styles
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BodyHeight ¶
BodyHeight is how many content rows a Frame with n sections can hold on a terminal height rows tall: the height minus the footer, the two edges and the n-1 rules between sections. A screen sizes its scrolling section to this less the fixed rows of its other sections.
func Box ¶
Box draws a titled, rounded box exactly width cells wide around sections, with a rule between each pair. Every line of every section is truncated to the inner width, never wrapped: a version string that wraps mid-token is the defect this exists to end (#85).
func Columns ¶
Columns lays left and right side by side with a vertical rule between them, left padded or truncated to leftWidth, both aligned to the top. Replaces the string-padding joinPanes the plan screen carried (AGENTS.md §4.8 codifies this as the two-pane shape).
func Dialog ¶
Dialog draws body in a titled box centred over under, for a width×height terminal — the shape every huh.Confirm takes from M10 on. The screen underneath stays visible (dimmed, its own colours stripped) so the decision keeps its context: the operator confirming a direct commit is still looking at the commits it ships. Built on lipgloss's compositor (Canvas and Layer), which is the one place the TUI uses it: a dialog is the case where covering the parent is the point, and everything else composes with JoinVertical (docs/tui/README.md).
The dialog is at least wide enough for its longest line plus the box, capped at the terminal; body lines wider than that are truncated. A terminal too small for the box gets the dialog alone, uncentred, so the question is never lost behind the chrome.
func Span ¶
Span words a duration: "just now" under a minute, then "12m", "3h 48m", "3 days", "5 weeks", "3 months", "2 years". Coarse on purpose — the reader is comparing builds, not timing them.
func StatusBar ¶
StatusBar renders one line exactly width cells wide: left text, then right text flush against the right edge. When both do not fit, left is truncated with an ellipsis so the key hints on the right stay visible; when even right alone does not fit, right is cut. Both arguments may carry ANSI styling; widths are measured on the visible text.
Types ¶
type Frame ¶
type Frame struct {
Title string
Sections []string
// Panes are full-width blocks (already rendered, a Box each) stacked under the main box
// and above the footer — the matrix's in-flight pane. Empty strings are skipped.
Panes []string
}
Frame is the shape every hoist screen is drawn in (AGENTS.md §4.8, M10): a titled, rounded box whose Sections are separated by rules, and a Footer — the status bar — that is always the terminal's last line no matter how tall the box is. The box is tight to its content; a screen that wants it to fill the terminal sizes its own section (a viewport, a table) to Frame.BodyHeight. Nothing here draws a box character by hand: the edges, the junctions and the title line all come from lipgloss's Border, so the widths are right by construction rather than by counting.
A screen's View is `ui.Frame{...}.Render(styles, width, height)`; a sub-pane inside a section (the in-flight panel under the matrix) is Box, the same thing without a footer.
func (Frame) Render ¶
Render draws the frame for a width×height terminal: the box, then blank rows, then the footer on the last line. Content wider than the box is truncated with "…"; content taller than the space above the footer is cut from the bottom (the screen is expected to have sized its scrolling section, see BodyHeight). A width or height too small to hold a box (under 4 columns or 3 rows) renders only what fits.
type Styles ¶
type Styles struct {
// Dark records which background the palette was built for.
Dark bool
// Header styles a table header cell, Cell an ordinary cell, Selected the cursor row.
Header, Cell, Selected lipgloss.Style
// Status styles the status-bar summary, Notice a transient message shown in its place,
// Hint the key hints on the right of the bar.
Status, Notice, Hint lipgloss.Style
// Help styles the expanded help line toggled by ?.
Help lipgloss.Style
// Chrome (M10). Border colours every frame and pane edge; Title the name in a frame's
// top edge; Rule a section divider's own text, when it carries one.
Border, Title, Rule lipgloss.Style
// Semantic colours, reinforcing a word rather than replacing it (the state is always
// spelled out; colour is the second channel). Good: pinned, green CI, "in staging".
// Warn: drifted, split, a migration, a blocked step. Bad: a failed step, an error line.
// Dim: external, an unreached step, "…10 more". Accent: the cursor, an id, a command
// the operator should type. Production: the amber temperature a production target
// gives a header or a mode chip.
Good, Warn, Bad, Dim, Accent, Production lipgloss.Style
// Add and Del colour the + and - lines of a diff.
Add, Del lipgloss.Style
}
Styles is the palette for one terminal background. The root model builds it once from tea.BackgroundColorMsg and pushes it into every screen; screens never pick colours themselves, so a theme change is one call.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package uitest is the one harness every screen's tests render through (AGENTS.md §4.8, M10): a golden comparison at a stated terminal size that also asserts the shape a terminal would actually show — exactly height lines, none wider than width — and a way to drive a screen with real keypresses, so a test can never pass by setting the field a key would have set.
|
Package uitest is the one harness every screen's tests render through (AGENTS.md §4.8, M10): a golden comparison at a stated terminal size that also asserts the shape a terminal would actually show — exactly height lines, none wider than width — and a way to drive a screen with real keypresses, so a test can never pass by setting the field a key would have set. |