Skip to content

Commit a9e1346

Browse files
authored
Merge pull request #12 from prime-run/dev
fix: colorschemes dir path
2 parents 5f78a9c + f295c5c commit a9e1346

File tree

5 files changed

+366
-14
lines changed

5 files changed

+366
-14
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
)
1313

1414
require (
15+
github.com/atotto/clipboard v0.1.4 // indirect
1516
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
1617
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
1718
github.com/charmbracelet/harmonica v0.2.0 // indirect
@@ -28,6 +29,7 @@ require (
2829
github.com/muesli/cancelreader v0.2.2 // indirect
2930
github.com/muesli/termenv v0.16.0 // indirect
3031
github.com/rivo/uniseg v0.4.7 // indirect
32+
github.com/sahilm/fuzzy v0.1.1 // indirect
3133
github.com/spf13/pflag v1.0.6 // indirect
3234
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
3335
golang.org/x/sync v0.13.0 // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
2+
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
13
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
24
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
35
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
@@ -21,6 +23,8 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6
2123
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
2224
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
2325
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
26+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
27+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
2428
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
2529
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
2630
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -39,6 +43,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
3943
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
4044
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
4145
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
46+
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
47+
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
4248
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
4349
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
4450
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=

ui/settings.go

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package ui
33
import (
44
"encoding/json"
55
"fmt"
6+
"github.com/charmbracelet/bubbles/list"
7+
tea "github.com/charmbracelet/bubbletea"
8+
"github.com/charmbracelet/lipgloss"
69
"os"
710
"path/filepath"
811
)
@@ -158,3 +161,232 @@ func InitSettings() {
158161
ApplySettings()
159162
}
160163
}
164+
165+
type SettingsItem struct {
166+
title string
167+
options []string
168+
details string
169+
selected int
170+
expanded bool
171+
key string
172+
}
173+
174+
func (i SettingsItem) Title() string {
175+
arrow := "→"
176+
if i.expanded {
177+
arrow = "↓"
178+
}
179+
return fmt.Sprintf("%s %s", arrow, i.title)
180+
}
181+
182+
func (i SettingsItem) Description() string {
183+
return fmt.Sprintf("%s: %s", i.options[i.selected], i.details)
184+
}
185+
186+
func (i SettingsItem) FilterValue() string { return i.title }
187+
188+
type SettingsModel struct {
189+
list list.Model
190+
height, width int
191+
settings UserSettings
192+
}
193+
194+
func createSettingsItems(settings UserSettings) []list.Item {
195+
themeOptions := []string{"default", "dark", "light"}
196+
themeSelected := 0
197+
for i, opt := range themeOptions {
198+
if opt == settings.ThemeName {
199+
themeSelected = i
200+
break
201+
}
202+
}
203+
204+
cursorOptions := []string{"block", "underline"}
205+
cursorSelected := 0
206+
for i, opt := range cursorOptions {
207+
if opt == settings.CursorType {
208+
cursorSelected = i
209+
break
210+
}
211+
}
212+
213+
gameModeOptions := []string{GameModeNormal, GameModeSimple}
214+
gameModeSelected := 0
215+
for i, opt := range gameModeOptions {
216+
if opt == settings.GameMode {
217+
gameModeSelected = i
218+
break
219+
}
220+
}
221+
222+
textLengthOptions := []string{TextLengthShort, TextLengthMedium, TextLengthLong, TextLengthVeryLong}
223+
textLengthSelected := 0
224+
for i, opt := range textLengthOptions {
225+
if opt == settings.TextLength {
226+
textLengthSelected = i
227+
break
228+
}
229+
}
230+
231+
refreshRateOptions := []string{"5", "10", "15", "20", "30"}
232+
refreshRateSelected := 0
233+
for i, opt := range refreshRateOptions {
234+
if opt == fmt.Sprintf("%d", settings.RefreshRate) {
235+
refreshRateSelected = i
236+
break
237+
}
238+
}
239+
240+
return []list.Item{
241+
&SettingsItem{
242+
title: "Theme",
243+
options: themeOptions,
244+
details: "Select your preferred theme",
245+
selected: themeSelected,
246+
key: "theme",
247+
},
248+
&SettingsItem{
249+
title: "Cursor Type",
250+
options: cursorOptions,
251+
details: "Choose cursor appearance",
252+
selected: cursorSelected,
253+
key: "cursor",
254+
},
255+
&SettingsItem{
256+
title: "Game Mode",
257+
options: gameModeOptions,
258+
details: "Select game difficulty mode",
259+
selected: gameModeSelected,
260+
key: "game_mode",
261+
},
262+
&SettingsItem{
263+
title: "Text Length",
264+
options: textLengthOptions,
265+
details: "Choose text length for typing",
266+
selected: textLengthSelected,
267+
key: "text_length",
268+
},
269+
&SettingsItem{
270+
title: "Refresh Rate",
271+
options: refreshRateOptions,
272+
details: "Set UI refresh rate (FPS)",
273+
selected: refreshRateSelected,
274+
key: "refresh_rate",
275+
},
276+
}
277+
}
278+
279+
func initialSettingsModel() SettingsModel {
280+
settings := CurrentSettings
281+
items := createSettingsItems(settings)
282+
283+
l := list.New(items, list.NewDefaultDelegate(), 0, 0)
284+
l.SetShowHelp(false)
285+
l.SetFilteringEnabled(false)
286+
l.SetShowStatusBar(false)
287+
l.Title = "Settings"
288+
l.Styles.Title = SettingsTitleStyle
289+
290+
return SettingsModel{
291+
list: l,
292+
settings: settings,
293+
}
294+
}
295+
296+
func (m SettingsModel) Init() tea.Cmd { return nil }
297+
298+
func (m SettingsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
299+
switch msg := msg.(type) {
300+
case tea.WindowSizeMsg:
301+
m.width, m.height = msg.Width, msg.Height
302+
m.list.SetSize(m.width/3, m.height/2)
303+
304+
case tea.KeyMsg:
305+
switch msg.String() {
306+
case "q", "ctrl+c":
307+
return m, tea.Quit
308+
case "enter":
309+
if i, ok := m.list.SelectedItem().(*SettingsItem); ok {
310+
if !i.expanded {
311+
i.expanded = true
312+
} else {
313+
i.selected = (i.selected + 1) % len(i.options)
314+
switch i.key {
315+
case "theme":
316+
m.settings.ThemeName = i.options[i.selected]
317+
case "cursor":
318+
m.settings.CursorType = i.options[i.selected]
319+
case "game_mode":
320+
m.settings.GameMode = i.options[i.selected]
321+
case "text_length":
322+
m.settings.TextLength = i.options[i.selected]
323+
case "refresh_rate":
324+
fmt.Sscanf(i.options[i.selected], "%d", &m.settings.RefreshRate)
325+
}
326+
UpdateSettings(m.settings)
327+
}
328+
}
329+
case "esc":
330+
if i, ok := m.list.SelectedItem().(*SettingsItem); ok {
331+
i.expanded = false
332+
}
333+
}
334+
}
335+
336+
var cmd tea.Cmd
337+
m.list, cmd = m.list.Update(msg)
338+
return m, cmd
339+
}
340+
341+
func (m SettingsModel) View() string {
342+
if m.width == 0 {
343+
return "Loading..."
344+
}
345+
346+
listView := SettingsListStyle.Render(m.list.View())
347+
348+
details := "Select an item to view details"
349+
if i, ok := m.list.SelectedItem().(*SettingsItem); ok {
350+
if i.expanded {
351+
details = fmt.Sprintf("%s\n\nCurrent: %s\n\nOptions:\n",
352+
i.details,
353+
i.options[i.selected],
354+
)
355+
for idx, opt := range i.options {
356+
bullet := "•"
357+
if idx == i.selected {
358+
bullet = ">"
359+
}
360+
details += fmt.Sprintf("%s %s\n", bullet, opt)
361+
}
362+
} else {
363+
details = i.details
364+
}
365+
}
366+
367+
detailsView := SettingsDetailsStyle.Render(details)
368+
369+
content := lipgloss.Place(
370+
m.width,
371+
m.height-1,
372+
lipgloss.Center,
373+
lipgloss.Center,
374+
lipgloss.JoinHorizontal(lipgloss.Top, listView, detailsView),
375+
)
376+
377+
help := lipgloss.PlaceHorizontal(
378+
m.width,
379+
lipgloss.Center,
380+
SettingsHelpStyle.Render("↑/↓: Navigate • Enter: Select • Esc: Back • q: Quit"),
381+
)
382+
383+
return lipgloss.JoinVertical(lipgloss.Bottom, content, help)
384+
}
385+
386+
func ShowSettings() error {
387+
p := tea.NewProgram(initialSettingsModel(), tea.WithAltScreen())
388+
if _, err := p.Run(); err != nil {
389+
return fmt.Errorf("error running settings program: %w", err)
390+
}
391+
return nil
392+
}

ui/styles.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,23 @@ func UpdateStyles() {
5757
Foreground(GetColor("cursor_underline")).
5858
Underline(true)
5959

60+
SettingsListStyle = lipgloss.NewStyle().
61+
Width(MaxWidth/3 - 4).
62+
MarginLeft(2).
63+
MarginRight(2)
64+
65+
SettingsDetailsStyle = lipgloss.NewStyle().
66+
Width(MaxWidth / 2).
67+
MarginLeft(2)
68+
69+
SettingsTitleStyle = lipgloss.NewStyle().
70+
Background(lipgloss.Color("62")).
71+
Foreground(lipgloss.Color("0")).
72+
Padding(0, 1)
73+
74+
SettingsHelpStyle = lipgloss.NewStyle().
75+
Foreground(lipgloss.Color("241"))
76+
6077
EndGameTitleStyle = lipgloss.NewStyle().
6178
Foreground(GetColor("text_correct")).
6279
Bold(true).
@@ -109,9 +126,10 @@ var DimStyle lipgloss.Style
109126
var TextContainerStyle lipgloss.Style
110127
var BlockCursorStyle lipgloss.Style
111128
var UnderlineCursorStyle lipgloss.Style
112-
113-
// endgame screen styles
114-
// .
129+
var SettingsListStyle lipgloss.Style
130+
var SettingsDetailsStyle lipgloss.Style
131+
var SettingsTitleStyle lipgloss.Style
132+
var SettingsHelpStyle lipgloss.Style
115133
var EndGameTitleStyle lipgloss.Style
116134
var EndGameStatsBoxStyle lipgloss.Style
117135
var EndGameWpmStyle lipgloss.Style

0 commit comments

Comments
 (0)