view.go
 1  package main
 2  
 3  import (
 4  	"fmt"
 5  	"strings"
 6  
 7  	"github.com/charmbracelet/lipgloss"
 8  )
 9  
10  // View renders the entire UI
11  func (m model) View() string {
12  	if !m.ready {
13  		return "\n  Initializing Kamaji TUI..."
14  	}
15  
16  	var sb strings.Builder
17  
18  	// Header (empty for now, or could add ASCII art)
19  	// sb.WriteString("\n")
20  
21  	// Message viewport
22  	sb.WriteString(m.viewport.View())
23  	sb.WriteString("\n")
24  
25  	// Status bars
26  	sb.WriteString(m.renderStatusBars())
27  	sb.WriteString("\n")
28  
29  	// Input area
30  	sb.WriteString(m.renderInputArea())
31  	sb.WriteString("\n")
32  
33  	// Footer
34  	sb.WriteString(m.renderFooter())
35  
36  	return sb.String()
37  }
38  
39  // renderStatusBars renders provider and shell status
40  func (m model) renderStatusBars() string {
41  	// Provider status
42  	providerText := fmt.Sprintf("🔧 %s: %s", m.provider, m.model)
43  	providerBar := statusBarStyle.Render(providerText)
44  
45  	// Shell status
46  	shellText := fmt.Sprintf("🐚 Shell: %s", m.shellCwd)
47  	shellBar := statusBarStyle.Render(shellText)
48  
49  	// Combine
50  	return lipgloss.JoinVertical(
51  		lipgloss.Left,
52  		providerBar,
53  		shellBar,
54  	)
55  }
56  
57  // renderInputArea renders the text input field
58  func (m model) renderInputArea() string {
59  	if m.loading {
60  		spinner := []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
61  		frame := spinner[m.spinnerFrame%len(spinner)]
62  		loading := lipgloss.NewStyle().
63  			Foreground(accentColor).
64  			Bold(true).
65  			Render(frame + " Agent is thinking...")
66  		return statusBarStyle.Width(m.width).Render(loading)
67  	}
68  	return m.textarea.View()
69  }
70  
71  // renderFooter renders keyboard shortcuts
72  func (m model) renderFooter() string {
73  	shortcuts := "Ctrl+C: Quit  |  Enter: Send  |  PgUp/PgDn: Scroll"
74  	return footerStyle.Render(shortcuts)
75  }