1package components
2
3import (
4 "gordon/internal/adapters/in/cli/ui/styles"
5
6 "github.com/charmbracelet/lipgloss"
7 "github.com/charmbracelet/lipgloss/table"
8)
9
10// TableColumn defines a table column.
11type TableColumn struct {
12 Title string
13 Width int
14}
15
16// TableModel is a styled table component.
17type TableModel struct {
18 columns []TableColumn
19 rows [][]string
20 border lipgloss.Border
21 borderStyle lipgloss.Style
22 headerStyle lipgloss.Style
23 cellStyle lipgloss.Style
24 oddStyle lipgloss.Style
25 evenStyle lipgloss.Style
26 width int
27}
28
29// TableOption configures a TableModel.
30type TableOption func(*TableModel)
31
32// NewTable creates a new styled table.
33func NewTable(opts ...TableOption) *TableModel {
34 t := &TableModel{
35 border: lipgloss.RoundedBorder(),
36 borderStyle: lipgloss.NewStyle().Foreground(styles.ColorBorder),
37 headerStyle: lipgloss.NewStyle().
38 Bold(true).
39 Foreground(styles.ColorPrimary).
40 Padding(0, 1),
41 cellStyle: lipgloss.NewStyle().
42 Foreground(styles.ColorText).
43 Padding(0, 1),
44 oddStyle: lipgloss.NewStyle().
45 Foreground(styles.ColorText).
46 Padding(0, 1),
47 evenStyle: lipgloss.NewStyle().
48 Foreground(styles.ColorText).
49 Padding(0, 1),
50 }
51
52 for _, opt := range opts {
53 opt(t)
54 }
55
56 return t
57}
58
59// WithColumns sets the table columns.
60func WithColumns(cols []TableColumn) TableOption {
61 return func(t *TableModel) {
62 t.columns = cols
63 }
64}
65
66// WithRows sets the table rows.
67func WithRows(rows [][]string) TableOption {
68 return func(t *TableModel) {
69 t.rows = rows
70 }
71}
72
73// WithBorder sets the table border style.
74func WithBorder(b lipgloss.Border) TableOption {
75 return func(t *TableModel) {
76 t.border = b
77 }
78}
79
80// WithTableWidth sets the table width.
81func WithTableWidth(w int) TableOption {
82 return func(t *TableModel) {
83 t.width = w
84 }
85}
86
87// WithHeaderStyle sets the header style.
88func WithHeaderStyle(s lipgloss.Style) TableOption {
89 return func(t *TableModel) {
90 t.headerStyle = s
91 }
92}
93
94// WithCellStyle sets the cell style.
95func WithCellStyle(s lipgloss.Style) TableOption {
96 return func(t *TableModel) {
97 t.cellStyle = s
98 t.oddStyle = s
99 t.evenStyle = s
100 }
101}
102
103// WithAlternateRows enables alternating row colors.
104func WithAlternateRows(odd, even lipgloss.Style) TableOption {
105 return func(t *TableModel) {
106 t.oddStyle = odd
107 t.evenStyle = even
108 }
109}
110
111// SetColumns sets the table columns.
112func (t *TableModel) SetColumns(cols []TableColumn) {
113 t.columns = cols
114}
115
116// SetRows sets the table rows.
117func (t *TableModel) SetRows(rows [][]string) {
118 t.rows = rows
119}
120
121// AddRow adds a row to the table.
122func (t *TableModel) AddRow(row []string) {
123 t.rows = append(t.rows, row)
124}
125
126// ClearRows removes all rows from the table.
127func (t *TableModel) ClearRows() {
128 t.rows = nil
129}
130
131// Render renders the table as a string.
132func (t *TableModel) Render() string {
133 if len(t.columns) == 0 {
134 return ""
135 }
136
137 // Extract headers
138 headers := make([]string, len(t.columns))
139 for i, col := range t.columns {
140 headers[i] = col.Title
141 }
142
143 // Create table
144 tbl := table.New().
145 Border(t.border).
146 BorderStyle(t.borderStyle).
147 Headers(headers...).
148 Rows(t.rows...).
149 StyleFunc(func(row, col int) lipgloss.Style {
150 if row == table.HeaderRow {
151 return t.headerStyle
152 }
153 if row%2 == 0 {
154 return t.evenStyle
155 }
156 return t.oddStyle
157 })
158
159 // Apply width if set
160 if t.width > 0 {
161 tbl = tbl.Width(t.width)
162 }
163
164 return tbl.String()
165}
166
167// View returns the table view (alias for Render).
168func (t *TableModel) View() string {
169 return t.Render()
170}
171
172// SimpleTable creates a simple table with headers and rows.
173// This is a convenience function for quick table rendering.
174func SimpleTable(headers []string, rows [][]string) string {
175 cols := make([]TableColumn, len(headers))
176 for i, h := range headers {
177 cols[i] = TableColumn{Title: h}
178 }
179
180 t := NewTable(
181 WithColumns(cols),
182 WithRows(rows),
183 )
184
185 return t.Render()
186}
187
188// RouteTable creates a table specifically for displaying routes.
189func RouteTable(routes [][]string) string {
190 return SimpleTable(
191 []string{"Domain", "Image", "Status"},
192 routes,
193 )
194}
195
196// TokenTable creates a table specifically for displaying tokens.
197func TokenTable(tokens [][]string) string {
198 return SimpleTable(
199 []string{"ID", "Subject", "Scopes", "Expires", "Revoked"},
200 tokens,
201 )
202}
203
204// SecretTable creates a table specifically for displaying secrets.
205func SecretTable(secrets [][]string) string {
206 return SimpleTable(
207 []string{"Key", "Value"},
208 secrets,
209 )
210}