fbe444c3ab
- Add Bubble Tea TUI model with Init/Update/View - Implement host list screen with keyboard navigation (up/down/enter/q) - Add styled rendering for hosts, selection, tags - Create hostkeeper tui CLI command - Add tests for TUI initialization and host loading - Update project state documentation
102 lines
2.1 KiB
Go
102 lines
2.1 KiB
Go
package tui
|
|
|
|
import (
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
|
|
"git.tukangketik.id/swanadiva/hostkeeper/internal/models"
|
|
)
|
|
|
|
// Styles for TUI components
|
|
var (
|
|
TitleStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("86")).Bold(true)
|
|
SubtitleStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241"))
|
|
HighlightStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("212")).Bold(true)
|
|
ErrorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("196")).Bold(true)
|
|
SuccessStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("76")).Bold(true)
|
|
InfoStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("117"))
|
|
)
|
|
|
|
// Screen represents different TUI screens
|
|
type Screen int
|
|
|
|
const (
|
|
ScreenHostList Screen = iota
|
|
ScreenConnection
|
|
ScreenSettings
|
|
)
|
|
|
|
// Model represents the main TUI model
|
|
type Model struct {
|
|
CurrentScreen Screen
|
|
Hosts []*models.Host
|
|
SelectedIndex int
|
|
Error error
|
|
Quit bool
|
|
}
|
|
|
|
// New creates a new TUI model
|
|
func New() *Model {
|
|
return &Model{
|
|
CurrentScreen: ScreenHostList,
|
|
SelectedIndex: 0,
|
|
Quit: false,
|
|
}
|
|
}
|
|
|
|
// Init initializes the TUI
|
|
func (m *Model) Init() tea.Cmd {
|
|
return nil
|
|
}
|
|
|
|
// Update handles messages and updates the model
|
|
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "ctrl+c", "q":
|
|
m.Quit = true
|
|
return m, tea.Quit
|
|
|
|
case "up", "k":
|
|
if m.SelectedIndex > 0 {
|
|
m.SelectedIndex--
|
|
}
|
|
|
|
case "down", "j":
|
|
if m.SelectedIndex < len(m.Hosts)-1 {
|
|
m.SelectedIndex++
|
|
}
|
|
|
|
case "enter", " ":
|
|
if len(m.Hosts) > 0 {
|
|
return m, tea.Quit
|
|
}
|
|
}
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
// View renders the TUI
|
|
func (m *Model) View() string {
|
|
if m.Quit {
|
|
return "Thanks for using hostkeeper!\n"
|
|
}
|
|
|
|
switch m.CurrentScreen {
|
|
case ScreenHostList:
|
|
return renderHostList(m)
|
|
default:
|
|
return "Screen not implemented yet"
|
|
}
|
|
}
|
|
|
|
// LoadHosts loads hosts into the TUI model
|
|
func (m *Model) LoadHosts(hosts []*models.Host) {
|
|
m.Hosts = hosts
|
|
if len(hosts) > 0 && m.SelectedIndex >= len(hosts) {
|
|
m.SelectedIndex = len(hosts) - 1
|
|
}
|
|
}
|