feat: introduce theme management and performance improvements (#7)
This commit is contained in:
24
internal/theme/ansi.go
Normal file
24
internal/theme/ansi.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package theme
|
||||
|
||||
// ANSI palette uses standard terminal colors (0-15)
|
||||
// this allows the theme to inherit from the user's terminal color scheme
|
||||
var paletteANSI = Palette{
|
||||
Name: "ansi",
|
||||
|
||||
Fg: "15", // bright white
|
||||
FgMuted: "7", // white
|
||||
FgSubtle: "8", // bright black (gray)
|
||||
Bg: "0", // black
|
||||
BgMuted: "0", // black
|
||||
Border: "8", // bright black (gray)
|
||||
|
||||
Red: "1", // red
|
||||
Green: "2", // green
|
||||
Yellow: "3", // yellow
|
||||
Blue: "4", // blue
|
||||
Magenta: "5", // magenta
|
||||
Cyan: "6", // cyan
|
||||
Orange: "3", // yellow (ansi has no orange, fallback to yellow)
|
||||
Gray: "8", // bright black
|
||||
}
|
||||
|
||||
87
internal/theme/catppuccin.go
Normal file
87
internal/theme/catppuccin.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package theme
|
||||
|
||||
// catppuccin mocha (dark)
|
||||
// https://github.com/catppuccin/catppuccin
|
||||
var paletteCatppuccinMocha = Palette{
|
||||
Name: "catppuccin-mocha",
|
||||
|
||||
Fg: "#cdd6f4", // text
|
||||
FgMuted: "#a6adc8", // subtext0
|
||||
FgSubtle: "#6c7086", // overlay0
|
||||
Bg: "#1e1e2e", // base
|
||||
BgMuted: "#313244", // surface0
|
||||
Border: "#45475a", // surface1
|
||||
|
||||
Red: "#f38ba8",
|
||||
Green: "#a6e3a1",
|
||||
Yellow: "#f9e2af",
|
||||
Blue: "#89b4fa",
|
||||
Magenta: "#cba6f7", // mauve
|
||||
Cyan: "#94e2d5", // teal
|
||||
Orange: "#fab387", // peach
|
||||
Gray: "#585b70", // surface2
|
||||
}
|
||||
|
||||
// catppuccin macchiato (medium-dark)
|
||||
var paletteCatppuccinMacchiato = Palette{
|
||||
Name: "catppuccin-macchiato",
|
||||
|
||||
Fg: "#cad3f5", // text
|
||||
FgMuted: "#a5adcb", // subtext0
|
||||
FgSubtle: "#6e738d", // overlay0
|
||||
Bg: "#24273a", // base
|
||||
BgMuted: "#363a4f", // surface0
|
||||
Border: "#494d64", // surface1
|
||||
|
||||
Red: "#ed8796",
|
||||
Green: "#a6da95",
|
||||
Yellow: "#eed49f",
|
||||
Blue: "#8aadf4",
|
||||
Magenta: "#c6a0f6", // mauve
|
||||
Cyan: "#8bd5ca", // teal
|
||||
Orange: "#f5a97f", // peach
|
||||
Gray: "#5b6078", // surface2
|
||||
}
|
||||
|
||||
// catppuccin frappe (medium)
|
||||
var paletteCatppuccinFrappe = Palette{
|
||||
Name: "catppuccin-frappe",
|
||||
|
||||
Fg: "#c6d0f5", // text
|
||||
FgMuted: "#a5adce", // subtext0
|
||||
FgSubtle: "#737994", // overlay0
|
||||
Bg: "#303446", // base
|
||||
BgMuted: "#414559", // surface0
|
||||
Border: "#51576d", // surface1
|
||||
|
||||
Red: "#e78284",
|
||||
Green: "#a6d189",
|
||||
Yellow: "#e5c890",
|
||||
Blue: "#8caaee",
|
||||
Magenta: "#ca9ee6", // mauve
|
||||
Cyan: "#81c8be", // teal
|
||||
Orange: "#ef9f76", // peach
|
||||
Gray: "#626880", // surface2
|
||||
}
|
||||
|
||||
// catppuccin latte (light)
|
||||
var paletteCatppuccinLatte = Palette{
|
||||
Name: "catppuccin-latte",
|
||||
|
||||
Fg: "#4c4f69", // text
|
||||
FgMuted: "#6c6f85", // subtext0
|
||||
FgSubtle: "#9ca0b0", // overlay0
|
||||
Bg: "#eff1f5", // base
|
||||
BgMuted: "#ccd0da", // surface0
|
||||
Border: "#bcc0cc", // surface1
|
||||
|
||||
Red: "#d20f39",
|
||||
Green: "#40a02b",
|
||||
Yellow: "#df8e1d",
|
||||
Blue: "#1e66f5",
|
||||
Magenta: "#8839ef", // mauve
|
||||
Cyan: "#179299", // teal
|
||||
Orange: "#fe640b", // peach
|
||||
Gray: "#acb0be", // surface2
|
||||
}
|
||||
|
||||
24
internal/theme/dracula.go
Normal file
24
internal/theme/dracula.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package theme
|
||||
|
||||
// dracula theme
|
||||
// https://draculatheme.com/
|
||||
var paletteDracula = Palette{
|
||||
Name: "dracula",
|
||||
|
||||
Fg: "#f8f8f2", // foreground
|
||||
FgMuted: "#f8f8f2", // foreground
|
||||
FgSubtle: "#6272a4", // comment
|
||||
Bg: "#282a36", // background
|
||||
BgMuted: "#44475a", // selection
|
||||
Border: "#44475a", // selection
|
||||
|
||||
Red: "#ff5555",
|
||||
Green: "#50fa7b",
|
||||
Yellow: "#f1fa8c",
|
||||
Blue: "#6272a4", // dracula uses comment color for blue tones
|
||||
Magenta: "#bd93f9", // purple
|
||||
Cyan: "#8be9fd",
|
||||
Orange: "#ffb86c",
|
||||
Gray: "#6272a4", // comment
|
||||
}
|
||||
|
||||
45
internal/theme/gruvbox.go
Normal file
45
internal/theme/gruvbox.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package theme
|
||||
|
||||
// gruvbox dark
|
||||
// https://github.com/morhetz/gruvbox
|
||||
var paletteGruvboxDark = Palette{
|
||||
Name: "gruvbox-dark",
|
||||
|
||||
Fg: "#ebdbb2", // fg
|
||||
FgMuted: "#d5c4a1", // fg2
|
||||
FgSubtle: "#a89984", // fg4
|
||||
Bg: "#282828", // bg
|
||||
BgMuted: "#3c3836", // bg1
|
||||
Border: "#504945", // bg2
|
||||
|
||||
Red: "#fb4934",
|
||||
Green: "#b8bb26",
|
||||
Yellow: "#fabd2f",
|
||||
Blue: "#83a598",
|
||||
Magenta: "#d3869b", // purple
|
||||
Cyan: "#8ec07c", // aqua
|
||||
Orange: "#fe8019",
|
||||
Gray: "#928374",
|
||||
}
|
||||
|
||||
// gruvbox light
|
||||
var paletteGruvboxLight = Palette{
|
||||
Name: "gruvbox-light",
|
||||
|
||||
Fg: "#3c3836", // fg
|
||||
FgMuted: "#504945", // fg2
|
||||
FgSubtle: "#7c6f64", // fg4
|
||||
Bg: "#fbf1c7", // bg
|
||||
BgMuted: "#ebdbb2", // bg1
|
||||
Border: "#d5c4a1", // bg2
|
||||
|
||||
Red: "#cc241d",
|
||||
Green: "#98971a",
|
||||
Yellow: "#d79921",
|
||||
Blue: "#458588",
|
||||
Magenta: "#b16286", // purple
|
||||
Cyan: "#689d6a", // aqua
|
||||
Orange: "#d65d0e",
|
||||
Gray: "#928374",
|
||||
}
|
||||
|
||||
49
internal/theme/mono.go
Normal file
49
internal/theme/mono.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package theme
|
||||
|
||||
import "github.com/charmbracelet/lipgloss"
|
||||
|
||||
// createMonoTheme creates a monochrome theme (no colors)
|
||||
// useful for accessibility, piping output, or minimal terminals
|
||||
func createMonoTheme() *Theme {
|
||||
baseStyle := lipgloss.NewStyle()
|
||||
boldStyle := lipgloss.NewStyle().Bold(true)
|
||||
|
||||
return &Theme{
|
||||
Name: "mono",
|
||||
Styles: Styles{
|
||||
Header: boldStyle,
|
||||
Border: baseStyle,
|
||||
Selected: boldStyle,
|
||||
Watched: 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,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
24
internal/theme/nord.go
Normal file
24
internal/theme/nord.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package theme
|
||||
|
||||
// nord theme
|
||||
// https://www.nordtheme.com/
|
||||
var paletteNord = Palette{
|
||||
Name: "nord",
|
||||
|
||||
Fg: "#eceff4", // snow storm - nord6
|
||||
FgMuted: "#d8dee9", // snow storm - nord4
|
||||
FgSubtle: "#4c566a", // polar night - nord3
|
||||
Bg: "#2e3440", // polar night - nord0
|
||||
BgMuted: "#3b4252", // polar night - nord1
|
||||
Border: "#434c5e", // polar night - nord2
|
||||
|
||||
Red: "#bf616a", // aurora - nord11
|
||||
Green: "#a3be8c", // aurora - nord14
|
||||
Yellow: "#ebcb8b", // aurora - nord13
|
||||
Blue: "#81a1c1", // frost - nord9
|
||||
Magenta: "#b48ead", // aurora - nord15
|
||||
Cyan: "#88c0d0", // frost - nord8
|
||||
Orange: "#d08770", // aurora - nord12
|
||||
Gray: "#4c566a", // polar night - nord3
|
||||
}
|
||||
|
||||
24
internal/theme/one_dark.go
Normal file
24
internal/theme/one_dark.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package theme
|
||||
|
||||
// one dark theme (atom editor)
|
||||
// https://github.com/atom/atom/tree/master/packages/one-dark-syntax
|
||||
var paletteOneDark = Palette{
|
||||
Name: "one-dark",
|
||||
|
||||
Fg: "#abb2bf", // foreground
|
||||
FgMuted: "#9da5b4", // foreground muted
|
||||
FgSubtle: "#5c6370", // comment
|
||||
Bg: "#282c34", // background
|
||||
BgMuted: "#21252b", // gutter background
|
||||
Border: "#3e4451", // selection
|
||||
|
||||
Red: "#e06c75",
|
||||
Green: "#98c379",
|
||||
Yellow: "#e5c07b",
|
||||
Blue: "#61afef",
|
||||
Magenta: "#c678dd", // purple
|
||||
Cyan: "#56b6c2",
|
||||
Orange: "#d19a66",
|
||||
Gray: "#5c6370", // comment
|
||||
}
|
||||
|
||||
111
internal/theme/palette.go
Normal file
111
internal/theme/palette.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package theme
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
// Palette defines the semantic colors for a theme
|
||||
type Palette struct {
|
||||
Name string
|
||||
|
||||
// base colors
|
||||
Fg string // primary foreground
|
||||
FgMuted string // secondary/muted foreground
|
||||
FgSubtle string // subtle/disabled foreground
|
||||
Bg string // primary background
|
||||
BgMuted string // secondary background (selections, highlights)
|
||||
Border string // border color
|
||||
|
||||
// semantic colors
|
||||
Red string
|
||||
Green string
|
||||
Yellow string
|
||||
Blue string
|
||||
Magenta string
|
||||
Cyan string
|
||||
Orange string
|
||||
Gray string
|
||||
}
|
||||
|
||||
// Color converts a palette color string to a lipgloss.TerminalColor.
|
||||
// If the string is 1-2 characters, it's treated as an ANSI color code.
|
||||
// Otherwise, it's treated as a hex color.
|
||||
func (p *Palette) Color(c string) lipgloss.TerminalColor {
|
||||
if c == "" {
|
||||
return lipgloss.NoColor{}
|
||||
}
|
||||
|
||||
if len(c) <= 2 {
|
||||
n, err := strconv.Atoi(c)
|
||||
if err == nil {
|
||||
return lipgloss.ANSIColor(n)
|
||||
}
|
||||
}
|
||||
|
||||
return lipgloss.Color(c)
|
||||
}
|
||||
|
||||
// ToTheme converts a Palette to a Theme with lipgloss styles
|
||||
func (p *Palette) ToTheme() *Theme {
|
||||
return &Theme{
|
||||
Name: p.Name,
|
||||
Styles: Styles{
|
||||
Header: lipgloss.NewStyle().
|
||||
Bold(true).
|
||||
Foreground(p.Color(p.Fg)),
|
||||
|
||||
Border: lipgloss.NewStyle().
|
||||
Foreground(p.Color(p.Border)),
|
||||
|
||||
Selected: lipgloss.NewStyle().
|
||||
Bold(true).
|
||||
Foreground(p.Color(p.Fg)),
|
||||
|
||||
Watched: lipgloss.NewStyle().
|
||||
Bold(true).
|
||||
Foreground(p.Color(p.Orange)),
|
||||
|
||||
Normal: lipgloss.NewStyle().
|
||||
Foreground(p.Color(p.FgMuted)),
|
||||
|
||||
Error: lipgloss.NewStyle().
|
||||
Foreground(p.Color(p.Red)),
|
||||
|
||||
Success: lipgloss.NewStyle().
|
||||
Foreground(p.Color(p.Green)),
|
||||
|
||||
Warning: lipgloss.NewStyle().
|
||||
Foreground(p.Color(p.Yellow)),
|
||||
|
||||
Footer: lipgloss.NewStyle().
|
||||
Foreground(p.Color(p.FgSubtle)),
|
||||
|
||||
Background: lipgloss.NewStyle(),
|
||||
|
||||
Proto: ProtoStyles{
|
||||
TCP: lipgloss.NewStyle().Foreground(p.Color(p.Green)),
|
||||
UDP: lipgloss.NewStyle().Foreground(p.Color(p.Magenta)),
|
||||
Unix: lipgloss.NewStyle().Foreground(p.Color(p.Gray)),
|
||||
TCP6: lipgloss.NewStyle().Foreground(p.Color(p.Cyan)),
|
||||
UDP6: lipgloss.NewStyle().Foreground(p.Color(p.Blue)),
|
||||
},
|
||||
|
||||
State: StateStyles{
|
||||
Listen: lipgloss.NewStyle().Foreground(p.Color(p.Green)),
|
||||
Established: lipgloss.NewStyle().Foreground(p.Color(p.Blue)),
|
||||
TimeWait: lipgloss.NewStyle().Foreground(p.Color(p.Yellow)),
|
||||
CloseWait: lipgloss.NewStyle().Foreground(p.Color(p.Orange)),
|
||||
SynSent: lipgloss.NewStyle().Foreground(p.Color(p.Magenta)),
|
||||
SynRecv: lipgloss.NewStyle().Foreground(p.Color(p.Magenta)),
|
||||
FinWait1: lipgloss.NewStyle().Foreground(p.Color(p.Red)),
|
||||
FinWait2: lipgloss.NewStyle().Foreground(p.Color(p.Red)),
|
||||
Closing: lipgloss.NewStyle().Foreground(p.Color(p.Red)),
|
||||
LastAck: lipgloss.NewStyle().Foreground(p.Color(p.Red)),
|
||||
Closed: lipgloss.NewStyle().Foreground(p.Color(p.Gray)),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
14
internal/theme/readme.md
Normal file
14
internal/theme/readme.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# theme Palettes
|
||||
|
||||
the color palettes in this directory were generated by an LLM agent (Claude Opus 4.5) using web search to fetch the official color specifications from each themes documentation
|
||||
as it is with llm agents its possible the colors may be wrong
|
||||
|
||||
Sources:
|
||||
- [Catppuccin](https://github.com/catppuccin/catppuccin)
|
||||
- [Dracula](https://draculatheme.com/)
|
||||
- [Gruvbox](https://github.com/morhetz/gruvbox)
|
||||
- [Nord](https://www.nordtheme.com/)
|
||||
- [One Dark](https://github.com/atom/one-dark-syntax)
|
||||
- [Solarized](https://ethanschoonover.com/solarized/)
|
||||
- [Tokyo Night](https://github.com/enkia/tokyo-night-vscode-theme)
|
||||
|
||||
45
internal/theme/solarized.go
Normal file
45
internal/theme/solarized.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package theme
|
||||
|
||||
// solarized dark theme
|
||||
// https://ethanschoonover.com/solarized/
|
||||
var paletteSolarizedDark = Palette{
|
||||
Name: "solarized-dark",
|
||||
|
||||
Fg: "#839496", // base0
|
||||
FgMuted: "#93a1a1", // base1
|
||||
FgSubtle: "#586e75", // base01
|
||||
Bg: "#002b36", // base03
|
||||
BgMuted: "#073642", // base02
|
||||
Border: "#073642", // base02
|
||||
|
||||
Red: "#dc322f",
|
||||
Green: "#859900",
|
||||
Yellow: "#b58900",
|
||||
Blue: "#268bd2",
|
||||
Magenta: "#d33682",
|
||||
Cyan: "#2aa198",
|
||||
Orange: "#cb4b16",
|
||||
Gray: "#657b83", // base00
|
||||
}
|
||||
|
||||
// solarized light theme
|
||||
var paletteSolarizedLight = Palette{
|
||||
Name: "solarized-light",
|
||||
|
||||
Fg: "#657b83", // base00
|
||||
FgMuted: "#586e75", // base01
|
||||
FgSubtle: "#93a1a1", // base1
|
||||
Bg: "#fdf6e3", // base3
|
||||
BgMuted: "#eee8d5", // base2
|
||||
Border: "#eee8d5", // base2
|
||||
|
||||
Red: "#dc322f",
|
||||
Green: "#859900",
|
||||
Yellow: "#b58900",
|
||||
Blue: "#268bd2",
|
||||
Magenta: "#d33682",
|
||||
Cyan: "#2aa198",
|
||||
Orange: "#cb4b16",
|
||||
Gray: "#839496", // base0
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package theme
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
@@ -52,152 +53,73 @@ type StateStyles struct {
|
||||
Closed lipgloss.Style
|
||||
}
|
||||
|
||||
var (
|
||||
themes map[string]*Theme
|
||||
)
|
||||
var themes map[string]*Theme
|
||||
|
||||
func init() {
|
||||
themes = map[string]*Theme{
|
||||
"default": createAdaptiveTheme(),
|
||||
"mono": createMonoTheme(),
|
||||
}
|
||||
themes = make(map[string]*Theme)
|
||||
|
||||
// ansi theme (default) - inherits from terminal colors
|
||||
themes["ansi"] = paletteANSI.ToTheme()
|
||||
|
||||
// catppuccin variants
|
||||
themes["catppuccin-mocha"] = paletteCatppuccinMocha.ToTheme()
|
||||
themes["catppuccin-macchiato"] = paletteCatppuccinMacchiato.ToTheme()
|
||||
themes["catppuccin-frappe"] = paletteCatppuccinFrappe.ToTheme()
|
||||
themes["catppuccin-latte"] = paletteCatppuccinLatte.ToTheme()
|
||||
|
||||
// gruvbox variants
|
||||
themes["gruvbox-dark"] = paletteGruvboxDark.ToTheme()
|
||||
themes["gruvbox-light"] = paletteGruvboxLight.ToTheme()
|
||||
|
||||
// dracula
|
||||
themes["dracula"] = paletteDracula.ToTheme()
|
||||
|
||||
// nord
|
||||
themes["nord"] = paletteNord.ToTheme()
|
||||
|
||||
// tokyo night variants
|
||||
themes["tokyo-night"] = paletteTokyoNight.ToTheme()
|
||||
themes["tokyo-night-storm"] = paletteTokyoNightStorm.ToTheme()
|
||||
themes["tokyo-night-light"] = paletteTokyoNightLight.ToTheme()
|
||||
|
||||
// solarized variants
|
||||
themes["solarized-dark"] = paletteSolarizedDark.ToTheme()
|
||||
themes["solarized-light"] = paletteSolarizedLight.ToTheme()
|
||||
|
||||
// one dark
|
||||
themes["one-dark"] = paletteOneDark.ToTheme()
|
||||
|
||||
// monochrome (no colors)
|
||||
themes["mono"] = createMonoTheme()
|
||||
}
|
||||
|
||||
// GetTheme returns a theme by name, with auto-detection support
|
||||
// DefaultTheme is the theme used when none is specified
|
||||
const DefaultTheme = "ansi"
|
||||
|
||||
// GetTheme returns a theme by name
|
||||
func GetTheme(name string) *Theme {
|
||||
if name == "auto" {
|
||||
// lipgloss handles adaptive colors, so we just return the default
|
||||
return themes["default"]
|
||||
if name == "" || name == "auto" || name == "default" {
|
||||
return themes[DefaultTheme]
|
||||
}
|
||||
|
||||
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"]
|
||||
return themes[DefaultTheme]
|
||||
}
|
||||
|
||||
// ListThemes returns available theme names
|
||||
// ListThemes returns available theme names sorted alphabetically
|
||||
func ListThemes() []string {
|
||||
var names []string
|
||||
names := make([]string, 0, len(themes))
|
||||
for name := range themes {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
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) {
|
||||
|
||||
66
internal/theme/tokyo_night.go
Normal file
66
internal/theme/tokyo_night.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package theme
|
||||
|
||||
// tokyo night theme
|
||||
// https://github.com/enkia/tokyo-night-vscode-theme
|
||||
var paletteTokyoNight = Palette{
|
||||
Name: "tokyo-night",
|
||||
|
||||
Fg: "#c0caf5", // foreground
|
||||
FgMuted: "#a9b1d6", // foreground dark
|
||||
FgSubtle: "#565f89", // comment
|
||||
Bg: "#1a1b26", // background
|
||||
BgMuted: "#24283b", // background highlight
|
||||
Border: "#414868", // border
|
||||
|
||||
Red: "#f7768e",
|
||||
Green: "#9ece6a",
|
||||
Yellow: "#e0af68",
|
||||
Blue: "#7aa2f7",
|
||||
Magenta: "#bb9af7", // purple
|
||||
Cyan: "#7dcfff",
|
||||
Orange: "#ff9e64",
|
||||
Gray: "#565f89", // comment
|
||||
}
|
||||
|
||||
// tokyo night storm variant
|
||||
var paletteTokyoNightStorm = Palette{
|
||||
Name: "tokyo-night-storm",
|
||||
|
||||
Fg: "#c0caf5", // foreground
|
||||
FgMuted: "#a9b1d6", // foreground dark
|
||||
FgSubtle: "#565f89", // comment
|
||||
Bg: "#24283b", // background (storm is slightly lighter)
|
||||
BgMuted: "#1f2335", // background dark
|
||||
Border: "#414868", // border
|
||||
|
||||
Red: "#f7768e",
|
||||
Green: "#9ece6a",
|
||||
Yellow: "#e0af68",
|
||||
Blue: "#7aa2f7",
|
||||
Magenta: "#bb9af7", // purple
|
||||
Cyan: "#7dcfff",
|
||||
Orange: "#ff9e64",
|
||||
Gray: "#565f89", // comment
|
||||
}
|
||||
|
||||
// tokyo night light variant
|
||||
var paletteTokyoNightLight = Palette{
|
||||
Name: "tokyo-night-light",
|
||||
|
||||
Fg: "#343b58", // foreground
|
||||
FgMuted: "#565a6e", // foreground dark
|
||||
FgSubtle: "#9699a3", // comment
|
||||
Bg: "#d5d6db", // background
|
||||
BgMuted: "#cbccd1", // background highlight
|
||||
Border: "#b4b5b9", // border
|
||||
|
||||
Red: "#8c4351",
|
||||
Green: "#485e30",
|
||||
Yellow: "#8f5e15",
|
||||
Blue: "#34548a",
|
||||
Magenta: "#5a4a78", // purple
|
||||
Cyan: "#0f4b6e",
|
||||
Orange: "#965027",
|
||||
Gray: "#9699a3", // comment
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user