@@ -5,9 +5,11 @@ import (
55 "fmt"
66 "io"
77 "net/http"
8+ "strings"
89 "time"
910
1011 "github.com/charmbracelet/bubbles/table"
12+ "github.com/charmbracelet/bubbles/textinput"
1113 tea "github.com/charmbracelet/bubbletea"
1214 "github.com/charmbracelet/lipgloss"
1315 "github.com/digitalghost-dev/poke-cli/styling"
@@ -19,13 +21,42 @@ type CardsModel struct {
1921 ImageMap map [string ]string
2022 PriceMap map [string ]string
2123 RegulationMarkMap map [string ]string
24+ AllRows []table.Row
2225 Quitting bool
26+ Search textinput.Model
2327 SelectedOption string
2428 SeriesName string
2529 Table table.Model
30+ TableStyles table.Styles
2631 ViewImage bool
2732}
2833
34+ const (
35+ activeTableSelectedBg lipgloss.Color = "#FFCC00"
36+ inactiveTableSelectedBg lipgloss.Color = "#808080"
37+ )
38+
39+ func cardTableStyles (selectedBg lipgloss.Color ) table.Styles {
40+ s := table .DefaultStyles ()
41+ s .Header = s .Header .
42+ BorderStyle (lipgloss .NormalBorder ()).
43+ BorderForeground (lipgloss .Color ("#FFCC00" )).
44+ BorderBottom (true )
45+ s .Selected = s .Selected .
46+ Foreground (lipgloss .Color ("#000" )).
47+ Background (selectedBg )
48+ return s
49+ }
50+
51+ func (m * CardsModel ) syncTableStylesForFocus () {
52+ if m .Search .Focused () {
53+ m .TableStyles = cardTableStyles (inactiveTableSelectedBg )
54+ } else {
55+ m .TableStyles = cardTableStyles (activeTableSelectedBg )
56+ }
57+ m .Table .SetStyles (m .TableStyles )
58+ }
59+
2960func (m CardsModel ) Init () tea.Cmd {
3061 return nil
3162}
@@ -36,16 +67,46 @@ func (m CardsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
3667 switch msg := msg .(type ) {
3768 case tea.KeyMsg :
3869 switch msg .String () {
39- case "esc" , " ctrl+c" :
70+ case "ctrl+c" :
4071 m .Quitting = true
4172 return m , tea .Quit
42- case " " :
43- m .ViewImage = true
73+ case "esc" :
74+ // If in the search bar, exit search mode instead of quitting.
75+ if m .Search .Focused () {
76+ m .Search .Blur ()
77+ m .Table .Focus ()
78+ m .syncTableStylesForFocus ()
79+ return m , nil
80+ }
81+ m .Quitting = true
4482 return m , tea .Quit
83+ case "?" :
84+ if ! m .Search .Focused () {
85+ m .ViewImage = true
86+ return m , tea .Quit
87+ }
88+ case "tab" :
89+ if m .Search .Focused () {
90+ m .Search .Blur ()
91+ m .Table .Focus ()
92+ } else {
93+ m .Table .Blur ()
94+ m .Search .Focus ()
95+ }
96+ m .syncTableStylesForFocus ()
97+ return m , nil
4598 }
4699 }
47100
48- m .Table , bubbleCmd = m .Table .Update (msg )
101+ if m .Search .Focused () {
102+ prev := m .Search .Value ()
103+ m .Search , bubbleCmd = m .Search .Update (msg )
104+ if m .Search .Value () != prev {
105+ m .applyFilter ()
106+ }
107+ } else {
108+ m .Table , bubbleCmd = m .Table .Update (msg )
109+ }
49110
50111 // Keep the selected option in sync on every update
51112 if row := m .Table .SelectedRow (); len (row ) > 0 {
@@ -58,6 +119,28 @@ func (m CardsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
58119 return m , bubbleCmd
59120}
60121
122+ func (m * CardsModel ) applyFilter () {
123+ q := strings .TrimSpace (strings .ToLower (m .Search .Value ()))
124+ if q == "" {
125+ m .Table .SetRows (m .AllRows )
126+ m .Table .SetCursor (0 )
127+ return
128+ }
129+
130+ filtered := make ([]table.Row , 0 , len (m .AllRows ))
131+ for _ , r := range m .AllRows {
132+ if len (r ) == 0 {
133+ continue
134+ }
135+ if strings .Contains (strings .ToLower (r [0 ]), q ) {
136+ filtered = append (filtered , r )
137+ }
138+ }
139+
140+ m .Table .SetRows (filtered )
141+ m .Table .SetCursor (0 )
142+ }
143+
61144func (m CardsModel ) View () string {
62145 if m .Quitting {
63146 return "\n Quitting card search...\n \n "
@@ -75,7 +158,8 @@ func (m CardsModel) View() string {
75158 selectedCard = cardName + "\n ---\n " + price + "\n ---\n " + illustrator + "\n ---\n " + regulationMark
76159 }
77160
78- leftPanel := styling .TypesTableBorder .Render (m .Table .View ())
161+ leftContent := lipgloss .JoinVertical (lipgloss .Left , m .Search .View (), m .Table .View ())
162+ leftPanel := styling .TypesTableBorder .Render (leftContent )
79163
80164 rightPanel := lipgloss .NewStyle ().
81165 Width (40 ).
@@ -87,9 +171,10 @@ func (m CardsModel) View() string {
87171
88172 screen := lipgloss .JoinHorizontal (lipgloss .Top , leftPanel , rightPanel )
89173
90- return fmt .Sprintf ("Highlight a card!\n %s\n %s" ,
174+ return fmt .Sprintf (
175+ "Highlight a card!\n %s\n %s" ,
91176 screen ,
92- styling .KeyMenu .Render ("↑ (move up)\n ↓ (move down)\n space (view image)\n ctrl+c | esc (quit)" ))
177+ styling .KeyMenu .Render ("↑ (move up)\n ↓ (move down)\n ? (view image) \n tab (toggle search )\n ctrl+c | esc (quit)" ))
93178}
94179
95180type cardData struct {
@@ -117,10 +202,13 @@ func CardsList(setID string) (CardsModel, error) {
117202
118203 // Extract card names and build table rows + price map
119204 rows := make ([]table.Row , len (allCards ))
205+ allRows := rows
206+
120207 priceMap := make (map [string ]string )
121208 imageMap := make (map [string ]string )
122209 illustratorMap := make (map [string ]string )
123210 regulationMarkMap := make (map [string ]string )
211+
124212 for i , card := range allCards {
125213 rows [i ] = []string {card .NumberPlusName }
126214 if card .MarketPrice != 0 {
@@ -144,29 +232,32 @@ func CardsList(setID string) (CardsModel, error) {
144232 imageMap [card .NumberPlusName ] = card .ImageURL
145233 }
146234
235+ ti := textinput .New ()
236+ ti .Placeholder = "type name..."
237+ ti .Prompt = "🔎 "
238+ ti .CharLimit = 24
239+ ti .Width = 30
240+ ti .Blur ()
241+
147242 t := table .New (
148243 table .WithColumns ([]table.Column {{Title : "Card Name" , Width : 35 }}),
149244 table .WithRows (rows ),
150245 table .WithFocused (true ),
151- table .WithHeight (28 ),
246+ table .WithHeight (27 ),
152247 )
153248
154- s := table .DefaultStyles ()
155- s .Header = s .Header .
156- BorderStyle (lipgloss .NormalBorder ()).
157- BorderForeground (lipgloss .Color ("#FFCC00" )).
158- BorderBottom (true )
159- s .Selected = s .Selected .
160- Foreground (lipgloss .Color ("#000" )).
161- Background (lipgloss .Color ("#FFCC00" ))
162- t .SetStyles (s )
249+ styles := cardTableStyles (activeTableSelectedBg )
250+ t .SetStyles (styles )
163251
164252 return CardsModel {
165- IllustratorMap : illustratorMap ,
166- ImageMap : imageMap ,
167- PriceMap : priceMap ,
168- RegulationMarkMap : regulationMarkMap ,
169- Table : t ,
253+ AllRows : allRows ,
254+ IllustratorMap : illustratorMap ,
255+ ImageMap : imageMap ,
256+ PriceMap : priceMap ,
257+ RegulationMarkMap : regulationMarkMap ,
258+ Search : ti ,
259+ Table : t ,
260+ TableStyles : styles ,
170261 }, nil
171262}
172263
0 commit comments