Files
porthole/internal/ui/styles.go
OpenCode Test 1421b4659e feat: implement ControlTower TUI for cluster and host monitoring
Add complete TUI application for monitoring Kubernetes clusters and host
systems. Features include:

Core features:
- Collector framework with concurrent scheduling
- Host collectors: disk, memory, load, network
- Kubernetes collectors: pods, nodes, workloads, events with informers
- Issue deduplication, state management, and resolve-after logic
- Bubble Tea TUI with table view, details pane, and filtering
- JSON export functionality

UX improvements:
- Help overlay with keybindings
- Priority/category filters with visual indicators
- Direct priority jump (0/1/2/3)
- Bulk acknowledge (Shift+A)
- Clipboard copy (y)
- Theme toggle (T)
- Age format toggle (d)
- Wide title toggle (t)
- Vi-style navigation (j/k)
- Home/End jump (g/G)
- Rollup drill-down in details

Robustness:
- Grace period for unreachable clusters
- Rollups for high-volume issues
- Flap suppression
- RBAC error handling

Files: All core application code with tests for host collectors,
engine, store, model, and export packages.
2025-12-24 13:29:51 -08:00

123 lines
3.3 KiB
Go

package ui
import "github.com/charmbracelet/lipgloss"
// ThemeMode represents the UI theme mode.
type ThemeMode int
const (
ThemeAuto ThemeMode = iota
ThemeLight
ThemeDark
)
// Styles centralizes all lipgloss styling.
// Keep these simple: excessive styling can slow rendering at high row counts.
type Styles struct {
HeaderBar lipgloss.Style
HeaderKey lipgloss.Style
HeaderVal lipgloss.Style
FilterActive lipgloss.Style
TableHeader lipgloss.Style
TableCell lipgloss.Style
P0 lipgloss.Style
P1 lipgloss.Style
P2 lipgloss.Style
P3 lipgloss.Style
StateOpen lipgloss.Style
StateAck lipgloss.Style
StateRes lipgloss.Style
DetailsTitle lipgloss.Style
DetailsBody lipgloss.Style
Muted lipgloss.Style
Error lipgloss.Style
}
// LightTheme returns light theme styles.
func LightTheme() Styles {
base := lipgloss.NewStyle()
muted := base.Foreground(lipgloss.Color("8"))
return Styles{
HeaderBar: base.
Background(lipgloss.Color("236")).
Foreground(lipgloss.Color("252")).
Padding(0, 1),
HeaderKey: base.Foreground(lipgloss.Color("250")).Bold(true),
HeaderVal: base.Foreground(lipgloss.Color("254")),
FilterActive: base.Bold(true).Foreground(lipgloss.Color("46")),
TableHeader: base.Foreground(lipgloss.Color("252")).Bold(true),
TableCell: base.Foreground(lipgloss.Color("252")),
P0: base.Foreground(lipgloss.Color("9")).Bold(true),
P1: base.Foreground(lipgloss.Color("208")).Bold(true),
P2: base.Foreground(lipgloss.Color("11")),
P3: base.Foreground(lipgloss.Color("10")),
StateOpen: base.Foreground(lipgloss.Color("252")),
StateAck: base.Foreground(lipgloss.Color("14")),
StateRes: muted,
DetailsTitle: base.Bold(true).Foreground(lipgloss.Color("252")),
DetailsBody: base.Foreground(lipgloss.Color("252")),
Muted: muted,
Error: base.Foreground(lipgloss.Color("9")),
}
}
// DarkTheme returns dark theme styles with better contrast.
func DarkTheme() Styles {
base := lipgloss.NewStyle()
muted := base.Foreground(lipgloss.Color("245"))
return Styles{
HeaderBar: base.
Background(lipgloss.Color("238")).
Foreground(lipgloss.Color("231")).
Padding(0, 1),
HeaderKey: base.Foreground(lipgloss.Color("159")).Bold(true),
HeaderVal: base.Foreground(lipgloss.Color("231")),
FilterActive: base.Bold(true).Foreground(lipgloss.Color("84")),
TableHeader: base.Foreground(lipgloss.Color("231")).Bold(true),
TableCell: base.Foreground(lipgloss.Color("231")),
P0: base.Foreground(lipgloss.Color("203")).Bold(true),
P1: base.Foreground(lipgloss.Color("229")).Bold(true),
P2: base.Foreground(lipgloss.Color("48")),
P3: base.Foreground(lipgloss.Color("42")),
StateOpen: base.Foreground(lipgloss.Color("231")),
StateAck: base.Foreground(lipgloss.Color("48")),
StateRes: muted,
DetailsTitle: base.Bold(true).Foreground(lipgloss.Color("231")),
DetailsBody: base.Foreground(lipgloss.Color("231")),
Muted: muted,
Error: base.Foreground(lipgloss.Color("203")),
}
}
func defaultStyles() Styles {
// Default to light theme for backwards compatibility
return LightTheme()
}
func defaultStylesForMode(themeMode ThemeMode) Styles {
switch themeMode {
case ThemeLight:
return LightTheme()
case ThemeDark:
return DarkTheme()
default:
// Auto mode defaults to light theme
return LightTheme()
}
}