Skip to content

Commit 6b86b98

Browse files
authored
Merge pull request #622 from rumpl/feat-theme
Refactor the styles
2 parents 3edc9bb + 2dd3ff6 commit 6b86b98

9 files changed

Lines changed: 312 additions & 269 deletions

File tree

pkg/tui/components/message/message.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77

88
"github.com/charmbracelet/bubbles/v2/spinner"
99
tea "github.com/charmbracelet/bubbletea/v2"
10-
"github.com/charmbracelet/lipgloss/v2"
1110

1211
"github.com/docker/cagent/pkg/tui/components/markdown"
1312
"github.com/docker/cagent/pkg/tui/core/layout"
@@ -79,9 +78,8 @@ func (mv *messageModel) Render(width int) string {
7978
case types.MessageTypeSpinner:
8079
return mv.spinner.View()
8180
case types.MessageTypeUser:
82-
s := lipgloss.NewStyle().PaddingLeft(1).BorderLeft(true).BorderStyle(lipgloss.ThickBorder())
83-
if rendered, err := markdown.NewRenderer(width - len(s.Render(""))).Render(msg.Content); err == nil {
84-
return s.Render(strings.TrimRight(rendered, "\n\r\t "))
81+
if rendered, err := markdown.NewRenderer(width - len(styles.UserMessageBorderStyle.Render(""))).Render(msg.Content); err == nil {
82+
return styles.UserMessageBorderStyle.Render(strings.TrimRight(rendered, "\n\r\t "))
8583
}
8684

8785
return msg.Content

pkg/tui/components/messages/messages.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/docker/cagent/pkg/tui/components/tool"
2323
"github.com/docker/cagent/pkg/tui/core"
2424
"github.com/docker/cagent/pkg/tui/core/layout"
25+
"github.com/docker/cagent/pkg/tui/styles"
2526
"github.com/docker/cagent/pkg/tui/types"
2627
)
2728

@@ -989,14 +990,9 @@ func (m *model) highlightLine(line string, startCol, endCol int) string {
989990
return line
990991
}
991992

992-
// TODO(rumpl): move style to styles.go
993-
selectionStyle := lipgloss.NewStyle().
994-
Background(lipgloss.Color("237")).
995-
Foreground(lipgloss.Color("255"))
996-
997993
runes := []rune(plainLine)
998994
before := string(runes[:startRuneIdx])
999-
selected := selectionStyle.Render(string(runes[startRuneIdx:endRuneIdx]))
995+
selected := styles.SelectionStyle.Render(string(runes[startRuneIdx:endRuneIdx]))
1000996
after := ""
1001997
if endRuneIdx < len(runes) {
1002998
after = string(runes[endRuneIdx:])

pkg/tui/components/notification/notification.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,10 @@ func (n *Notification) View() string {
7575
return ""
7676
}
7777

78-
notificationStyle := styles.BaseStyle.
79-
Border(lipgloss.RoundedBorder()).
80-
BorderForeground(styles.SuccessStyle.GetForeground()).
81-
Padding(0, 1).
82-
MaxWidth(maxWidth)
83-
84-
return notificationStyle.Render(n.text)
78+
return styles.
79+
NotificationStyle.
80+
MaxWidth(maxWidth).
81+
Render(n.text)
8582
}
8683

8784
func (n *Notification) GetLayer() *lipgloss.Layer {

pkg/tui/components/tool/syntax.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import (
55

66
"github.com/alecthomas/chroma/v2"
77
"github.com/alecthomas/chroma/v2/lexers"
8-
"github.com/alecthomas/chroma/v2/styles"
8+
chromastyles "github.com/alecthomas/chroma/v2/styles"
99
"github.com/aymanbagabas/go-udiff"
1010
"github.com/charmbracelet/lipgloss/v2"
1111
"github.com/mattn/go-runewidth"
12+
13+
"github.com/docker/cagent/pkg/tui/styles"
1214
)
1315

1416
// syntaxHighlight applies syntax highlighting to code and returns styled text
@@ -19,9 +21,9 @@ func syntaxHighlight(code, filePath string) []chromaToken {
1921
}
2022
lexer = chroma.Coalesce(lexer)
2123

22-
style := styles.Get("monokai")
24+
style := chromastyles.Get("monokai")
2325
if style == nil {
24-
style = styles.Fallback
26+
style = chromastyles.Fallback
2527
}
2628

2729
iterator, err := lexer.Tokenise(nil, code)
@@ -84,21 +86,17 @@ func renderDiffWithSyntaxHighlight(diff []*udiff.Hunk, filePath string, width in
8486
const tabWidth = 4
8587
var output strings.Builder
8688

87-
removeStyle := lipgloss.NewStyle().Background(lipgloss.Color("#553333"))
88-
addStyle := lipgloss.NewStyle().Background(lipgloss.Color("#2E402E"))
89-
unchangedStyle := lipgloss.NewStyle()
90-
9189
for _, hunk := range diff {
9290
for _, line := range hunk.Lines {
9391
var lineStyle lipgloss.Style
9492

9593
switch line.Kind {
9694
case udiff.Delete:
97-
lineStyle = removeStyle
95+
lineStyle = styles.DiffRemoveStyle
9896
case udiff.Insert:
99-
lineStyle = addStyle
97+
lineStyle = styles.DiffAddStyle
10098
case udiff.Equal:
101-
lineStyle = unchangedStyle
99+
lineStyle = styles.DiffUnchangedStyle
102100
}
103101

104102
expandedContent := strings.ReplaceAll(line.Content, "\t", strings.Repeat(" ", tabWidth))

pkg/tui/dialog/command_palette.go

Lines changed: 23 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/charmbracelet/lipgloss/v2"
1010

1111
"github.com/docker/cagent/pkg/tui/core"
12+
"github.com/docker/cagent/pkg/tui/styles"
1213
)
1314

1415
// CommandExecuteMsg is sent when a command is selected
@@ -183,31 +184,17 @@ func (d *commandPaletteDialog) filterCommands() {
183184

184185
// View renders the command palette dialog
185186
func (d *commandPaletteDialog) View() string {
186-
dialogWidth := min(d.width*80/100, 70)
187-
if dialogWidth < 80 {
188-
dialogWidth = 80
189-
}
187+
dialogWidth := max(min(d.width*80/100, 70), 80)
190188

191189
maxHeight := min(d.height*70/100, 30)
192190
contentWidth := dialogWidth - 6
193191

194-
dialogStyle := lipgloss.NewStyle().
195-
Border(lipgloss.RoundedBorder()).
196-
BorderForeground(lipgloss.Color("#6b7280")).
197-
Padding(1, 2).
198-
Width(dialogWidth)
199-
200-
titleStyle := lipgloss.NewStyle().
201-
Bold(true).
202-
Foreground(lipgloss.Color("#9ca3af")).
203-
Width(contentWidth)
204-
title := titleStyle.Render("Commands")
192+
title := styles.DialogTitleStyle.Width(contentWidth).Render("Commands")
205193

206194
d.textInput.SetWidth(contentWidth)
207195
searchInput := d.textInput.View()
208196

209-
separator := lipgloss.NewStyle().
210-
Foreground(lipgloss.Color("#4b5563")).
197+
separator := styles.DialogSeparatorStyle.
211198
Width(contentWidth).
212199
Render(strings.Repeat("─", contentWidth))
213200

@@ -234,11 +221,7 @@ func (d *commandPaletteDialog) View() string {
234221

235222
commands := categoryMap[catName]
236223

237-
categoryStyle := lipgloss.NewStyle().
238-
Bold(true).
239-
Foreground(lipgloss.Color("#6b7280")).
240-
MarginTop(1)
241-
commandList = append(commandList, categoryStyle.Render(catName))
224+
commandList = append(commandList, styles.PaletteCategoryStyle.Render(catName))
242225
itemCount++
243226

244227
for _, cmd := range commands {
@@ -247,28 +230,25 @@ func (d *commandPaletteDialog) View() string {
247230
}
248231

249232
isSelected := currentIndex == d.selected
250-
commandLine := d.renderCommand(cmd, isSelected, contentWidth)
233+
commandLine := d.renderCommand(cmd, isSelected)
251234
commandList = append(commandList, commandLine)
252235
itemCount++
253236
currentIndex++
254237
}
255238
}
256239

257240
if len(d.filtered) == 0 {
258-
noResultsStyle := lipgloss.NewStyle().
259-
Foreground(lipgloss.Color("#6b7280")).
241+
commandList = append(commandList, "", styles.DialogContentStyle.
260242
Italic(true).
261243
Align(lipgloss.Center).
262-
Width(contentWidth)
263-
commandList = append(commandList, "", noResultsStyle.Render("No commands found"))
244+
Width(contentWidth).
245+
Render("No commands found"))
264246
}
265247

266-
helpStyle := lipgloss.NewStyle().
267-
Foreground(lipgloss.Color("#6b7280")).
268-
Italic(true).
248+
help := styles.DialogHelpStyle.
269249
MarginTop(1).
270-
Width(contentWidth)
271-
help := helpStyle.Render("↑/↓ navigate • enter execute • esc close")
250+
Width(contentWidth).
251+
Render("↑/↓ navigate • enter execute • esc close")
272252

273253
parts := []string{
274254
title,
@@ -279,45 +259,28 @@ func (d *commandPaletteDialog) View() string {
279259
parts = append(parts, commandList...)
280260
parts = append(parts, "", help)
281261

282-
content := lipgloss.JoinVertical(lipgloss.Left, parts...)
283-
return dialogStyle.Render(content)
262+
return styles.DialogStyle.
263+
Width(dialogWidth).
264+
Render(lipgloss.JoinVertical(lipgloss.Left, parts...))
284265
}
285266

286267
// renderCommand renders a single command in the list
287-
func (d *commandPaletteDialog) renderCommand(cmd Command, selected bool, width int) string {
288-
var style lipgloss.Style
289-
290-
if selected {
291-
style = lipgloss.NewStyle().
292-
Background(lipgloss.Color("#374151")).
293-
Foreground(lipgloss.Color("#f9fafb")).
294-
Bold(true).
295-
Width(width).
296-
Padding(0, 1)
297-
} else {
298-
style = lipgloss.NewStyle().
299-
Foreground(lipgloss.Color("#d1d5db")).
300-
Width(width).
301-
Padding(0, 1)
268+
func (d *commandPaletteDialog) renderCommand(cmd Command, selected bool) string {
269+
text := " " + cmd.Label
270+
if cmd.Description != "" {
271+
text += " - " + cmd.Description
302272
}
303273

304-
labelStyle := lipgloss.NewStyle()
305-
descStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#9ca3af"))
306-
307-
text := " " + labelStyle.Render(cmd.Label)
308-
if cmd.Description != "" {
309-
text += " " + descStyle.Render("- "+cmd.Description)
274+
if selected {
275+
return styles.PaletteSelectedStyle.Render(text)
310276
}
311277

312-
return style.Render(text)
278+
return styles.PaletteUnselectedStyle.Render(text)
313279
}
314280

315281
// Position calculates the position to center the dialog
316282
func (d *commandPaletteDialog) Position() (row, col int) {
317-
dialogWidth := min(d.width*80/100, 70)
318-
if dialogWidth < 50 {
319-
dialogWidth = 50
320-
}
283+
dialogWidth := max(min(d.width*80/100, 70), 50)
321284

322285
maxHeight := min(d.height*70/100, 30)
323286

pkg/tui/dialog/max_iterations.go

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/docker/cagent/pkg/app"
1212
"github.com/docker/cagent/pkg/tui/core"
13+
"github.com/docker/cagent/pkg/tui/styles"
1314
)
1415

1516
// maxIterationsDialog implements DialogModel for max iterations confirmation
@@ -133,59 +134,37 @@ func (d *maxIterationsDialog) View() string {
133134
frameHorizontal := (padX * 2) + 2
134135
contentWidth := max(10, dialogWidth-frameHorizontal)
135136

136-
dialogStyle := lipgloss.NewStyle().
137-
Border(lipgloss.RoundedBorder()).
138-
BorderForeground(lipgloss.Color("#f59e0b")).
139-
Foreground(lipgloss.Color("#d1d5db")).
137+
dialogStyle := styles.DialogWarningStyle.
140138
Padding(padY, padX).
141-
Width(dialogWidth).
142-
Align(lipgloss.Left)
139+
Width(dialogWidth)
143140

144-
titleStyle := lipgloss.NewStyle().
145-
Bold(true).
146-
Foreground(lipgloss.Color("#f59e0b")).
147-
Align(lipgloss.Center).
148-
Width(contentWidth)
149-
150-
messageStyle := lipgloss.NewStyle().
151-
Foreground(lipgloss.Color("#d1d5db")).
152-
Width(contentWidth)
153-
154-
questionStyle := lipgloss.NewStyle().
155-
Bold(true).
156-
Foreground(lipgloss.Color("#d1d5db")).
157-
Align(lipgloss.Center).
158-
Width(contentWidth)
159-
160-
optionsStyle := lipgloss.NewStyle().
161-
Foreground(lipgloss.Color("#9ca3af")).
162-
Align(lipgloss.Center).
163-
Width(contentWidth)
164-
165-
title := titleStyle.Render("Maximum Iterations Reached")
141+
title := styles.DialogTitleWarningStyle.
142+
Width(contentWidth).
143+
Render("Maximum Iterations Reached")
166144

167145
separatorWidth := max(1, contentWidth)
168-
separator := lipgloss.NewStyle().
169-
Foreground(lipgloss.Color("#4b5563")).
146+
separator := styles.DialogSeparatorStyle.
170147
Align(lipgloss.Center).
171148
Width(contentWidth).
172149
Render(strings.Repeat("─", separatorWidth))
173150

174151
// Info section
175152
infoText := fmt.Sprintf("Max Iterations: %d", d.maxIterations)
176153
infoWrapped := wrapDisplayText(infoText, contentWidth)
177-
infoSection := lipgloss.NewStyle().
178-
Foreground(lipgloss.Color("#d1d5db")).
179-
Render(infoWrapped)
154+
infoSection := styles.DialogContentStyle.Render(infoWrapped)
180155

181156
// Message section
182-
message := messageStyle.Render(wrapDisplayText("The agent may be stuck in a loop. This can happen with smaller or less capable models.", contentWidth))
157+
message := styles.DialogContentStyle.Render(wrapDisplayText("The agent may be stuck in a loop. This can happen with smaller or less capable models.", contentWidth))
183158

184159
// Question section
185-
question := questionStyle.Render(wrapDisplayText("Do you want to continue for 10 more iterations?", contentWidth))
160+
question := styles.DialogQuestionStyle.
161+
Width(contentWidth).
162+
Render(wrapDisplayText("Do you want to continue for 10 more iterations?", contentWidth))
186163

187164
// Options section
188-
options := optionsStyle.Render(wrapDisplayText("[Y]es [N]o", contentWidth))
165+
options := styles.DialogOptionsStyle.
166+
Width(contentWidth).
167+
Render(wrapDisplayText("[Y]es [N]o", contentWidth))
189168

190169
// Combine all parts with proper spacing
191170
parts := []string{title, separator, infoSection, "", message, "", question, "", options}

0 commit comments

Comments
 (0)