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 m.themeCursor > 0 {
18 m.themeCursor--
19 }
20 case "down", "j":
21 if m.themeCursor < len(themes)-1 {
22 m.themeCursor++
23 }
24 case "enter", "space", "right", "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 cursor := " "
50 style := accountItemStyle
51 if m.themeCursor == i {
52 cursor = "> "
53 style = selectedAccountItemStyle
54 }
55
56 b.WriteString(style.Render(cursor+label) + "\n")
57 }
58
59 b.WriteString("\n")
60
61 // Preview
62 var previewTheme theme.Theme
63 if m.themeCursor < len(themes) {
64 previewTheme = themes[m.themeCursor]
65 } else {
66 previewTheme = theme.ActiveTheme
67 }
68
69 previewWidth := m.width - 34 - 4
70 if previewWidth < 30 {
71 previewWidth = 30
72 }
73
74 b.WriteString(renderThemePreview(previewTheme, previewWidth) + "\n\n")
75
76 if !m.cfg.HideTips {
77 b.WriteString(TipStyle.Render("Tip: Custom themes can be added as JSON files in ~/.config/matcha/themes/") + "\n\n")
78 }
79
80 b.WriteString(helpStyle.Render(t("settings_theme.help")))
81
82 return b.String()
83}
84
85// renderThemePreview renders a small mockup showing how a theme looks.
86func renderThemePreview(t theme.Theme, previewWidth int) string {
87 if previewWidth > 60 {
88 previewWidth = 60
89 }
90
91 accent := lipgloss.NewStyle().Foreground(t.Accent)
92 accentBold := lipgloss.NewStyle().Foreground(t.Accent).Bold(true)
93 secondary := lipgloss.NewStyle().Foreground(t.Secondary)
94 muted := lipgloss.NewStyle().Foreground(t.MutedText)
95 dim := lipgloss.NewStyle().Foreground(t.DimText)
96 danger := lipgloss.NewStyle().Foreground(t.Danger)
97 warn := lipgloss.NewStyle().Foreground(t.Warning)
98 tip := lipgloss.NewStyle().Foreground(t.Tip).Italic(true)
99 link := lipgloss.NewStyle().Foreground(t.Link)
100 title := lipgloss.NewStyle().Foreground(t.AccentText).Background(t.AccentDark).Padding(0, 1)
101 activeTab := lipgloss.NewStyle().Foreground(t.Accent).Bold(true).Underline(true)
102 activeFolder := lipgloss.NewStyle().Background(t.Accent).Foreground(t.Contrast).Bold(true).Padding(0, 1)
103
104 var b strings.Builder
105
106 b.WriteString(title.Render("Preview: "+t.Name) + "\n\n")
107 b.WriteString(activeTab.Render("Inbox") + " " + secondary.Render("Sent") + " " + secondary.Render("Drafts") + "\n")
108 b.WriteString(secondary.Render(strings.Repeat("─", previewWidth)) + "\n")
109
110 b.WriteString(accentBold.Render("> ") + dim.Render("Alice ") + accent.Render("Meeting tomorrow") + " " + muted.Render("2m ago") + "\n")
111 b.WriteString(" " + dim.Render("Bob ") + secondary.Render("Re: Project update") + " " + muted.Render("1h ago") + "\n")
112 b.WriteString(" " + dim.Render("Carol ") + secondary.Render("Quick question") + " " + muted.Render("3h ago") + "\n\n")
113
114 b.WriteString(accentBold.Render("Folders") + "\n")
115 b.WriteString(activeFolder.Render(" INBOX ") + " " + secondary.Render("Sent") + " " + secondary.Render("Trash") + "\n\n")
116
117 b.WriteString(accentBold.Render("Success: ") + accent.Render("Email sent!") + "\n")
118 b.WriteString(danger.Render("Error: ") + danger.Render("Connection failed") + "\n")
119 b.WriteString(warn.Render("Update available: v2.0") + "\n")
120 b.WriteString(tip.Render("Tip: Press ? for help") + "\n")
121 b.WriteString(link.Render("https://example.com") + "\n")
122
123 box := lipgloss.NewStyle().
124 Border(lipgloss.RoundedBorder()).
125 BorderForeground(t.AccentDark).
126 Padding(1, 2).
127 Width(previewWidth).
128 Render(b.String())
129
130 return box
131}