1package styles
2
3import (
4 "image/color"
5
6 "charm.land/bubbles/v2/filepicker"
7 "charm.land/bubbles/v2/help"
8 "charm.land/bubbles/v2/textarea"
9 "charm.land/bubbles/v2/textinput"
10 tea "charm.land/bubbletea/v2"
11 "charm.land/glamour/v2/ansi"
12 "charm.land/lipgloss/v2"
13 "github.com/charmbracelet/crush/internal/ui/diffview"
14 "github.com/charmbracelet/x/exp/charmtone"
15)
16
17// quickStyleOpts is the palette of colors used by quickStyle to simplify the
18// process of building a theme.
19type quickStyleOpts struct {
20 // Brand.
21 primary color.Color
22 secondary color.Color
23 accent color.Color
24 keyword color.Color
25
26 // Default foreground and background colors.
27 fgBase color.Color
28 bgBase color.Color
29
30 // Low-contrast dividers, separators, and rule lines.
31 separator color.Color
32
33 fgSubtle color.Color
34 fgMoreSubtle color.Color
35 fgMostSubtle color.Color
36
37 // Contrast pairings: foregrounds designed to sit on top of a
38 // matching background role.
39 onPrimary color.Color // foreground on primary backgrounds.
40
41 bgMostVisible color.Color
42 bgLessVisible color.Color
43 bgLeastVisible color.Color
44
45 // Statuses.
46 destructive color.Color
47 error color.Color
48 warning color.Color
49 warningSubtle color.Color
50 busy color.Color
51 info color.Color
52 infoMoreSubtle color.Color
53 infoMostSubtle color.Color
54 success color.Color
55 successMoreSubtle color.Color
56 successMostSubtle color.Color
57}
58
59// quickStyle builds the default Styles (that is, the default theme, Charmtone
60// Pantera) from a palette of semi-semanticly-named colors.
61//
62// The idea here is that you can do most of the work on a theme with quickStyle,
63// then add overrides as needed.
64func quickStyle(o quickStyleOpts) Styles {
65 var (
66 base = lipgloss.NewStyle().Foreground(o.fgBase)
67 muted = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
68 subtle = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
69 s Styles
70 )
71
72 s.Background = o.bgBase
73
74 // Populate color fields
75 s.WorkingGradFromColor = o.primary
76 s.WorkingGradToColor = o.secondary
77 s.WorkingLabelColor = o.fgBase
78
79 s.TextInput = textinput.Styles{
80 Focused: textinput.StyleState{
81 Text: base,
82 Placeholder: base.Foreground(o.fgMostSubtle),
83 Prompt: base.Foreground(o.accent),
84 Suggestion: base.Foreground(o.fgMostSubtle),
85 },
86 Blurred: textinput.StyleState{
87 Text: base.Foreground(o.fgMoreSubtle),
88 Placeholder: base.Foreground(o.fgMostSubtle),
89 Prompt: base.Foreground(o.fgMoreSubtle),
90 Suggestion: base.Foreground(o.fgMostSubtle),
91 },
92 Cursor: textinput.CursorStyle{
93 Color: o.secondary,
94 Shape: tea.CursorBlock,
95 Blink: true,
96 },
97 }
98
99 s.Editor.Textarea = textarea.Styles{
100 Focused: textarea.StyleState{
101 Base: base,
102 Text: base,
103 LineNumber: base.Foreground(o.fgMostSubtle),
104 CursorLine: base,
105 CursorLineNumber: base.Foreground(o.fgMostSubtle),
106 Placeholder: base.Foreground(o.fgMostSubtle),
107 Prompt: base.Foreground(o.accent),
108 },
109 Blurred: textarea.StyleState{
110 Base: base,
111 Text: base.Foreground(o.fgMoreSubtle),
112 LineNumber: base.Foreground(o.fgMoreSubtle),
113 CursorLine: base,
114 CursorLineNumber: base.Foreground(o.fgMoreSubtle),
115 Placeholder: base.Foreground(o.fgMostSubtle),
116 Prompt: base.Foreground(o.fgMoreSubtle),
117 },
118 Cursor: textarea.CursorStyle{
119 Color: o.secondary,
120 Shape: tea.CursorBlock,
121 Blink: true,
122 },
123 }
124
125 s.Markdown = ansi.StyleConfig{
126 Document: ansi.StyleBlock{
127 StylePrimitive: ansi.StylePrimitive{
128 // BlockPrefix: "\n",
129 // BlockSuffix: "\n",
130 Color: hex(o.fgSubtle),
131 },
132 // Margin: new(uint(defaultMargin)),
133 },
134 BlockQuote: ansi.StyleBlock{
135 StylePrimitive: ansi.StylePrimitive{},
136 Indent: new(uint(1)),
137 IndentToken: new("│ "),
138 },
139 List: ansi.StyleList{
140 LevelIndent: defaultListIndent,
141 },
142 Heading: ansi.StyleBlock{
143 StylePrimitive: ansi.StylePrimitive{
144 BlockSuffix: "\n",
145 Color: hex(o.info),
146 Bold: new(true),
147 },
148 },
149 H1: ansi.StyleBlock{
150 StylePrimitive: ansi.StylePrimitive{
151 Prefix: " ",
152 Suffix: " ",
153 Color: hex(o.warningSubtle),
154 BackgroundColor: hex(o.primary),
155 Bold: new(true),
156 },
157 },
158 H2: ansi.StyleBlock{
159 StylePrimitive: ansi.StylePrimitive{
160 Prefix: "## ",
161 },
162 },
163 H3: ansi.StyleBlock{
164 StylePrimitive: ansi.StylePrimitive{
165 Prefix: "### ",
166 },
167 },
168 H4: ansi.StyleBlock{
169 StylePrimitive: ansi.StylePrimitive{
170 Prefix: "#### ",
171 },
172 },
173 H5: ansi.StyleBlock{
174 StylePrimitive: ansi.StylePrimitive{
175 Prefix: "##### ",
176 },
177 },
178 H6: ansi.StyleBlock{
179 StylePrimitive: ansi.StylePrimitive{
180 Prefix: "###### ",
181 Color: hex(o.successMostSubtle),
182 Bold: new(false),
183 },
184 },
185 Strikethrough: ansi.StylePrimitive{
186 CrossedOut: new(true),
187 },
188 Emph: ansi.StylePrimitive{
189 Italic: new(true),
190 },
191 Strong: ansi.StylePrimitive{
192 Bold: new(true),
193 },
194 HorizontalRule: ansi.StylePrimitive{
195 Color: hex(o.separator),
196 Format: "\n--------\n",
197 },
198 Item: ansi.StylePrimitive{
199 BlockPrefix: "• ",
200 },
201 Enumeration: ansi.StylePrimitive{
202 BlockPrefix: ". ",
203 },
204 Task: ansi.StyleTask{
205 StylePrimitive: ansi.StylePrimitive{},
206 Ticked: "[✓] ",
207 Unticked: "[ ] ",
208 },
209 Link: ansi.StylePrimitive{
210 Color: hex(charmtone.Zinc),
211 Underline: new(true),
212 },
213 LinkText: ansi.StylePrimitive{
214 Color: hex(o.successMostSubtle),
215 Bold: new(true),
216 },
217 Image: ansi.StylePrimitive{
218 Color: hex(charmtone.Cheeky),
219 Underline: new(true),
220 },
221 ImageText: ansi.StylePrimitive{
222 Color: hex(o.fgMoreSubtle),
223 Format: "Image: {{.text}} →",
224 },
225 Code: ansi.StyleBlock{
226 StylePrimitive: ansi.StylePrimitive{
227 Prefix: " ",
228 Suffix: " ",
229 Color: hex(o.destructive),
230 BackgroundColor: hex(o.bgLessVisible),
231 },
232 },
233 CodeBlock: ansi.StyleCodeBlock{
234 StyleBlock: ansi.StyleBlock{
235 StylePrimitive: ansi.StylePrimitive{
236 Color: hex(o.bgLessVisible),
237 },
238 Margin: new(uint(defaultMargin)),
239 },
240 Chroma: &ansi.Chroma{
241 Text: ansi.StylePrimitive{
242 Color: hex(o.fgSubtle),
243 },
244 Error: ansi.StylePrimitive{
245 Color: hex(o.onPrimary),
246 BackgroundColor: hex(o.error),
247 },
248 Comment: ansi.StylePrimitive{
249 Color: hex(o.fgMostSubtle),
250 },
251 CommentPreproc: ansi.StylePrimitive{
252 Color: hex(charmtone.Bengal),
253 },
254 Keyword: ansi.StylePrimitive{
255 Color: hex(o.info),
256 },
257 KeywordReserved: ansi.StylePrimitive{
258 Color: hex(charmtone.Pony),
259 },
260 KeywordNamespace: ansi.StylePrimitive{
261 Color: hex(charmtone.Pony),
262 },
263 KeywordType: ansi.StylePrimitive{
264 Color: hex(charmtone.Guppy),
265 },
266 Operator: ansi.StylePrimitive{
267 Color: hex(charmtone.Salmon),
268 },
269 Punctuation: ansi.StylePrimitive{
270 Color: hex(o.warningSubtle),
271 },
272 Name: ansi.StylePrimitive{
273 Color: hex(o.fgSubtle),
274 },
275 NameBuiltin: ansi.StylePrimitive{
276 Color: hex(charmtone.Cheeky),
277 },
278 NameTag: ansi.StylePrimitive{
279 Color: hex(charmtone.Mauve),
280 },
281 NameAttribute: ansi.StylePrimitive{
282 Color: hex(charmtone.Hazy),
283 },
284 NameClass: ansi.StylePrimitive{
285 Color: hex(charmtone.Salt),
286 Underline: new(true),
287 Bold: new(true),
288 },
289 NameDecorator: ansi.StylePrimitive{
290 Color: hex(charmtone.Citron),
291 },
292 NameFunction: ansi.StylePrimitive{
293 Color: hex(o.successMostSubtle),
294 },
295 LiteralNumber: ansi.StylePrimitive{
296 Color: hex(o.success),
297 },
298 LiteralString: ansi.StylePrimitive{
299 Color: hex(charmtone.Cumin),
300 },
301 LiteralStringEscape: ansi.StylePrimitive{
302 Color: hex(o.successMoreSubtle),
303 },
304 GenericDeleted: ansi.StylePrimitive{
305 Color: hex(o.destructive),
306 },
307 GenericEmph: ansi.StylePrimitive{
308 Italic: new(true),
309 },
310 GenericInserted: ansi.StylePrimitive{
311 Color: hex(o.successMostSubtle),
312 },
313 GenericStrong: ansi.StylePrimitive{
314 Bold: new(true),
315 },
316 GenericSubheading: ansi.StylePrimitive{
317 Color: hex(o.fgMoreSubtle),
318 },
319 Background: ansi.StylePrimitive{
320 BackgroundColor: hex(o.bgLessVisible),
321 },
322 },
323 },
324 Table: ansi.StyleTable{
325 StyleBlock: ansi.StyleBlock{
326 StylePrimitive: ansi.StylePrimitive{},
327 },
328 },
329 DefinitionDescription: ansi.StylePrimitive{
330 BlockPrefix: "\n ",
331 },
332 }
333
334 // QuietMarkdown style - muted colors on subtle background for thinking content.
335 plainBg := hex(o.bgLeastVisible)
336 plainFg := hex(o.fgMoreSubtle)
337 s.QuietMarkdown = ansi.StyleConfig{
338 Document: ansi.StyleBlock{
339 StylePrimitive: ansi.StylePrimitive{
340 Color: plainFg,
341 BackgroundColor: plainBg,
342 },
343 },
344 BlockQuote: ansi.StyleBlock{
345 StylePrimitive: ansi.StylePrimitive{
346 Color: plainFg,
347 BackgroundColor: plainBg,
348 },
349 Indent: new(uint(1)),
350 IndentToken: new("│ "),
351 },
352 List: ansi.StyleList{
353 LevelIndent: defaultListIndent,
354 },
355 Heading: ansi.StyleBlock{
356 StylePrimitive: ansi.StylePrimitive{
357 BlockSuffix: "\n",
358 Bold: new(true),
359 Color: plainFg,
360 BackgroundColor: plainBg,
361 },
362 },
363 H1: ansi.StyleBlock{
364 StylePrimitive: ansi.StylePrimitive{
365 Prefix: " ",
366 Suffix: " ",
367 Bold: new(true),
368 Color: plainFg,
369 BackgroundColor: plainBg,
370 },
371 },
372 H2: ansi.StyleBlock{
373 StylePrimitive: ansi.StylePrimitive{
374 Prefix: "## ",
375 Color: plainFg,
376 BackgroundColor: plainBg,
377 },
378 },
379 H3: ansi.StyleBlock{
380 StylePrimitive: ansi.StylePrimitive{
381 Prefix: "### ",
382 Color: plainFg,
383 BackgroundColor: plainBg,
384 },
385 },
386 H4: ansi.StyleBlock{
387 StylePrimitive: ansi.StylePrimitive{
388 Prefix: "#### ",
389 Color: plainFg,
390 BackgroundColor: plainBg,
391 },
392 },
393 H5: ansi.StyleBlock{
394 StylePrimitive: ansi.StylePrimitive{
395 Prefix: "##### ",
396 Color: plainFg,
397 BackgroundColor: plainBg,
398 },
399 },
400 H6: ansi.StyleBlock{
401 StylePrimitive: ansi.StylePrimitive{
402 Prefix: "###### ",
403 Color: plainFg,
404 BackgroundColor: plainBg,
405 },
406 },
407 Strikethrough: ansi.StylePrimitive{
408 CrossedOut: new(true),
409 Color: plainFg,
410 BackgroundColor: plainBg,
411 },
412 Emph: ansi.StylePrimitive{
413 Italic: new(true),
414 Color: plainFg,
415 BackgroundColor: plainBg,
416 },
417 Strong: ansi.StylePrimitive{
418 Bold: new(true),
419 Color: plainFg,
420 BackgroundColor: plainBg,
421 },
422 HorizontalRule: ansi.StylePrimitive{
423 Format: "\n--------\n",
424 Color: plainFg,
425 BackgroundColor: plainBg,
426 },
427 Item: ansi.StylePrimitive{
428 BlockPrefix: "• ",
429 Color: plainFg,
430 BackgroundColor: plainBg,
431 },
432 Enumeration: ansi.StylePrimitive{
433 BlockPrefix: ". ",
434 Color: plainFg,
435 BackgroundColor: plainBg,
436 },
437 Task: ansi.StyleTask{
438 StylePrimitive: ansi.StylePrimitive{
439 Color: plainFg,
440 BackgroundColor: plainBg,
441 },
442 Ticked: "[✓] ",
443 Unticked: "[ ] ",
444 },
445 Link: ansi.StylePrimitive{
446 Underline: new(true),
447 Color: plainFg,
448 BackgroundColor: plainBg,
449 },
450 LinkText: ansi.StylePrimitive{
451 Bold: new(true),
452 Color: plainFg,
453 BackgroundColor: plainBg,
454 },
455 Image: ansi.StylePrimitive{
456 Underline: new(true),
457 Color: plainFg,
458 BackgroundColor: plainBg,
459 },
460 ImageText: ansi.StylePrimitive{
461 Format: "Image: {{.text}} →",
462 Color: plainFg,
463 BackgroundColor: plainBg,
464 },
465 Code: ansi.StyleBlock{
466 StylePrimitive: ansi.StylePrimitive{
467 Prefix: " ",
468 Suffix: " ",
469 Color: plainFg,
470 BackgroundColor: plainBg,
471 },
472 },
473 CodeBlock: ansi.StyleCodeBlock{
474 StyleBlock: ansi.StyleBlock{
475 StylePrimitive: ansi.StylePrimitive{
476 Color: plainFg,
477 BackgroundColor: plainBg,
478 },
479 Margin: new(uint(defaultMargin)),
480 },
481 },
482 Table: ansi.StyleTable{
483 StyleBlock: ansi.StyleBlock{
484 StylePrimitive: ansi.StylePrimitive{
485 Color: plainFg,
486 BackgroundColor: plainBg,
487 },
488 },
489 },
490 DefinitionDescription: ansi.StylePrimitive{
491 BlockPrefix: "\n ",
492 Color: plainFg,
493 BackgroundColor: plainBg,
494 },
495 }
496
497 s.Help = help.Styles{
498 ShortKey: base.Foreground(o.fgMoreSubtle),
499 ShortDesc: base.Foreground(o.fgMostSubtle),
500 ShortSeparator: base.Foreground(o.separator),
501 Ellipsis: base.Foreground(o.separator),
502 FullKey: base.Foreground(o.fgMoreSubtle),
503 FullDesc: base.Foreground(o.fgMostSubtle),
504 FullSeparator: base.Foreground(o.separator),
505 }
506
507 s.Diff = diffview.Style{
508 DividerLine: diffview.LineStyle{
509 LineNumber: lipgloss.NewStyle().
510 Foreground(o.fgSubtle).
511 Background(o.bgLeastVisible),
512 Code: lipgloss.NewStyle().
513 Foreground(o.fgSubtle).
514 Background(o.bgLeastVisible),
515 },
516 MissingLine: diffview.LineStyle{
517 LineNumber: lipgloss.NewStyle().
518 Background(o.bgLeastVisible),
519 Code: lipgloss.NewStyle().
520 Background(o.bgLeastVisible),
521 },
522 EqualLine: diffview.LineStyle{
523 LineNumber: lipgloss.NewStyle().
524 Foreground(o.fgMoreSubtle).
525 Background(o.bgBase),
526 Code: lipgloss.NewStyle().
527 Foreground(o.fgMoreSubtle).
528 Background(o.bgBase),
529 },
530 InsertLine: diffview.LineStyle{
531 LineNumber: lipgloss.NewStyle().
532 Foreground(lipgloss.Color("#629657")).
533 Background(lipgloss.Color("#2b322a")),
534 Symbol: lipgloss.NewStyle().
535 Foreground(lipgloss.Color("#629657")).
536 Background(lipgloss.Color("#323931")),
537 Code: lipgloss.NewStyle().
538 Background(lipgloss.Color("#323931")),
539 },
540 DeleteLine: diffview.LineStyle{
541 LineNumber: lipgloss.NewStyle().
542 Foreground(lipgloss.Color("#a45c59")).
543 Background(lipgloss.Color("#312929")),
544 Symbol: lipgloss.NewStyle().
545 Foreground(lipgloss.Color("#a45c59")).
546 Background(lipgloss.Color("#383030")),
547 Code: lipgloss.NewStyle().
548 Background(lipgloss.Color("#383030")),
549 },
550 Filename: diffview.LineStyle{
551 LineNumber: lipgloss.NewStyle().
552 Foreground(o.fgSubtle).
553 Background(o.bgLeastVisible),
554 Code: lipgloss.NewStyle().
555 Foreground(o.fgSubtle).
556 Background(o.bgLeastVisible),
557 },
558 }
559
560 s.FilePicker = filepicker.Styles{
561 DisabledCursor: base.Foreground(o.fgMoreSubtle),
562 Cursor: base.Foreground(o.fgBase),
563 Symlink: base.Foreground(o.fgMostSubtle),
564 Directory: base.Foreground(o.primary),
565 File: base.Foreground(o.fgBase),
566 DisabledFile: base.Foreground(o.fgMoreSubtle),
567 DisabledSelected: base.Background(o.bgMostVisible).Foreground(o.fgMoreSubtle),
568 Permission: base.Foreground(o.fgMoreSubtle),
569 Selected: base.Background(o.primary).Foreground(o.fgBase),
570 FileSize: base.Foreground(o.fgMoreSubtle),
571 EmptyDirectory: base.Foreground(o.fgMoreSubtle).PaddingLeft(2).SetString("Empty directory"),
572 }
573
574 // borders
575 s.ToolCallSuccess = lipgloss.NewStyle().Foreground(o.success).SetString(ToolSuccess)
576
577 s.Header.Charm = base.Foreground(o.secondary)
578 s.Header.Diagonals = base.Foreground(o.primary)
579 s.Header.Percentage = muted
580 s.Header.Hypercredit = base.Foreground(charmtone.Dolly)
581 s.Header.Keystroke = muted
582 s.Header.KeystrokeTip = subtle
583 s.Header.WorkingDir = muted
584 s.Header.Separator = subtle
585 s.Header.Wrapper = lipgloss.NewStyle().Foreground(o.fgBase)
586 s.Header.LogoGradCanvas = lipgloss.NewStyle()
587 s.Header.LogoGradFromColor = o.secondary
588 s.Header.LogoGradToColor = o.primary
589
590 s.CompactDetails.Title = base
591 s.CompactDetails.View = base.Padding(0, 1, 1, 1).Border(lipgloss.RoundedBorder()).BorderForeground(o.primary)
592 s.CompactDetails.Version = lipgloss.NewStyle().Foreground(o.separator)
593
594 // Tool rendering styles
595 s.Tool.IconPending = base.Foreground(o.successMostSubtle).SetString(ToolPending)
596 s.Tool.IconSuccess = base.Foreground(o.success).SetString(ToolSuccess)
597 s.Tool.IconError = base.Foreground(o.error).SetString(ToolError)
598 s.Tool.IconCancelled = muted.SetString(ToolPending)
599
600 s.Tool.NameNormal = base.Foreground(o.info)
601 s.Tool.NameNested = base.Foreground(o.info)
602
603 s.Tool.ParamMain = subtle
604 s.Tool.ParamKey = subtle
605
606 // Content rendering - prepared styles that accept width parameter
607 s.Tool.ContentLine = muted.Background(o.bgLeastVisible)
608 s.Tool.ContentTruncation = muted.Background(o.bgLeastVisible)
609 s.Tool.ContentCodeLine = base.Background(o.bgBase).PaddingLeft(2)
610 s.Tool.ContentCodeTruncation = muted.Background(o.bgBase).PaddingLeft(2)
611 s.Tool.ContentCodeBg = o.bgBase
612 s.Tool.Body = base.PaddingLeft(2)
613
614 // Deprecated - kept for backward compatibility
615 s.Tool.ContentBg = muted.Background(o.bgLeastVisible)
616 s.Tool.ContentText = muted
617 s.Tool.ContentLineNumber = base.Foreground(o.fgMoreSubtle).Background(o.bgBase).PaddingRight(1).PaddingLeft(1)
618
619 s.Tool.StateWaiting = base.Foreground(o.fgMostSubtle)
620 s.Tool.StateCancelled = base.Foreground(o.fgMostSubtle)
621
622 s.Tool.ErrorTag = base.Padding(0, 1).Background(o.destructive).Foreground(o.onPrimary)
623 s.Tool.ErrorMessage = base.Foreground(o.fgSubtle)
624
625 // Diff and multi-edit styles
626 s.Tool.DiffTruncation = muted.Background(o.bgLeastVisible).PaddingLeft(2)
627 s.Tool.NoteTag = base.Padding(0, 1).Background(o.info).Foreground(o.onPrimary)
628 s.Tool.NoteMessage = base.Foreground(o.fgSubtle)
629
630 // Job header styles
631 s.Tool.JobIconPending = base.Foreground(o.successMostSubtle)
632 s.Tool.JobIconError = base.Foreground(o.error)
633 s.Tool.JobIconSuccess = base.Foreground(o.success)
634 s.Tool.JobToolName = base.Foreground(o.info)
635 s.Tool.JobAction = base.Foreground(o.infoMostSubtle)
636 s.Tool.JobPID = muted
637 s.Tool.JobDescription = subtle
638
639 // Agent task styles
640 s.Tool.AgentTaskTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(o.infoMoreSubtle).Foreground(o.onPrimary)
641 s.Tool.AgentPrompt = muted
642
643 // Agentic fetch styles
644 s.Tool.AgenticFetchPromptTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(o.success).Foreground(o.separator)
645
646 // Todo styles
647 s.Tool.TodoRatio = base.Foreground(o.infoMostSubtle)
648 s.Tool.TodoCompletedIcon = base.Foreground(o.success)
649 s.Tool.TodoInProgressIcon = base.Foreground(o.successMostSubtle)
650 s.Tool.TodoPendingIcon = base.Foreground(o.fgMoreSubtle)
651 s.Tool.TodoStatusNote = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
652 s.Tool.TodoItem = lipgloss.NewStyle().Foreground(o.fgBase)
653 s.Tool.TodoJustStarted = lipgloss.NewStyle().Foreground(o.fgBase)
654
655 // MCP styles
656 s.Tool.MCPName = base.Foreground(o.info)
657 s.Tool.MCPToolName = base.Foreground(o.infoMostSubtle)
658 s.Tool.MCPArrow = base.Foreground(o.info).SetString(ArrowRightIcon)
659
660 // Loading indicators for images, skills
661 s.Tool.ResourceLoadedText = base.Foreground(o.success)
662 s.Tool.ResourceLoadedIndicator = base.Foreground(o.successMostSubtle)
663 s.Tool.ResourceName = base
664 s.Tool.MediaType = base
665 s.Tool.ResourceSize = base.Foreground(o.fgMoreSubtle)
666
667 // Hook styles
668 s.Tool.HookLabel = base.Foreground(o.successMoreSubtle)
669 s.Tool.HookName = base
670 s.Tool.HookMatcher = base.Foreground(o.fgMoreSubtle)
671 s.Tool.HookArrow = base.Foreground(o.successMoreSubtle)
672 s.Tool.HookDetail = base.Foreground(o.fgMoreSubtle)
673 s.Tool.HookOK = base.Foreground(o.successMostSubtle)
674 s.Tool.HookDenied = base.Foreground(o.error)
675 s.Tool.HookDeniedLabel = base.Foreground(o.destructive)
676 s.Tool.HookDeniedReason = base.Foreground(o.bgMostVisible)
677 s.Tool.HookRewrote = base.Foreground(o.bgMostVisible)
678
679 // Tool-call action verbs and result-list styling.
680 s.Tool.ActionCreate = lipgloss.NewStyle().Foreground(o.successMoreSubtle)
681 s.Tool.ActionDestroy = lipgloss.NewStyle().Foreground(o.destructive)
682 s.Tool.ResultEmpty = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
683 s.Tool.ResultTruncation = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
684 s.Tool.ResultItemName = lipgloss.NewStyle().Foreground(o.fgBase)
685 s.Tool.ResultItemDesc = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
686
687 // Buttons
688 s.Button.Focused = lipgloss.NewStyle().Foreground(o.onPrimary).Background(o.secondary)
689 s.Button.Blurred = lipgloss.NewStyle().Foreground(o.fgBase).Background(o.bgLessVisible)
690
691 // Editor
692 s.Editor.PromptNormalFocused = lipgloss.NewStyle().Foreground(o.successMostSubtle).SetString("::: ")
693 s.Editor.PromptNormalBlurred = s.Editor.PromptNormalFocused.Foreground(o.fgMoreSubtle)
694 s.Editor.PromptYoloIconFocused = lipgloss.NewStyle().MarginRight(1).Foreground(o.fgMostSubtle).Background(o.busy).Bold(true).SetString(" ! ")
695 s.Editor.PromptYoloIconBlurred = s.Editor.PromptYoloIconFocused.Foreground(o.bgBase).Background(o.fgMoreSubtle)
696 s.Editor.PromptYoloDotsFocused = lipgloss.NewStyle().MarginRight(1).Foreground(o.warningSubtle).SetString(":::")
697 s.Editor.PromptYoloDotsBlurred = s.Editor.PromptYoloDotsFocused.Foreground(o.fgMoreSubtle)
698
699 s.Radio.On = lipgloss.NewStyle().Foreground(o.fgSubtle).SetString(RadioOn)
700 s.Radio.Off = lipgloss.NewStyle().Foreground(o.fgSubtle).SetString(RadioOff)
701 s.Radio.Label = lipgloss.NewStyle().Foreground(o.fgSubtle)
702
703 // Logo
704 s.Logo.FieldColor = o.primary
705 s.Logo.TitleColorA = o.secondary
706 s.Logo.TitleColorB = o.primary
707 s.Logo.CharmColor = o.secondary
708 s.Logo.VersionColor = o.primary
709 s.Logo.SmallCharm = lipgloss.NewStyle().Foreground(o.secondary)
710 s.Logo.SmallDiagonals = lipgloss.NewStyle().Foreground(o.primary)
711 s.Logo.GradCanvas = lipgloss.NewStyle()
712 s.Logo.SmallGradFromColor = o.secondary
713 s.Logo.SmallGradToColor = o.primary
714
715 // Section
716 s.Section.Title = subtle
717 s.Section.Line = base.Foreground(o.separator)
718
719 // Initialize
720 s.Initialize.Header = base
721 s.Initialize.Content = muted
722 s.Initialize.Accent = base.Foreground(o.successMostSubtle)
723
724 // ResourceGroup (LSP/MCP/skills sidebar lists).
725 s.Resource.Heading = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
726 s.Resource.Name = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
727 s.Resource.StatusText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
728 s.Resource.OfflineIcon = lipgloss.NewStyle().Foreground(o.bgMostVisible).SetString("●")
729 s.Resource.BusyIcon = s.Resource.OfflineIcon.Foreground(o.busy)
730 s.Resource.ErrorIcon = s.Resource.OfflineIcon.Foreground(o.destructive)
731 s.Resource.OnlineIcon = s.Resource.OfflineIcon.Foreground(o.successMostSubtle)
732 s.Resource.DisabledIcon = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).SetString("●")
733 s.Resource.AdditionalText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
734 s.Resource.CapabilityCount = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
735 s.Resource.RowTitleBase = lipgloss.NewStyle().Foreground(o.fgBase)
736 s.Resource.RowDescBase = lipgloss.NewStyle().Foreground(o.fgBase)
737 s.Resource.DefaultTitleFg = o.fgMoreSubtle
738 s.Resource.DefaultDescFg = o.fgMostSubtle
739
740 // LSP
741 s.LSP.ErrorDiagnostic = base.Foreground(o.error)
742 s.LSP.WarningDiagnostic = base.Foreground(o.warningSubtle)
743 s.LSP.HintDiagnostic = base.Foreground(o.fgSubtle)
744 s.LSP.InfoDiagnostic = base.Foreground(o.info)
745
746 // Files
747 s.Files.Path = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
748 s.Files.Additions = lipgloss.NewStyle().Foreground(o.successMostSubtle)
749 s.Files.Deletions = lipgloss.NewStyle().Foreground(o.error)
750 s.Files.SectionTitle = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
751 s.Files.EmptyMessage = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
752 s.Files.TruncationHint = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
753
754 // Sidebar
755 s.Sidebar.SessionTitle = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
756 s.Sidebar.WorkingDir = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
757
758 // ModelInfo
759 s.ModelInfo.Icon = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
760 s.ModelInfo.Name = lipgloss.NewStyle().Foreground(o.fgBase)
761 s.ModelInfo.Provider = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
762 s.ModelInfo.ProviderFallback = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).PaddingLeft(2)
763 s.ModelInfo.Reasoning = lipgloss.NewStyle().Foreground(o.fgMostSubtle).PaddingLeft(2)
764 s.ModelInfo.TokenCount = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
765 s.ModelInfo.TokenPercentage = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
766 s.ModelInfo.Cost = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
767 s.ModelInfo.HypercreditIcon = lipgloss.NewStyle().Foreground(charmtone.Dolly)
768 s.ModelInfo.HypercreditText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
769
770 // ResourceGroup
771 s.Resource.DefaultTitleFg = o.fgMoreSubtle
772 s.Resource.DefaultDescFg = o.fgMostSubtle
773
774 // Chat
775 messageFocussedBorder := lipgloss.Border{
776 Left: "▌",
777 }
778
779 s.Messages.NoContent = lipgloss.NewStyle().Foreground(o.fgBase)
780 s.Messages.UserBlurred = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
781 BorderForeground(o.primary).BorderStyle(lipgloss.NormalBorder())
782 s.Messages.UserFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
783 BorderForeground(o.primary).BorderStyle(messageFocussedBorder)
784 s.Messages.AssistantBlurred = s.Messages.NoContent.PaddingLeft(2)
785 s.Messages.AssistantFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
786 BorderForeground(o.successMostSubtle).BorderStyle(messageFocussedBorder)
787 s.Messages.Thinking = lipgloss.NewStyle().MaxHeight(10)
788 s.Messages.ErrorTag = lipgloss.NewStyle().Padding(0, 1).
789 Background(o.destructive).Foreground(o.onPrimary)
790 s.Messages.ErrorTitle = lipgloss.NewStyle().Foreground(o.fgSubtle)
791 s.Messages.ErrorDetails = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
792
793 // Message item styles
794 s.Messages.ToolCallFocused = muted.PaddingLeft(1).
795 BorderStyle(messageFocussedBorder).
796 BorderLeft(true).
797 BorderForeground(o.successMostSubtle)
798 s.Messages.ToolCallBlurred = muted.PaddingLeft(2)
799 // No padding or border for compact tool calls within messages
800 s.Messages.ToolCallCompact = muted
801 s.Messages.SectionHeader = base.PaddingLeft(2)
802 s.Messages.AssistantInfoIcon = subtle
803 s.Messages.AssistantInfoModel = muted
804 s.Messages.AssistantInfoProvider = subtle
805 s.Messages.AssistantInfoDuration = subtle
806 s.Messages.AssistantCanceled = lipgloss.NewStyle().Foreground(o.fgBase).Italic(true)
807
808 // Thinking section styles
809 s.Messages.ThinkingBox = subtle.Background(o.bgLeastVisible)
810 s.Messages.ThinkingTruncationHint = muted
811 s.Messages.ThinkingFooterTitle = muted
812 s.Messages.ThinkingFooterDuration = subtle
813
814 // Text selection.
815 s.TextSelection = lipgloss.NewStyle().Foreground(o.onPrimary).Background(o.primary)
816
817 // Dialog styles
818 s.Dialog.Title = base.Padding(0, 1).Foreground(o.primary)
819 s.Dialog.TitleText = base.Foreground(o.primary)
820 s.Dialog.TitleError = base.Foreground(o.destructive)
821 s.Dialog.TitleAccent = base.Foreground(o.success).Bold(true)
822 s.Dialog.TitleLineBase = lipgloss.NewStyle()
823 s.Dialog.TitleGradFromColor = o.primary
824 s.Dialog.TitleGradToColor = o.secondary
825
826 // Dialog.ListItem (commands, reasoning, models)
827 s.Dialog.ListItem.InfoBlurred = lipgloss.NewStyle().Foreground(o.fgBase)
828 s.Dialog.ListItem.InfoFocused = lipgloss.NewStyle().Foreground(o.fgBase)
829
830 // Dialog.Models
831 s.Dialog.Models.ConfiguredText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
832
833 // Dialog.Permissions
834 s.Dialog.Permissions.KeyText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
835 s.Dialog.Permissions.ValueText = lipgloss.NewStyle().Foreground(o.fgBase)
836 s.Dialog.Permissions.ParamsBg = o.bgLessVisible
837
838 // Dialog.Quit
839 s.Dialog.Quit.Content = lipgloss.NewStyle().Foreground(o.fgBase)
840 s.Dialog.Quit.Frame = lipgloss.NewStyle().BorderForeground(o.primary).Border(lipgloss.RoundedBorder()).Padding(1, 2)
841 s.Dialog.View = base.Border(lipgloss.RoundedBorder()).BorderForeground(o.primary)
842 s.Dialog.PrimaryText = base.Padding(0, 1).Foreground(o.primary)
843 s.Dialog.SecondaryText = base.Padding(0, 1).Foreground(o.fgMostSubtle)
844 s.Dialog.HelpView = base.Padding(0, 1).AlignHorizontal(lipgloss.Left)
845 s.Dialog.Help.ShortKey = base.Foreground(o.fgMoreSubtle)
846 s.Dialog.Help.ShortDesc = base.Foreground(o.fgMostSubtle)
847 s.Dialog.Help.ShortSeparator = base.Foreground(o.separator)
848 s.Dialog.Help.Ellipsis = base.Foreground(o.separator)
849 s.Dialog.Help.FullKey = base.Foreground(o.fgMoreSubtle)
850 s.Dialog.Help.FullDesc = base.Foreground(o.fgMostSubtle)
851 s.Dialog.Help.FullSeparator = base.Foreground(o.separator)
852 s.Dialog.NormalItem = base.Padding(0, 1).Foreground(o.fgBase)
853 s.Dialog.SelectedItem = base.Padding(0, 1).Background(o.primary).Foreground(o.onPrimary)
854 s.Dialog.InputPrompt = base.Margin(1, 1)
855
856 s.Dialog.List = base.Margin(0, 0, 1, 0)
857 s.Dialog.ContentPanel = base.Background(o.bgLessVisible).Foreground(o.fgBase).Padding(1, 2)
858 s.Dialog.Spinner = base.Foreground(o.secondary)
859 s.Dialog.ScrollbarThumb = base.Foreground(o.secondary)
860 s.Dialog.ScrollbarTrack = base.Foreground(o.separator)
861
862 s.Dialog.ImagePreview = lipgloss.NewStyle().Padding(0, 1).Foreground(o.fgMostSubtle)
863
864 // API key input dialog
865 s.Dialog.APIKey.Spinner = base.Foreground(o.success)
866
867 // OAuth dialog
868 s.Dialog.OAuth.Spinner = base.Foreground(o.successMoreSubtle)
869 s.Dialog.OAuth.Instructions = lipgloss.NewStyle().Foreground(o.fgBase)
870 s.Dialog.OAuth.UserCode = lipgloss.NewStyle().Bold(true).Foreground(o.fgBase)
871 s.Dialog.OAuth.Success = lipgloss.NewStyle().Foreground(o.successMoreSubtle)
872 s.Dialog.OAuth.Link = lipgloss.NewStyle().Foreground(o.successMostSubtle).Underline(true)
873 s.Dialog.OAuth.Enter = lipgloss.NewStyle().Foreground(o.keyword)
874 s.Dialog.OAuth.ErrorText = lipgloss.NewStyle().Foreground(o.error)
875 s.Dialog.OAuth.StatusText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
876 s.Dialog.OAuth.UserCodeBg = o.bgLeastVisible
877
878 s.Dialog.Arguments.Content = base.Padding(1)
879 s.Dialog.Arguments.Description = base.MarginBottom(1).MaxHeight(3)
880 s.Dialog.Arguments.InputLabelBlurred = base.Foreground(o.fgMoreSubtle)
881 s.Dialog.Arguments.InputLabelFocused = base.Bold(true)
882 s.Dialog.Arguments.InputRequiredMarkBlurred = base.Foreground(o.fgMoreSubtle).SetString("*")
883 s.Dialog.Arguments.InputRequiredMarkFocused = base.Foreground(o.primary).Bold(true).SetString("*")
884
885 s.Dialog.Sessions.DeletingTitle = s.Dialog.Title.Foreground(o.destructive)
886 s.Dialog.Sessions.DeletingView = s.Dialog.View.BorderForeground(o.destructive)
887 s.Dialog.Sessions.DeletingMessage = base.Padding(1)
888 s.Dialog.Sessions.DeletingTitleGradientFromColor = o.destructive
889 s.Dialog.Sessions.DeletingTitleGradientToColor = o.primary
890 s.Dialog.Sessions.DeletingItemBlurred = s.Dialog.NormalItem.Foreground(o.fgMostSubtle)
891 s.Dialog.Sessions.DeletingItemFocused = s.Dialog.SelectedItem.Background(o.destructive).Foreground(o.onPrimary)
892
893 s.Dialog.Sessions.RenamingingTitle = s.Dialog.Title.Foreground(o.warningSubtle)
894 s.Dialog.Sessions.RenamingView = s.Dialog.View.BorderForeground(o.warningSubtle)
895 s.Dialog.Sessions.RenamingingMessage = base.Padding(1)
896 s.Dialog.Sessions.RenamingTitleGradientFromColor = o.warningSubtle
897 s.Dialog.Sessions.RenamingTitleGradientToColor = o.accent
898 s.Dialog.Sessions.RenamingItemBlurred = s.Dialog.NormalItem.Foreground(o.fgMostSubtle)
899 s.Dialog.Sessions.RenamingingItemFocused = s.Dialog.SelectedItem.UnsetBackground().UnsetForeground()
900 s.Dialog.Sessions.RenamingPlaceholder = base.Foreground(o.fgMoreSubtle)
901 s.Dialog.Sessions.InfoBlurred = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
902 s.Dialog.Sessions.InfoFocused = lipgloss.NewStyle().Foreground(o.fgBase)
903
904 s.Status.Help = lipgloss.NewStyle().Padding(0, 1)
905 s.Status.SuccessIndicator = base.Foreground(o.bgLessVisible).Background(o.success).Padding(0, 1).Bold(true).SetString("OKAY!")
906 s.Status.InfoIndicator = s.Status.SuccessIndicator
907 s.Status.UpdateIndicator = s.Status.SuccessIndicator.SetString("HEY!")
908 s.Status.WarnIndicator = s.Status.SuccessIndicator.Foreground(o.bgMostVisible).Background(o.warning).SetString("WARNING")
909 s.Status.ErrorIndicator = s.Status.SuccessIndicator.Foreground(o.bgBase).Background(o.destructive).SetString("ERROR")
910 s.Status.SuccessMessage = base.Foreground(o.bgLessVisible).Background(o.successMostSubtle).Padding(0, 1)
911 s.Status.InfoMessage = s.Status.SuccessMessage
912 s.Status.UpdateMessage = s.Status.SuccessMessage
913 s.Status.WarnMessage = s.Status.SuccessMessage.Foreground(o.bgMostVisible).Background(o.warningSubtle)
914 s.Status.ErrorMessage = s.Status.SuccessMessage.Foreground(o.onPrimary).Background(o.error)
915
916 // Completions styles
917 s.Completions.Normal = base.Background(o.bgLessVisible).Foreground(o.fgBase)
918 s.Completions.Focused = base.Background(o.primary).Foreground(o.onPrimary)
919 s.Completions.Match = base.Underline(true)
920
921 // Attachments styles
922 attachmentIconStyle := base.Foreground(o.bgLessVisible).Background(o.success).Padding(0, 1)
923 s.Attachments.Image = attachmentIconStyle.SetString(ImageIcon)
924 s.Attachments.Text = attachmentIconStyle.SetString(TextIcon)
925 s.Attachments.Normal = base.Padding(0, 1).MarginRight(1).Background(o.fgMoreSubtle).Foreground(o.fgBase)
926 s.Attachments.Deleting = base.Padding(0, 1).Bold(true).Background(o.destructive).Foreground(o.fgBase)
927
928 // Pills styles
929 s.Pills.Base = base.Padding(0, 1)
930 s.Pills.Focused = base.Padding(0, 1).BorderStyle(lipgloss.RoundedBorder()).BorderForeground(o.bgMostVisible)
931 s.Pills.Blurred = base.Padding(0, 1).BorderStyle(lipgloss.HiddenBorder())
932 s.Pills.QueueItemPrefix = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).SetString(" •")
933 s.Pills.QueueItemText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
934 s.Pills.QueueLabel = lipgloss.NewStyle().Foreground(o.fgBase)
935 s.Pills.QueueIconBase = lipgloss.NewStyle().Foreground(o.fgBase)
936 s.Pills.QueueGradFromColor = o.error
937 s.Pills.QueueGradToColor = o.secondary
938 s.Pills.TodoLabel = lipgloss.NewStyle().Foreground(o.fgBase)
939 s.Pills.TodoProgress = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
940 s.Pills.TodoCurrentTask = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
941 s.Pills.TodoSpinner = lipgloss.NewStyle().Foreground(o.successMostSubtle)
942 s.Pills.HelpKey = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
943 s.Pills.HelpText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
944 s.Pills.Area = base
945
946 return s
947}