diff --git a/pkg/tui/chat.go b/pkg/tui/chat.go index d76a633..5155c64 100644 --- a/pkg/tui/chat.go +++ b/pkg/tui/chat.go @@ -255,6 +255,7 @@ func (m chatModel) Update(msg tea.Msg) (chatModel, tea.Cmd) { case msgMessagesLoaded: m.setMessages(msg) m.updateContent() + m.content.GotoBottom() case msgResponseChunk: chunk := string(msg) last := len(m.messages) - 1 diff --git a/pkg/tui/conversations.go b/pkg/tui/conversations.go index 6854c52..39ab0e6 100644 --- a/pkg/tui/conversations.go +++ b/pkg/tui/conversations.go @@ -21,14 +21,17 @@ type loadedConversation struct { type ( // sent when conversation list is loaded msgConversationsLoaded ([]loadedConversation) - // sent when each coversation's 'last reply' is loaded + // sent when a conversation is selected + msgConversationSelected models.Conversation ) type conversationsModel struct { basemodel conversations []loadedConversation - content viewport.Model + cursor int // index of the currently selected message message + + content viewport.Model } func newConversationsModel(tui *model) conversationsModel { @@ -48,10 +51,23 @@ func newConversationsModel(tui *model) conversationsModel { func (m *conversationsModel) handleInput(msg tea.KeyMsg) (bool, tea.Cmd) { switch msg.String() { case "enter": - // how to notify chats model - return true, func() tea.Msg { - return msgChangeState(stateChat) + if len(m.conversations) > 0 && m.cursor < len(m.conversations) { + return true, func() tea.Msg { + return msgConversationSelected(m.conversations[m.cursor].conv) + } } + case "j", "down": + if m.cursor < len(m.conversations)-1 { + m.cursor++ + m.content.SetContent(m.renderConversationList()) + } + return true, nil + case "k", "up": + if m.cursor > 0 { + m.cursor-- + m.content.SetContent(m.renderConversationList()) + } + return true, nil case "n": // new conversation case "d": @@ -80,8 +96,10 @@ func (m conversationsModel) Update(msg tea.Msg) (conversationsModel, tea.Cmd) { switch msg := msg.(type) { case msgChangeState: cmds = append(cmds, m.loadConversations()) + m.content.SetContent(m.renderConversationList()) case tea.WindowSizeMsg: m.handleResize(msg.Width, msg.Height) + m.content.SetContent(m.renderConversationList()) case msgConversationsLoaded: m.conversations = msg m.content.SetContent(m.renderConversationList()) @@ -175,17 +193,17 @@ func (m *conversationsModel) renderConversationList() string { PaddingLeft(1). Bold(true) - conversationHeadingStyle := lipgloss.NewStyle(). - MarginBottom(1). - PaddingLeft(2) + itemStyle := lipgloss.NewStyle(). + MarginBottom(1) - ageStyle := lipgloss.NewStyle().Faint(true) + ageStyle := lipgloss.NewStyle().Faint(true).SetString() titleStyle := lipgloss.NewStyle().Bold(true) - untitledStyle := titleStyle.Copy().Italic(true).Faint(true).SetString("(untitled)") + untitledStyle := lipgloss.NewStyle().Faint(true).Italic(true) + selectedStyle := lipgloss.NewStyle().Faint(true).Foreground(lipgloss.Color("6")) var currentCategory string sb := &strings.Builder{} - for _, c := range m.conversations { + for i, c := range m.conversations { lastReplyAge := now.Sub(c.lastReply.CreatedAt) var category string @@ -196,21 +214,32 @@ func (m *conversationsModel) renderConversationList() string { } } + // print the category if category != currentCategory { currentCategory = category fmt.Fprintf(sb, "%s\n", categoryStyle.Render(currentCategory)) } - tstyle := titleStyle + tStyle := titleStyle.Copy() + padding := " " if c.conv.Title == "" { - tstyle = untitledStyle + tStyle = tStyle.Inherit(untitledStyle).SetString("(untitled)") } + if i == m.cursor { + tStyle = tStyle.Inherit(selectedStyle) + } + + title := tStyle.Width(m.width - 3).PaddingLeft(2).Render(c.conv.Title) + if i == m.cursor { + title = ">" + title[1:] + } + heading := fmt.Sprintf( "%s\n%s", - tstyle.Render(c.conv.Title), - ageStyle.Render(util.HumanTimeElapsedSince(lastReplyAge)), + title, + padding + ageStyle.Render(util.HumanTimeElapsedSince(lastReplyAge)), ) - sb.WriteString(conversationHeadingStyle.Render(heading)) + sb.WriteString(itemStyle.Render(heading)) sb.WriteRune('\n') } return sb.String() diff --git a/pkg/tui/tui.go b/pkg/tui/tui.go index 3f74013..0b36bc1 100644 --- a/pkg/tui/tui.go +++ b/pkg/tui/tui.go @@ -132,6 +132,11 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.conversations.handleResize(m.width, m.height) } m.state = state(msg) + case msgConversationSelected: + m.opts.convShortname = msg.ShortName.String + cmds = append(cmds, func() tea.Msg { + return msgChangeState(stateChat) + }) case tea.WindowSizeMsg: m.width, m.height = msg.Width, msg.Height case msgError: