248 lines
6.8 KiB
Go
248 lines
6.8 KiB
Go
package theme
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
// Theme represents the visual styling for the TUI
|
|
type Theme struct {
|
|
Name string
|
|
Styles Styles
|
|
}
|
|
|
|
// Styles contains all the styling definitions
|
|
type Styles struct {
|
|
Header lipgloss.Style
|
|
Border lipgloss.Style
|
|
Selected lipgloss.Style
|
|
Watched lipgloss.Style
|
|
Normal lipgloss.Style
|
|
Error lipgloss.Style
|
|
Success lipgloss.Style
|
|
Warning lipgloss.Style
|
|
Proto ProtoStyles
|
|
State StateStyles
|
|
Footer lipgloss.Style
|
|
Background lipgloss.Style
|
|
}
|
|
|
|
// ProtoStyles contains protocol-specific colors
|
|
type ProtoStyles struct {
|
|
TCP lipgloss.Style
|
|
UDP lipgloss.Style
|
|
Unix lipgloss.Style
|
|
TCP6 lipgloss.Style
|
|
UDP6 lipgloss.Style
|
|
}
|
|
|
|
// StateStyles contains connection state-specific colors
|
|
type StateStyles struct {
|
|
Listen lipgloss.Style
|
|
Established lipgloss.Style
|
|
TimeWait lipgloss.Style
|
|
CloseWait lipgloss.Style
|
|
SynSent lipgloss.Style
|
|
SynRecv lipgloss.Style
|
|
FinWait1 lipgloss.Style
|
|
FinWait2 lipgloss.Style
|
|
Closing lipgloss.Style
|
|
LastAck lipgloss.Style
|
|
Closed lipgloss.Style
|
|
}
|
|
|
|
var (
|
|
themes map[string]*Theme
|
|
)
|
|
|
|
func init() {
|
|
themes = map[string]*Theme{
|
|
"default": createAdaptiveTheme(),
|
|
"mono": createMonoTheme(),
|
|
}
|
|
}
|
|
|
|
// GetTheme returns a theme by name, with auto-detection support
|
|
func GetTheme(name string) *Theme {
|
|
if name == "auto" {
|
|
// lipgloss handles adaptive colors, so we just return the default
|
|
return themes["default"]
|
|
}
|
|
|
|
if theme, exists := themes[name]; exists {
|
|
return theme
|
|
}
|
|
|
|
// a specific theme was requested (e.g. "dark", "light"), but we now use adaptive
|
|
// so we can just return the default theme and lipgloss will handle it
|
|
if name == "dark" || name == "light" {
|
|
return themes["default"]
|
|
}
|
|
|
|
// fallback to default
|
|
return themes["default"]
|
|
}
|
|
|
|
// ListThemes returns available theme names
|
|
func ListThemes() []string {
|
|
var names []string
|
|
for name := range themes {
|
|
names = append(names, name)
|
|
}
|
|
return names
|
|
}
|
|
|
|
// createAdaptiveTheme creates a clean, minimal theme
|
|
func createAdaptiveTheme() *Theme {
|
|
return &Theme{
|
|
Name: "default",
|
|
Styles: Styles{
|
|
Header: lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.AdaptiveColor{Light: "#1F2937", Dark: "#F9FAFB"}),
|
|
|
|
Watched: lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.AdaptiveColor{Light: "#D97706", Dark: "#F59E0B"}),
|
|
|
|
Border: lipgloss.NewStyle().
|
|
Foreground(lipgloss.AdaptiveColor{Light: "#D1D5DB", Dark: "#374151"}),
|
|
|
|
Selected: lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.AdaptiveColor{Light: "#1F2937", Dark: "#F9FAFB"}),
|
|
|
|
Normal: lipgloss.NewStyle().
|
|
Foreground(lipgloss.AdaptiveColor{Light: "#6B7280", Dark: "#9CA3AF"}),
|
|
|
|
Error: lipgloss.NewStyle().
|
|
Foreground(lipgloss.AdaptiveColor{Light: "#DC2626", Dark: "#F87171"}),
|
|
|
|
Success: lipgloss.NewStyle().
|
|
Foreground(lipgloss.AdaptiveColor{Light: "#059669", Dark: "#34D399"}),
|
|
|
|
Warning: lipgloss.NewStyle().
|
|
Foreground(lipgloss.AdaptiveColor{Light: "#D97706", Dark: "#FBBF24"}),
|
|
|
|
Footer: lipgloss.NewStyle().
|
|
Foreground(lipgloss.AdaptiveColor{Light: "#9CA3AF", Dark: "#6B7280"}),
|
|
|
|
Background: lipgloss.NewStyle(),
|
|
|
|
Proto: ProtoStyles{
|
|
TCP: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#059669", Dark: "#34D399"}),
|
|
UDP: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#7C3AED", Dark: "#A78BFA"}),
|
|
Unix: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#6B7280", Dark: "#9CA3AF"}),
|
|
TCP6: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#059669", Dark: "#34D399"}),
|
|
UDP6: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#7C3AED", Dark: "#A78BFA"}),
|
|
},
|
|
|
|
State: StateStyles{
|
|
Listen: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#059669", Dark: "#34D399"}),
|
|
Established: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#2563EB", Dark: "#60A5FA"}),
|
|
TimeWait: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#D97706", Dark: "#FBBF24"}),
|
|
CloseWait: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#D97706", Dark: "#FBBF24"}),
|
|
SynSent: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#7C3AED", Dark: "#A78BFA"}),
|
|
SynRecv: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#7C3AED", Dark: "#A78BFA"}),
|
|
FinWait1: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#DC2626", Dark: "#F87171"}),
|
|
FinWait2: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#DC2626", Dark: "#F87171"}),
|
|
Closing: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#DC2626", Dark: "#F87171"}),
|
|
LastAck: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#DC2626", Dark: "#F87171"}),
|
|
Closed: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#9CA3AF", Dark: "#6B7280"}),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// createMonoTheme creates a monochrome theme (no colors)
|
|
func createMonoTheme() *Theme {
|
|
baseStyle := lipgloss.NewStyle()
|
|
boldStyle := lipgloss.NewStyle().Bold(true)
|
|
|
|
return &Theme{
|
|
Name: "mono",
|
|
Styles: Styles{
|
|
Header: boldStyle,
|
|
Border: baseStyle,
|
|
Selected: boldStyle,
|
|
Normal: baseStyle,
|
|
Error: boldStyle,
|
|
Success: boldStyle,
|
|
Warning: boldStyle,
|
|
Footer: baseStyle,
|
|
Background: baseStyle,
|
|
|
|
Proto: ProtoStyles{
|
|
TCP: baseStyle,
|
|
UDP: baseStyle,
|
|
Unix: baseStyle,
|
|
TCP6: baseStyle,
|
|
UDP6: baseStyle,
|
|
},
|
|
|
|
State: StateStyles{
|
|
Listen: baseStyle,
|
|
Established: baseStyle,
|
|
TimeWait: baseStyle,
|
|
CloseWait: baseStyle,
|
|
SynSent: baseStyle,
|
|
SynRecv: baseStyle,
|
|
FinWait1: baseStyle,
|
|
FinWait2: baseStyle,
|
|
Closing: baseStyle,
|
|
LastAck: baseStyle,
|
|
Closed: baseStyle,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// GetProtoStyle returns the appropriate style for a protocol
|
|
func (s *Styles) GetProtoStyle(proto string) lipgloss.Style {
|
|
switch strings.ToLower(proto) {
|
|
case "tcp":
|
|
return s.Proto.TCP
|
|
case "udp":
|
|
return s.Proto.UDP
|
|
case "unix":
|
|
return s.Proto.Unix
|
|
case "tcp6":
|
|
return s.Proto.TCP6
|
|
case "udp6":
|
|
return s.Proto.UDP6
|
|
default:
|
|
return s.Normal
|
|
}
|
|
}
|
|
|
|
// GetStateStyle returns the appropriate style for a connection state
|
|
func (s *Styles) GetStateStyle(state string) lipgloss.Style {
|
|
switch strings.ToUpper(state) {
|
|
case "LISTEN":
|
|
return s.State.Listen
|
|
case "ESTABLISHED":
|
|
return s.State.Established
|
|
case "TIME_WAIT":
|
|
return s.State.TimeWait
|
|
case "CLOSE_WAIT":
|
|
return s.State.CloseWait
|
|
case "SYN_SENT":
|
|
return s.State.SynSent
|
|
case "SYN_RECV":
|
|
return s.State.SynRecv
|
|
case "FIN_WAIT1":
|
|
return s.State.FinWait1
|
|
case "FIN_WAIT2":
|
|
return s.State.FinWait2
|
|
case "CLOSING":
|
|
return s.State.Closing
|
|
case "LAST_ACK":
|
|
return s.State.LastAck
|
|
case "CLOSED":
|
|
return s.State.Closed
|
|
default:
|
|
return s.Normal
|
|
}
|
|
}
|