Go 74 lines
package tui
import (
"os"
"github.com/charmbracelet/lipgloss"
)
// styles holds the few rendered styles the control center uses. They are
// intentionally minimal and neutral (Constraint 4: precise, no emoji, no
// first person). When colour is disabled the styles degrade to plain
// text rather than changing layout.
type styles struct {
brand lipgloss.Style // logo accent (matches the "eco" half of the README mark)
logoMuted lipgloss.Style // logo accent for the leading "e"; adapts to terminal background (near-black on light, near-white on dark) to mirror the two PNG mark variants
prompt lipgloss.Style // » input prompt
dim lipgloss.Style // hint line, secondary text
dimmer lipgloss.Style // status footer — sits below placeholder weight
key lipgloss.Style // command names, key labels
value lipgloss.Style // primary readable body text — table values, free-text body
tableHeader lipgloss.Style // column header cells in a section table
warn lipgloss.Style // cautionary inline notes
ok lipgloss.Style // success inline notes
}
// colorEnabled reports whether coloured output is wanted. The NO_COLOR
// convention (any non-empty value disables colour) is honoured; a value
// the user cannot override (a non-terminal sink) is handled separately
// by the non-interactive path.
func colorEnabled() bool {
return os.Getenv("NO_COLOR") == ""
}
// newStyles builds the style set. With colour off every style is the
// identity style, so the same View code path renders readable plain
// text under NO_COLOR or a dumb terminal.
func newStyles(color bool) styles {
if !color {
plain := lipgloss.NewStyle()
return styles{
brand: plain, logoMuted: plain, prompt: plain,
dim: plain, dimmer: plain, key: plain,
value: plain, tableHeader: plain,
warn: plain, ok: plain,
}
}
// Atom One Dark palette. Blue (#61afef, the palette's blue slot) is
// the eeco brand accent — logo "eco", prompt, command names, primary
// affordances. Green stays a semantic success signal only (never an
// accent). Greys form a three-step hierarchy: body > hint > footer.
const (
blue = "#61afef" // brand accent — logo "eco", prompt, command names
cyan = "#66b2ff" // table headers
yellow = "#e5c07b" // cautions
green = "#98c379" // success only
fgWhite = "#ffffff" // primary body text
fgGrey = "#abb2bf" // hints, secondary text
fgFooter = "#5c6370" // status footer, faintest
nearDark = "#282c34" // light-background foreground
)
return styles{
brand: lipgloss.NewStyle().Foreground(lipgloss.Color(blue)).Bold(true),
logoMuted: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: nearDark, Dark: fgGrey}).Bold(true),
prompt: lipgloss.NewStyle().Foreground(lipgloss.Color(blue)).Bold(true),
dim: lipgloss.NewStyle().Foreground(lipgloss.Color(fgGrey)),
dimmer: lipgloss.NewStyle().Foreground(lipgloss.Color(fgFooter)),
key: lipgloss.NewStyle().Foreground(lipgloss.Color(blue)).Bold(true),
value: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: nearDark, Dark: fgWhite}),
tableHeader: lipgloss.NewStyle().Foreground(lipgloss.Color(cyan)).Bold(true),
warn: lipgloss.NewStyle().Foreground(lipgloss.Color(yellow)).Bold(true),
ok: lipgloss.NewStyle().Foreground(lipgloss.Color(green)).Bold(true),
}
}