components

package
v0.1.0-rc3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package components — timeutil.go provides time-formatting utilities used across panes that display timestamps in human-readable relative form.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FormatRelativeTime

func FormatRelativeTime(t time.Time) string

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

func NewControls(t theme.Theme, isPlaying, shuffleOn bool, repeatMode string) Controls

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).

func (Controls) Render

func (c Controls) Render() string

Render returns the controls row as a string.

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

func NewFilter(t theme.Theme) *Filter

NewFilter creates a Filter configured with the given theme. The filter starts in an inactive state; call Toggle() to activate it.

func (*Filter) BorderLabel

func (f *Filter) BorderLabel() string

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) IsActive

func (f *Filter) IsActive() bool

IsActive returns whether the filter is currently accepting input.

func (*Filter) Matches

func (f *Filter) Matches(text string) bool

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

func (f *Filter) MatchesAny(texts ...string) bool

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

func (f *Filter) Query() string

Query returns the current filter text (the last committed or in-progress query).

func (*Filter) SetWidth

func (f *Filter) SetWidth(width int)

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

func (f *Filter) Update(msg tea.Msg) tea.Cmd

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.

func (*Filter) View

func (f *Filter) View(width int) string

View renders the filter input bar at the given width. Returns an empty string 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

func NewInfoBox(th theme.Theme) *InfoBox

NewInfoBox creates an InfoBox using the given theme.

func (*InfoBox) Render

func (b *InfoBox) Render(title string, lines []string, focused bool) string

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.

func (*InfoBox) SetSize

func (b *InfoBox) SetSize(w, h int)

SetSize updates the total width and height of the box (including the border rows and columns themselves).

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

func (t *Table) Columns() []ColumnDef

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

func (t *Table) CurrentPage() int

CurrentPage returns the current page number (1-indexed). Delegates to the inner model's pointer-receiver method.

func (*Table) GotoPage

func (t *Table) GotoPage(page int)

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

func (t *Table) Rows() []map[string]string

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

func (t *Table) SelectedIndex() int

SelectedIndex returns the currently highlighted row index (0-based).

func (*Table) SetFocused

func (t *Table) SetFocused(focused bool)

SetFocused enables or disables keyboard navigation. When unfocused the highlight cursor is hidden and key events are not processed.

func (*Table) SetPlayingIndex

func (t *Table) SetPlayingIndex(index int)

SetPlayingIndex marks which row index shows the ▶ indicator. Pass -1 to clear the indicator. The rows are re-applied immediately.

func (*Table) SetRichRows

func (t *Table) SetRichRows(rows []map[string]any)

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

func (t *Table) SetRows(rows []map[string]string)

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

func (t *Table) SetSize(width, height int)

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).

func (*Table) Update

func (t *Table) Update(msg tea.Msg) tea.Cmd

Update forwards tea.Msg events to the inner bubble-table model and returns any resulting command. Key events only take effect when the table is focused.

func (*Table) View

func (t *Table) View() string

View renders the table to a string. Call SetSize before first render.

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.

Directories

Path Synopsis
Package viz provides the visualizer engine for the NowPlaying pane.
Package viz provides the visualizer engine for the NowPlaying pane.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL