glow/ui/styles.go
Drew Smirnoff 1a13810c34
chore: bump bubbletea to v2 (#1002)
Signed-off-by: drew <me@andrinoff.com>
2026-08-10 18:21:27 +04:00

168 lines
5.7 KiB
Go

package ui
import (
"image/color"
"charm.land/lipgloss/v2"
)
// Styles contains all styles used in the UI. They are resolved from light and
// dark color variants according to the terminal's background color, which
// Bubble Tea reports via tea.BackgroundColorMsg. Until then, we default to
// a dark background.
type Styles struct {
lightDark lipgloss.LightDarkFunc
fuchsia color.Color
dimNormalFg func(...string) string
brightGrayFg func(...string) string
dimBrightGrayFg func(...string) string
grayFg func(...string) string
midGrayFg func(...string) string
darkGrayFg lipgloss.Style
greenFg func(...string) string
semiDimGreenFg func(...string) string
dimGreenFg func(...string) string
fuchsiaFg func(...string) string
dimFuchsiaFg func(...string) string
dullFuchsiaFg func(...string) string
dimDullFuchsiaFg func(...string) string
redFg func(...string) string
tabStyle lipgloss.Style
selectedTabStyle lipgloss.Style
errorTitleStyle lipgloss.Style
subtleStyle lipgloss.Style
paginationStyle lipgloss.Style
statusBarScrollPosStyle func(...string) string
statusBarNoteStyle func(...string) string
statusBarHelpStyle func(...string) string
statusBarMessageStyle func(...string) string
statusBarMessageScrollPosStyle func(...string) string
statusBarMessageHelpStyle func(...string) string
helpViewStyle func(...string) string
lineNumberStyle func(...string) string
dividerDot lipgloss.Style
dividerBar lipgloss.Style
logoStyle lipgloss.Style
stashSpinnerStyle lipgloss.Style
stashInputPromptStyle lipgloss.Style
}
// newStyles builds all styles for the given terminal background.
func newStyles(isDark bool) Styles {
s := Styles{lightDark: lipgloss.LightDark(isDark)}
// Colors
normalDim := s.adaptive("#A49FA5", "#777777")
gray := s.adaptive("#909090", "#626262")
midGray := s.adaptive("#B2B2B2", "#4A4A4A")
darkGray := s.adaptive("#DDDADA", "#3C3C3C")
brightGray := s.adaptive("#847A85", "#979797")
dimBrightGray := s.adaptive("#C2B8C2", "#4D4D4D")
cream := s.adaptive("#FFFDF5", "#FFFDF5")
yellowGreen := s.adaptive("#04B575", "#ECFD65")
s.fuchsia = s.adaptive("#EE6FF8", "#EE6FF8")
dimFuchsia := s.adaptive("#F1A8FF", "#99519E")
dullFuchsia := s.adaptive("#F793FF", "#AD58B4")
dimDullFuchsia := s.adaptive("#F6C9FF", "#7B4380")
green := lipgloss.Color("#04B575")
red := s.adaptive("#FF4672", "#ED567A")
semiDimGreen := s.adaptive("#35D79C", "#036B46")
dimGreen := s.adaptive("#72D2B0", "#0B5137")
// Pager colors
mintGreen := s.adaptive("#89F0CB", "#89F0CB")
darkGreen := s.adaptive("#1C8760", "#1C8760")
lineNumberFg := s.adaptive("#656565", "#7D7D7D")
statusBarNoteFg := s.adaptive("#656565", "#7D7D7D")
statusBarBg := s.adaptive("#E6E6E6", "#242424")
// Render-func styles
s.dimNormalFg = lipgloss.NewStyle().Foreground(normalDim).Render
s.brightGrayFg = lipgloss.NewStyle().Foreground(brightGray).Render
s.dimBrightGrayFg = lipgloss.NewStyle().Foreground(dimBrightGray).Render
s.grayFg = lipgloss.NewStyle().Foreground(gray).Render
s.midGrayFg = lipgloss.NewStyle().Foreground(midGray).Render
s.darkGrayFg = lipgloss.NewStyle().Foreground(darkGray)
s.greenFg = lipgloss.NewStyle().Foreground(green).Render
s.semiDimGreenFg = lipgloss.NewStyle().Foreground(semiDimGreen).Render
s.dimGreenFg = lipgloss.NewStyle().Foreground(dimGreen).Render
s.fuchsiaFg = lipgloss.NewStyle().Foreground(s.fuchsia).Render
s.dimFuchsiaFg = lipgloss.NewStyle().Foreground(dimFuchsia).Render
s.dullFuchsiaFg = lipgloss.NewStyle().Foreground(dullFuchsia).Render
s.dimDullFuchsiaFg = lipgloss.NewStyle().Foreground(dimDullFuchsia).Render
s.redFg = lipgloss.NewStyle().Foreground(red).Render
// Named styles
s.tabStyle = lipgloss.NewStyle().Foreground(s.adaptive("#909090", "#626262"))
s.selectedTabStyle = lipgloss.NewStyle().Foreground(s.adaptive("#333333", "#979797"))
s.errorTitleStyle = lipgloss.NewStyle().Foreground(cream).Background(red).Padding(0, 1)
s.subtleStyle = lipgloss.NewStyle().Foreground(s.adaptive("#9B9B9B", "#5C5C5C"))
s.paginationStyle = s.subtleStyle
// Pager styles
s.statusBarScrollPosStyle = lipgloss.NewStyle().
Foreground(s.adaptive("#949494", "#5A5A5A")).
Background(statusBarBg).
Render
s.statusBarNoteStyle = lipgloss.NewStyle().
Foreground(statusBarNoteFg).
Background(statusBarBg).
Render
s.statusBarHelpStyle = lipgloss.NewStyle().
Foreground(statusBarNoteFg).
Background(s.adaptive("#DCDCDC", "#323232")).
Render
s.statusBarMessageStyle = lipgloss.NewStyle().
Foreground(mintGreen).
Background(darkGreen).
Render
s.statusBarMessageScrollPosStyle = lipgloss.NewStyle().
Foreground(mintGreen).
Background(darkGreen).
Render
s.statusBarMessageHelpStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#B6FFE4")).
Background(green).
Render
s.helpViewStyle = lipgloss.NewStyle().
Foreground(statusBarNoteFg).
Background(s.adaptive("#f2f2f2", "#1B1B1B")).
Render
s.lineNumberStyle = lipgloss.NewStyle().
Foreground(lineNumberFg).
Render
// Stash styles
s.dividerDot = s.darkGrayFg.SetString(" • ")
s.dividerBar = s.darkGrayFg.SetString(" │ ")
s.logoStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#ECFD65")).
Background(s.fuchsia).
Bold(true)
s.stashSpinnerStyle = lipgloss.NewStyle().
Foreground(gray)
s.stashInputPromptStyle = lipgloss.NewStyle().
Foreground(yellowGreen).
MarginRight(1)
return s
}
// adaptive returns a color appropriate for the current terminal background.
func (s Styles) adaptive(light, dark string) color.Color {
return s.lightDark(lipgloss.Color(light), lipgloss.Color(dark))
}