Documentation
¶
Overview ¶
Package ui provides terminal user interface components for scoreline.
Package ui provides rendering functions for the terminal user interface.
Index ¶
- Constants
- func AdaptiveGradientColors() (startHex, endHex string)
- func CreateGoalLinkDisplay(goalText, replayURL string) string
- func DialogBadge(value string) string
- func DialogBadgeHighlight(value string) string
- func DialogSize(screenWidth, screenHeight, contentWidth, contentHeight int) (width, height int)
- func FilterInputStyles() (cursorStyle, promptStyle lipgloss.Style)
- func Hyperlink(text, url string) string
- func HyperlinkWithFallback(text, url, fallbackIndicator string) string
- func IsValidReplayURL(url string) bool
- func MakeGoalLinkKey(matchID, minute int) string
- func NewMatchListDelegate() list.DefaultDelegate
- func OpenURL(url string) error
- func RenderCricketArchivesView(width, height int, matches []cricket.Match, selected int, ...) string
- func RenderCricketLiveView(width, height int, matches []cricket.Match, selected int, ...) string
- func RenderCricketMenu(width, height, selected int, bannerType constants.StatusBannerType, ...) string
- func RenderCricketSettingsView(width, height int, state *CricketSettingsState, apiKeyConfigured bool, ...) string
- func RenderDialogFrame(title, content string, width, height int) string
- func RenderDialogFrameWithHelp(title, content, help string, width, height int) string
- func RenderDialogTitleBar(title string, width int) string
- func RenderGradientText(text string) string
- func RenderLiveMatchesListPanel(width, height int, listModel list.Model, upcomingMatches []MatchDisplay) string
- func RenderMainMenu(width, height, selected int, sp spinner.Model, ...) string
- func RenderMatchDetails(cfg MatchDetailsConfig) (headerContent, scrollableContent string)
- func RenderMatchDetailsPanel(width, height int, details *api.MatchDetails) string
- func RenderMultiPanelViewWithList(width, height int, listModel list.Model, details *api.MatchDetails, ...) string
- func RenderPlaceholderView(width, height int, title, message, help string, ...) string
- func RenderSettingsView(width, height int, state *SettingsState, bannerType constants.StatusBannerType) string
- func RenderSportSelector(width, height, selected int, bannerType constants.StatusBannerType, ...) string
- func RenderStatsListPanel(width, height int, finishedList list.Model, dateRange int, ...) string
- func RenderStatsViewWithList(width, height int, finishedList list.Model, details *api.MatchDetails, ...) string
- func SpinnerStyle() lipgloss.Style
- func SpinnerTick() tea.Cmd
- func ToMatchListItems(matches []MatchDisplay) []list.Item
- func Truncate(text string, width int) string
- type CricketSettingsState
- func (s *CricketSettingsState) Adjust(delta int)
- func (s *CricketSettingsState) BackspaceEditText()
- func (s *CricketSettingsState) BeginEdit()
- func (s *CricketSettingsState) CancelEdit()
- func (s *CricketSettingsState) CommitEdit()
- func (s *CricketSettingsState) InsertEditText(text string)
- func (s *CricketSettingsState) Move(delta int)
- func (s *CricketSettingsState) Save() error
- func (s *CricketSettingsState) Toggle()
- type Dialog
- type DialogAction
- type DialogActionClose
- type DialogOverlay
- func (o *DialogOverlay) CloseDialog(dialogID string)
- func (o *DialogOverlay) CloseFrontDialog()
- func (o *DialogOverlay) ContainsDialog(dialogID string) bool
- func (o *DialogOverlay) FrontDialog() Dialog
- func (o *DialogOverlay) HasDialogs() bool
- func (o *DialogOverlay) OpenDialog(dialog Dialog)
- func (o *DialogOverlay) Update(msg tea.Msg) DialogAction
- func (o *DialogOverlay) View(width, height int) string
- type FormationsDialog
- type GoalLinksMap
- type LeagueListDelegate
- type LeagueListItem
- type MatchDetailsConfig
- type MatchDisplay
- type MatchListItem
- type RandomCharSpinner
- type SettingsState
- type StandingsDialog
- type StatisticsDialog
- type TickMsg
Constants ¶
const ( DefaultDialogMaxWidth = 104 DefaultDialogMaxHeight = 39 )
Dialog sizing constants (30% larger for better readability).
const ( StandingsDialogID = "standings" FormationsDialogID = "formations" StatisticsDialogID = "statistics" )
Dialog IDs
const ( CardSymbolYellow = "▪" // Small square for yellow cards CardSymbolRed = "■" // Filled square for red cards )
Card symbols - consistent across all views
const ReplayLinkIndicator = "[▶REPLAY]"
ReplayLinkIndicator is the visual indicator for replay links.
const ReplayLinkIndicatorAlt = "[replay]"
ReplayLinkIndicatorAlt is an alternative ASCII indicator for terminals without emoji.
const SpinnerTickInterval = 70 * time.Millisecond
SpinnerTickInterval is the unified tick rate for all spinners (70ms ≈ 14 fps). This balances smooth animation with keyboard responsiveness.
Variables ¶
This section is empty.
Functions ¶
func AdaptiveGradientColors ¶
func AdaptiveGradientColors() (startHex, endHex string)
AdaptiveGradientColors returns the appropriate gradient start/end hex colors based on the terminal background (light or dark). This is a convenience wrapper around design.AdaptiveGradientColors.
func CreateGoalLinkDisplay ¶
CreateGoalLinkDisplay creates a display string for a goal with replay link. Returns the text with hyperlink if available, or plain text if not. If the terminal doesn't support hyperlinks OR no URL is provided, returns the original goalText unchanged (no visible difference).
func DialogBadge ¶
DialogBadge wraps a value with a subtle background.
func DialogBadgeHighlight ¶
DialogBadgeHighlight wraps a value with a highlighted background.
func DialogSize ¶
DialogSize calculates appropriate dialog dimensions based on content and screen size.
func FilterInputStyles ¶
FilterInputStyles returns cursor and prompt styles for list filter input. Cursor: neon cyan (solid color), Prompt: neon red to match theme.
func Hyperlink ¶
Hyperlink creates a terminal hyperlink using OSC 8 escape sequences. Falls back to plain text with URL suffix if terminal doesn't support OSC 8.
func HyperlinkWithFallback ¶
HyperlinkWithFallback creates a hyperlink with a visible fallback indicator. If OSC 8 is supported, returns a clickable link. Otherwise, returns text with a link indicator like [📹].
func IsValidReplayURL ¶
IsValidReplayURL validates that a URL is a valid HTTP/HTTPS URL and not a marker. Returns true only for valid http:// or https:// URLs. Filters out empty strings, "__NOT_FOUND__" markers, and invalid URL schemes.
func MakeGoalLinkKey ¶
MakeGoalLinkKey creates a key for the goal links map.
func NewMatchListDelegate ¶
func NewMatchListDelegate() list.DefaultDelegate
NewMatchListDelegate creates a custom list delegate for match items. Height is set to 3 to accommodate title + 2-line description (with KO time). Uses Neon Gradient styling: red title, cyan description on selection.
func OpenURL ¶
OpenURL opens a URL in the default browser. Use this as a fallback when OSC 8 hyperlinks aren't supported.
func RenderCricketArchivesView ¶
func RenderCricketArchivesView(width, height int, matches []cricket.Match, selected int, details *cricket.MatchDetails, loading bool, lastError string, bannerType constants.StatusBannerType) string
RenderCricketArchivesView renders locally indexed Cricsheet archive matches.
func RenderCricketLiveView ¶
func RenderCricketLiveView(width, height int, matches []cricket.Match, selected int, details *cricket.MatchDetails, bannerType constants.StatusBannerType) string
RenderCricketLiveView renders a cricket-native live dashboard.
func RenderCricketMenu ¶
func RenderCricketMenu(width, height, selected int, bannerType constants.StatusBannerType, animatedLogo *logo.AnimatedLogo) string
RenderCricketMenu renders the cricket main menu.
func RenderCricketSettingsView ¶
func RenderCricketSettingsView(width, height int, state *CricketSettingsState, apiKeyConfigured bool, bannerType constants.StatusBannerType) string
RenderCricketSettingsView renders cricket-specific settings.
func RenderDialogFrame ¶
RenderDialogFrame wraps content in a dialog frame with title bar.
func RenderDialogFrameWithHelp ¶
RenderDialogFrameWithHelp wraps content in a dialog frame with title bar and help text.
func RenderDialogTitleBar ¶
RenderDialogTitleBar creates a full-width title bar with background.
func RenderGradientText ¶
RenderGradientText applies a gradient (cyan to red) to multi-line text. Exported wrapper for external use.
func RenderLiveMatchesListPanel ¶
func RenderLiveMatchesListPanel(width, height int, listModel list.Model, upcomingMatches []MatchDisplay) string
RenderLiveMatchesListPanel renders the left panel using bubbletea list component.
func RenderMainMenu ¶
func RenderMainMenu(width, height, selected int, sp spinner.Model, randomSpinner *RandomCharSpinner, loading bool, bannerType constants.StatusBannerType, animatedLogo *logo.AnimatedLogo) string
RenderMainMenu renders the soccer main menu view with navigation options. width and height specify the terminal dimensions. selected indicates which menu item is currently selected (0-indexed). sp is the spinner model to display when loading (for other views). randomSpinner is the random character spinner for main view. loading indicates if the spinner should be shown. bannerType determines what status banner (if any) to display at the top. animatedLogo is the animated logo instance for the main view.
func RenderMatchDetails ¶
func RenderMatchDetails(cfg MatchDetailsConfig) (headerContent, scrollableContent string)
RenderMatchDetails renders match details content, returning header and scrollable content separately. This unified function is used by both live and stats views.
func RenderMatchDetailsPanel ¶
func RenderMatchDetailsPanel(width, height int, details *api.MatchDetails) string
RenderMatchDetailsPanel is an exported version for debug scripts.
func RenderMultiPanelViewWithList ¶
func RenderMultiPanelViewWithList(width, height int, listModel list.Model, details *api.MatchDetails, liveUpdates []string, sp spinner.Model, loading bool, randomSpinner *RandomCharSpinner, viewLoading bool, leaguesLoaded int, totalLeagues int, pollingSpinner *RandomCharSpinner, isPolling bool, upcomingMatches []MatchDisplay, goalLinks GoalLinksMap, bannerType constants.StatusBannerType, lastError string) string
RenderMultiPanelViewWithList renders the live matches view with list component.
func RenderPlaceholderView ¶
func RenderPlaceholderView(width, height int, title, message, help string, bannerType constants.StatusBannerType) string
RenderPlaceholderView renders a simple sport-native placeholder screen.
func RenderSettingsView ¶
func RenderSettingsView(width, height int, state *SettingsState, bannerType constants.StatusBannerType) string
RenderSettingsView renders the settings view for league customization. Uses minimal styling consistent with the rest of the app (red/cyan neon theme). bannerType determines what status banner (if any) to display at the top.
func RenderSportSelector ¶
func RenderSportSelector(width, height, selected int, bannerType constants.StatusBannerType, animatedLogo *logo.AnimatedLogo) string
RenderSportSelector renders the first-run sport selection menu.
func RenderStatsListPanel ¶
func RenderStatsListPanel(width, height int, finishedList list.Model, dateRange int, rightPanelFocused bool) string
RenderStatsListPanel renders the left panel for stats view.
func RenderStatsViewWithList ¶
func RenderStatsViewWithList(width, height int, finishedList list.Model, details *api.MatchDetails, randomSpinner *RandomCharSpinner, viewLoading bool, dateRange int, daysLoaded int, totalDays int, goalLinks GoalLinksMap, bannerType constants.StatusBannerType, detailsViewport *viewport.Model, rightPanelFocused bool, scrollOffset int, lastError string) string
RenderStatsViewWithList renders the stats view with list component.
func SpinnerStyle ¶
SpinnerStyle returns the style for the spinner.
func SpinnerTick ¶
SpinnerTick returns a command that generates a TickMsg after the standard interval. This is the ONLY function that should create spinner ticks - ensures single tick chain.
func ToMatchListItems ¶
func ToMatchListItems(matches []MatchDisplay) []list.Item
ToMatchListItems converts a slice of MatchDisplay to list items.
Types ¶
type CricketSettingsState ¶
type CricketSettingsState struct {
Settings data.CricketSettings
Cursor int
Saved bool
Editing bool
EditRow int
EditText string
}
CricketSettingsState holds editable cricket-specific settings.
func NewCricketSettingsState ¶
func NewCricketSettingsState() *CricketSettingsState
NewCricketSettingsState loads cricket settings for the settings view.
func (*CricketSettingsState) Adjust ¶
func (s *CricketSettingsState) Adjust(delta int)
Adjust changes numeric settings on the selected row.
func (*CricketSettingsState) BackspaceEditText ¶
func (s *CricketSettingsState) BackspaceEditText()
BackspaceEditText removes the last byte from the active editor.
func (*CricketSettingsState) BeginEdit ¶
func (s *CricketSettingsState) BeginEdit()
BeginEdit starts text editing for list-style settings.
func (*CricketSettingsState) CancelEdit ¶
func (s *CricketSettingsState) CancelEdit()
CancelEdit exits the active text editor without applying changes.
func (*CricketSettingsState) CommitEdit ¶
func (s *CricketSettingsState) CommitEdit()
CommitEdit saves the active text editor into settings.
func (*CricketSettingsState) InsertEditText ¶
func (s *CricketSettingsState) InsertEditText(text string)
InsertEditText appends typed text to the active editor.
func (*CricketSettingsState) Move ¶
func (s *CricketSettingsState) Move(delta int)
Move moves the selected settings row.
func (*CricketSettingsState) Save ¶
func (s *CricketSettingsState) Save() error
Save persists cricket-specific settings without changing soccer settings.
func (*CricketSettingsState) Toggle ¶
func (s *CricketSettingsState) Toggle()
Toggle toggles a format row.
type Dialog ¶
type Dialog interface {
// ID returns the unique identifier of the dialog.
ID() string
// Update processes a message and returns the updated dialog and an optional action.
Update(msg tea.Msg) (Dialog, DialogAction)
// View renders the dialog content within the specified dimensions.
View(width, height int) string
}
Dialog is a component that can be displayed as an overlay on top of the UI.
type DialogAction ¶
type DialogAction any
DialogAction represents an action returned by a dialog after handling a message.
type DialogActionClose ¶
type DialogActionClose struct{}
DialogActionClose signals that the dialog should be closed.
type DialogOverlay ¶
type DialogOverlay struct {
// contains filtered or unexported fields
}
DialogOverlay manages multiple dialogs as an overlay stack.
func NewDialogOverlay ¶
func NewDialogOverlay() *DialogOverlay
NewDialogOverlay creates a new DialogOverlay instance.
func (*DialogOverlay) CloseDialog ¶
func (o *DialogOverlay) CloseDialog(dialogID string)
CloseDialog removes the dialog with the specified ID from the stack.
func (*DialogOverlay) CloseFrontDialog ¶
func (o *DialogOverlay) CloseFrontDialog()
CloseFrontDialog closes the front (topmost) dialog in the stack.
func (*DialogOverlay) ContainsDialog ¶
func (o *DialogOverlay) ContainsDialog(dialogID string) bool
ContainsDialog checks if a dialog with the specified ID exists.
func (*DialogOverlay) FrontDialog ¶
func (o *DialogOverlay) FrontDialog() Dialog
FrontDialog returns the front (topmost) dialog, or nil if there are no dialogs.
func (*DialogOverlay) HasDialogs ¶
func (o *DialogOverlay) HasDialogs() bool
HasDialogs checks if there are any active dialogs.
func (*DialogOverlay) OpenDialog ¶
func (o *DialogOverlay) OpenDialog(dialog Dialog)
OpenDialog adds a new dialog to the stack.
func (*DialogOverlay) Update ¶
func (o *DialogOverlay) Update(msg tea.Msg) DialogAction
Update handles message routing to the front dialog. Returns the action from the dialog, if any.
func (*DialogOverlay) View ¶
func (o *DialogOverlay) View(width, height int) string
View renders the overlay with the front dialog centered.
type FormationsDialog ¶
type FormationsDialog struct {
// contains filtered or unexported fields
}
FormationsDialog displays the match formations for both teams.
func NewFormationsDialog ¶
func NewFormationsDialog( homeTeam, awayTeam string, homeFormation, awayFormation string, homeStarting, awayStarting []api.PlayerInfo, ) *FormationsDialog
NewFormationsDialog creates a new formations dialog.
func (*FormationsDialog) ID ¶
func (d *FormationsDialog) ID() string
ID returns the dialog identifier.
func (*FormationsDialog) Update ¶
func (d *FormationsDialog) Update(msg tea.Msg) (Dialog, DialogAction)
Update handles input for the formations dialog.
func (*FormationsDialog) View ¶
func (d *FormationsDialog) View(width, height int) string
View renders the formations view.
type GoalLinksMap ¶
GoalLinksMap maps goal keys (matchID:minute) to replay URLs.
func (GoalLinksMap) GetReplayURL ¶
func (g GoalLinksMap) GetReplayURL(matchID, minute int) string
GetReplayURL returns the replay URL for a goal if available.
type LeagueListDelegate ¶
type LeagueListDelegate struct {
list.DefaultDelegate
}
LeagueListDelegate is a custom delegate that renders checkboxes separately from titles. This fixes the filter cursor positioning issue by keeping the checkbox out of the title.
func NewLeagueListDelegate ¶
func NewLeagueListDelegate() LeagueListDelegate
NewLeagueListDelegate creates a custom list delegate for league selection. Height is set to 2 to show league name (with checkbox) and country. Uses same red/cyan neon styling as match delegate for consistency. The checkbox is rendered separately from the title to fix filter cursor positioning.
func (LeagueListDelegate) HighlightMatches ¶
func (d LeagueListDelegate) HighlightMatches(text, filterValue string) string
HighlightMatches highlights matching text in the title using FilterMatch style.
type LeagueListItem ¶
type LeagueListItem struct {
League data.LeagueInfo
Selected bool
}
LeagueListItem implements the list.Item interface for league selection.
func (LeagueListItem) Description ¶
func (l LeagueListItem) Description() string
Description returns the country.
func (LeagueListItem) FilterValue ¶
func (l LeagueListItem) FilterValue() string
FilterValue returns the value used for filtering (league name + country).
func (LeagueListItem) Title ¶
func (l LeagueListItem) Title() string
Title returns the league name with selection indicator.
type MatchDetailsConfig ¶
type MatchDetailsConfig struct {
Width, Height int
Details *api.MatchDetails
GoalLinks GoalLinksMap
// View-specific features
ShowStatistics bool // Stats view only
ShowHighlights bool // Stats view only
// Live view state
LiveUpdates []string
PollingSpinner *RandomCharSpinner
IsPolling bool
Loading bool
// Stats view state
Focused bool
}
MatchDetailsConfig holds all parameters for rendering match details.
type MatchDisplay ¶
MatchDisplay wraps a match with display information for rendering.
func (MatchDisplay) Description ¶
func (m MatchDisplay) Description() string
Description returns a formatted description for the match. Shows score, league, live time on first line; KO time on second line.
func (MatchDisplay) Title ¶
func (m MatchDisplay) Title() string
Title returns a formatted title for the match.
type MatchListItem ¶
type MatchListItem struct {
Match api.Match
Display MatchDisplay
}
MatchListItem implements the list.Item interface for matches.
func (MatchListItem) Description ¶
func (m MatchListItem) Description() string
Description returns the match description for the list item.
func (MatchListItem) FilterValue ¶
func (m MatchListItem) FilterValue() string
FilterValue returns the value to use for filtering. Returns team names for searching (e.g., "Arsenal vs Chelsea").
func (MatchListItem) Title ¶
func (m MatchListItem) Title() string
Title returns the match title for the list item.
type RandomCharSpinner ¶
type RandomCharSpinner struct {
// contains filtered or unexported fields
}
RandomCharSpinner is a custom spinner that displays a wave of random characters. Note: Spinners do NOT self-tick. The app manages the tick chain centrally.
func NewRandomCharSpinner ¶
func NewRandomCharSpinner() *RandomCharSpinner
NewRandomCharSpinner creates a new random character spinner.
func (*RandomCharSpinner) SetWidth ¶
func (r *RandomCharSpinner) SetWidth(width int)
SetWidth sets the width of the spinner and resizes the display buffer.
func (*RandomCharSpinner) Tick ¶
func (r *RandomCharSpinner) Tick()
Tick advances the spinner animation - randomizes all characters for trendy effect. Does NOT return a tick command - the app manages the tick chain.
func (*RandomCharSpinner) View ¶
func (r *RandomCharSpinner) View() string
View renders the spinner with gradient colors.
type SettingsState ¶
type SettingsState struct {
List list.Model // List component for league navigation
Selected map[int]bool // Map of league ID -> selected
Leagues []data.LeagueInfo // All leagues for current region
AllLeagues []data.LeagueInfo // All leagues across all regions
Regions []string // Available regions
CurrentRegion int // Index of current region
HasChanges bool // Whether there are unsaved changes
}
SettingsState holds the state for the settings view.
func NewSettingsState ¶
func NewSettingsState() *SettingsState
NewSettingsState creates a new settings state with current saved preferences.
func (*SettingsState) NextRegion ¶
func (s *SettingsState) NextRegion()
NextRegion switches to the next region (with wraparound).
func (*SettingsState) PreviousRegion ¶
func (s *SettingsState) PreviousRegion()
PreviousRegion switches to the previous region (with wraparound).
func (*SettingsState) Save ¶
func (s *SettingsState) Save() error
Save persists the current selection to settings.yaml.
func (*SettingsState) SelectedCount ¶
func (s *SettingsState) SelectedCount() int
SelectedCount returns the number of selected leagues.
func (*SettingsState) Toggle ¶
func (s *SettingsState) Toggle()
Toggle toggles the selection state of the currently highlighted league.
type StandingsDialog ¶
type StandingsDialog struct {
// contains filtered or unexported fields
}
StandingsDialog displays the league standings table for a match.
func NewStandingsDialog ¶
func NewStandingsDialog(leagueName string, standings []api.LeagueTableEntry, homeTeamID, awayTeamID int) *StandingsDialog
NewStandingsDialog creates a new standings dialog.
func (*StandingsDialog) ID ¶
func (d *StandingsDialog) ID() string
ID returns the dialog identifier.
func (*StandingsDialog) Update ¶
func (d *StandingsDialog) Update(msg tea.Msg) (Dialog, DialogAction)
Update handles input for the standings dialog.
func (*StandingsDialog) View ¶
func (d *StandingsDialog) View(width, height int) string
View renders the standings table.
type StatisticsDialog ¶
type StatisticsDialog struct {
// contains filtered or unexported fields
}
StatisticsDialog displays all match statistics in a comparison view.
func NewStatisticsDialog ¶
func NewStatisticsDialog(homeTeam, awayTeam string, homeScore, awayScore int, statistics []api.MatchStatistic) *StatisticsDialog
NewStatisticsDialog creates a new statistics dialog.
func (*StatisticsDialog) ID ¶
func (d *StatisticsDialog) ID() string
ID returns the dialog identifier.
func (*StatisticsDialog) Update ¶
func (d *StatisticsDialog) Update(msg tea.Msg) (Dialog, DialogAction)
Update handles input for the statistics dialog.
func (*StatisticsDialog) View ¶
func (d *StatisticsDialog) View(width, height int) string
View renders the statistics comparison.
Source Files
¶
- colors.go
- cricket_archives.go
- cricket_live.go
- cricket_settings.go
- dialog.go
- dialog_formations.go
- dialog_standings.go
- dialog_statistics.go
- dialog_styles.go
- hyperlink.go
- list_delegate.go
- list_items.go
- list_panels.go
- match_details.go
- matches.go
- menu.go
- neon_styles.go
- panels.go
- parse.go
- placeholder.go
- random_spinner.go
- settings.go
- spinner.go
- ui.go