@@ -3,34 +3,21 @@ package components
33import (
44 "strings"
55
6- "charm.land/bubbles/v2/textinput"
76 tea "charm.land/bubbletea/v2"
87 lipgloss "charm.land/lipgloss/v2"
98 "github.com/deeploy-sh/deeploy/internal/tui/ui/styles"
109)
1110
12- // ScrollItem interface für Items in der Liste
13- type ScrollItem interface {
14- Title () string
15- FilterValue () string
16- }
11+ // ScrollItem is a marker interface for list row payloads.
12+ type ScrollItem interface {}
1713
18- // PrefixedItem optionales Interface für Items mit Prefix (●, [P], etc.)
19- type PrefixedItem interface {
20- Prefix () string
21- }
22-
23- // SuffixedItem optionales Interface für Items mit Suffix (count, status, etc.)
24- type SuffixedItem interface {
25- Suffix () string
26- }
14+ type RowRenderer func (item ScrollItem , width int , selected bool ) string
2715
2816// ScrollListConfig für NewScrollList
2917type ScrollListConfig struct {
30- Width int
31- Height int
32- WithInput bool
33- Placeholder string
18+ Width int
19+ Height int
20+ RenderRow RowRenderer
3421}
3522
3623// ScrollList ist eine einfache scrollbare Liste mit echtem Zeile-für-Zeile Scrolling
@@ -41,26 +28,16 @@ type ScrollList struct {
4128 viewStart int // erstes sichtbares item
4229 width int
4330 height int // anzahl sichtbarer items
44- input * textinput. Model
31+ renderRow RowRenderer
4532}
4633
4734func NewScrollList (items []ScrollItem , cfg ScrollListConfig ) ScrollList {
4835 l := ScrollList {
49- allItems : items ,
50- items : items ,
51- width : cfg .Width ,
52- height : cfg .Height ,
53- }
54-
55- if cfg .WithInput {
56- ti := NewTextInput (20 )
57- ti .Placeholder = cfg .Placeholder
58- if ti .Placeholder == "" {
59- ti .Placeholder = "Type to search..."
60- }
61- ti .Focus ()
62- ti .CharLimit = 100
63- l .input = & ti
36+ allItems : items ,
37+ items : items ,
38+ width : cfg .Width ,
39+ height : cfg .Height ,
40+ renderRow : cfg .RenderRow ,
6441 }
6542
6643 return l
@@ -104,6 +81,9 @@ func (m ScrollList) Items() []ScrollItem { return m.items }
10481
10582func (m * ScrollList ) SetWidth (w int ) { m .width = w }
10683func (m * ScrollList ) SetHeight (h int ) { m .height = h }
84+ func (m * ScrollList ) SetRenderer (r RowRenderer ) {
85+ m .renderRow = r
86+ }
10787
10888func (m * ScrollList ) Select (index int ) {
10989 if index >= 0 && index < len (m .items ) {
@@ -129,55 +109,19 @@ func (m *ScrollList) SetItems(items []ScrollItem) {
129109}
130110
131111func (m ScrollList ) Init () tea.Cmd {
132- if m .input != nil {
133- return textinput .Blink
134- }
135112 return nil
136113}
137114
138- func (m * ScrollList ) filter () {
139- if m .input == nil {
140- return
141- }
142-
143- query := strings .ToLower (m .input .Value ())
144- if query == "" {
145- m .items = m .allItems
146- } else {
147- var filtered []ScrollItem
148- for _ , item := range m .allItems {
149- if strings .Contains (strings .ToLower (item .FilterValue ()), query ) {
150- filtered = append (filtered , item )
151- }
152- }
153- m .items = filtered
154- }
155-
156- // Reset cursor wenn nötig
157- if m .cursor >= len (m .items ) {
158- m .cursor = max (0 , len (m .items )- 1 )
159- }
160- m .viewStart = 0
161- }
162-
163115func (m ScrollList ) Update (msg tea.Msg ) (ScrollList , tea.Cmd ) {
164116 var cmd tea.Cmd
165117
166- // Input updaten wenn vorhanden (für Blink und Typing)
167- if m .input != nil {
168- * m .input , cmd = m .input .Update (msg )
169- m .filter ()
170- }
171-
172118 // Navigation (vim-style + mouse)
173119 switch msg := msg .(type ) {
174120 case tea.KeyPressMsg :
175121 key := msg .String ()
176122
177- // Mit Input: Ctrl+P/N, Tab/Shift+Tab, Pfeiltasten
178- // Ohne Input: zusätzlich j/k
179- isUp := msg .Code == tea .KeyUp || key == "ctrl+p" || key == "shift+tab" || (m .input == nil && key == "k" )
180- isDown := msg .Code == tea .KeyDown || key == "ctrl+n" || key == "tab" || (m .input == nil && key == "j" )
123+ isUp := msg .Code == tea .KeyUp || key == "ctrl+p" || key == "shift+tab" || key == "k"
124+ isDown := msg .Code == tea .KeyDown || key == "ctrl+n" || key == "tab" || key == "j"
181125
182126 switch {
183127 case isUp :
@@ -197,22 +141,6 @@ func (m ScrollList) Update(msg tea.Msg) (ScrollList, tea.Cmd) {
197141 return m , cmd
198142}
199143
200- func (m ScrollList ) HasInput () bool {
201- return m .input != nil
202- }
203-
204- func (m ScrollList ) InputView () string {
205- if m .input == nil {
206- return ""
207- }
208- return lipgloss .NewStyle ().
209- Width (m .width ).
210- Background (styles .ColorBackgroundPanel ()).
211- PaddingLeft (1 ).
212- PaddingBottom (1 ).
213- Render (m .input .View ())
214- }
215-
216144func (m ScrollList ) View () string {
217145 var lines []string
218146
@@ -228,44 +156,15 @@ func (m ScrollList) View() string {
228156 for i := m .viewStart ; i < end ; i ++ {
229157 item := m .items [i ]
230158 selected := i == m .cursor
231-
232- // Get prefix if item implements PrefixedItem
233- prefix := ""
234- pi , ok := item .(PrefixedItem )
235- if ok {
236- prefix = pi .Prefix () + " "
237- }
238-
239- // Get suffix if item implements SuffixedItem
240- suffix := ""
241- si , ok := item .(SuffixedItem )
242- if ok {
243- suffix = si .Suffix ()
244- }
245-
246- title := item .Title ()
247- // Calculate space-between padding (1 leading + 1 trailing space)
248- usedWidth := 2 + len (prefix ) + len (title ) + len (suffix )
249- padding := max (1 , m .width - usedWidth )
250-
251- content := " " + prefix + title + strings .Repeat (" " , padding ) + suffix + " "
252- lineStyle := lipgloss .NewStyle ().Width (m .width )
253-
254- var line string
255- if selected {
256- line = lineStyle .
257- Background (styles .ColorPrimary ()).
258- Foreground (styles .ColorBackground ()).
259- Bold (true ).
260- Render (content )
261- } else {
262- line = lineStyle .
159+ if m .renderRow == nil {
160+ lines = append (lines , lipgloss .NewStyle ().
161+ Width (m .width ).
263162 Background (styles .ColorBackgroundPanel ()).
264- Foreground (styles .ColorForeground ()).
265- Render (content )
163+ Foreground (styles .ColorError ()).
164+ Render (" missing row renderer" ))
165+ continue
266166 }
267-
268- lines = append (lines , line )
167+ lines = append (lines , m .renderRow (item , m .width , selected ))
269168 }
270169 }
271170
0 commit comments