summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authoradamdottv <[email protected]>2025-06-18 15:12:18 -0500
committeradamdottv <[email protected]>2025-06-18 15:12:24 -0500
commitac777b77cfbab686a8f924293626df5781af56e9 (patch)
tree0fa38e07e8746b9e4b52e24576c1452fd22cdf62
parent5944ae2023a76c578b74da7da0bb4524330b50f6 (diff)
downloadopencode-ac777b77cfbab686a8f924293626df5781af56e9.tar.gz
opencode-ac777b77cfbab686a8f924293626df5781af56e9.zip
fix(tui): modal visuals
-rw-r--r--packages/tui/internal/components/dialog/help.go2
-rw-r--r--packages/tui/internal/components/dialog/models.go23
-rw-r--r--packages/tui/internal/components/dialog/session.go20
-rw-r--r--packages/tui/internal/components/list/list.go5
-rw-r--r--packages/tui/internal/components/modal/modal.go26
-rw-r--r--packages/tui/internal/tui/tui.go6
6 files changed, 44 insertions, 38 deletions
diff --git a/packages/tui/internal/components/dialog/help.go b/packages/tui/internal/components/dialog/help.go
index 6041fd5e7..87d6e89f0 100644
--- a/packages/tui/internal/components/dialog/help.go
+++ b/packages/tui/internal/components/dialog/help.go
@@ -83,6 +83,6 @@ type HelpDialog interface {
func NewHelpDialog(commands []commands.Command) HelpDialog {
return &helpDialog{
commands: commands,
- modal: modal.New(),
+ modal: modal.New(modal.WithTitle("Help")),
}
}
diff --git a/packages/tui/internal/components/dialog/models.go b/packages/tui/internal/components/dialog/models.go
index dfb11dffb..786b092c0 100644
--- a/packages/tui/internal/components/dialog/models.go
+++ b/packages/tui/internal/components/dialog/models.go
@@ -180,6 +180,7 @@ func (m *modelDialog) switchProvider(offset int) {
m.hScrollOffset = newOffset
m.provider = m.availableProviders[m.hScrollOffset]
+ m.modal.SetTitle(fmt.Sprintf("Select %s Model", m.provider.Name))
m.setupModelsForProvider(m.provider.Id)
}
@@ -189,14 +190,6 @@ func (m *modelDialog) View() string {
Background(t.BackgroundElement()).
Foreground(t.Text())
- // Capitalize first letter of provider name
- title := baseStyle.
- Foreground(t.Primary()).
- Bold(true).
- Width(maxDialogWidth).
- Padding(0, 0, 1).
- Render(fmt.Sprintf("Select %s Model", m.provider.Name))
-
// Render visible models
endIdx := min(m.scrollOffset+numVisibleModels, len(m.provider.Models))
modelItems := make([]string, 0, endIdx-m.scrollOffset)
@@ -217,8 +210,9 @@ func (m *modelDialog) View() string {
content := lipgloss.JoinVertical(
lipgloss.Left,
- title,
- baseStyle.Width(maxDialogWidth).Render(lipgloss.JoinVertical(lipgloss.Left, modelItems...)),
+ baseStyle.
+ Width(maxDialogWidth).
+ Render(lipgloss.JoinVertical(lipgloss.Left, modelItems...)),
scrollIndicator,
)
@@ -238,12 +232,7 @@ func (m *modelDialog) getScrollIndicators(maxWidth int) string {
}
if m.hScrollPossible {
- if m.hScrollOffset > 0 {
- indicator = "← " + indicator
- }
- if m.hScrollOffset < len(m.availableProviders)-1 {
- indicator += "→"
- }
+ indicator = "← " + indicator + "→"
}
if indicator == "" {
@@ -313,6 +302,6 @@ func NewModelDialog(app *app.App) ModelDialog {
hScrollOffset: 0,
hScrollPossible: len(availableProviders) > 1,
provider: availableProviders[0],
- modal: modal.New(),
+ modal: modal.New(modal.WithTitle(fmt.Sprintf("Select %s Model", availableProviders[0].Name))),
}
}
diff --git a/packages/tui/internal/components/dialog/session.go b/packages/tui/internal/components/dialog/session.go
index b59ebe3d5..52eac1e29 100644
--- a/packages/tui/internal/components/dialog/session.go
+++ b/packages/tui/internal/components/dialog/session.go
@@ -19,14 +19,12 @@ type SessionDialog interface {
layout.Modal
}
-type sessionItem struct {
- session client.SessionInfo
-}
+type sessionItem client.SessionInfo
func (s sessionItem) Render(selected bool, width int) string {
t := theme.CurrentTheme()
baseStyle := styles.BaseStyle().
- Width(width - 2).
+ Width(width - 4).
Background(t.BackgroundElement())
if selected {
@@ -39,7 +37,7 @@ func (s sessionItem) Render(selected bool, width int) string {
Foreground(t.Text())
}
- return baseStyle.Padding(0, 1).Render(s.session.Title)
+ return baseStyle.Padding(0, 1).Render(s.Title)
}
type sessionDialog struct {
@@ -60,15 +58,14 @@ func (s *sessionDialog) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
s.width = msg.Width
s.height = msg.Height
s.list.SetMaxWidth(layout.Current.Container.Width - 12)
- case tea.KeyMsg:
+ case tea.KeyPressMsg:
switch msg.String() {
case "enter":
if item, idx := s.list.GetSelectedItem(); idx >= 0 {
- selectedSession := item.session
- s.selectedSessionID = selectedSession.Id
+ s.selectedSessionID = item.Id
return s, tea.Sequence(
util.CmdHandler(modal.CloseModalMsg{}),
- util.CmdHandler(app.SessionSelectedMsg(&selectedSession)),
+ util.CmdHandler(app.SessionSelectedMsg(&item)),
)
}
}
@@ -94,7 +91,10 @@ func NewSessionDialog(app *app.App) SessionDialog {
var sessionItems []sessionItem
for _, sess := range sessions {
- sessionItems = append(sessionItems, sessionItem{session: sess})
+ if sess.ParentID != nil {
+ continue
+ }
+ sessionItems = append(sessionItems, sessionItem(sess))
}
list := list.NewListComponent(
diff --git a/packages/tui/internal/components/list/list.go b/packages/tui/internal/components/list/list.go
index cefcaabef..cd0bf18c0 100644
--- a/packages/tui/internal/components/list/list.go
+++ b/packages/tui/internal/components/list/list.go
@@ -1,9 +1,10 @@
package list
import (
+ "strings"
+
"github.com/charmbracelet/bubbles/v2/key"
tea "github.com/charmbracelet/bubbletea/v2"
- "github.com/charmbracelet/lipgloss/v2"
)
type ListItem interface {
@@ -148,7 +149,7 @@ func (c *listComponent[T]) View() string {
listItems = append(listItems, title)
}
- return lipgloss.JoinVertical(lipgloss.Left, listItems...)
+ return strings.Join(listItems, "\n")
}
func NewListComponent[T ListItem](items []T, maxVisibleItems int, fallbackMsg string, useAlphaNumericKeys bool) List[T] {
diff --git a/packages/tui/internal/components/modal/modal.go b/packages/tui/internal/components/modal/modal.go
index 88e37c50b..e57de0afe 100644
--- a/packages/tui/internal/components/modal/modal.go
+++ b/packages/tui/internal/components/modal/modal.go
@@ -1,6 +1,8 @@
package modal
import (
+ "strings"
+
"github.com/charmbracelet/lipgloss/v2"
"github.com/sst/opencode/internal/layout"
"github.com/sst/opencode/internal/styles"
@@ -66,6 +68,10 @@ func New(opts ...ModalOption) *Modal {
return m
}
+func (m *Modal) SetTitle(title string) {
+ m.title = title
+}
+
// Render renders the modal centered on the screen
func (m *Modal) Render(contentView string, background string) string {
t := theme.CurrentTheme()
@@ -95,15 +101,21 @@ func (m *Modal) Render(contentView string, background string) string {
titleStyle := baseStyle.
Foreground(t.Primary()).
Bold(true).
- Width(innerWidth).
Padding(0, 1)
- titleView := titleStyle.Render(m.title)
- finalContent = lipgloss.JoinVertical(
- lipgloss.Left,
- titleView,
- contentView,
- )
+ // titleView := titleStyle.Render(m.title)
+ escStyle := baseStyle.Foreground(t.TextMuted()).Bold(false)
+ escText := escStyle.Render("esc")
+
+ // Calculate position for esc text
+ titleWidth := lipgloss.Width(m.title)
+ escWidth := lipgloss.Width(escText)
+ spacesNeeded := max(0, innerWidth-titleWidth-escWidth-3)
+ spacer := strings.Repeat(" ", spacesNeeded)
+ titleLine := m.title + spacer + escText
+ titleLine = titleStyle.Render(titleLine)
+
+ finalContent = strings.Join([]string{titleLine, contentView}, "\n") + "\n"
} else {
finalContent = contentView
}
diff --git a/packages/tui/internal/tui/tui.go b/packages/tui/internal/tui/tui.go
index 9fe52cdab..98d16ecc4 100644
--- a/packages/tui/internal/tui/tui.go
+++ b/packages/tui/internal/tui/tui.go
@@ -204,8 +204,12 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
a.layout.SetSize(a.width, a.height)
case app.SessionSelectedMsg:
+ var err error
a.app.Session = msg
- a.app.Messages, _ = a.app.ListMessages(context.Background(), msg.Id)
+ a.app.Messages, err = a.app.ListMessages(context.Background(), msg.Id)
+ if err != nil {
+ slog.Error("Failed to list messages", "error", err)
+ }
case app.ModelSelectedMsg:
a.app.Provider = &msg.Provider
a.app.Model = &msg.Model