summaryrefslogtreecommitdiffhomepage
path: root/packages/tui/internal/components/dialog/theme.go
diff options
context:
space:
mode:
authoradamdottv <[email protected]>2025-06-12 16:00:20 -0500
committeradamdottv <[email protected]>2025-06-12 16:00:26 -0500
commit653965ef5908a240f6038609e17bc8fa27640203 (patch)
tree439910084fdcea0c45856ad0132f916fd9038a4b /packages/tui/internal/components/dialog/theme.go
parentca0ea3f94dc1929071efc93bfcf708c8cf054be8 (diff)
downloadopencode-653965ef5908a240f6038609e17bc8fa27640203.tar.gz
opencode-653965ef5908a240f6038609e17bc8fa27640203.zip
wip: refactoring tui
Diffstat (limited to 'packages/tui/internal/components/dialog/theme.go')
-rw-r--r--packages/tui/internal/components/dialog/theme.go219
1 files changed, 74 insertions, 145 deletions
diff --git a/packages/tui/internal/components/dialog/theme.go b/packages/tui/internal/components/dialog/theme.go
index 4704cb42e..66fd5feec 100644
--- a/packages/tui/internal/components/dialog/theme.go
+++ b/packages/tui/internal/components/dialog/theme.go
@@ -1,9 +1,9 @@
package dialog
import (
- "github.com/charmbracelet/bubbles/v2/key"
tea "github.com/charmbracelet/bubbletea/v2"
- "github.com/charmbracelet/lipgloss/v2"
+ "github.com/sst/opencode/internal/components/modal"
+ components "github.com/sst/opencode/internal/components/util"
"github.com/sst/opencode/internal/layout"
"github.com/sst/opencode/internal/status"
"github.com/sst/opencode/internal/styles"
@@ -16,184 +16,113 @@ type ThemeChangedMsg struct {
ThemeName string
}
-// CloseThemeDialogMsg is sent when the theme dialog is closed
-type CloseThemeDialogMsg struct{}
-
// ThemeDialog interface for the theme switching dialog
type ThemeDialog interface {
- layout.ModelWithView
- layout.Bindings
+ layout.Modal
}
-type themeDialogComponent struct {
- themes []string
- selectedIdx int
- width int
- height int
- currentTheme string
+type themeItem struct {
+ name string
}
-type themeKeyMap struct {
- Up key.Binding
- Down key.Binding
- Enter key.Binding
- Escape key.Binding
- J key.Binding
- K key.Binding
-}
+func (t themeItem) Render(selected bool, width int) string {
+ th := theme.CurrentTheme()
+ baseStyle := styles.BaseStyle().
+ Width(width - 2).
+ Background(th.BackgroundElement())
+
+ if selected {
+ baseStyle = baseStyle.
+ Background(th.Primary()).
+ Foreground(th.BackgroundElement()).
+ Bold(true)
+ } else {
+ baseStyle = baseStyle.
+ Foreground(th.Text())
+ }
-var themeKeys = themeKeyMap{
- Up: key.NewBinding(
- key.WithKeys("up"),
- key.WithHelp("↑", "previous theme"),
- ),
- Down: key.NewBinding(
- key.WithKeys("down"),
- key.WithHelp("↓", "next theme"),
- ),
- Enter: key.NewBinding(
- key.WithKeys("enter"),
- key.WithHelp("enter", "select theme"),
- ),
- Escape: key.NewBinding(
- key.WithKeys("esc"),
- key.WithHelp("esc", "close"),
- ),
- J: key.NewBinding(
- key.WithKeys("j"),
- key.WithHelp("j", "next theme"),
- ),
- K: key.NewBinding(
- key.WithKeys("k"),
- key.WithHelp("k", "previous theme"),
- ),
+ return baseStyle.Padding(0, 1).Render(t.name)
}
-func (t *themeDialogComponent) Init() tea.Cmd {
- // Load available themes and update selectedIdx based on current theme
- t.themes = theme.AvailableThemes()
- t.currentTheme = theme.CurrentThemeName()
+type themeDialog struct {
+ width int
+ height int
- // Find the current theme in the list
- for i, name := range t.themes {
- if name == t.currentTheme {
- t.selectedIdx = i
- break
- }
- }
+ modal *modal.Modal
+ list components.SimpleList[themeItem]
+}
+func (t *themeDialog) Init() tea.Cmd {
return nil
}
-func (t *themeDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (t *themeDialog) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
+ case tea.WindowSizeMsg:
+ t.width = msg.Width
+ t.height = msg.Height
case tea.KeyMsg:
- switch {
- case key.Matches(msg, themeKeys.Up) || key.Matches(msg, themeKeys.K):
- if t.selectedIdx > 0 {
- t.selectedIdx--
- }
- return t, nil
- case key.Matches(msg, themeKeys.Down) || key.Matches(msg, themeKeys.J):
- if t.selectedIdx < len(t.themes)-1 {
- t.selectedIdx++
- }
- return t, nil
- case key.Matches(msg, themeKeys.Enter):
- if len(t.themes) > 0 {
+ switch msg.String() {
+ case "enter":
+ if item, idx := t.list.GetSelectedItem(); idx >= 0 {
previousTheme := theme.CurrentThemeName()
- selectedTheme := t.themes[t.selectedIdx]
+ selectedTheme := item.name
if previousTheme == selectedTheme {
- return t, util.CmdHandler(CloseThemeDialogMsg{})
+ return t, util.CmdHandler(modal.CloseModalMsg{})
}
if err := theme.SetTheme(selectedTheme); err != nil {
status.Error(err.Error())
return t, nil
}
- return t, util.CmdHandler(ThemeChangedMsg{
- ThemeName: selectedTheme,
- })
+ return t, tea.Batch(
+ util.CmdHandler(ThemeChangedMsg{ThemeName: selectedTheme}),
+ util.CmdHandler(modal.CloseModalMsg{}),
+ )
}
- case key.Matches(msg, themeKeys.Escape):
- return t, util.CmdHandler(CloseThemeDialogMsg{})
}
- case tea.WindowSizeMsg:
- t.width = msg.Width
- t.height = msg.Height
- }
- return t, nil
-}
-
-func (t *themeDialogComponent) View() string {
- currentTheme := theme.CurrentTheme()
- baseStyle := styles.BaseStyle()
-
- if len(t.themes) == 0 {
- return baseStyle.Padding(1, 2).
- Border(lipgloss.RoundedBorder()).
- BorderBackground(currentTheme.Background()).
- BorderForeground(currentTheme.TextMuted()).
- Width(40).
- Render("No themes available")
}
- // Calculate max width needed for theme names
- maxWidth := 40 // Minimum width
- for _, themeName := range t.themes {
- if len(themeName) > maxWidth-4 { // Account for padding
- maxWidth = len(themeName) + 4
- }
- }
+ var cmd tea.Cmd
+ listModel, cmd := t.list.Update(msg)
+ t.list = listModel.(components.SimpleList[themeItem])
+ return t, cmd
+}
- maxWidth = max(30, min(maxWidth, t.width-15)) // Limit width to avoid overflow
+func (t *themeDialog) Render(background string) string {
+ return t.modal.Render(t.list.View(), background)
+}
- // Build the theme list
- themeItems := make([]string, 0, len(t.themes))
- for i, themeName := range t.themes {
- itemStyle := baseStyle.Width(maxWidth)
+func (t *themeDialog) Close() tea.Cmd {
+ return nil
+}
- if i == t.selectedIdx {
- itemStyle = itemStyle.
- Background(currentTheme.Primary()).
- Foreground(currentTheme.Background()).
- Bold(true)
+// NewThemeDialog creates a new theme switching dialog
+func NewThemeDialog() ThemeDialog {
+ themes := theme.AvailableThemes()
+ currentTheme := theme.CurrentThemeName()
+
+ var themeItems []themeItem
+ var selectedIdx int
+ for i, name := range themes {
+ themeItems = append(themeItems, themeItem{name: name})
+ if name == currentTheme {
+ selectedIdx = i
}
-
- themeItems = append(themeItems, itemStyle.Padding(0, 1).Render(themeName))
}
- title := baseStyle.
- Foreground(currentTheme.Primary()).
- Bold(true).
- Width(maxWidth).
- Padding(0, 1).
- Render("Select Theme")
-
- content := lipgloss.JoinVertical(
- lipgloss.Left,
- title,
- baseStyle.Width(maxWidth).Render(""),
- baseStyle.Width(maxWidth).Render(lipgloss.JoinVertical(lipgloss.Left, themeItems...)),
- baseStyle.Width(maxWidth).Render(""),
+ list := components.NewSimpleList(
+ themeItems,
+ 10, // maxVisibleThemes
+ "No themes available",
+ true,
)
- return baseStyle.Padding(1, 2).
- Border(lipgloss.RoundedBorder()).
- BorderBackground(currentTheme.Background()).
- BorderForeground(currentTheme.TextMuted()).
- Width(lipgloss.Width(content) + 4).
- Render(content)
-}
+ // Set the initial selection to the current theme
+ list.SetSelectedIndex(selectedIdx)
-func (t *themeDialogComponent) BindingKeys() []key.Binding {
- return layout.KeyMapToSlice(themeKeys)
-}
-
-// NewThemeDialogCmp creates a new theme switching dialog
-func NewThemeDialogCmp() ThemeDialog {
- return &themeDialogComponent{
- themes: []string{},
- selectedIdx: 0,
- currentTheme: "",
+ return &themeDialog{
+ list: list,
+ modal: modal.New(modal.WithTitle("Select Theme"), modal.WithMaxWidth(40)),
}
}
+