Files
kit/internal/ui/styles.go
T

370 lines
9.6 KiB
Go
Raw Normal View History

2025-06-09 14:38:31 +03:00
package ui
import (
"charm.land/lipgloss/v2"
2025-06-09 14:38:31 +03:00
"github.com/charmbracelet/glamour"
"github.com/charmbracelet/glamour/ansi"
2025-09-02 09:30:20 +02:00
"github.com/mark3labs/mcphost/internal/config"
"github.com/spf13/viper"
2025-06-09 14:38:31 +03:00
)
const defaultMargin = 1
// Helper functions for style pointers
//
//go:fix inline
func boolPtr(b bool) *bool { return new(b) }
//go:fix inline
func stringPtr(s string) *string { return new(s) }
//go:fix inline
func uintPtr(u uint) *uint { return new(u) }
2025-06-09 14:38:31 +03:00
2025-11-12 16:48:46 +03:00
// BaseStyle returns a new, empty lipgloss style that can be customized with
// additional styling methods. This serves as the foundation for building more
// complex styled components.
2025-06-09 14:38:31 +03:00
func BaseStyle() lipgloss.Style {
return lipgloss.NewStyle()
}
2025-11-12 16:48:46 +03:00
// GetMarkdownRenderer creates and returns a configured glamour.TermRenderer for
// rendering markdown content with syntax highlighting and proper formatting. The
// renderer is customized with our theme colors and adapted to the specified width.
2025-06-09 14:38:31 +03:00
func GetMarkdownRenderer(width int) *glamour.TermRenderer {
r, _ := glamour.NewTermRenderer(
glamour.WithStyles(generateMarkdownStyleConfig()),
glamour.WithWordWrap(width),
)
return r
}
// generateMarkdownStyleConfig creates an ansi.StyleConfig for markdown rendering
func generateMarkdownStyleConfig() ansi.StyleConfig {
2025-09-02 09:30:20 +02:00
2025-06-25 17:24:37 +03:00
var textColor, mutedColor string
2025-09-02 09:30:20 +02:00
var headingColor, emphColor, strongColor, linkColor, codeColor, errorColor, keywordColor, stringColor, numberColor, commentColor string
var mdTheme config.MarkdownTheme
err := config.FilepathOr("markdown-theme", &mdTheme)
fromConfig := err == nil && viper.InConfig("markdown-theme")
if fromConfig && IsDarkBackground() {
2025-09-02 09:30:20 +02:00
textColor = mdTheme.Text.Light
mutedColor = mdTheme.Muted.Light
headingColor = mdTheme.Heading.Light
emphColor = mdTheme.Emph.Light
strongColor = mdTheme.Strong.Light
linkColor = mdTheme.Link.Light
codeColor = mdTheme.Code.Light
errorColor = mdTheme.Error.Light
keywordColor = mdTheme.Keyword.Light
stringColor = mdTheme.String.Light
numberColor = mdTheme.Number.Light
commentColor = mdTheme.Comment.Light
} else if fromConfig {
textColor = mdTheme.Text.Dark
mutedColor = mdTheme.Muted.Dark
headingColor = mdTheme.Heading.Dark
emphColor = mdTheme.Emph.Dark
strongColor = mdTheme.Strong.Dark
linkColor = mdTheme.Link.Dark
codeColor = mdTheme.Code.Dark
errorColor = mdTheme.Error.Dark
keywordColor = mdTheme.Keyword.Dark
stringColor = mdTheme.String.Dark
numberColor = mdTheme.Number.Dark
commentColor = mdTheme.Comment.Dark
} else if IsDarkBackground() {
2025-06-25 17:24:37 +03:00
textColor = "#F9FAFB" // Light text for dark backgrounds
mutedColor = "#9CA3AF" // Light muted for dark backgrounds
// Dark background colors
headingColor = "#22D3EE" // Cyan
emphColor = "#FDE047" // Yellow
strongColor = "#F9FAFB" // Light gray
linkColor = "#60A5FA" // Blue
codeColor = "#D1D5DB" // Light gray
errorColor = "#F87171" // Red
keywordColor = "#C084FC" // Purple
stringColor = "#34D399" // Green
numberColor = "#FBBF24" // Orange
commentColor = "#9CA3AF" // Muted gray
} else {
2025-09-02 09:30:20 +02:00
textColor = "#1F2937" // Dark text for light backgrounds
mutedColor = "#6B7280" // Dark muted for light backgrounds
2025-06-25 17:24:37 +03:00
// Light background colors
headingColor = "#0891B2" // Dark cyan
emphColor = "#D97706" // Orange
strongColor = "#1F2937" // Dark gray
linkColor = "#2563EB" // Blue
codeColor = "#374151" // Dark gray
errorColor = "#DC2626" // Red
keywordColor = "#7C3AED" // Purple
stringColor = "#059669" // Green
numberColor = "#D97706" // Orange
commentColor = "#6B7280" // Muted gray
}
// Don't apply background in markdown - let the block renderer handle it
bgColor := ""
2025-06-09 14:38:31 +03:00
return ansi.StyleConfig{
Document: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockPrefix: "",
BlockSuffix: "",
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
2025-06-25 17:24:37 +03:00
Margin: uintPtr(0), // Remove margin to prevent spacing
2025-06-09 14:38:31 +03:00
},
BlockQuote: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: new(mutedColor),
Italic: new(true),
2025-06-09 14:38:31 +03:00
Prefix: "┃ ",
},
Indent: uintPtr(1),
IndentToken: new(lipgloss.NewStyle().Background(lipgloss.Color(bgColor)).Render(" ")),
2025-06-09 14:38:31 +03:00
},
List: ansi.StyleList{
2025-06-25 17:24:37 +03:00
LevelIndent: 0, // Remove list indentation
2025-06-09 14:38:31 +03:00
StyleBlock: ansi.StyleBlock{
IndentToken: new(lipgloss.NewStyle().Background(lipgloss.Color(bgColor)).Render(" ")),
2025-06-09 14:38:31 +03:00
StylePrimitive: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
},
},
Heading: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockSuffix: "\n",
Color: new(headingColor),
Bold: new(true),
2025-06-09 14:38:31 +03:00
},
},
H1: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "# ",
Color: new(headingColor),
Bold: new(true),
2025-06-09 14:38:31 +03:00
},
},
H2: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "## ",
Color: new(headingColor),
Bold: new(true),
2025-06-09 14:38:31 +03:00
},
},
H3: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "### ",
Color: new(headingColor),
Bold: new(true),
2025-06-09 14:38:31 +03:00
},
},
H4: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "#### ",
Color: new(headingColor),
Bold: new(true),
2025-06-09 14:38:31 +03:00
},
},
H5: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "##### ",
Color: new(headingColor),
Bold: new(true),
2025-06-09 14:38:31 +03:00
},
},
H6: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "###### ",
Color: new(headingColor),
Bold: new(true),
2025-06-09 14:38:31 +03:00
},
},
Strikethrough: ansi.StylePrimitive{
CrossedOut: new(true),
Color: new(mutedColor),
2025-06-09 14:38:31 +03:00
},
Emph: ansi.StylePrimitive{
Color: new(emphColor),
2025-06-25 17:24:37 +03:00
Italic: new(true),
2025-06-09 14:38:31 +03:00
},
Strong: ansi.StylePrimitive{
Bold: new(true),
Color: new(strongColor),
2025-06-09 14:38:31 +03:00
},
HorizontalRule: ansi.StylePrimitive{
Color: new(mutedColor),
2025-06-09 14:38:31 +03:00
Format: "\n─────────────────────────────────────────\n",
},
Item: ansi.StylePrimitive{
BlockPrefix: "• ",
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
Enumeration: ansi.StylePrimitive{
BlockPrefix: ". ",
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
Task: ansi.StyleTask{
StylePrimitive: ansi.StylePrimitive{},
Ticked: "[✓] ",
Unticked: "[ ] ",
},
Link: ansi.StylePrimitive{
Color: new(linkColor),
2025-06-25 17:24:37 +03:00
Underline: new(true),
2025-06-09 14:38:31 +03:00
},
LinkText: ansi.StylePrimitive{
Color: new(linkColor),
2025-06-25 17:24:37 +03:00
Bold: new(true),
2025-06-09 14:38:31 +03:00
},
Image: ansi.StylePrimitive{
Color: new(linkColor),
2025-06-25 17:24:37 +03:00
Underline: new(true),
2025-06-09 14:38:31 +03:00
Format: "🖼 {{.text}}",
},
ImageText: ansi.StylePrimitive{
Color: new(linkColor),
2025-06-25 17:24:37 +03:00
2025-06-09 14:38:31 +03:00
Format: "{{.text}}",
},
Code: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: new(codeColor),
2025-06-25 17:24:37 +03:00
2025-06-09 14:38:31 +03:00
Prefix: "",
Suffix: "",
},
},
CodeBlock: ansi.StyleCodeBlock{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
2025-06-25 17:24:37 +03:00
Prefix: "",
Color: new(codeColor),
2025-06-09 14:38:31 +03:00
},
2025-06-25 17:24:37 +03:00
Margin: uintPtr(0), // Remove margin
2025-06-09 14:38:31 +03:00
},
Chroma: &ansi.Chroma{
Text: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
Error: ansi.StylePrimitive{
Color: new(errorColor),
2025-06-09 14:38:31 +03:00
},
Comment: ansi.StylePrimitive{
Color: new(commentColor),
2025-06-09 14:38:31 +03:00
},
CommentPreproc: ansi.StylePrimitive{
Color: new(keywordColor),
2025-06-09 14:38:31 +03:00
},
Keyword: ansi.StylePrimitive{
Color: new(keywordColor),
2025-06-09 14:38:31 +03:00
},
KeywordReserved: ansi.StylePrimitive{
Color: new(keywordColor),
2025-06-09 14:38:31 +03:00
},
KeywordNamespace: ansi.StylePrimitive{
Color: new(keywordColor),
2025-06-09 14:38:31 +03:00
},
KeywordType: ansi.StylePrimitive{
Color: new(keywordColor),
2025-06-09 14:38:31 +03:00
},
Operator: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
Punctuation: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
Name: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
NameBuiltin: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
NameTag: ansi.StylePrimitive{
Color: new(keywordColor),
2025-06-09 14:38:31 +03:00
},
NameAttribute: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
NameClass: ansi.StylePrimitive{
Color: new(keywordColor),
2025-06-09 14:38:31 +03:00
},
NameConstant: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
NameDecorator: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
NameFunction: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
LiteralNumber: ansi.StylePrimitive{
Color: new(numberColor),
2025-06-09 14:38:31 +03:00
},
LiteralString: ansi.StylePrimitive{
Color: new(stringColor),
2025-06-09 14:38:31 +03:00
},
LiteralStringEscape: ansi.StylePrimitive{
Color: new(keywordColor),
2025-06-09 14:38:31 +03:00
},
GenericDeleted: ansi.StylePrimitive{
Color: new(errorColor),
2025-06-09 14:38:31 +03:00
},
GenericEmph: ansi.StylePrimitive{
Color: new(emphColor),
2025-06-25 17:24:37 +03:00
Italic: new(true),
2025-06-09 14:38:31 +03:00
},
GenericInserted: ansi.StylePrimitive{
Color: new(stringColor),
2025-06-09 14:38:31 +03:00
},
GenericStrong: ansi.StylePrimitive{
Color: new(strongColor),
2025-06-25 17:24:37 +03:00
Bold: new(true),
2025-06-09 14:38:31 +03:00
},
GenericSubheading: ansi.StylePrimitive{
Color: new(headingColor),
2025-06-09 14:38:31 +03:00
},
},
},
Table: ansi.StyleTable{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockPrefix: "\n",
BlockSuffix: "\n",
},
},
CenterSeparator: new("┼"),
ColumnSeparator: new("│"),
RowSeparator: new("─"),
2025-06-09 14:38:31 +03:00
},
DefinitionDescription: ansi.StylePrimitive{
BlockPrefix: "\n ",
Color: new(linkColor),
2025-06-09 14:38:31 +03:00
},
Text: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
Paragraph: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: new(textColor),
2025-06-09 14:38:31 +03:00
},
},
}
}
// toMarkdown renders markdown content using glamour
func toMarkdown(content string, width int) string {
r := GetMarkdownRenderer(width)
rendered, _ := r.Render(content)
return rendered
2025-06-10 01:21:17 +03:00
}