tui.go

 1package tui
 2
 3import (
 4	"github.com/charmbracelet/bubbles/key"
 5	tea "github.com/charmbracelet/bubbletea"
 6	"github.com/kujtimiihoxha/termai/internal/tui/layout"
 7	"github.com/kujtimiihoxha/termai/internal/tui/page"
 8)
 9
10type keyMap struct {
11	Logs key.Binding
12	Back key.Binding
13	Quit key.Binding
14}
15
16var keys = keyMap{
17	Logs: key.NewBinding(
18		key.WithKeys("L"),
19		key.WithHelp("L", "logs"),
20	),
21	Back: key.NewBinding(
22		key.WithKeys("esc"),
23		key.WithHelp("esc", "back"),
24	),
25	Quit: key.NewBinding(
26		key.WithKeys("ctrl+c", "q"),
27		key.WithHelp("ctrl+c/q", "quit"),
28	),
29}
30
31type appModel struct {
32	width, height int
33	currentPage   page.PageID
34	previousPage  page.PageID
35	pages         map[page.PageID]tea.Model
36	loadedPages   map[page.PageID]bool
37}
38
39func (a appModel) Init() tea.Cmd {
40	cmd := a.pages[a.currentPage].Init()
41	a.loadedPages[a.currentPage] = true
42	return cmd
43}
44
45func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
46	switch msg := msg.(type) {
47	case tea.WindowSizeMsg:
48		a.width, a.height = msg.Width, msg.Height
49	case tea.KeyMsg:
50		if key.Matches(msg, keys.Quit) {
51			return a, tea.Quit
52		}
53		if key.Matches(msg, keys.Back) {
54			if a.previousPage != "" {
55				return a, a.moveToPage(a.previousPage)
56			}
57			return a, nil
58		}
59		if key.Matches(msg, keys.Logs) {
60			return a, a.moveToPage(page.LogsPage)
61		}
62	}
63	p, cmd := a.pages[a.currentPage].Update(msg)
64	if p != nil {
65		a.pages[a.currentPage] = p
66	}
67	return a, cmd
68}
69
70func (a *appModel) moveToPage(pageID page.PageID) tea.Cmd {
71	var cmd tea.Cmd
72	if _, ok := a.loadedPages[pageID]; !ok {
73		cmd = a.pages[pageID].Init()
74		a.loadedPages[pageID] = true
75	}
76	a.previousPage = a.currentPage
77	a.currentPage = pageID
78	if sizable, ok := a.pages[a.currentPage].(layout.Sizeable); ok {
79		sizable.SetSize(a.width, a.height)
80	}
81
82	return cmd
83}
84
85func (a appModel) View() string {
86	return a.pages[a.currentPage].View()
87}
88
89func New() tea.Model {
90	return &appModel{
91		currentPage: page.ReplPage,
92		loadedPages: make(map[page.PageID]bool),
93		pages: map[page.PageID]tea.Model{
94			page.LogsPage: page.NewLogsPage(),
95			page.InitPage: page.NewInitPage(),
96			page.ReplPage: page.NewReplPage(),
97		},
98	}
99}