clone

fifteen puzzle games for the terminal, with daily puzzles, weekly ladders and xp, built on bubble tea

refactor: prepare for bubbletea v2 migration

Dami committed 0cd14ad
- Add root-level KeyMap using bubbles/key bindings to replace raw
  tea.Key* constants in update.go (10 occurrences eliminated)
- Isolate lipgloss.GetFrameSize() behind ui.RootFrameSize() helper
- Replace style.GetBackground()/GetForeground() calls with exported
  color token variables (CursorFG, CursorBG, CursorWarmBG, ConflictFG,
  ConflictBG) -- eliminates all v1-specific Get* API usage
- Extract ui.CenterView() helper to centralize lipgloss.Place() pattern
  (8 occurrences in view.go reduced to single call site)
commit
0cd14ad12c4221dbf67ca4be65481aa36bd1bcf3
parent
6de7d24fbbdd9bf764352fd260e7593bb6dd60cd
author
Dami <dami.etoile@gmail.com>
8 files changed, +95 -40
Mgame/style.go22+++++++++++++-----
Mhitori/style.go13+++-------
Akeys.go37++++++++++++++++++++++++++++++
Mnonogram/style.go7+++--
Mtakuzu/style.go3+--
Mui/style.go12++++++++++
Mupdate.go25+++++++++++----------
Mview.go16++++++------
M game/style.go +16 -6
@@ -7,11 +7,21 @@ import (
77 "github.com/charmbracelet/lipgloss"88 )99 10+// Shared cursor color tokens, used both in style construction and for11+// composite styling where a cursor color is applied on top of another style.12+var (13+ CursorFG = lipgloss.AdaptiveColor{Light: "255", Dark: "235"}14+ CursorBG = lipgloss.AdaptiveColor{Light: "130", Dark: "173"}15+ CursorWarmBG = lipgloss.AdaptiveColor{Light: "130", Dark: "214"}16+ ConflictFG = lipgloss.AdaptiveColor{Light: "160", Dark: "167"}17+ ConflictBG = lipgloss.AdaptiveColor{Light: "224", Dark: "52"}18+)19+1020 var (1121 titleStyle = lipgloss.NewStyle().1222 Bold(true).1323 Foreground(lipgloss.AdaptiveColor{Light: "255", Dark: "255"}).14- Background(lipgloss.AdaptiveColor{Light: "130", Dark: "173"}).24+ Background(CursorBG).1525 Padding(0, 1)1626 1727 solvedBadgeStyle = lipgloss.NewStyle().
@@ -22,21 +32,21 @@ var (
2232 // Used by lightsout, sudoku, wordsearch.2333 CursorStyle = lipgloss.NewStyle().2434 Bold(true).25- Foreground(lipgloss.AdaptiveColor{Light: "255", Dark: "235"}).26- Background(lipgloss.AdaptiveColor{Light: "130", Dark: "173"})35+ Foreground(CursorFG).36+ Background(CursorBG)2737 2838 // CursorWarmStyle highlights the cursor with a warmer background.2939 // Used by hitori, takuzu, nonogram.3040 CursorWarmStyle = lipgloss.NewStyle().3141 Bold(true).32- Foreground(lipgloss.AdaptiveColor{Light: "255", Dark: "235"}).33- Background(lipgloss.AdaptiveColor{Light: "130", Dark: "214"})42+ Foreground(CursorFG).43+ Background(CursorWarmBG)3444 3545 // CursorSolvedStyle highlights the cursor position on a solved grid.3646 // Shared across all puzzle types.3747 CursorSolvedStyle = lipgloss.NewStyle().3848 Bold(true).39- Foreground(lipgloss.AdaptiveColor{Light: "255", Dark: "235"}).49+ Foreground(CursorFG).4050 Background(lipgloss.AdaptiveColor{Light: "28", Dark: "28"})4151 4252 // StatusBarStyle is the shared style for the status/help bar below each puzzle grid.
M hitori/style.go +4 -9
A keys.go +37 -0
M nonogram/style.go +4 -3
M takuzu/style.go +1 -2
M ui/style.go +12 -0
M update.go +13 -12
@@ -9,6 +9,7 @@ import (
99 "github.com/FelineStateMachine/puzzletea/store"1010 "github.com/FelineStateMachine/puzzletea/ui"1111 12+ "github.com/charmbracelet/bubbles/key"1213 "github.com/charmbracelet/bubbles/viewport"1314 tea "github.com/charmbracelet/bubbletea"1415 "github.com/charmbracelet/glamour"
@@ -22,7 +23,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
2223 return m.handleSpawnComplete(msg)2324 2425 case tea.WindowSizeMsg:25- h, v := ui.RootStyle.GetFrameSize()26+ h, v := ui.RootFrameSize()2627 w, ht := msg.Width-h, msg.Height-v2728 m.width = w2829 m.height = ht
@@ -47,8 +48,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
4748 case tea.KeyMsg:4849 // During generation, only allow Escape (to cancel) and Ctrl+C (to quit).4950 if m.state == generatingView {50- switch msg.Type {51- case tea.KeyEscape:51+ switch {52+ case key.Matches(msg, rootKeys.Escape):5253 if m.dailyPending {5354 m.dailyPending = false5455 m.state = mainMenuView
@@ -56,33 +57,33 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
5657 m.state = modeSelectView5758 }5859 return m, nil59- case tea.KeyCtrlC:60+ case key.Matches(msg, rootKeys.Quit):6061 return m, tea.Quit6162 }6263 return m, nil6364 }64- switch msg.Type {65- case tea.KeyCtrlN:65+ switch {66+ case key.Matches(msg, rootKeys.MainMenu):6667 m = saveCurrentGame(m, store.StatusInProgress)6768 m.state = mainMenuView6869 m.debug = false69- case tea.KeyEnter:70+ case key.Matches(msg, rootKeys.Enter):7071 if m.state != gameView {7172 return m.handleEnter()7273 }73- case tea.KeyEscape:74+ case key.Matches(msg, rootKeys.Escape):7475 return m.handleEscape()75- case tea.KeyCtrlC:76+ case key.Matches(msg, rootKeys.Quit):7677 m = saveCurrentGame(m, store.StatusAbandoned)7778 return m, tea.Quit78- case tea.KeyCtrlE:79+ case key.Matches(msg, rootKeys.Debug):7980 m.debug = !m.debug80- case tea.KeyCtrlH:81+ case key.Matches(msg, rootKeys.FullHelp):8182 m.showFullHelp = !m.showFullHelp8283 if m.state == gameView && m.game != nil {8384 m.game, _ = m.game.Update(game.HelpToggleMsg{Show: m.showFullHelp})8485 }85- case tea.KeyCtrlR:86+ case key.Matches(msg, rootKeys.ResetGame):8687 if m.state == gameView && m.game != nil {8788 m.game = m.game.Reset()8889 }
M view.go +8 -8
@@ -11,14 +11,14 @@ import (
1111 func (m model) View() string {1212 switch m.state {1313 case mainMenuView:14- return ui.RootStyle.Render(lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, m.mainMenuList.View()))14+ return ui.CenterView(m.width, m.height, m.mainMenuList.View())1515 case gameSelectView:16- return ui.RootStyle.Render(lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, m.gameSelectList.View()))16+ return ui.CenterView(m.width, m.height, m.gameSelectList.View())1717 case modeSelectView:18- return ui.RootStyle.Render(lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, m.modeSelectList.View()))18+ return ui.CenterView(m.width, m.height, m.modeSelectList.View())1919 case generatingView:2020 s := m.spinner.View() + " Generating puzzle..."21- return ui.RootStyle.Render(lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, s))21+ return ui.CenterView(m.width, m.height, s)2222 case continueView:2323 var s string2424 if len(m.continueGames) == 0 {
@@ -32,7 +32,7 @@ func (m model) View() string {
3232 Render("Saved Games")3333 s = lipgloss.JoinVertical(lipgloss.Left, title, "", m.continueTable.View())3434 }35- return ui.RootStyle.Render(lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, s))35+ return ui.CenterView(m.width, m.height, s)3636 case gameView:3737 if m.game == nil {3838 return ""
@@ -45,9 +45,9 @@ func (m model) View() string {
4545 m.game.View(),4646 debugInfo,4747 )48- return ui.RootStyle.Render(lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, s))48+ return ui.CenterView(m.width, m.height, s)4949 case helpSelectView:50- return ui.RootStyle.Render(lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, m.helpSelectList.View()))50+ return ui.CenterView(m.width, m.height, m.helpSelectList.View())5151 case helpDetailView:5252 footer := lipgloss.NewStyle().5353 Foreground(ui.MenuTextDim).
@@ -56,7 +56,7 @@ func (m model) View() string {
5656 m.helpViewport.View(),5757 footer,5858 )59- return ui.RootStyle.Render(lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, s))59+ return ui.CenterView(m.width, m.height, s)6060 default:6161 return fmt.Sprintf("unknown state: %d", m.state)6262 }