Skip to content

Commit c57cb5b

Browse files
committed
Start building out the TUI.
1 parent 58832e2 commit c57cb5b

File tree

3 files changed

+222
-0
lines changed

3 files changed

+222
-0
lines changed

cmd/main.go

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
tea "github.com/charmbracelet/bubbletea"
8+
"github.com/charmbracelet/lipgloss"
9+
)
10+
11+
func main() {
12+
p := tea.NewProgram(initialModel())
13+
if _, err := p.Run(); err != nil {
14+
fmt.Println("Error running program:", err)
15+
}
16+
}
17+
18+
const (
19+
dotChar = " • "
20+
)
21+
22+
var (
23+
keywordStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("211"))
24+
subtleStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241"))
25+
checkboxStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("212"))
26+
dotStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("236")).Render(dotChar)
27+
mainStyle = lipgloss.NewStyle().MarginLeft(2)
28+
)
29+
30+
type model struct {
31+
quitting bool
32+
choice int
33+
chosen bool
34+
}
35+
36+
type (
37+
frameMsg struct{}
38+
)
39+
40+
func initialModel() model {
41+
return model{
42+
quitting: false,
43+
choice: 0,
44+
chosen: false,
45+
}
46+
}
47+
48+
func (m model) Init() tea.Cmd {
49+
return nil
50+
}
51+
52+
func frame() tea.Cmd {
53+
return tea.Tick(time.Second/60, func(time.Time) tea.Msg {
54+
return frameMsg{}
55+
})
56+
}
57+
58+
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
59+
switch msg := msg.(type) {
60+
case tea.KeyMsg:
61+
if !m.chosen {
62+
return m.handleMainScreen(msg)
63+
} else {
64+
return m.handleSubScreen(msg)
65+
}
66+
}
67+
return m, nil
68+
}
69+
70+
func (m model) handleMainScreen(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
71+
switch msg.String() {
72+
case "ctrl+c", "esc":
73+
m.quitting = true
74+
return m, tea.Quit
75+
case "j", "down":
76+
m.choice++
77+
if m.choice > 4 {
78+
m.choice = 4
79+
}
80+
case "k", "up":
81+
m.choice--
82+
if m.choice < 0 {
83+
m.choice = 0
84+
}
85+
case "enter":
86+
m.chosen = true
87+
return m, frame()
88+
}
89+
90+
return m, nil
91+
}
92+
93+
func (m model) handleSubScreen(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
94+
switch msg.String() {
95+
case "ctrl+c":
96+
m.quitting = true
97+
return m, tea.Quit
98+
99+
case "esc":
100+
m.chosen = false
101+
102+
}
103+
return m, nil
104+
}
105+
106+
func (m model) View() string {
107+
var s string
108+
if m.quitting {
109+
return "\n See you later!\n\n"
110+
}
111+
if !m.chosen {
112+
s = choicesView(m)
113+
} else {
114+
switch m.choice {
115+
case 0:
116+
s = keywordStyle.Render("You chose Git / Git LFS!")
117+
case 1:
118+
s = keywordStyle.Render("You chose Godot!")
119+
case 2:
120+
s = keywordStyle.Render("You chose Rust!")
121+
case 3:
122+
s = keywordStyle.Render("You chose Zig!")
123+
case 4:
124+
s = keywordStyle.Render("You chose Docker!")
125+
default:
126+
s = keywordStyle.Render("Unknown choice")
127+
}
128+
}
129+
return mainStyle.Render("\n" + s + "\n\n")
130+
}
131+
132+
func choicesView(m model) string {
133+
c := m.choice
134+
135+
tpl := "Where would you like to begin?\n\n"
136+
tpl += "%s\n\n"
137+
tpl += subtleStyle.Render("j/k, up/down: select") + dotStyle +
138+
subtleStyle.Render("enter: choose") + dotStyle +
139+
subtleStyle.Render("ctrl+c, esc: quit")
140+
141+
choices := fmt.Sprintf(
142+
"%s\n%s\n%s\n%s\n%s",
143+
checkbox("Git / Git LFS", c == 0),
144+
checkbox("Godot", c == 1),
145+
checkbox("Rust", c == 2),
146+
checkbox("Zig", c == 3),
147+
checkbox("Docker", c == 4),
148+
)
149+
150+
return fmt.Sprintf(tpl, choices)
151+
}
152+
153+
func checkbox(label string, checked bool) string {
154+
if checked {
155+
return checkboxStyle.Render("[x] " + label)
156+
}
157+
return fmt.Sprintf("[ ] %s", label)
158+
}

go.mod

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module github.com/reia-dev-helper
2+
3+
go 1.22.0
4+
5+
require (
6+
github.com/charmbracelet/bubbletea v0.25.0
7+
github.com/charmbracelet/lipgloss v0.9.1
8+
)
9+
10+
require (
11+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
12+
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
13+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
14+
github.com/mattn/go-isatty v0.0.18 // indirect
15+
github.com/mattn/go-localereader v0.0.1 // indirect
16+
github.com/mattn/go-runewidth v0.0.15 // indirect
17+
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
18+
github.com/muesli/cancelreader v0.2.2 // indirect
19+
github.com/muesli/reflow v0.3.0 // indirect
20+
github.com/muesli/termenv v0.15.2 // indirect
21+
github.com/rivo/uniseg v0.2.0 // indirect
22+
golang.org/x/sync v0.1.0 // indirect
23+
golang.org/x/sys v0.12.0 // indirect
24+
golang.org/x/term v0.6.0 // indirect
25+
golang.org/x/text v0.3.8 // indirect
26+
)

go.sum

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
2+
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
3+
github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
4+
github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
5+
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
6+
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
7+
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
8+
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
9+
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
10+
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
11+
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
12+
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
13+
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
14+
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
15+
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
16+
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
17+
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
18+
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
19+
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
20+
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
21+
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
22+
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
23+
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
24+
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
25+
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
26+
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
27+
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
28+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
29+
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
30+
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
31+
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
32+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
33+
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
34+
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
35+
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
36+
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
37+
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
38+
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=

0 commit comments

Comments
 (0)