Files
correx/apps/tui-go/internal/app/theme.go
T
kami f922b855eb feat: add Go/Bubble Tea TUI rewrite (apps/tui-go)
Reimplement the TUI in Go using Bubble Tea, replacing the Kotlin/Tamboui
app. Same WebSocket protocol, soft-rounded layout with blue accent theme.
2026-05-30 00:00:35 +04:00

143 lines
4.7 KiB
Go

package app
import "github.com/charmbracelet/lipgloss"
// Palette is the "Soft" chrome from docs/visual/ref with the blue accent:
// rounded borders, opaque dark panels, generous spacing.
type Palette struct {
Bg lipgloss.Color // panel/background fill
BgDeep lipgloss.Color // outermost backdrop (slightly darker)
BgPanel lipgloss.Color // inside-panel fill
Sel lipgloss.Color // selection row background
Border lipgloss.Color // idle panel border
BorderHi lipgloss.Color // active panel border
Fg lipgloss.Color // primary text
FgStrong lipgloss.Color // headings / emphasis
Dim lipgloss.Color // labels, secondary text
Faint lipgloss.Color // tertiary, hints
Accent lipgloss.Color // blue accent
Accent2 lipgloss.Color // secondary accent
OK lipgloss.Color
Warn lipgloss.Color
Bad lipgloss.Color
CatLifecycle lipgloss.Color
CatContext lipgloss.Color
CatInference lipgloss.Color
CatTool lipgloss.Color
CatDomain lipgloss.Color
CatApproval lipgloss.Color
}
// SoftBlue mirrors the reference Soft theme (#14161a bg, #ced3da fg) with the
// blue accent the user chose.
var SoftBlue = Palette{
BgDeep: lipgloss.Color("#101216"),
Bg: lipgloss.Color("#14161a"),
BgPanel: lipgloss.Color("#171a1f"),
Sel: lipgloss.Color("#1b2733"),
Border: lipgloss.Color("#262b33"),
BorderHi: lipgloss.Color("#4a9eff"),
Fg: lipgloss.Color("#ced3da"),
FgStrong: lipgloss.Color("#e8edf2"),
Dim: lipgloss.Color("#7c8794"),
Faint: lipgloss.Color("#525c68"),
Accent: lipgloss.Color("#4a9eff"),
Accent2: lipgloss.Color("#56c8d8"),
OK: lipgloss.Color("#7fd88f"),
Warn: lipgloss.Color("#e8c06a"),
Bad: lipgloss.Color("#e87f7f"),
CatLifecycle: lipgloss.Color("#c98fd9"),
CatContext: lipgloss.Color("#b9c0c9"),
CatInference: lipgloss.Color("#56c8d8"),
CatTool: lipgloss.Color("#8fd96a"),
CatDomain: lipgloss.Color("#e8b765"),
CatApproval: lipgloss.Color("#e8c06a"),
}
// Theme holds prebuilt lipgloss styles derived from a Palette. Every style sets
// a Background so the panels are fully opaque (no terminal wallpaper bleed).
type Theme struct {
P Palette
Screen lipgloss.Style // full backdrop fill
Panel lipgloss.Style // idle rounded panel
PanelHi lipgloss.Style // active rounded panel
PanelTitle lipgloss.Style // uppercase dim header label
TitleHi lipgloss.Style // active header label
Text lipgloss.Style
Strong lipgloss.Style
Dim lipgloss.Style
Faint lipgloss.Style
Accent lipgloss.Style
SelRow lipgloss.Style
Status lipgloss.Style // top bar
Footer lipgloss.Style // bottom hints
Input lipgloss.Style // input bar panel
Overlay lipgloss.Style // modal box
Scrim lipgloss.Style // dim backdrop behind modals
}
// NewTheme builds the style set for a palette.
func NewTheme(p Palette) Theme {
base := lipgloss.NewStyle().Background(p.Bg).Foreground(p.Fg)
roundBase := func(border lipgloss.Color) lipgloss.Style {
return lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(border).
BorderBackground(p.Bg).
Background(p.Bg).
Foreground(p.Fg).
Padding(0, 1)
}
return Theme{
P: p,
Screen: lipgloss.NewStyle().Background(p.BgDeep).Foreground(p.Fg),
Panel: roundBase(p.Border),
PanelHi: roundBase(p.BorderHi),
PanelTitle: lipgloss.NewStyle().Background(p.Bg).Foreground(p.Dim).Bold(true),
TitleHi: lipgloss.NewStyle().Background(p.Bg).Foreground(p.Accent).Bold(true),
Text: base,
Strong: lipgloss.NewStyle().Background(p.Bg).Foreground(p.FgStrong).Bold(true),
Dim: lipgloss.NewStyle().Background(p.Bg).Foreground(p.Dim),
Faint: lipgloss.NewStyle().Background(p.Bg).Foreground(p.Faint),
Accent: lipgloss.NewStyle().Background(p.Bg).Foreground(p.Accent).Bold(true),
SelRow: lipgloss.NewStyle().Background(p.Sel).Foreground(p.FgStrong),
Status: lipgloss.NewStyle().Background(p.BgPanel).Foreground(p.Dim),
Footer: lipgloss.NewStyle().Background(p.BgDeep).Foreground(p.Faint),
Input: roundBase(p.BorderHi),
Overlay: lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(p.Accent).
BorderBackground(p.BgPanel).
Background(p.BgPanel).
Foreground(p.Fg).
Padding(1, 2),
Scrim: lipgloss.NewStyle().Background(p.BgDeep).Foreground(p.Faint),
}
}
// categoryColor maps an event category label to its accent color.
func (t Theme) categoryColor(cat string) lipgloss.Color {
switch cat {
case "Lifecycle":
return t.P.CatLifecycle
case "Context":
return t.P.CatContext
case "Inference":
return t.P.CatInference
case "Tool":
return t.P.CatTool
case "Domain":
return t.P.CatDomain
case "Approval":
return t.P.CatApproval
default:
return t.P.Dim
}
}