Documentation
¶
Overview ¶
Package components — timeutil.go provides time-formatting utilities used across panes that display timestamps in human-readable relative form.
Index ¶
- func FormatRelativeTime(t time.Time) string
- func NewNotifications(t theme.Theme) *bubbleup.AlertModel
- func RebuildTableTheme(th theme.Theme, cols []ColumnDef, rows []map[string]string, focused bool) (*Table, *Filter)
- type ColumnDef
- type Controls
- type Filter
- func (f *Filter) BorderLabel() string
- func (f *Filter) ClearQuery()
- func (f *Filter) IsActive() bool
- func (f *Filter) Matches(text string) bool
- func (f *Filter) MatchesAny(texts ...string) bool
- func (f *Filter) Query() string
- func (f *Filter) SetWidth(width int)
- func (f *Filter) Toggle()
- func (f *Filter) Update(msg tea.Msg) tea.Cmd
- func (f *Filter) View(width int) string
- type GradientSeekBar
- type GradientVolumeBar
- type InfoBox
- type Table
- func (t *Table) Columns() []ColumnDef
- func (t *Table) CurrentPage() int
- func (t *Table) GotoPage(page int)
- func (t *Table) GotoTop()
- func (t *Table) Rows() []map[string]string
- func (t *Table) SelectedIndex() int
- func (t *Table) SetFocused(focused bool)
- func (t *Table) SetPlayingIndex(index int)
- func (t *Table) SetRichRows(rows []map[string]any)
- func (t *Table) SetRows(rows []map[string]string)
- func (t *Table) SetSize(width, height int)
- func (t *Table) Update(msg tea.Msg) tea.Cmd
- func (t *Table) View() string
- type TableChrome
- type TableConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FormatRelativeTime ¶
FormatRelativeTime returns a human-readable relative timestamp:
< 1 min → "just now"
1–59 min → "{n} min ago"
1–23 hr → "{n} hr ago"
1–6 days → "{n} days ago"
>= 7 days → "Jan 2" short date
func NewNotifications ¶
func NewNotifications(t theme.Theme) *bubbleup.AlertModel
NewNotifications creates a BubbleUp AlertModel configured with Spotnik theme colors and glyph prefixes resolved via uikit.RegisterBubbleupAlerts. Glyph prefixes honour uikit.ActiveMode() so ASCII mode produces ASCII prefixes.
Toast notifications are positioned at the bottom-right per DESIGN.md §12.
IMPORTANT: Always call Render(content) in View() — never View(). BubbleUp's View() returns an empty string by design; Render() overlays the alert on top of the full rendered view string.
func RebuildTableTheme ¶
func RebuildTableTheme( th theme.Theme, cols []ColumnDef, rows []map[string]string, focused bool, ) (*Table, *Filter)
RebuildTableTheme creates a new Table with updated theme colors and re-applies the existing rows from the old table. Called by pane SetTheme() to avoid repeating the same 10-line pattern across all 8 panes.
Usage:
func (p *MyPane) SetTheme(th theme.Theme) {
p.theme = th
cols := []ColumnDef{
{Key: "index", Header: "#", FlexFactor: 1, Color: th.ColumnIndex()},
{Key: "track", Header: "Track", FlexFactor: 9, Color: th.ColumnPrimary()},
}
p.table, p.filter = components.RebuildTableTheme(th, cols, p.table.Rows(), p.focused && !p.filter.IsActive())
}
Types ¶
type ColumnDef ¶
type ColumnDef struct {
// Key is the data key used as a map lookup in each row.
Key string
// Header is the text shown in the column header row.
Header string
// FlexFactor controls the column's relative share of available width.
// A column with FlexFactor 2 gets twice the space of one with FlexFactor 1.
FlexFactor int
// Color is the lipgloss foreground color applied to data cells in this column.
Color lipgloss.Color
}
ColumnDef defines a table column with its display properties.
type Controls ¶
type Controls struct {
// contains filtered or unexported fields
}
Controls renders the transport controls row: shuffle play/pause queue repeat. It is a thin compatibility wrapper around uikit.PlaybackControls that translates the legacy string repeat-mode arg ("off" / "context" / "track") to the typed uikit.RepeatMode enum. Callers use the same NewControls signature as before.
func NewControls ¶
NewControls creates a Controls renderer with the given state and theme. repeatMode must be one of "off", "context", or "track"; any other value is treated as "off" (RepeatOff).
type Filter ¶
type Filter struct {
// contains filtered or unexported fields
}
Filter provides in-pane text filtering using bubbles/textinput. It is not a tea.Model itself — the pane Update() calls Filter.Update() and the pane View() embeds Filter.View() in its rendered output.
func NewFilter ¶
NewFilter creates a Filter configured with the given theme. The filter starts in an inactive state; call Toggle() to activate it.
func (*Filter) BorderLabel ¶
BorderLabel returns the text to embed in the pane border when the filter has an active query. Returns an empty string when inactive or when the query is empty. e.g., `filtering: "rock"`.
func (*Filter) ClearQuery ¶
func (f *Filter) ClearQuery()
ClearQuery clears the committed filter query without changing active state. Called by panes to implement Esc-to-clear when the filter input is closed but a committed query is still narrowing results.
func (*Filter) Matches ¶
Matches returns true if text contains the filter query as a case-insensitive substring. Returns true unconditionally when the query is empty (including when the filter is inactive).
func (*Filter) MatchesAny ¶
MatchesAny returns true if at least one of the provided strings satisfies Matches. Returns true unconditionally when the query is empty (consistent with Matches).
func (*Filter) Query ¶
Query returns the current filter text (the last committed or in-progress query).
func (*Filter) SetWidth ¶
SetWidth updates the visible width of the filter input bar. Call this from the pane's SetSize so View() remains side-effect-free.
func (*Filter) Toggle ¶
func (f *Filter) Toggle()
Toggle activates or deactivates the filter. Activating focuses the text input. Deactivating blurs the input and clears the query.
func (*Filter) Update ¶
Update handles input events when the filter is active.
- Esc: deactivates the filter and clears the query
- Enter: deactivates the filter but preserves the current query
- All other keys: forwarded to the internal textinput
Returns a tea.Cmd if the textinput produced one (e.g. cursor blink). Returns nil when the filter is inactive.
type GradientSeekBar ¶
type GradientSeekBar struct {
// contains filtered or unexported fields
}
GradientSeekBar renders a seek bar with a gradient fill interpolated from Gradient1() (left) to Gradient2() (right), with an empty portion in Surface().
func NewGradientSeekBar ¶
func NewGradientSeekBar(t theme.Theme) *GradientSeekBar
NewGradientSeekBar creates a gradient seek bar using theme tokens.
func (*GradientSeekBar) Render ¶
func (b *GradientSeekBar) Render(progressMs, durationMs int) string
Render returns the seek bar string for the given progress. progressMs and durationMs are in milliseconds. Format: "1:41 ████████████████░░░░░░░░░░░░░░ 5:30"
func (*GradientSeekBar) SetWidth ¶
func (b *GradientSeekBar) SetWidth(width int)
SetWidth updates the bar width.
type GradientVolumeBar ¶
type GradientVolumeBar struct {
// contains filtered or unexported fields
}
GradientVolumeBar renders a volume bar with color bands and a music note icon. Format: "♪ ████▎░░░░░░░░░ 31%"
Full cells use █; the fractional last cell uses the §5.7 partial-block algorithm (▏▎▍▌▋▊▉) giving sub-character resolution on every 1% step. Empty cells use ░ (GlyphBarEmpty).
Color bands:
- 0-33%: Gradient1() (green/cool)
- 34-66%: Gradient2() (yellow/warm)
- 67-100%: Gradient3() (red/hot)
Icon color:
- volume > 0: ♪ in Gradient1() color
- volume = 0: ♪ in TextMuted() color
func NewGradientVolumeBar ¶
func NewGradientVolumeBar(t theme.Theme) *GradientVolumeBar
NewGradientVolumeBar creates a gradient volume bar using theme tokens.
func (*GradientVolumeBar) Render ¶
func (b *GradientVolumeBar) Render(volume int) string
Render returns the volume bar string for the given volume level. Volume is clamped to [0, 100]. Format: "♪ ████▎░░░░░░░░░ 31%"
Full cells use █ (U+2588). The fractional last cell uses the §5.7 partial-block thresholds (▏▎▍▌▋▊▉) so the bar moves smoothly on every 1% step. Empty cells use ░ (GlyphBarEmpty).
func (*GradientVolumeBar) SetWidth ¶
func (b *GradientVolumeBar) SetWidth(width int)
SetWidth updates the total component width (including icon and percentage).
type InfoBox ¶
type InfoBox struct {
// contains filtered or unexported fields
}
InfoBox renders a bordered sub-pane with a title in the top border and vertically-centered content lines inside. Border glyphs are resolved via uikit.PaneChrome so the output honours ui.glyphs = "ascii" / "unicode".
func NewInfoBox ¶
NewInfoBox creates an InfoBox using the given theme.
func (*InfoBox) Render ¶
Render returns the InfoBox as a multi-line string.
title is rendered in the top border: ╭─ Title ─────────────╮ (unicode) or +- Title -------------+ (ascii), depending on uikit.ActiveMode(). lines contains the content to vertically-center inside the box. Border colour encodes focus state: focused → ActiveBorder(), unfocused → InactiveBorder(). PaneChrome is always passed Focused=true so it does not additionally apply a Faint dim over the chosen colour.
Content behaviour:
- Each line is truncated (with "…") to the inner width (width-2).
- If len(lines) exceeds the inner height (height-2) the excess is truncated from the bottom — the top lines (track name, artist) are always shown first.
- Remaining vertical space is distributed as topPad above and bottom padding below to centre the block.
type Table ¶
type Table struct {
// contains filtered or unexported fields
}
Table wraps bubble-table with Spotnik styling conventions: borderless mode, per-column colors, selected row highlighting, and a playing indicator.
func NewTable ¶
func NewTable(cfg TableConfig) *Table
NewTable creates a Table with the given configuration. Call SetSize before calling View to set dimensions.
func (*Table) Columns ¶
Columns returns the column definitions used to construct this table. Primarily used in tests to verify that the correct color tokens were applied.
func (*Table) CurrentPage ¶
CurrentPage returns the current page number (1-indexed). Delegates to the inner model's pointer-receiver method.
func (*Table) GotoPage ¶
GotoPage navigates to the given page number (1-indexed). Used in tests to seed a non-first-page state before verifying that GotoTop resets it.
func (*Table) GotoTop ¶
func (t *Table) GotoTop()
GotoTop resets the table scroll position to the first page. Used by panes to implement the universal Esc scroll-reset behaviour.
func (*Table) Rows ¶
Rows returns the current table data as a slice of row maps. Used by RebuildTableTheme to copy existing data into a freshly themed table.
func (*Table) SelectedIndex ¶
SelectedIndex returns the currently highlighted row index (0-based).
func (*Table) SetFocused ¶
SetFocused enables or disables keyboard navigation. When unfocused the highlight cursor is hidden and key events are not processed.
func (*Table) SetPlayingIndex ¶
SetPlayingIndex marks which row index shows the ▶ indicator. Pass -1 to clear the indicator. The rows are re-applied immediately.
func (*Table) SetRichRows ¶
SetRichRows updates the table data with rows whose cell values may be either plain strings (rendered with the column's foreground colour) or btable.StyledCell instances (rendered with a per-cell foreground while still inheriting the row-level highlight background). Used by panes that need per-row colour variation that single-value column Color cannot express (e.g. GatewayLivePane's per-event-kind glyph colours).
Existing SetRows([]map[string]string) callers are unaffected.
func (*Table) SetRows ¶
SetRows updates the table data. Each row is a map[string]string keyed by the column Key values defined in ColumnDef. Rows are re-styled immediately. Calling SetRows clears any previously set rich rows.
func (*Table) SetSize ¶
SetSize updates the table dimensions. Recalculates column widths and page size. The emptyBorder adds top+bottom lines; with ShowHeader the separator adds another. Total overhead is 6 lines (header visible) or 4 lines (no header).
type TableChrome ¶
type TableChrome struct {
// Columns defines the column layout and per-column colour tokens.
Columns []ColumnDef
// Theme provides colour tokens for header, selection, and playing indicator.
Theme theme.Theme
// contains filtered or unexported fields
}
TableChrome wraps Table. The primitive's role is to standardise construction — column tokens, header colour, playing-indicator colour — so that panes no longer build TableConfig literals inline.
Call sites are not changed; panes continue to call NewTable directly. TableChrome is the canonical wrapping pattern for future migrations.
func (*TableChrome) Inner ¶
func (t *TableChrome) Inner() *Table
Inner returns the wrapped *Table, constructing it on first call. The inner table owns all interactive state (scroll position, selection, etc.); TableChrome is effectively stateless from the caller's perspective.
type TableConfig ¶
type TableConfig struct {
// Columns defines the column layout and per-column colors.
Columns []ColumnDef
// Theme provides color tokens for header, selection, and playing indicator.
Theme theme.Theme
// PlayingIndex is the row index that shows the ▶ indicator (-1 = none).
PlayingIndex int
// ShowHeader controls whether the column header row is rendered.
ShowHeader bool
}
TableConfig holds configuration for creating a Table.