Every colour was a 256-colour ANSI index hardcoded in styles.go, so changing the palette meant editing the styles themselves. This puts a semantic token set between the two: styles name roles, a theme supplies the colours. internal/theme holds the twelve tokens, the two built-ins (gruvbox-dark, the new default, and gruvbox-light) and the loader for user themes in ~/.config/terdut-tui/themes/. A user file may 'extends:' a built-in and override only what it cares about, and may shadow a built-in name to tweak it in place. Unknown keys, malformed colours and incomplete themes are refused with a message naming what went wrong. Colours are truecolor hex now: lipgloss downsamples for 256- and 16-colour terminals and honours NO_COLOR, so themes carry no fallbacks of their own. An ANSI index is still accepted for anyone who would rather follow their terminal's own palette. The 21 package-level style vars become a Styles struct on the Model, which is what rule 3 asked for all along; the four free functions in view.go take one as their first argument. The embedded bubbles components are restyled from the same tokens — otherwise a theme would leave a pink selected row and grey help text behind. Note that the table's Cell style deliberately keeps no foreground: bubbles renders cells before wrapping the row in Selected, so a colour there cuts the selection highlight short.
This commit is contained in:
+21
-19
@@ -5,12 +5,12 @@ import (
|
||||
"time"
|
||||
|
||||
"git.ryuvia.com/niklas/terdut-tui/internal/api"
|
||||
"git.ryuvia.com/niklas/terdut-tui/internal/theme"
|
||||
"github.com/charmbracelet/bubbles/help"
|
||||
"github.com/charmbracelet/bubbles/table"
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
"github.com/charmbracelet/bubbles/viewport"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
// ── Enums ──────────────────────────────────────────────────────────────────
|
||||
@@ -244,12 +244,14 @@ type Model struct {
|
||||
apiKeyRevokeInput textinput.Model
|
||||
revealedAPIKey api.APIKey
|
||||
|
||||
help help.Model
|
||||
keys keyMap
|
||||
help help.Model
|
||||
keys keyMap
|
||||
styles Styles
|
||||
}
|
||||
|
||||
func NewModel(client *api.Client, serverURL string, refreshInterval time.Duration) Model {
|
||||
ts := defaultTableStyles()
|
||||
func NewModel(client *api.Client, serverURL string, refreshInterval time.Duration, th theme.Theme) Model {
|
||||
st := newStyles(th)
|
||||
ts := st.Table()
|
||||
|
||||
incidentT := table.New(table.WithFocused(true))
|
||||
incidentT.SetStyles(ts)
|
||||
@@ -301,6 +303,15 @@ func NewModel(client *api.Client, serverURL string, refreshInterval time.Duratio
|
||||
revokeIn.Placeholder = "integer key ID"
|
||||
revokeIn.CharLimit = 20
|
||||
|
||||
for _, in := range []*textinput.Model{
|
||||
¬eIn, &snoozeIn, &usernameIn, &emailIn, &topicIn, &keyNameIn, &revokeIn,
|
||||
} {
|
||||
*in = st.Input(*in)
|
||||
}
|
||||
|
||||
helpModel := help.New()
|
||||
helpModel.Styles = st.Help()
|
||||
|
||||
now := time.Now().UTC()
|
||||
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
|
||||
weekday := int(today.Weekday())
|
||||
@@ -333,8 +344,9 @@ func NewModel(client *api.Client, serverURL string, refreshInterval time.Duratio
|
||||
ntfyTopicInput: topicIn,
|
||||
apiKeyNameInput: keyNameIn,
|
||||
apiKeyRevokeInput: revokeIn,
|
||||
help: help.New(),
|
||||
help: helpModel,
|
||||
keys: keys,
|
||||
styles: st,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,16 +356,6 @@ func (m Model) Init() tea.Cmd {
|
||||
|
||||
// ── Table rebuilders ───────────────────────────────────────────────────────
|
||||
|
||||
func defaultTableStyles() table.Styles {
|
||||
s := table.DefaultStyles()
|
||||
s.Header = s.Header.Bold(true)
|
||||
s.Selected = s.Selected.
|
||||
Foreground(lipgloss.Color("0")).
|
||||
Background(colorPrimary).
|
||||
Bold(true)
|
||||
return s
|
||||
}
|
||||
|
||||
// setRows replaces a table's rows and keeps its cursor in a state the rest of
|
||||
// this package can rely on: valid whenever the table has any rows at all.
|
||||
//
|
||||
@@ -433,16 +435,16 @@ func (m *Model) refreshDetailContent() {
|
||||
return
|
||||
}
|
||||
if m.mode == modeAlertDetail {
|
||||
m.detailViewport.SetContent(buildAlertDetailContent(m.selectedAlert, m.width))
|
||||
m.detailViewport.SetContent(buildAlertDetailContent(m.styles, m.selectedAlert, m.width))
|
||||
return
|
||||
}
|
||||
m.detailViewport.SetContent(
|
||||
buildIncidentDetailContent(m.selectedIncident, m.timeline, m.noteCursor, m.width))
|
||||
buildIncidentDetailContent(m.styles, m.selectedIncident, m.timeline, m.noteCursor, m.width))
|
||||
}
|
||||
|
||||
func (m *Model) refreshStatsContent() {
|
||||
m.statsViewport.SetContent(
|
||||
buildStatsContent(m.incidentStats, m.topAlerts, m.hourStats, m.dayStats, m.width))
|
||||
buildStatsContent(m.styles, m.incidentStats, m.topAlerts, m.hourStats, m.dayStats, m.width))
|
||||
}
|
||||
|
||||
func (m Model) statsViewportHeight() int {
|
||||
|
||||
Reference in New Issue
Block a user