chore(ui): theme prep

This commit is contained in:
Christian Rocha
2026-04-26 11:19:19 -04:00
parent f686999663
commit 755f6fae6f
10 changed files with 1027 additions and 943 deletions
+1 -1
View File
@@ -233,7 +233,7 @@ func (app *App) RunNonInteractive(ctx context.Context, output io.Writer, prompt,
progress = app.config.Config().Options.Progress == nil || *app.config.Config().Options.Progress
if !hideSpinner && stderrTTY {
t := styles.DefaultStyles()
t := styles.CharmtonePantera()
// Detect background color to set the appropriate color for the
// spinner's 'Generating...' text. Without this, that text would be
+1 -1
View File
@@ -189,7 +189,7 @@ func runNonInteractive(
progress = ws.Config.Options.Progress == nil || *ws.Config.Options.Progress
if !hideSpinner && stderrTTY {
t := styles.DefaultStyles()
t := styles.CharmtonePantera()
hasDarkBG := true
if stdinTTY && stdoutTTY {
+2 -2
View File
@@ -438,7 +438,7 @@ func outputSessionJSON(w io.Writer, sess session.Session, msgs []*message.Messag
}
func outputSessionHuman(ctx context.Context, sess session.Session, msgs []*message.Message) error {
sty := styles.DefaultStyles()
styles := styles.CharmtonePantera()
toolResults := chat.BuildToolResultMap(msgs)
width := sessionOutputWidth
@@ -479,7 +479,7 @@ func outputSessionHuman(ctx context.Context, sess session.Session, msgs []*messa
first := true
for _, msg := range msgs {
items := chat.ExtractMessageItems(&sty, msg, toolResults)
items := chat.ExtractMessageItems(&styles, msg, toolResults)
for _, item := range items {
if !first {
fmt.Fprintln(&buf)
+1 -1
View File
@@ -56,7 +56,7 @@ func TestLooksLikeMarkdown(t *testing.T) {
func TestRenderToolResultTextContent(t *testing.T) {
t.Parallel()
sty := styles.DefaultStyles()
sty := styles.CharmtonePantera()
styPtr := &sty
widths := toolResultContentWidths{Body: 80, Diff: 82}
+1 -1
View File
@@ -33,7 +33,7 @@ func (c *Common) Config() *config.Config {
// DefaultCommon returns the default common UI configurations.
func DefaultCommon(ws workspace.Workspace) *Common {
s := styles.DefaultStyles()
s := styles.CharmtonePantera()
return &Common{
Workspace: ws,
Styles: &s,
+1 -1
View File
@@ -18,7 +18,7 @@ func main() {
fmt.Fprintf(os.Stderr, "Could not get terminal size: %s", err)
}
s := styles.DefaultStyles()
s := styles.CharmtonePantera()
opts := logo.Opts{
FieldColor: s.Logo.FieldColor,
TitleColorA: s.Logo.TitleColorA,
+2 -2
View File
@@ -16,7 +16,7 @@ import (
func TestSkillStatusItemsIncludesBuiltinSkills(t *testing.T) {
t.Parallel()
st := uistyles.DefaultStyles()
st := uistyles.CharmtonePantera()
ui := &UI{
com: &common.Common{Styles: &st},
skillStates: []*skills.SkillState{
@@ -61,7 +61,7 @@ func TestSkillStatusItemsIncludesBuiltinSkills(t *testing.T) {
func TestSkillStatusItemsExcludesDisabledSkills(t *testing.T) {
t.Parallel()
st := uistyles.DefaultStyles()
st := uistyles.CharmtonePantera()
ui := &UI{
com: &common.Common{
Styles: &st,
+968
View File
@@ -0,0 +1,968 @@
package styles
import (
"image/color"
"charm.land/bubbles/v2/filepicker"
"charm.land/bubbles/v2/help"
"charm.land/bubbles/v2/textarea"
"charm.land/bubbles/v2/textinput"
tea "charm.land/bubbletea/v2"
"charm.land/glamour/v2/ansi"
"charm.land/lipgloss/v2"
"github.com/charmbracelet/crush/internal/ui/diffview"
"github.com/charmbracelet/x/exp/charmtone"
)
// quickStyleOpts is the palette of colors used by quickStyle to build a
// complete Styles value. Each field maps to a semantic role in the UI.
type quickStyleOpts struct {
// Brand.
primary color.Color
secondary color.Color
tertiary color.Color
// Foregrounds.
fgBase color.Color
fgMuted color.Color
fgHalfMuted color.Color
fgSubtle color.Color
// Contrast pairings: foregrounds designed to sit on top of a
// matching background role.
onPrimary color.Color // foreground on primary backgrounds.
onAccent color.Color // foreground on saturated status/accent backgrounds.
// Backgrounds.
bgBase color.Color
bgBaseLighter color.Color
bgSubtle color.Color
bgOverlay color.Color
// Borders.
border color.Color
borderFocus color.Color
// Status.
danger color.Color
error color.Color
warning color.Color
warningStrong color.Color
busy color.Color
info color.Color
infoSubtle color.Color
infoMuted color.Color
success color.Color
successSubtle color.Color
successMuted color.Color
}
// quickStyle builds a complete Styles value from a palette of semantic
// colors. Themes should populate quickStyleOpts and call this rather than
// re-implementing every style rule.
//
// The idea here is that you can do most of the work with quickStyle, then
// add overrides as needed.
func quickStyle(o quickStyleOpts) Styles {
var (
primary = o.primary
secondary = o.secondary
tertiary = o.tertiary
fgBase = o.fgBase
fgMuted = o.fgMuted
fgHalfMuted = o.fgHalfMuted
fgSubtle = o.fgSubtle
onPrimary = o.onPrimary
onAccent = o.onAccent
bgBase = o.bgBase
bgBaseLighter = o.bgBaseLighter
bgSubtle = o.bgSubtle
bgOverlay = o.bgOverlay
border = o.border
borderFocus = o.borderFocus
danger = o.danger
error = o.error
warning = o.warning
warningStrong = o.warningStrong
busy = o.busy
info = o.info
infoSubtle = o.infoSubtle
infoMuted = o.infoMuted
success = o.success
successSubtle = o.successSubtle
successMuted = o.successMuted
)
var (
base = lipgloss.NewStyle().Foreground(fgBase)
muted = lipgloss.NewStyle().Foreground(fgMuted)
subtle = lipgloss.NewStyle().Foreground(fgSubtle)
s Styles
)
s.Background = bgBase
// Populate color fields
s.WorkingGradFromColor = primary
s.WorkingGradToColor = secondary
s.WorkingLabelColor = fgBase
s.TextInput = textinput.Styles{
Focused: textinput.StyleState{
Text: base,
Placeholder: base.Foreground(fgSubtle),
Prompt: base.Foreground(tertiary),
Suggestion: base.Foreground(fgSubtle),
},
Blurred: textinput.StyleState{
Text: base.Foreground(fgMuted),
Placeholder: base.Foreground(fgSubtle),
Prompt: base.Foreground(fgMuted),
Suggestion: base.Foreground(fgSubtle),
},
Cursor: textinput.CursorStyle{
Color: secondary,
Shape: tea.CursorBlock,
Blink: true,
},
}
s.Editor.Textarea = textarea.Styles{
Focused: textarea.StyleState{
Base: base,
Text: base,
LineNumber: base.Foreground(fgSubtle),
CursorLine: base,
CursorLineNumber: base.Foreground(fgSubtle),
Placeholder: base.Foreground(fgSubtle),
Prompt: base.Foreground(tertiary),
},
Blurred: textarea.StyleState{
Base: base,
Text: base.Foreground(fgMuted),
LineNumber: base.Foreground(fgMuted),
CursorLine: base,
CursorLineNumber: base.Foreground(fgMuted),
Placeholder: base.Foreground(fgSubtle),
Prompt: base.Foreground(fgMuted),
},
Cursor: textarea.CursorStyle{
Color: secondary,
Shape: tea.CursorBlock,
Blink: true,
},
}
s.Markdown = ansi.StyleConfig{
Document: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
// BlockPrefix: "\n",
// BlockSuffix: "\n",
Color: hex(fgHalfMuted),
},
// Margin: new(uint(defaultMargin)),
},
BlockQuote: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
Indent: new(uint(1)),
IndentToken: new("│ "),
},
List: ansi.StyleList{
LevelIndent: defaultListIndent,
},
Heading: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockSuffix: "\n",
Color: hex(info),
Bold: new(true),
},
},
H1: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Color: hex(warning),
BackgroundColor: hex(primary),
Bold: new(true),
},
},
H2: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "## ",
},
},
H3: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "### ",
},
},
H4: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "#### ",
},
},
H5: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "##### ",
},
},
H6: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "###### ",
Color: hex(successMuted),
Bold: new(false),
},
},
Strikethrough: ansi.StylePrimitive{
CrossedOut: new(true),
},
Emph: ansi.StylePrimitive{
Italic: new(true),
},
Strong: ansi.StylePrimitive{
Bold: new(true),
},
HorizontalRule: ansi.StylePrimitive{
Color: hex(border),
Format: "\n--------\n",
},
Item: ansi.StylePrimitive{
BlockPrefix: "• ",
},
Enumeration: ansi.StylePrimitive{
BlockPrefix: ". ",
},
Task: ansi.StyleTask{
StylePrimitive: ansi.StylePrimitive{},
Ticked: "[✓] ",
Unticked: "[ ] ",
},
Link: ansi.StylePrimitive{
Color: hex(charmtone.Zinc),
Underline: new(true),
},
LinkText: ansi.StylePrimitive{
Color: hex(successMuted),
Bold: new(true),
},
Image: ansi.StylePrimitive{
Color: hex(charmtone.Cheeky),
Underline: new(true),
},
ImageText: ansi.StylePrimitive{
Color: hex(fgMuted),
Format: "Image: {{.text}} →",
},
Code: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Color: hex(danger),
BackgroundColor: hex(bgSubtle),
},
},
CodeBlock: ansi.StyleCodeBlock{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: hex(bgSubtle),
},
Margin: new(uint(defaultMargin)),
},
Chroma: &ansi.Chroma{
Text: ansi.StylePrimitive{
Color: hex(fgHalfMuted),
},
Error: ansi.StylePrimitive{
Color: hex(onAccent),
BackgroundColor: hex(error),
},
Comment: ansi.StylePrimitive{
Color: hex(fgSubtle),
},
CommentPreproc: ansi.StylePrimitive{
Color: hex(charmtone.Bengal),
},
Keyword: ansi.StylePrimitive{
Color: hex(info),
},
KeywordReserved: ansi.StylePrimitive{
Color: hex(charmtone.Pony),
},
KeywordNamespace: ansi.StylePrimitive{
Color: hex(charmtone.Pony),
},
KeywordType: ansi.StylePrimitive{
Color: hex(charmtone.Guppy),
},
Operator: ansi.StylePrimitive{
Color: hex(charmtone.Salmon),
},
Punctuation: ansi.StylePrimitive{
Color: hex(warning),
},
Name: ansi.StylePrimitive{
Color: hex(fgHalfMuted),
},
NameBuiltin: ansi.StylePrimitive{
Color: hex(charmtone.Cheeky),
},
NameTag: ansi.StylePrimitive{
Color: hex(charmtone.Mauve),
},
NameAttribute: ansi.StylePrimitive{
Color: hex(charmtone.Hazy),
},
NameClass: ansi.StylePrimitive{
Color: hex(charmtone.Salt),
Underline: new(true),
Bold: new(true),
},
NameDecorator: ansi.StylePrimitive{
Color: hex(charmtone.Citron),
},
NameFunction: ansi.StylePrimitive{
Color: hex(successMuted),
},
LiteralNumber: ansi.StylePrimitive{
Color: hex(success),
},
LiteralString: ansi.StylePrimitive{
Color: hex(charmtone.Cumin),
},
LiteralStringEscape: ansi.StylePrimitive{
Color: hex(successSubtle),
},
GenericDeleted: ansi.StylePrimitive{
Color: hex(danger),
},
GenericEmph: ansi.StylePrimitive{
Italic: new(true),
},
GenericInserted: ansi.StylePrimitive{
Color: hex(successMuted),
},
GenericStrong: ansi.StylePrimitive{
Bold: new(true),
},
GenericSubheading: ansi.StylePrimitive{
Color: hex(fgMuted),
},
Background: ansi.StylePrimitive{
BackgroundColor: hex(bgSubtle),
},
},
},
Table: ansi.StyleTable{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
},
},
DefinitionDescription: ansi.StylePrimitive{
BlockPrefix: "\n ",
},
}
// QuietMarkdown style - muted colors on subtle background for thinking content.
plainBg := hex(bgBaseLighter)
plainFg := hex(fgMuted)
s.QuietMarkdown = ansi.StyleConfig{
Document: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: plainFg,
BackgroundColor: plainBg,
},
},
BlockQuote: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: plainFg,
BackgroundColor: plainBg,
},
Indent: new(uint(1)),
IndentToken: new("│ "),
},
List: ansi.StyleList{
LevelIndent: defaultListIndent,
},
Heading: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockSuffix: "\n",
Bold: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
},
H1: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Bold: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
},
H2: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "## ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
H3: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "### ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
H4: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "#### ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
H5: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "##### ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
H6: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "###### ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
Strikethrough: ansi.StylePrimitive{
CrossedOut: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
Emph: ansi.StylePrimitive{
Italic: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
Strong: ansi.StylePrimitive{
Bold: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
HorizontalRule: ansi.StylePrimitive{
Format: "\n--------\n",
Color: plainFg,
BackgroundColor: plainBg,
},
Item: ansi.StylePrimitive{
BlockPrefix: "• ",
Color: plainFg,
BackgroundColor: plainBg,
},
Enumeration: ansi.StylePrimitive{
BlockPrefix: ". ",
Color: plainFg,
BackgroundColor: plainBg,
},
Task: ansi.StyleTask{
StylePrimitive: ansi.StylePrimitive{
Color: plainFg,
BackgroundColor: plainBg,
},
Ticked: "[✓] ",
Unticked: "[ ] ",
},
Link: ansi.StylePrimitive{
Underline: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
LinkText: ansi.StylePrimitive{
Bold: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
Image: ansi.StylePrimitive{
Underline: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
ImageText: ansi.StylePrimitive{
Format: "Image: {{.text}} →",
Color: plainFg,
BackgroundColor: plainBg,
},
Code: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
CodeBlock: ansi.StyleCodeBlock{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: plainFg,
BackgroundColor: plainBg,
},
Margin: new(uint(defaultMargin)),
},
},
Table: ansi.StyleTable{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: plainFg,
BackgroundColor: plainBg,
},
},
},
DefinitionDescription: ansi.StylePrimitive{
BlockPrefix: "\n ",
Color: plainFg,
BackgroundColor: plainBg,
},
}
s.Help = help.Styles{
ShortKey: base.Foreground(fgMuted),
ShortDesc: base.Foreground(fgSubtle),
ShortSeparator: base.Foreground(border),
Ellipsis: base.Foreground(border),
FullKey: base.Foreground(fgMuted),
FullDesc: base.Foreground(fgSubtle),
FullSeparator: base.Foreground(border),
}
s.Diff = diffview.Style{
DividerLine: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Foreground(fgHalfMuted).
Background(bgBaseLighter),
Code: lipgloss.NewStyle().
Foreground(fgHalfMuted).
Background(bgBaseLighter),
},
MissingLine: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Background(bgBaseLighter),
Code: lipgloss.NewStyle().
Background(bgBaseLighter),
},
EqualLine: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Foreground(fgMuted).
Background(bgBase),
Code: lipgloss.NewStyle().
Foreground(fgMuted).
Background(bgBase),
},
InsertLine: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Foreground(lipgloss.Color("#629657")).
Background(lipgloss.Color("#2b322a")),
Symbol: lipgloss.NewStyle().
Foreground(lipgloss.Color("#629657")).
Background(lipgloss.Color("#323931")),
Code: lipgloss.NewStyle().
Background(lipgloss.Color("#323931")),
},
DeleteLine: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Foreground(lipgloss.Color("#a45c59")).
Background(lipgloss.Color("#312929")),
Symbol: lipgloss.NewStyle().
Foreground(lipgloss.Color("#a45c59")).
Background(lipgloss.Color("#383030")),
Code: lipgloss.NewStyle().
Background(lipgloss.Color("#383030")),
},
Filename: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Foreground(fgHalfMuted).
Background(bgBaseLighter),
Code: lipgloss.NewStyle().
Foreground(fgHalfMuted).
Background(bgBaseLighter),
},
}
s.FilePicker = filepicker.Styles{
DisabledCursor: base.Foreground(fgMuted),
Cursor: base.Foreground(fgBase),
Symlink: base.Foreground(fgSubtle),
Directory: base.Foreground(primary),
File: base.Foreground(fgBase),
DisabledFile: base.Foreground(fgMuted),
DisabledSelected: base.Background(bgOverlay).Foreground(fgMuted),
Permission: base.Foreground(fgMuted),
Selected: base.Background(primary).Foreground(fgBase),
FileSize: base.Foreground(fgMuted),
EmptyDirectory: base.Foreground(fgMuted).PaddingLeft(2).SetString("Empty directory"),
}
// borders
s.ToolCallSuccess = lipgloss.NewStyle().Foreground(success).SetString(ToolSuccess)
s.Header.Charm = base.Foreground(secondary)
s.Header.Diagonals = base.Foreground(primary)
s.Header.Percentage = muted
s.Header.Keystroke = muted
s.Header.KeystrokeTip = subtle
s.Header.WorkingDir = muted
s.Header.Separator = subtle
s.Header.Wrapper = lipgloss.NewStyle().Foreground(fgBase)
s.Header.LogoGradCanvas = lipgloss.NewStyle()
s.Header.LogoGradFromColor = secondary
s.Header.LogoGradToColor = primary
s.CompactDetails.Title = base
s.CompactDetails.View = base.Padding(0, 1, 1, 1).Border(lipgloss.RoundedBorder()).BorderForeground(borderFocus)
s.CompactDetails.Version = lipgloss.NewStyle().Foreground(border)
// Tool rendering styles
s.Tool.IconPending = base.Foreground(successMuted).SetString(ToolPending)
s.Tool.IconSuccess = base.Foreground(success).SetString(ToolSuccess)
s.Tool.IconError = base.Foreground(error).SetString(ToolError)
s.Tool.IconCancelled = muted.SetString(ToolPending)
s.Tool.NameNormal = base.Foreground(info)
s.Tool.NameNested = base.Foreground(info)
s.Tool.ParamMain = subtle
s.Tool.ParamKey = subtle
// Content rendering - prepared styles that accept width parameter
s.Tool.ContentLine = muted.Background(bgBaseLighter)
s.Tool.ContentTruncation = muted.Background(bgBaseLighter)
s.Tool.ContentCodeLine = base.Background(bgBase).PaddingLeft(2)
s.Tool.ContentCodeTruncation = muted.Background(bgBase).PaddingLeft(2)
s.Tool.ContentCodeBg = bgBase
s.Tool.Body = base.PaddingLeft(2)
// Deprecated - kept for backward compatibility
s.Tool.ContentBg = muted.Background(bgBaseLighter)
s.Tool.ContentText = muted
s.Tool.ContentLineNumber = base.Foreground(fgMuted).Background(bgBase).PaddingRight(1).PaddingLeft(1)
s.Tool.StateWaiting = base.Foreground(fgSubtle)
s.Tool.StateCancelled = base.Foreground(fgSubtle)
s.Tool.ErrorTag = base.Padding(0, 1).Background(danger).Foreground(onAccent)
s.Tool.ErrorMessage = base.Foreground(fgHalfMuted)
// Diff and multi-edit styles
s.Tool.DiffTruncation = muted.Background(bgBaseLighter).PaddingLeft(2)
s.Tool.NoteTag = base.Padding(0, 1).Background(info).Foreground(onAccent)
s.Tool.NoteMessage = base.Foreground(fgHalfMuted)
// Job header styles
s.Tool.JobIconPending = base.Foreground(successMuted)
s.Tool.JobIconError = base.Foreground(error)
s.Tool.JobIconSuccess = base.Foreground(success)
s.Tool.JobToolName = base.Foreground(info)
s.Tool.JobAction = base.Foreground(infoMuted)
s.Tool.JobPID = muted
s.Tool.JobDescription = subtle
// Agent task styles
s.Tool.AgentTaskTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(infoSubtle).Foreground(onAccent)
s.Tool.AgentPrompt = muted
// Agentic fetch styles
s.Tool.AgenticFetchPromptTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(success).Foreground(border)
// Todo styles
s.Tool.TodoRatio = base.Foreground(infoMuted)
s.Tool.TodoCompletedIcon = base.Foreground(success)
s.Tool.TodoInProgressIcon = base.Foreground(successMuted)
s.Tool.TodoPendingIcon = base.Foreground(fgMuted)
s.Tool.TodoStatusNote = lipgloss.NewStyle().Foreground(fgSubtle)
s.Tool.TodoItem = lipgloss.NewStyle().Foreground(fgBase)
s.Tool.TodoJustStarted = lipgloss.NewStyle().Foreground(fgBase)
// MCP styles
s.Tool.MCPName = base.Foreground(info)
s.Tool.MCPToolName = base.Foreground(infoMuted)
s.Tool.MCPArrow = base.Foreground(info).SetString(ArrowRightIcon)
// Loading indicators for images, skills
s.Tool.ResourceLoadedText = base.Foreground(success)
s.Tool.ResourceLoadedIndicator = base.Foreground(successMuted)
s.Tool.ResourceName = base
s.Tool.MediaType = base
s.Tool.ResourceSize = base.Foreground(fgMuted)
// Tool-call action verbs and result-list styling.
s.Tool.ActionCreate = lipgloss.NewStyle().Foreground(successSubtle)
s.Tool.ActionDestroy = lipgloss.NewStyle().Foreground(danger)
s.Tool.ResultEmpty = lipgloss.NewStyle().Foreground(fgSubtle)
s.Tool.ResultTruncation = lipgloss.NewStyle().Foreground(fgSubtle)
s.Tool.ResultItemName = lipgloss.NewStyle().Foreground(fgBase)
s.Tool.ResultItemDesc = lipgloss.NewStyle().Foreground(fgSubtle)
// Buttons
s.Button.Focused = lipgloss.NewStyle().Foreground(onAccent).Background(secondary)
s.Button.Blurred = lipgloss.NewStyle().Foreground(fgBase).Background(bgSubtle)
// Editor
s.Editor.PromptNormalFocused = lipgloss.NewStyle().Foreground(successMuted).SetString("::: ")
s.Editor.PromptNormalBlurred = s.Editor.PromptNormalFocused.Foreground(fgMuted)
s.Editor.PromptYoloIconFocused = lipgloss.NewStyle().MarginRight(1).Foreground(fgSubtle).Background(busy).Bold(true).SetString(" ! ")
s.Editor.PromptYoloIconBlurred = s.Editor.PromptYoloIconFocused.Foreground(bgBase).Background(fgMuted)
s.Editor.PromptYoloDotsFocused = lipgloss.NewStyle().MarginRight(1).Foreground(warning).SetString(":::")
s.Editor.PromptYoloDotsBlurred = s.Editor.PromptYoloDotsFocused.Foreground(fgMuted)
s.Radio.On = lipgloss.NewStyle().Foreground(fgHalfMuted).SetString(RadioOn)
s.Radio.Off = lipgloss.NewStyle().Foreground(fgHalfMuted).SetString(RadioOff)
s.Radio.Label = lipgloss.NewStyle().Foreground(fgHalfMuted)
// Logo
s.Logo.FieldColor = primary
s.Logo.TitleColorA = secondary
s.Logo.TitleColorB = primary
s.Logo.CharmColor = secondary
s.Logo.VersionColor = primary
s.Logo.SmallCharm = lipgloss.NewStyle().Foreground(secondary)
s.Logo.SmallDiagonals = lipgloss.NewStyle().Foreground(primary)
s.Logo.GradCanvas = lipgloss.NewStyle()
s.Logo.SmallGradFromColor = secondary
s.Logo.SmallGradToColor = primary
// Section
s.Section.Title = subtle
s.Section.Line = base.Foreground(border)
// Initialize
s.Initialize.Header = base
s.Initialize.Content = muted
s.Initialize.Accent = base.Foreground(successMuted)
// ResourceGroup (LSP/MCP/skills sidebar lists).
s.Resource.Heading = lipgloss.NewStyle().Foreground(fgSubtle)
s.Resource.Name = lipgloss.NewStyle().Foreground(fgMuted)
s.Resource.StatusText = lipgloss.NewStyle().Foreground(fgSubtle)
s.Resource.OfflineIcon = lipgloss.NewStyle().Foreground(bgOverlay).SetString("●")
s.Resource.BusyIcon = s.Resource.OfflineIcon.Foreground(busy)
s.Resource.ErrorIcon = s.Resource.OfflineIcon.Foreground(danger)
s.Resource.OnlineIcon = s.Resource.OfflineIcon.Foreground(successMuted)
s.Resource.DisabledIcon = lipgloss.NewStyle().Foreground(fgMuted).SetString("●")
s.Resource.AdditionalText = lipgloss.NewStyle().Foreground(fgSubtle)
s.Resource.CapabilityCount = lipgloss.NewStyle().Foreground(fgSubtle)
s.Resource.RowTitleBase = lipgloss.NewStyle().Foreground(fgBase)
s.Resource.RowDescBase = lipgloss.NewStyle().Foreground(fgBase)
s.Resource.DefaultTitleFg = fgMuted
s.Resource.DefaultDescFg = fgSubtle
// LSP
s.LSP.ErrorDiagnostic = base.Foreground(error)
s.LSP.WarningDiagnostic = base.Foreground(warning)
s.LSP.HintDiagnostic = base.Foreground(fgHalfMuted)
s.LSP.InfoDiagnostic = base.Foreground(info)
// Files
s.Files.Path = lipgloss.NewStyle().Foreground(fgMuted)
s.Files.Additions = lipgloss.NewStyle().Foreground(successMuted)
s.Files.Deletions = lipgloss.NewStyle().Foreground(error)
s.Files.SectionTitle = lipgloss.NewStyle().Foreground(fgSubtle)
s.Files.EmptyMessage = lipgloss.NewStyle().Foreground(fgSubtle)
s.Files.TruncationHint = lipgloss.NewStyle().Foreground(fgSubtle)
// Sidebar
s.Sidebar.SessionTitle = lipgloss.NewStyle().Foreground(fgMuted)
s.Sidebar.WorkingDir = lipgloss.NewStyle().Foreground(fgMuted)
// ModelInfo
s.ModelInfo.Icon = lipgloss.NewStyle().Foreground(fgSubtle)
s.ModelInfo.Name = lipgloss.NewStyle().Foreground(fgBase)
s.ModelInfo.Provider = lipgloss.NewStyle().Foreground(fgMuted)
s.ModelInfo.ProviderFallback = lipgloss.NewStyle().Foreground(fgMuted).PaddingLeft(2)
s.ModelInfo.Reasoning = lipgloss.NewStyle().Foreground(fgSubtle).PaddingLeft(2)
s.ModelInfo.TokenCount = lipgloss.NewStyle().Foreground(fgSubtle)
s.ModelInfo.TokenPercentage = lipgloss.NewStyle().Foreground(fgMuted)
s.ModelInfo.Cost = lipgloss.NewStyle().Foreground(fgMuted)
// ResourceGroup
s.Resource.DefaultTitleFg = fgMuted
s.Resource.DefaultDescFg = fgSubtle
// Chat
messageFocussedBorder := lipgloss.Border{
Left: "▌",
}
s.Messages.NoContent = lipgloss.NewStyle().Foreground(fgBase)
s.Messages.UserBlurred = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
BorderForeground(primary).BorderStyle(lipgloss.NormalBorder())
s.Messages.UserFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
BorderForeground(primary).BorderStyle(messageFocussedBorder)
s.Messages.AssistantBlurred = s.Messages.NoContent.PaddingLeft(2)
s.Messages.AssistantFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
BorderForeground(successMuted).BorderStyle(messageFocussedBorder)
s.Messages.Thinking = lipgloss.NewStyle().MaxHeight(10)
s.Messages.ErrorTag = lipgloss.NewStyle().Padding(0, 1).
Background(danger).Foreground(onAccent)
s.Messages.ErrorTitle = lipgloss.NewStyle().Foreground(fgHalfMuted)
s.Messages.ErrorDetails = lipgloss.NewStyle().Foreground(fgSubtle)
// Message item styles
s.Messages.ToolCallFocused = muted.PaddingLeft(1).
BorderStyle(messageFocussedBorder).
BorderLeft(true).
BorderForeground(successMuted)
s.Messages.ToolCallBlurred = muted.PaddingLeft(2)
// No padding or border for compact tool calls within messages
s.Messages.ToolCallCompact = muted
s.Messages.SectionHeader = base.PaddingLeft(2)
s.Messages.AssistantInfoIcon = subtle
s.Messages.AssistantInfoModel = muted
s.Messages.AssistantInfoProvider = subtle
s.Messages.AssistantInfoDuration = subtle
s.Messages.AssistantCanceled = lipgloss.NewStyle().Foreground(fgBase).Italic(true)
// Thinking section styles
s.Messages.ThinkingBox = subtle.Background(bgBaseLighter)
s.Messages.ThinkingTruncationHint = muted
s.Messages.ThinkingFooterTitle = muted
s.Messages.ThinkingFooterDuration = subtle
// Text selection.
s.TextSelection = lipgloss.NewStyle().Foreground(onPrimary).Background(primary)
// Dialog styles
s.Dialog.Title = base.Padding(0, 1).Foreground(primary)
s.Dialog.TitleText = base.Foreground(primary)
s.Dialog.TitleError = base.Foreground(danger)
s.Dialog.TitleAccent = base.Foreground(success).Bold(true)
s.Dialog.TitleLineBase = lipgloss.NewStyle()
s.Dialog.TitleGradFromColor = primary
s.Dialog.TitleGradToColor = secondary
// Dialog.ListItem (commands, reasoning, models)
s.Dialog.ListItem.InfoBlurred = lipgloss.NewStyle().Foreground(fgBase)
s.Dialog.ListItem.InfoFocused = lipgloss.NewStyle().Foreground(fgBase)
// Dialog.Models
s.Dialog.Models.ConfiguredText = lipgloss.NewStyle().Foreground(fgSubtle)
// Dialog.Permissions
s.Dialog.Permissions.KeyText = lipgloss.NewStyle().Foreground(fgMuted)
s.Dialog.Permissions.ValueText = lipgloss.NewStyle().Foreground(fgBase)
s.Dialog.Permissions.ParamsBg = bgSubtle
// Dialog.Quit
s.Dialog.Quit.Content = lipgloss.NewStyle().Foreground(fgBase)
s.Dialog.Quit.Frame = lipgloss.NewStyle().BorderForeground(borderFocus).Border(lipgloss.RoundedBorder()).Padding(1, 2)
s.Dialog.View = base.Border(lipgloss.RoundedBorder()).BorderForeground(borderFocus)
s.Dialog.PrimaryText = base.Padding(0, 1).Foreground(primary)
s.Dialog.SecondaryText = base.Padding(0, 1).Foreground(fgSubtle)
s.Dialog.HelpView = base.Padding(0, 1).AlignHorizontal(lipgloss.Left)
s.Dialog.Help.ShortKey = base.Foreground(fgMuted)
s.Dialog.Help.ShortDesc = base.Foreground(fgSubtle)
s.Dialog.Help.ShortSeparator = base.Foreground(border)
s.Dialog.Help.Ellipsis = base.Foreground(border)
s.Dialog.Help.FullKey = base.Foreground(fgMuted)
s.Dialog.Help.FullDesc = base.Foreground(fgSubtle)
s.Dialog.Help.FullSeparator = base.Foreground(border)
s.Dialog.NormalItem = base.Padding(0, 1).Foreground(fgBase)
s.Dialog.SelectedItem = base.Padding(0, 1).Background(primary).Foreground(fgBase)
s.Dialog.InputPrompt = base.Margin(1, 1)
s.Dialog.List = base.Margin(0, 0, 1, 0)
s.Dialog.ContentPanel = base.Background(bgSubtle).Foreground(fgBase).Padding(1, 2)
s.Dialog.Spinner = base.Foreground(secondary)
s.Dialog.ScrollbarThumb = base.Foreground(secondary)
s.Dialog.ScrollbarTrack = base.Foreground(border)
s.Dialog.ImagePreview = lipgloss.NewStyle().Padding(0, 1).Foreground(fgSubtle)
// API key input dialog
s.Dialog.APIKey.Spinner = base.Foreground(success)
// OAuth dialog
s.Dialog.OAuth.Spinner = base.Foreground(successSubtle)
s.Dialog.OAuth.Instructions = lipgloss.NewStyle().Foreground(onAccent)
s.Dialog.OAuth.UserCode = lipgloss.NewStyle().Bold(true).Foreground(onAccent)
s.Dialog.OAuth.Success = lipgloss.NewStyle().Foreground(successSubtle)
s.Dialog.OAuth.Link = lipgloss.NewStyle().Foreground(successMuted).Underline(true)
s.Dialog.OAuth.Enter = lipgloss.NewStyle().Foreground(primary)
s.Dialog.OAuth.ErrorText = lipgloss.NewStyle().Foreground(error)
s.Dialog.OAuth.StatusText = lipgloss.NewStyle().Foreground(fgMuted)
s.Dialog.OAuth.UserCodeBg = bgBaseLighter
s.Dialog.Arguments.Content = base.Padding(1)
s.Dialog.Arguments.Description = base.MarginBottom(1).MaxHeight(3)
s.Dialog.Arguments.InputLabelBlurred = base.Foreground(fgMuted)
s.Dialog.Arguments.InputLabelFocused = base.Bold(true)
s.Dialog.Arguments.InputRequiredMarkBlurred = base.Foreground(fgMuted).SetString("*")
s.Dialog.Arguments.InputRequiredMarkFocused = base.Foreground(primary).Bold(true).SetString("*")
s.Dialog.Sessions.DeletingTitle = s.Dialog.Title.Foreground(danger)
s.Dialog.Sessions.DeletingView = s.Dialog.View.BorderForeground(danger)
s.Dialog.Sessions.DeletingMessage = base.Padding(1)
s.Dialog.Sessions.DeletingTitleGradientFromColor = danger
s.Dialog.Sessions.DeletingTitleGradientToColor = primary
s.Dialog.Sessions.DeletingItemBlurred = s.Dialog.NormalItem.Foreground(fgSubtle)
s.Dialog.Sessions.DeletingItemFocused = s.Dialog.SelectedItem.Background(danger).Foreground(onAccent)
s.Dialog.Sessions.RenamingingTitle = s.Dialog.Title.Foreground(warning)
s.Dialog.Sessions.RenamingView = s.Dialog.View.BorderForeground(warning)
s.Dialog.Sessions.RenamingingMessage = base.Padding(1)
s.Dialog.Sessions.RenamingTitleGradientFromColor = warning
s.Dialog.Sessions.RenamingTitleGradientToColor = tertiary
s.Dialog.Sessions.RenamingItemBlurred = s.Dialog.NormalItem.Foreground(fgSubtle)
s.Dialog.Sessions.RenamingingItemFocused = s.Dialog.SelectedItem.UnsetBackground().UnsetForeground()
s.Dialog.Sessions.RenamingPlaceholder = base.Foreground(fgMuted)
s.Dialog.Sessions.InfoBlurred = lipgloss.NewStyle().Foreground(fgSubtle)
s.Dialog.Sessions.InfoFocused = lipgloss.NewStyle().Foreground(fgBase)
s.Status.Help = lipgloss.NewStyle().Padding(0, 1)
s.Status.SuccessIndicator = base.Foreground(bgSubtle).Background(success).Padding(0, 1).Bold(true).SetString("OKAY!")
s.Status.InfoIndicator = s.Status.SuccessIndicator
s.Status.UpdateIndicator = s.Status.SuccessIndicator.SetString("HEY!")
s.Status.WarnIndicator = s.Status.SuccessIndicator.Foreground(bgOverlay).Background(warningStrong).SetString("WARNING")
s.Status.ErrorIndicator = s.Status.SuccessIndicator.Foreground(bgBase).Background(danger).SetString("ERROR")
s.Status.SuccessMessage = base.Foreground(bgSubtle).Background(successMuted).Padding(0, 1)
s.Status.InfoMessage = s.Status.SuccessMessage
s.Status.UpdateMessage = s.Status.SuccessMessage
s.Status.WarnMessage = s.Status.SuccessMessage.Foreground(bgOverlay).Background(warning)
s.Status.ErrorMessage = s.Status.SuccessMessage.Foreground(onAccent).Background(error)
// Completions styles
s.Completions.Normal = base.Background(bgSubtle).Foreground(fgBase)
s.Completions.Focused = base.Background(primary).Foreground(onAccent)
s.Completions.Match = base.Underline(true)
// Attachments styles
attachmentIconStyle := base.Foreground(bgSubtle).Background(success).Padding(0, 1)
s.Attachments.Image = attachmentIconStyle.SetString(ImageIcon)
s.Attachments.Text = attachmentIconStyle.SetString(TextIcon)
s.Attachments.Normal = base.Padding(0, 1).MarginRight(1).Background(fgMuted).Foreground(fgBase)
s.Attachments.Deleting = base.Padding(0, 1).Bold(true).Background(danger).Foreground(fgBase)
// Pills styles
s.Pills.Base = base.Padding(0, 1)
s.Pills.Focused = base.Padding(0, 1).BorderStyle(lipgloss.RoundedBorder()).BorderForeground(bgOverlay)
s.Pills.Blurred = base.Padding(0, 1).BorderStyle(lipgloss.HiddenBorder())
s.Pills.QueueItemPrefix = lipgloss.NewStyle().Foreground(fgMuted).SetString(" •")
s.Pills.QueueItemText = lipgloss.NewStyle().Foreground(fgMuted)
s.Pills.QueueLabel = lipgloss.NewStyle().Foreground(fgBase)
s.Pills.QueueIconBase = lipgloss.NewStyle().Foreground(fgBase)
s.Pills.QueueGradFromColor = error
s.Pills.QueueGradToColor = secondary
s.Pills.TodoLabel = lipgloss.NewStyle().Foreground(fgBase)
s.Pills.TodoProgress = lipgloss.NewStyle().Foreground(fgMuted)
s.Pills.TodoCurrentTask = lipgloss.NewStyle().Foreground(fgSubtle)
s.Pills.TodoSpinner = lipgloss.NewStyle().Foreground(successMuted)
s.Pills.HelpKey = lipgloss.NewStyle().Foreground(fgMuted)
s.Pills.HelpText = lipgloss.NewStyle().Foreground(fgSubtle)
s.Pills.Area = base
return s
}
+9 -934
View File
@@ -1,6 +1,8 @@
// Package styles define styling and theming for the project.
package styles
import (
"fmt"
"image/color"
"strings"
@@ -8,12 +10,10 @@ import (
"charm.land/bubbles/v2/help"
"charm.land/bubbles/v2/textarea"
"charm.land/bubbles/v2/textinput"
tea "charm.land/bubbletea/v2"
"charm.land/glamour/v2/ansi"
"charm.land/lipgloss/v2"
"github.com/alecthomas/chroma/v2"
"github.com/charmbracelet/crush/internal/ui/diffview"
"github.com/charmbracelet/x/exp/charmtone"
)
const (
@@ -566,938 +566,13 @@ func (s *Styles) DialogHelpStyles() help.Styles {
return help.Styles(s.Dialog.Help)
}
// DefaultStyles returns the default styles for the UI.
func DefaultStyles() Styles {
var (
primary = charmtone.Charple
secondary = charmtone.Dolly
tertiary = charmtone.Bok
// accent = charmtone.Zest
// Backgrounds
bgBase = charmtone.Pepper
bgBaseLighter = charmtone.BBQ
bgSubtle = charmtone.Charcoal
bgOverlay = charmtone.Iron
// Foregrounds
fgBase = charmtone.Ash
fgMuted = charmtone.Squid
fgHalfMuted = charmtone.Smoke
fgSubtle = charmtone.Oyster
// fgSelected = charmtone.Salt
// Borders
border = charmtone.Charcoal
borderFocus = charmtone.Charple
// Status
error = charmtone.Sriracha
warning = charmtone.Zest
info = charmtone.Malibu
// Colors
white = charmtone.Butter
blueLight = charmtone.Sardine
blue = charmtone.Malibu
blueDark = charmtone.Damson
// yellow = charmtone.Mustard
yellow = charmtone.Mustard
// citron = charmtone.Citron
greenLight = charmtone.Bok
green = charmtone.Julep
greenDark = charmtone.Guac
// greenLight = charmtone.Bok
red = charmtone.Coral
redDark = charmtone.Sriracha
// redLight = charmtone.Salmon
// cherry = charmtone.Cherry
)
normalBorder := lipgloss.NormalBorder()
base := lipgloss.NewStyle().Foreground(fgBase)
muted := lipgloss.NewStyle().Foreground(fgMuted)
subtle := lipgloss.NewStyle().Foreground(fgSubtle)
s := Styles{}
s.Background = bgBase
// Populate color fields
s.WorkingGradFromColor = primary
s.WorkingGradToColor = secondary
s.WorkingLabelColor = fgBase
s.TextInput = textinput.Styles{
Focused: textinput.StyleState{
Text: base,
Placeholder: base.Foreground(fgSubtle),
Prompt: base.Foreground(tertiary),
Suggestion: base.Foreground(fgSubtle),
},
Blurred: textinput.StyleState{
Text: base.Foreground(fgMuted),
Placeholder: base.Foreground(fgSubtle),
Prompt: base.Foreground(fgMuted),
Suggestion: base.Foreground(fgSubtle),
},
Cursor: textinput.CursorStyle{
Color: secondary,
Shape: tea.CursorBlock,
Blink: true,
},
}
s.Editor.Textarea = textarea.Styles{
Focused: textarea.StyleState{
Base: base,
Text: base,
LineNumber: base.Foreground(fgSubtle),
CursorLine: base,
CursorLineNumber: base.Foreground(fgSubtle),
Placeholder: base.Foreground(fgSubtle),
Prompt: base.Foreground(tertiary),
},
Blurred: textarea.StyleState{
Base: base,
Text: base.Foreground(fgMuted),
LineNumber: base.Foreground(fgMuted),
CursorLine: base,
CursorLineNumber: base.Foreground(fgMuted),
Placeholder: base.Foreground(fgSubtle),
Prompt: base.Foreground(fgMuted),
},
Cursor: textarea.CursorStyle{
Color: secondary,
Shape: tea.CursorBlock,
Blink: true,
},
}
s.Markdown = ansi.StyleConfig{
Document: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
// BlockPrefix: "\n",
// BlockSuffix: "\n",
Color: new(charmtone.Smoke.Hex()),
},
// Margin: new(uint(defaultMargin)),
},
BlockQuote: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
Indent: new(uint(1)),
IndentToken: new("│ "),
},
List: ansi.StyleList{
LevelIndent: defaultListIndent,
},
Heading: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockSuffix: "\n",
Color: new(charmtone.Malibu.Hex()),
Bold: new(true),
},
},
H1: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Color: new(charmtone.Zest.Hex()),
BackgroundColor: new(charmtone.Charple.Hex()),
Bold: new(true),
},
},
H2: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "## ",
},
},
H3: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "### ",
},
},
H4: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "#### ",
},
},
H5: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "##### ",
},
},
H6: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "###### ",
Color: new(charmtone.Guac.Hex()),
Bold: new(false),
},
},
Strikethrough: ansi.StylePrimitive{
CrossedOut: new(true),
},
Emph: ansi.StylePrimitive{
Italic: new(true),
},
Strong: ansi.StylePrimitive{
Bold: new(true),
},
HorizontalRule: ansi.StylePrimitive{
Color: new(charmtone.Charcoal.Hex()),
Format: "\n--------\n",
},
Item: ansi.StylePrimitive{
BlockPrefix: "• ",
},
Enumeration: ansi.StylePrimitive{
BlockPrefix: ". ",
},
Task: ansi.StyleTask{
StylePrimitive: ansi.StylePrimitive{},
Ticked: "[✓] ",
Unticked: "[ ] ",
},
Link: ansi.StylePrimitive{
Color: new(charmtone.Zinc.Hex()),
Underline: new(true),
},
LinkText: ansi.StylePrimitive{
Color: new(charmtone.Guac.Hex()),
Bold: new(true),
},
Image: ansi.StylePrimitive{
Color: new(charmtone.Cheeky.Hex()),
Underline: new(true),
},
ImageText: ansi.StylePrimitive{
Color: new(charmtone.Squid.Hex()),
Format: "Image: {{.text}} →",
},
Code: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Color: new(charmtone.Coral.Hex()),
BackgroundColor: new(charmtone.Charcoal.Hex()),
},
},
CodeBlock: ansi.StyleCodeBlock{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: new(charmtone.Charcoal.Hex()),
},
Margin: new(uint(defaultMargin)),
},
Chroma: &ansi.Chroma{
Text: ansi.StylePrimitive{
Color: new(charmtone.Smoke.Hex()),
},
Error: ansi.StylePrimitive{
Color: new(charmtone.Butter.Hex()),
BackgroundColor: new(charmtone.Sriracha.Hex()),
},
Comment: ansi.StylePrimitive{
Color: new(charmtone.Oyster.Hex()),
},
CommentPreproc: ansi.StylePrimitive{
Color: new(charmtone.Bengal.Hex()),
},
Keyword: ansi.StylePrimitive{
Color: new(charmtone.Malibu.Hex()),
},
KeywordReserved: ansi.StylePrimitive{
Color: new(charmtone.Pony.Hex()),
},
KeywordNamespace: ansi.StylePrimitive{
Color: new(charmtone.Pony.Hex()),
},
KeywordType: ansi.StylePrimitive{
Color: new(charmtone.Guppy.Hex()),
},
Operator: ansi.StylePrimitive{
Color: new(charmtone.Salmon.Hex()),
},
Punctuation: ansi.StylePrimitive{
Color: new(charmtone.Zest.Hex()),
},
Name: ansi.StylePrimitive{
Color: new(charmtone.Smoke.Hex()),
},
NameBuiltin: ansi.StylePrimitive{
Color: new(charmtone.Cheeky.Hex()),
},
NameTag: ansi.StylePrimitive{
Color: new(charmtone.Mauve.Hex()),
},
NameAttribute: ansi.StylePrimitive{
Color: new(charmtone.Hazy.Hex()),
},
NameClass: ansi.StylePrimitive{
Color: new(charmtone.Salt.Hex()),
Underline: new(true),
Bold: new(true),
},
NameDecorator: ansi.StylePrimitive{
Color: new(charmtone.Citron.Hex()),
},
NameFunction: ansi.StylePrimitive{
Color: new(charmtone.Guac.Hex()),
},
LiteralNumber: ansi.StylePrimitive{
Color: new(charmtone.Julep.Hex()),
},
LiteralString: ansi.StylePrimitive{
Color: new(charmtone.Cumin.Hex()),
},
LiteralStringEscape: ansi.StylePrimitive{
Color: new(charmtone.Bok.Hex()),
},
GenericDeleted: ansi.StylePrimitive{
Color: new(charmtone.Coral.Hex()),
},
GenericEmph: ansi.StylePrimitive{
Italic: new(true),
},
GenericInserted: ansi.StylePrimitive{
Color: new(charmtone.Guac.Hex()),
},
GenericStrong: ansi.StylePrimitive{
Bold: new(true),
},
GenericSubheading: ansi.StylePrimitive{
Color: new(charmtone.Squid.Hex()),
},
Background: ansi.StylePrimitive{
BackgroundColor: new(charmtone.Charcoal.Hex()),
},
},
},
Table: ansi.StyleTable{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
},
},
DefinitionDescription: ansi.StylePrimitive{
BlockPrefix: "\n ",
},
}
// QuietMarkdown style - muted colors on subtle background for thinking content.
plainBg := new(bgBaseLighter.Hex())
plainFg := new(fgMuted.Hex())
s.QuietMarkdown = ansi.StyleConfig{
Document: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: plainFg,
BackgroundColor: plainBg,
},
},
BlockQuote: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: plainFg,
BackgroundColor: plainBg,
},
Indent: new(uint(1)),
IndentToken: new("│ "),
},
List: ansi.StyleList{
LevelIndent: defaultListIndent,
},
Heading: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockSuffix: "\n",
Bold: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
},
H1: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Bold: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
},
H2: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "## ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
H3: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "### ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
H4: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "#### ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
H5: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "##### ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
H6: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "###### ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
Strikethrough: ansi.StylePrimitive{
CrossedOut: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
Emph: ansi.StylePrimitive{
Italic: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
Strong: ansi.StylePrimitive{
Bold: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
HorizontalRule: ansi.StylePrimitive{
Format: "\n--------\n",
Color: plainFg,
BackgroundColor: plainBg,
},
Item: ansi.StylePrimitive{
BlockPrefix: "• ",
Color: plainFg,
BackgroundColor: plainBg,
},
Enumeration: ansi.StylePrimitive{
BlockPrefix: ". ",
Color: plainFg,
BackgroundColor: plainBg,
},
Task: ansi.StyleTask{
StylePrimitive: ansi.StylePrimitive{
Color: plainFg,
BackgroundColor: plainBg,
},
Ticked: "[✓] ",
Unticked: "[ ] ",
},
Link: ansi.StylePrimitive{
Underline: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
LinkText: ansi.StylePrimitive{
Bold: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
Image: ansi.StylePrimitive{
Underline: new(true),
Color: plainFg,
BackgroundColor: plainBg,
},
ImageText: ansi.StylePrimitive{
Format: "Image: {{.text}} →",
Color: plainFg,
BackgroundColor: plainBg,
},
Code: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Color: plainFg,
BackgroundColor: plainBg,
},
},
CodeBlock: ansi.StyleCodeBlock{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: plainFg,
BackgroundColor: plainBg,
},
Margin: new(uint(defaultMargin)),
},
},
Table: ansi.StyleTable{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: plainFg,
BackgroundColor: plainBg,
},
},
},
DefinitionDescription: ansi.StylePrimitive{
BlockPrefix: "\n ",
Color: plainFg,
BackgroundColor: plainBg,
},
}
s.Help = help.Styles{
ShortKey: base.Foreground(fgMuted),
ShortDesc: base.Foreground(fgSubtle),
ShortSeparator: base.Foreground(border),
Ellipsis: base.Foreground(border),
FullKey: base.Foreground(fgMuted),
FullDesc: base.Foreground(fgSubtle),
FullSeparator: base.Foreground(border),
}
s.Diff = diffview.Style{
DividerLine: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Foreground(fgHalfMuted).
Background(bgBaseLighter),
Code: lipgloss.NewStyle().
Foreground(fgHalfMuted).
Background(bgBaseLighter),
},
MissingLine: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Background(bgBaseLighter),
Code: lipgloss.NewStyle().
Background(bgBaseLighter),
},
EqualLine: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Foreground(fgMuted).
Background(bgBase),
Code: lipgloss.NewStyle().
Foreground(fgMuted).
Background(bgBase),
},
InsertLine: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Foreground(lipgloss.Color("#629657")).
Background(lipgloss.Color("#2b322a")),
Symbol: lipgloss.NewStyle().
Foreground(lipgloss.Color("#629657")).
Background(lipgloss.Color("#323931")),
Code: lipgloss.NewStyle().
Background(lipgloss.Color("#323931")),
},
DeleteLine: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Foreground(lipgloss.Color("#a45c59")).
Background(lipgloss.Color("#312929")),
Symbol: lipgloss.NewStyle().
Foreground(lipgloss.Color("#a45c59")).
Background(lipgloss.Color("#383030")),
Code: lipgloss.NewStyle().
Background(lipgloss.Color("#383030")),
},
Filename: diffview.LineStyle{
LineNumber: lipgloss.NewStyle().
Foreground(fgHalfMuted).
Background(bgBaseLighter),
Code: lipgloss.NewStyle().
Foreground(fgHalfMuted).
Background(bgBaseLighter),
},
}
s.FilePicker = filepicker.Styles{
DisabledCursor: base.Foreground(fgMuted),
Cursor: base.Foreground(fgBase),
Symlink: base.Foreground(fgSubtle),
Directory: base.Foreground(primary),
File: base.Foreground(fgBase),
DisabledFile: base.Foreground(fgMuted),
DisabledSelected: base.Background(bgOverlay).Foreground(fgMuted),
Permission: base.Foreground(fgMuted),
Selected: base.Background(primary).Foreground(fgBase),
FileSize: base.Foreground(fgMuted),
EmptyDirectory: base.Foreground(fgMuted).PaddingLeft(2).SetString("Empty directory"),
}
// borders
s.ToolCallSuccess = lipgloss.NewStyle().Foreground(green).SetString(ToolSuccess)
s.Header.Charm = base.Foreground(secondary)
s.Header.Diagonals = base.Foreground(primary)
s.Header.Percentage = muted
s.Header.Keystroke = muted
s.Header.KeystrokeTip = subtle
s.Header.WorkingDir = muted
s.Header.Separator = subtle
s.Header.Wrapper = lipgloss.NewStyle().Foreground(fgBase)
s.Header.LogoGradCanvas = lipgloss.NewStyle()
s.Header.LogoGradFromColor = secondary
s.Header.LogoGradToColor = primary
s.CompactDetails.Title = base
s.CompactDetails.View = base.Padding(0, 1, 1, 1).Border(lipgloss.RoundedBorder()).BorderForeground(borderFocus)
s.CompactDetails.Version = lipgloss.NewStyle().Foreground(border)
// Tool rendering styles
s.Tool.IconPending = base.Foreground(greenDark).SetString(ToolPending)
s.Tool.IconSuccess = base.Foreground(green).SetString(ToolSuccess)
s.Tool.IconError = base.Foreground(redDark).SetString(ToolError)
s.Tool.IconCancelled = muted.SetString(ToolPending)
s.Tool.NameNormal = base.Foreground(blue)
s.Tool.NameNested = base.Foreground(blue)
s.Tool.ParamMain = subtle
s.Tool.ParamKey = subtle
// Content rendering - prepared styles that accept width parameter
s.Tool.ContentLine = muted.Background(bgBaseLighter)
s.Tool.ContentTruncation = muted.Background(bgBaseLighter)
s.Tool.ContentCodeLine = base.Background(bgBase).PaddingLeft(2)
s.Tool.ContentCodeTruncation = muted.Background(bgBase).PaddingLeft(2)
s.Tool.ContentCodeBg = bgBase
s.Tool.Body = base.PaddingLeft(2)
// Deprecated - kept for backward compatibility
s.Tool.ContentBg = muted.Background(bgBaseLighter)
s.Tool.ContentText = muted
s.Tool.ContentLineNumber = base.Foreground(fgMuted).Background(bgBase).PaddingRight(1).PaddingLeft(1)
s.Tool.StateWaiting = base.Foreground(fgSubtle)
s.Tool.StateCancelled = base.Foreground(fgSubtle)
s.Tool.ErrorTag = base.Padding(0, 1).Background(red).Foreground(white)
s.Tool.ErrorMessage = base.Foreground(fgHalfMuted)
// Diff and multi-edit styles
s.Tool.DiffTruncation = muted.Background(bgBaseLighter).PaddingLeft(2)
s.Tool.NoteTag = base.Padding(0, 1).Background(info).Foreground(white)
s.Tool.NoteMessage = base.Foreground(fgHalfMuted)
// Job header styles
s.Tool.JobIconPending = base.Foreground(greenDark)
s.Tool.JobIconError = base.Foreground(redDark)
s.Tool.JobIconSuccess = base.Foreground(green)
s.Tool.JobToolName = base.Foreground(blue)
s.Tool.JobAction = base.Foreground(blueDark)
s.Tool.JobPID = muted
s.Tool.JobDescription = subtle
// Agent task styles
s.Tool.AgentTaskTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(blueLight).Foreground(white)
s.Tool.AgentPrompt = muted
// Agentic fetch styles
s.Tool.AgenticFetchPromptTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(green).Foreground(border)
// Todo styles
s.Tool.TodoRatio = base.Foreground(blueDark)
s.Tool.TodoCompletedIcon = base.Foreground(green)
s.Tool.TodoInProgressIcon = base.Foreground(greenDark)
s.Tool.TodoPendingIcon = base.Foreground(fgMuted)
s.Tool.TodoStatusNote = lipgloss.NewStyle().Foreground(fgSubtle)
s.Tool.TodoItem = lipgloss.NewStyle().Foreground(fgBase)
s.Tool.TodoJustStarted = lipgloss.NewStyle().Foreground(fgBase)
// MCP styles
s.Tool.MCPName = base.Foreground(blue)
s.Tool.MCPToolName = base.Foreground(blueDark)
s.Tool.MCPArrow = base.Foreground(blue).SetString(ArrowRightIcon)
// Loading indicators for images, skills
s.Tool.ResourceLoadedText = base.Foreground(green)
s.Tool.ResourceLoadedIndicator = base.Foreground(greenDark)
s.Tool.ResourceName = base
s.Tool.MediaType = base
s.Tool.ResourceSize = base.Foreground(fgMuted)
// Tool-call action verbs and result-list styling.
s.Tool.ActionCreate = lipgloss.NewStyle().Foreground(greenLight)
s.Tool.ActionDestroy = lipgloss.NewStyle().Foreground(red)
s.Tool.ResultEmpty = lipgloss.NewStyle().Foreground(fgSubtle)
s.Tool.ResultTruncation = lipgloss.NewStyle().Foreground(fgSubtle)
s.Tool.ResultItemName = lipgloss.NewStyle().Foreground(fgBase)
s.Tool.ResultItemDesc = lipgloss.NewStyle().Foreground(fgSubtle)
// Hook styles
s.Tool.HookLabel = base.Foreground(green)
s.Tool.HookName = base
s.Tool.HookMatcher = base.Foreground(fgMuted)
s.Tool.HookArrow = base.Foreground(green)
s.Tool.HookDetail = base.Foreground(fgMuted)
s.Tool.HookOK = base.Foreground(charmtone.Guac)
s.Tool.HookDenied = base.Foreground(charmtone.Sriracha)
s.Tool.HookDeniedLabel = base.Foreground(red)
s.Tool.HookDeniedReason = base.Foreground(charmtone.Iron)
s.Tool.HookRewrote = base.Foreground(charmtone.Iron)
// Buttons
s.Button.Focused = lipgloss.NewStyle().Foreground(white).Background(secondary)
s.Button.Blurred = lipgloss.NewStyle().Foreground(fgBase).Background(bgSubtle)
// Editor
s.Editor.PromptNormalFocused = lipgloss.NewStyle().Foreground(greenDark).SetString("::: ")
s.Editor.PromptNormalBlurred = s.Editor.PromptNormalFocused.Foreground(fgMuted)
s.Editor.PromptYoloIconFocused = lipgloss.NewStyle().MarginRight(1).Foreground(charmtone.Oyster).Background(charmtone.Citron).Bold(true).SetString(" ! ")
s.Editor.PromptYoloIconBlurred = s.Editor.PromptYoloIconFocused.Foreground(charmtone.Pepper).Background(charmtone.Squid)
s.Editor.PromptYoloDotsFocused = lipgloss.NewStyle().MarginRight(1).Foreground(charmtone.Zest).SetString(":::")
s.Editor.PromptYoloDotsBlurred = s.Editor.PromptYoloDotsFocused.Foreground(charmtone.Squid)
s.Radio.On = lipgloss.NewStyle().Foreground(fgHalfMuted).SetString(RadioOn)
s.Radio.Off = lipgloss.NewStyle().Foreground(fgHalfMuted).SetString(RadioOff)
s.Radio.Label = lipgloss.NewStyle().Foreground(fgHalfMuted)
// Logo
s.Logo.FieldColor = primary
s.Logo.TitleColorA = secondary
s.Logo.TitleColorB = primary
s.Logo.CharmColor = secondary
s.Logo.VersionColor = primary
s.Logo.SmallCharm = lipgloss.NewStyle().Foreground(secondary)
s.Logo.SmallDiagonals = lipgloss.NewStyle().Foreground(primary)
s.Logo.GradCanvas = lipgloss.NewStyle()
s.Logo.SmallGradFromColor = secondary
s.Logo.SmallGradToColor = primary
// Section
s.Section.Title = subtle
s.Section.Line = base.Foreground(charmtone.Charcoal)
// Initialize
s.Initialize.Header = base
s.Initialize.Content = muted
s.Initialize.Accent = base.Foreground(greenDark)
// ResourceGroup (LSP/MCP/skills sidebar lists).
s.Resource.Heading = lipgloss.NewStyle().Foreground(charmtone.Oyster)
s.Resource.Name = lipgloss.NewStyle().Foreground(charmtone.Squid)
s.Resource.StatusText = lipgloss.NewStyle().Foreground(charmtone.Oyster)
s.Resource.OfflineIcon = lipgloss.NewStyle().Foreground(charmtone.Iron).SetString("●")
s.Resource.BusyIcon = s.Resource.OfflineIcon.Foreground(charmtone.Citron)
s.Resource.ErrorIcon = s.Resource.OfflineIcon.Foreground(charmtone.Coral)
s.Resource.OnlineIcon = s.Resource.OfflineIcon.Foreground(charmtone.Guac)
s.Resource.DisabledIcon = lipgloss.NewStyle().Foreground(fgMuted).SetString("●")
s.Resource.AdditionalText = lipgloss.NewStyle().Foreground(charmtone.Oyster)
s.Resource.CapabilityCount = lipgloss.NewStyle().Foreground(fgSubtle)
s.Resource.RowTitleBase = lipgloss.NewStyle().Foreground(fgBase)
s.Resource.RowDescBase = lipgloss.NewStyle().Foreground(fgBase)
s.Resource.DefaultTitleFg = fgMuted
s.Resource.DefaultDescFg = fgSubtle
// LSP
s.LSP.ErrorDiagnostic = base.Foreground(redDark)
s.LSP.WarningDiagnostic = base.Foreground(warning)
s.LSP.HintDiagnostic = base.Foreground(fgHalfMuted)
s.LSP.InfoDiagnostic = base.Foreground(info)
// Files
s.Files.Path = lipgloss.NewStyle().Foreground(fgMuted)
s.Files.Additions = lipgloss.NewStyle().Foreground(greenDark)
s.Files.Deletions = lipgloss.NewStyle().Foreground(redDark)
s.Files.SectionTitle = lipgloss.NewStyle().Foreground(fgSubtle)
s.Files.EmptyMessage = lipgloss.NewStyle().Foreground(fgSubtle)
s.Files.TruncationHint = lipgloss.NewStyle().Foreground(fgSubtle)
// Sidebar
s.Sidebar.SessionTitle = lipgloss.NewStyle().Foreground(fgMuted)
s.Sidebar.WorkingDir = lipgloss.NewStyle().Foreground(fgMuted)
// ModelInfo
s.ModelInfo.Icon = lipgloss.NewStyle().Foreground(fgSubtle)
s.ModelInfo.Name = lipgloss.NewStyle().Foreground(fgBase)
s.ModelInfo.Provider = lipgloss.NewStyle().Foreground(fgMuted)
s.ModelInfo.ProviderFallback = lipgloss.NewStyle().Foreground(fgMuted).PaddingLeft(2)
s.ModelInfo.Reasoning = lipgloss.NewStyle().Foreground(fgSubtle).PaddingLeft(2)
s.ModelInfo.TokenCount = lipgloss.NewStyle().Foreground(fgSubtle)
s.ModelInfo.TokenPercentage = lipgloss.NewStyle().Foreground(fgMuted)
s.ModelInfo.Cost = lipgloss.NewStyle().Foreground(fgMuted)
// ResourceGroup
s.Resource.DefaultTitleFg = fgMuted
s.Resource.DefaultDescFg = fgSubtle
// Chat
messageFocussedBorder := lipgloss.Border{
Left: "▌",
}
s.Messages.NoContent = lipgloss.NewStyle().Foreground(fgBase)
s.Messages.UserBlurred = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
BorderForeground(primary).BorderStyle(normalBorder)
s.Messages.UserFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
BorderForeground(primary).BorderStyle(messageFocussedBorder)
s.Messages.AssistantBlurred = s.Messages.NoContent.PaddingLeft(2)
s.Messages.AssistantFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
BorderForeground(greenDark).BorderStyle(messageFocussedBorder)
s.Messages.Thinking = lipgloss.NewStyle().MaxHeight(10)
s.Messages.ErrorTag = lipgloss.NewStyle().Padding(0, 1).
Background(red).Foreground(white)
s.Messages.ErrorTitle = lipgloss.NewStyle().Foreground(fgHalfMuted)
s.Messages.ErrorDetails = lipgloss.NewStyle().Foreground(fgSubtle)
// Message item styles
s.Messages.ToolCallFocused = muted.PaddingLeft(1).
BorderStyle(messageFocussedBorder).
BorderLeft(true).
BorderForeground(greenDark)
s.Messages.ToolCallBlurred = muted.PaddingLeft(2)
// No padding or border for compact tool calls within messages
s.Messages.ToolCallCompact = muted
s.Messages.SectionHeader = base.PaddingLeft(2)
s.Messages.AssistantInfoIcon = subtle
s.Messages.AssistantInfoModel = muted
s.Messages.AssistantInfoProvider = subtle
s.Messages.AssistantInfoDuration = subtle
s.Messages.AssistantCanceled = lipgloss.NewStyle().Foreground(fgBase).Italic(true)
// Thinking section styles
s.Messages.ThinkingBox = subtle.Background(bgBaseLighter)
s.Messages.ThinkingTruncationHint = muted
s.Messages.ThinkingFooterTitle = muted
s.Messages.ThinkingFooterDuration = subtle
// Text selection.
s.TextSelection = lipgloss.NewStyle().Foreground(charmtone.Salt).Background(charmtone.Charple)
// Dialog styles
s.Dialog.Title = base.Padding(0, 1).Foreground(primary)
s.Dialog.TitleText = base.Foreground(primary)
s.Dialog.TitleError = base.Foreground(red)
s.Dialog.TitleAccent = base.Foreground(green).Bold(true)
s.Dialog.TitleLineBase = lipgloss.NewStyle()
s.Dialog.TitleGradFromColor = primary
s.Dialog.TitleGradToColor = secondary
// Dialog.ListItem (commands, reasoning, models)
s.Dialog.ListItem.InfoBlurred = lipgloss.NewStyle().Foreground(fgBase)
s.Dialog.ListItem.InfoFocused = lipgloss.NewStyle().Foreground(fgBase)
// Dialog.Models
s.Dialog.Models.ConfiguredText = lipgloss.NewStyle().Foreground(fgSubtle)
// Dialog.Permissions
s.Dialog.Permissions.KeyText = lipgloss.NewStyle().Foreground(fgMuted)
s.Dialog.Permissions.ValueText = lipgloss.NewStyle().Foreground(fgBase)
s.Dialog.Permissions.ParamsBg = bgSubtle
// Dialog.Quit
s.Dialog.Quit.Content = lipgloss.NewStyle().Foreground(fgBase)
s.Dialog.Quit.Frame = lipgloss.NewStyle().BorderForeground(borderFocus).Border(lipgloss.RoundedBorder()).Padding(1, 2)
s.Dialog.View = base.Border(lipgloss.RoundedBorder()).BorderForeground(borderFocus)
s.Dialog.PrimaryText = base.Padding(0, 1).Foreground(primary)
s.Dialog.SecondaryText = base.Padding(0, 1).Foreground(fgSubtle)
s.Dialog.HelpView = base.Padding(0, 1).AlignHorizontal(lipgloss.Left)
s.Dialog.Help.ShortKey = base.Foreground(fgMuted)
s.Dialog.Help.ShortDesc = base.Foreground(fgSubtle)
s.Dialog.Help.ShortSeparator = base.Foreground(border)
s.Dialog.Help.Ellipsis = base.Foreground(border)
s.Dialog.Help.FullKey = base.Foreground(fgMuted)
s.Dialog.Help.FullDesc = base.Foreground(fgSubtle)
s.Dialog.Help.FullSeparator = base.Foreground(border)
s.Dialog.NormalItem = base.Padding(0, 1).Foreground(fgBase)
s.Dialog.SelectedItem = base.Padding(0, 1).Background(primary).Foreground(fgBase)
s.Dialog.InputPrompt = base.Margin(1, 1)
s.Dialog.List = base.Margin(0, 0, 1, 0)
s.Dialog.ContentPanel = base.Background(bgSubtle).Foreground(fgBase).Padding(1, 2)
s.Dialog.Spinner = base.Foreground(secondary)
s.Dialog.ScrollbarThumb = base.Foreground(secondary)
s.Dialog.ScrollbarTrack = base.Foreground(border)
s.Dialog.ImagePreview = lipgloss.NewStyle().Padding(0, 1).Foreground(fgSubtle)
// API key input dialog
s.Dialog.APIKey.Spinner = base.Foreground(green)
// OAuth dialog
s.Dialog.OAuth.Spinner = base.Foreground(greenLight)
s.Dialog.OAuth.Instructions = lipgloss.NewStyle().Foreground(white)
s.Dialog.OAuth.UserCode = lipgloss.NewStyle().Bold(true).Foreground(white)
s.Dialog.OAuth.Success = lipgloss.NewStyle().Foreground(greenLight)
s.Dialog.OAuth.Link = lipgloss.NewStyle().Foreground(greenDark).Underline(true)
s.Dialog.OAuth.Enter = lipgloss.NewStyle().Foreground(primary)
s.Dialog.OAuth.ErrorText = lipgloss.NewStyle().Foreground(error)
s.Dialog.OAuth.StatusText = lipgloss.NewStyle().Foreground(fgMuted)
s.Dialog.OAuth.UserCodeBg = bgBaseLighter
s.Dialog.Arguments.Content = base.Padding(1)
s.Dialog.Arguments.Description = base.MarginBottom(1).MaxHeight(3)
s.Dialog.Arguments.InputLabelBlurred = base.Foreground(fgMuted)
s.Dialog.Arguments.InputLabelFocused = base.Bold(true)
s.Dialog.Arguments.InputRequiredMarkBlurred = base.Foreground(fgMuted).SetString("*")
s.Dialog.Arguments.InputRequiredMarkFocused = base.Foreground(primary).Bold(true).SetString("*")
s.Dialog.Sessions.DeletingTitle = s.Dialog.Title.Foreground(red)
s.Dialog.Sessions.DeletingView = s.Dialog.View.BorderForeground(red)
s.Dialog.Sessions.DeletingMessage = base.Padding(1)
s.Dialog.Sessions.DeletingTitleGradientFromColor = red
s.Dialog.Sessions.DeletingTitleGradientToColor = primary
s.Dialog.Sessions.DeletingItemBlurred = s.Dialog.NormalItem.Foreground(fgSubtle)
s.Dialog.Sessions.DeletingItemFocused = s.Dialog.SelectedItem.Background(red).Foreground(charmtone.Butter)
s.Dialog.Sessions.RenamingingTitle = s.Dialog.Title.Foreground(charmtone.Zest)
s.Dialog.Sessions.RenamingView = s.Dialog.View.BorderForeground(charmtone.Zest)
s.Dialog.Sessions.RenamingingMessage = base.Padding(1)
s.Dialog.Sessions.RenamingTitleGradientFromColor = charmtone.Zest
s.Dialog.Sessions.RenamingTitleGradientToColor = charmtone.Bok
s.Dialog.Sessions.RenamingItemBlurred = s.Dialog.NormalItem.Foreground(fgSubtle)
s.Dialog.Sessions.RenamingingItemFocused = s.Dialog.SelectedItem.UnsetBackground().UnsetForeground()
s.Dialog.Sessions.RenamingPlaceholder = base.Foreground(charmtone.Squid)
s.Dialog.Sessions.InfoBlurred = lipgloss.NewStyle().Foreground(fgSubtle)
s.Dialog.Sessions.InfoFocused = lipgloss.NewStyle().Foreground(fgBase)
s.Status.Help = lipgloss.NewStyle().Padding(0, 1)
s.Status.SuccessIndicator = base.Foreground(bgSubtle).Background(green).Padding(0, 1).Bold(true).SetString("OKAY!")
s.Status.InfoIndicator = s.Status.SuccessIndicator
s.Status.UpdateIndicator = s.Status.SuccessIndicator.SetString("HEY!")
s.Status.WarnIndicator = s.Status.SuccessIndicator.Foreground(bgOverlay).Background(yellow).SetString("WARNING")
s.Status.ErrorIndicator = s.Status.SuccessIndicator.Foreground(bgBase).Background(red).SetString("ERROR")
s.Status.SuccessMessage = base.Foreground(bgSubtle).Background(greenDark).Padding(0, 1)
s.Status.InfoMessage = s.Status.SuccessMessage
s.Status.UpdateMessage = s.Status.SuccessMessage
s.Status.WarnMessage = s.Status.SuccessMessage.Foreground(bgOverlay).Background(warning)
s.Status.ErrorMessage = s.Status.SuccessMessage.Foreground(white).Background(redDark)
// Completions styles
s.Completions.Normal = base.Background(bgSubtle).Foreground(fgBase)
s.Completions.Focused = base.Background(primary).Foreground(white)
s.Completions.Match = base.Underline(true)
// Attachments styles
attachmentIconStyle := base.Foreground(bgSubtle).Background(green).Padding(0, 1)
s.Attachments.Image = attachmentIconStyle.SetString(ImageIcon)
s.Attachments.Text = attachmentIconStyle.SetString(TextIcon)
s.Attachments.Normal = base.Padding(0, 1).MarginRight(1).Background(fgMuted).Foreground(fgBase)
s.Attachments.Deleting = base.Padding(0, 1).Bold(true).Background(red).Foreground(fgBase)
// Pills styles
s.Pills.Base = base.Padding(0, 1)
s.Pills.Focused = base.Padding(0, 1).BorderStyle(lipgloss.RoundedBorder()).BorderForeground(bgOverlay)
s.Pills.Blurred = base.Padding(0, 1).BorderStyle(lipgloss.HiddenBorder())
s.Pills.QueueItemPrefix = lipgloss.NewStyle().Foreground(fgMuted).SetString(" •")
s.Pills.QueueItemText = lipgloss.NewStyle().Foreground(fgMuted)
s.Pills.QueueLabel = lipgloss.NewStyle().Foreground(fgBase)
s.Pills.QueueIconBase = lipgloss.NewStyle().Foreground(fgBase)
s.Pills.QueueGradFromColor = redDark
s.Pills.QueueGradToColor = secondary
s.Pills.TodoLabel = lipgloss.NewStyle().Foreground(fgBase)
s.Pills.TodoProgress = lipgloss.NewStyle().Foreground(fgMuted)
s.Pills.TodoCurrentTask = lipgloss.NewStyle().Foreground(fgSubtle)
s.Pills.TodoSpinner = lipgloss.NewStyle().Foreground(greenDark)
s.Pills.HelpKey = lipgloss.NewStyle().Foreground(fgMuted)
s.Pills.HelpText = lipgloss.NewStyle().Foreground(fgSubtle)
s.Pills.Area = base
return s
// hex returns a pointer to the "#rrggbb" representation of c. It's used to
// satisfy glamour's string-pointer API when configuring markdown colors
// from the theme palette.
func hex(c color.Color) *string {
r, g, b, _ := c.RGBA()
s := fmt.Sprintf("#%02x%02x%02x", r>>8, g>>8, b>>8)
return &s
}
func chromaStyle(style ansi.StylePrimitive) string {
+41
View File
@@ -0,0 +1,41 @@
package styles
import "github.com/charmbracelet/x/exp/charmtone"
// CharmtonePantera returns the Charmtone dark theme. It's the default style
// for the UI.
func CharmtonePantera() Styles {
return quickStyle(quickStyleOpts{
primary: charmtone.Charple,
secondary: charmtone.Dolly,
tertiary: charmtone.Bok,
fgBase: charmtone.Ash,
fgMuted: charmtone.Squid,
fgHalfMuted: charmtone.Smoke,
fgSubtle: charmtone.Oyster,
onPrimary: charmtone.Salt,
onAccent: charmtone.Butter,
bgBase: charmtone.Pepper,
bgBaseLighter: charmtone.BBQ,
bgSubtle: charmtone.Charcoal,
bgOverlay: charmtone.Iron,
border: charmtone.Charcoal,
borderFocus: charmtone.Charple,
danger: charmtone.Coral,
error: charmtone.Sriracha,
warning: charmtone.Zest,
warningStrong: charmtone.Mustard,
busy: charmtone.Citron,
info: charmtone.Malibu,
infoSubtle: charmtone.Sardine,
infoMuted: charmtone.Damson,
success: charmtone.Julep,
successSubtle: charmtone.Bok,
successMuted: charmtone.Guac,
})
}