summaryrefslogtreecommitdiff
path: root/internal/client/ui.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/client/ui.go')
-rw-r--r--internal/client/ui.go124
1 files changed, 124 insertions, 0 deletions
diff --git a/internal/client/ui.go b/internal/client/ui.go
new file mode 100644
index 0000000..839c0cd
--- /dev/null
+++ b/internal/client/ui.go
@@ -0,0 +1,124 @@
+package client
+
+import (
+ "fmt"
+ "log"
+ "strings"
+
+ "github.com/charmbracelet/bubbles/cursor"
+ "github.com/charmbracelet/bubbles/textarea"
+ "github.com/charmbracelet/bubbles/viewport"
+ tea "github.com/charmbracelet/bubbletea"
+ "github.com/charmbracelet/lipgloss"
+
+ "github.com/kyren223/eko/pkg/assert"
+)
+
+func startUI() {
+ p := tea.NewProgram(initialModel(), tea.WithAltScreen())
+ if _, err := p.Run(); err != nil {
+ log.Println("charm ui error:", err)
+ }
+}
+
+type model struct {
+ viewport viewport.Model
+ messages []string
+ textarea textarea.Model
+ senderStyle lipgloss.Style
+ err error
+}
+
+func initialModel() model {
+ ta := textarea.New()
+ ta.Placeholder = "Send a message..."
+ ta.Focus()
+
+ ta.Prompt = "┃ "
+ ta.CharLimit = 280
+
+ ta.SetWidth(30)
+ ta.SetHeight(3)
+
+ // Remove cursor line styling
+ ta.FocusedStyle.CursorLine = lipgloss.NewStyle()
+
+ ta.ShowLineNumbers = false
+
+ vp := viewport.New(30, 20)
+ vp.SetContent("Welcome to Eko!\n Type a message and press Enter to send.")
+
+ ta.KeyMap.InsertNewline.SetEnabled(false)
+
+ messages, err := getMessages()
+ assert.NoError(err, "TODO HANDLE ERROR")
+ vp.SetContent(strings.Join(messages, "\n"))
+
+ return model{
+ textarea: ta,
+ messages: messages,
+ viewport: vp,
+ senderStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("5")),
+ err: nil,
+ }
+}
+
+func (m model) Init() tea.Cmd {
+ return textarea.Blink
+}
+
+func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+ switch msg := msg.(type) {
+ case tea.WindowSizeMsg:
+ m.viewport.Width = msg.Width
+ m.textarea.SetWidth(msg.Width)
+ return m, tea.Printf("%dx%d", msg.Width, msg.Height)
+ case tea.KeyMsg:
+ switch msg.Type {
+ case tea.KeyEsc, tea.KeyCtrlC:
+ // Quit.
+ fmt.Println(m.textarea.Value())
+ return m, tea.Quit
+ case tea.KeyEnter:
+ value := m.textarea.Value()
+
+ content := strings.TrimSpace(value)
+ if content == "" {
+ // Don't send empty messages.
+ return m, nil
+ }
+ assert.NoError(sendMessage(content), "TODO HANDLE ERROR")
+ messages, err := getMessages()
+ assert.NoError(err, "TODO HANDLE ERROR")
+
+ // m.messages = append(m.messages, m.senderStyle.Render("You: ")+content)
+ m.messages = messages
+ m.viewport.SetContent(strings.Join(m.messages, "\n"))
+ m.textarea.Reset()
+ m.viewport.GotoBottom()
+ return m, nil
+ default:
+ // Send all other keypresses to the textarea.
+ var cmd tea.Cmd
+ m.textarea, cmd = m.textarea.Update(msg)
+ return m, cmd
+ }
+
+ case cursor.BlinkMsg:
+ // Textarea should also process cursor blinks.
+ var cmd tea.Cmd
+ m.textarea, cmd = m.textarea.Update(msg)
+ return m, cmd
+
+ default:
+ return m, nil
+ }
+}
+
+func (m model) View() string {
+ return fmt.Sprintf(
+ "%s\n\n%s",
+ m.viewport.View(),
+ m.textarea.View(),
+ ) + "\n\n"
+}