settings_theme.go

  1package tui
  2
  3import (
  4	"strings"
  5
  6	tea "charm.land/bubbletea/v2"
  7	"charm.land/lipgloss/v2"
  8	"github.com/floatpane/matcha/config"
  9	"github.com/floatpane/matcha/theme"
 10)
 11
 12func (m *Settings) updateTheme(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
 13	themes := theme.AllThemes()
 14
 15	switch msg.String() {
 16	case "up", "k":
 17		if len(themes) > 0 {
 18			m.themeCursor = (m.themeCursor - 1 + len(themes)) % len(themes)
 19		}
 20	case keyDown, "j":
 21		if len(themes) > 0 {
 22			m.themeCursor = (m.themeCursor + 1) % len(themes)
 23		}
 24	case keyEnter, "space", keyRight, "l":
 25		if m.themeCursor < len(themes) {
 26			selected := themes[m.themeCursor]
 27			theme.SetTheme(selected.Name)
 28			RebuildStyles()
 29			m.cfg.Theme = selected.Name
 30			_ = config.SaveConfig(m.cfg)
 31		}
 32	}
 33	return m, nil
 34}
 35
 36func (m *Settings) viewTheme() string {
 37	themes := theme.AllThemes()
 38	var b strings.Builder
 39
 40	b.WriteString(titleStyle.Render(t("settings_theme.title")) + "\n\n")
 41
 42	for i, thm := range themes {
 43		isActive := thm.Name == theme.ActiveTheme.Name
 44		label := thm.Name
 45		if isActive {
 46			label += " (" + t("settings_theme.current") + ")"
 47		}
 48
 49		selected := m.themeCursor == i
 50		cursor := m.contentCursor(selected)
 51		style := m.contentItemStyle(selected)
 52
 53		b.WriteString(style.Render(cursor+label) + "\n")
 54	}
 55
 56	b.WriteString("\n")
 57
 58	// Preview
 59	var previewTheme theme.Theme
 60	if m.themeCursor < len(themes) {
 61		previewTheme = themes[m.themeCursor]
 62	} else {
 63		previewTheme = theme.ActiveTheme
 64	}
 65
 66	previewWidth := m.width - 34 - 4
 67	if previewWidth < 30 {
 68		previewWidth = 30
 69	}
 70
 71	b.WriteString(renderThemePreview(previewTheme, previewWidth) + "\n\n")
 72
 73	if !m.cfg.HideTips {
 74		b.WriteString(TipStyle.Render("Tip: Custom themes can be added as JSON files in ~/.config/matcha/themes/") + "\n\n")
 75	}
 76
 77	b.WriteString(helpStyle.Render(t("settings_theme.help")))
 78
 79	return b.String()
 80}
 81
 82// renderThemePreview renders a small mockup showing how a theme looks.
 83func renderThemePreview(t theme.Theme, previewWidth int) string {
 84	if previewWidth > 60 {
 85		previewWidth = 60
 86	}
 87
 88	accent := lipgloss.NewStyle().Foreground(t.Accent)
 89	accentBold := lipgloss.NewStyle().Foreground(t.Accent).Bold(true)
 90	secondary := lipgloss.NewStyle().Foreground(t.Secondary)
 91	muted := lipgloss.NewStyle().Foreground(t.MutedText)
 92	dim := lipgloss.NewStyle().Foreground(t.DimText)
 93	danger := lipgloss.NewStyle().Foreground(t.Danger)
 94	warn := lipgloss.NewStyle().Foreground(t.Warning)
 95	tip := lipgloss.NewStyle().Foreground(t.Tip).Italic(true)
 96	link := lipgloss.NewStyle().Foreground(t.Link)
 97	title := lipgloss.NewStyle().Foreground(t.AccentText).Background(t.AccentDark).Padding(0, 1)
 98	activeTab := lipgloss.NewStyle().Foreground(t.Accent).Bold(true).Underline(true)
 99	activeFolder := lipgloss.NewStyle().Background(t.Accent).Foreground(t.Contrast).Bold(true).Padding(0, 1)
100
101	var b strings.Builder
102
103	b.WriteString(title.Render("Preview: "+t.Name) + "\n\n")
104	b.WriteString(activeTab.Render("Inbox") + "  " + secondary.Render("Sent") + "  " + secondary.Render("Drafts") + "\n")
105	b.WriteString(secondary.Render(strings.Repeat("─", previewWidth)) + "\n")
106
107	b.WriteString(accentBold.Render("> ") + dim.Render("Alice  ") + accent.Render("Meeting tomorrow") + "  " + muted.Render("2m ago") + "\n")
108	b.WriteString("  " + dim.Render("Bob    ") + secondary.Render("Re: Project update") + "  " + muted.Render("1h ago") + "\n")
109	b.WriteString("  " + dim.Render("Carol  ") + secondary.Render("Quick question") + "    " + muted.Render("3h ago") + "\n\n")
110
111	b.WriteString(accentBold.Render("Folders") + "\n")
112	b.WriteString(activeFolder.Render(" INBOX ") + "  " + secondary.Render("Sent") + "  " + secondary.Render("Trash") + "\n\n")
113
114	b.WriteString(accentBold.Render("Success: ") + accent.Render("Email sent!") + "\n")
115	b.WriteString(danger.Render("Error: ") + danger.Render("Connection failed") + "\n")
116	b.WriteString(warn.Render("Update available: v2.0") + "\n")
117	b.WriteString(tip.Render("Tip: Press ? for help") + "\n")
118	b.WriteString(link.Render("https://example.com") + "\n")
119
120	box := lipgloss.NewStyle().
121		Border(lipgloss.RoundedBorder()).
122		BorderForeground(t.AccentDark).
123		Padding(1, 2).
124		Width(previewWidth).
125		Render(b.String())
126
127	return box
128}