diff --git a/README.md b/README.md index 1fe799b..8a8c049 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ type app struct { } func newApp() tea.Model { - theme := style.DefaultTheme() + theme := myTheme() // define your own style.Theme leftStyle := lipgloss.NewStyle(). PaddingRight(2). diff --git a/doc.go b/doc.go index 221c45e..cae7525 100644 --- a/doc.go +++ b/doc.go @@ -20,7 +20,7 @@ // Create panels that implement [tea.Model], then pass them to [shell.New]: // // s := shell.New(shell.Config{ -// Theme: style.DefaultTheme(), +// Theme: myTheme, // LeftPanel: &myLeftPanel{}, // MainPanel: &myMainPanel{}, // Keybinds: tuishell.GlobalKeys(false), diff --git a/docs/shell.md b/docs/shell.md index 7e0ecd3..c418feb 100644 --- a/docs/shell.md +++ b/docs/shell.md @@ -25,7 +25,7 @@ type Config struct { | Option | Default | |--------|---------| | `LeftPanelWidth` | 30 | -| `MainFrameStyle` | `style.MainFrameStyle(theme)` — normal border with `theme.Border` color | +| `MainFrameStyle` | Normal border with `theme.Border` color | | `RightPanel` | `nil` (no right panel) | | `AppIcon` | `""` (empty statusline label) | | `DevMode` | `false` | @@ -34,7 +34,7 @@ type Config struct { ```go s := shell.New(shell.Config{ - Theme: style.DefaultTheme(), + Theme: myTheme, LeftPanel: &myLeftPanel{}, MainPanel: &myMainPanel{}, Keybinds: tuishell.GlobalKeys(false), @@ -45,7 +45,7 @@ s := shell.New(shell.Config{ ## Full Example ```go -theme := style.DefaultTheme() +theme := myTheme() leftStyle := lipgloss.NewStyle(). PaddingRight(2). diff --git a/docs/theming.md b/docs/theming.md index 175cbb2..82654c7 100644 --- a/docs/theming.md +++ b/docs/theming.md @@ -45,27 +45,15 @@ type Theme struct { } ``` -## Default Theme +## Creating a Theme -`style.DefaultTheme()` returns a violet-based theme (used by mrglab): - -```go -theme := style.DefaultTheme() -// Primary: Violet[300] (#a78bfa) -// Success: Green[300] -// Danger: Red[300] -// etc. -``` - -## Custom Theme - -Create your own theme by defining all 30 tokens: +Define all 30 tokens to create your theme: ```go import "charm.land/lipgloss/v2" -jiraTheme := style.Theme{ - Primary: lipgloss.Color("#0052CC"), // Jira blue +myTheme := style.Theme{ + Primary: lipgloss.Color("#0052CC"), PrimaryBright: lipgloss.Color("#2684FF"), PrimaryFg: lipgloss.Color("#FFFFFF"), PrimaryDim: lipgloss.Color("#0747A6"), @@ -100,23 +88,6 @@ jiraTheme := style.Theme{ } ``` -## Color Palettes - -tuishell provides Tailwind-style color palettes for convenience: - -```go -import "github.com/felipeospina21/tuishell/style" - -style.Blue[400] // "#60a5fa" -style.Red[500] // "#ef4444" -style.Green[300] // "#86efac" -style.Yellow[400] // "#facc15" -style.Violet[600] // "#7c3aed" -style.Orange[400] // "#fb923c" -``` - -Each palette has shades: `50`, `100`, `200`, `300`, `400`, `500`, `600`, `700`, `800`, `900`. - ## Using Theme in Components Pass the theme when creating the shell: diff --git a/hub/hub.go b/hub/hub.go index 8314d20..90d54b0 100644 --- a/hub/hub.go +++ b/hub/hub.go @@ -51,7 +51,7 @@ var backKey = key.NewBinding( // New creates a hub model from the given app entries. func New(apps []AppEntry) Model { - theme := style.DefaultTheme() + theme := defaultTheme() items := make([]list.Item, len(apps)) for i, a := range apps { diff --git a/hub/theme.go b/hub/theme.go new file mode 100644 index 0000000..61f0066 --- /dev/null +++ b/hub/theme.go @@ -0,0 +1,43 @@ +package hub + +import ( + "charm.land/lipgloss/v2" + "github.com/felipeospina21/tuishell/style" +) + +func defaultTheme() style.Theme { + return style.Theme{ + Primary: lipgloss.Color("#b8a6ff"), + PrimaryBright: lipgloss.Color("#9673ff"), + PrimaryFg: lipgloss.Color("#f2f0ff"), + PrimaryDim: lipgloss.Color("#4c01d6"), + + Info: lipgloss.Color("#3ac4d9"), + InfoBright: lipgloss.Color("#1ca7be"), + Success: lipgloss.Color("#6beaaf"), + SuccessBright: lipgloss.Color("#3ad994"), + Danger: lipgloss.Color("#f9a8a8"), + DangerBright: lipgloss.Color("#f47575"), + Warning: lipgloss.Color("#ffe043"), + WarningBright: lipgloss.Color("#ffcc14"), + Caution: lipgloss.Color("#ff8237"), + + Text: lipgloss.Color("#C4C4C4"), + TextInverse: lipgloss.Color("#111"), + TextDimmed: lipgloss.Color("#777777"), + Muted: lipgloss.Color("#999999"), + Dim: lipgloss.Color("#444444"), + Border: lipgloss.Color("#3f4145"), + ModalBorder: lipgloss.Color("#666666"), + SurfaceDim: lipgloss.Color("#1e1e24"), + SelectionBorder: lipgloss.Color("#AD58B4"), + + StatusText: lipgloss.Color("#FFFDF5"), + StatusNormal: lipgloss.Color("#6914ff"), + StatusLoading: lipgloss.Color("#1A7A94"), + StatusError: lipgloss.Color("#CE3060"), + StatusDev: lipgloss.Color("#4E8212"), + StatusAccent1: lipgloss.Color("#A550DF"), + StatusAccent2: lipgloss.Color("#6124DF"), + } +} diff --git a/layout.go b/layout.go index b8be1ca..ca3d032 100644 --- a/layout.go +++ b/layout.go @@ -33,10 +33,12 @@ type LayoutConfig struct { StatuslineLines int } -// DefaultLayoutConfig returns a config using the default theme. +// DefaultLayoutConfig returns a config using the given theme. func DefaultLayoutConfig(t style.Theme) LayoutConfig { return LayoutConfig{ - MainFrameStyle: style.MainFrameStyle(t), + MainFrameStyle: lipgloss.NewStyle(). + Border(lipgloss.NormalBorder()). + BorderForeground(t.Border), StatusBarStyle: lipgloss.NewStyle().Margin(0, 0), LeftPanelStyle: lipgloss.NewStyle(), RightPanelStyle: lipgloss.NewStyle(), diff --git a/popover/examples/confirm/main.go b/popover/examples/confirm/main.go index ef15dd4..65efd8e 100644 --- a/popover/examples/confirm/main.go +++ b/popover/examples/confirm/main.go @@ -21,7 +21,7 @@ type model struct { } func newModel() model { - t := style.DefaultTheme() + t := defaultTheme() return model{theme: t, confirm: popover.NewConfirm(t)} } diff --git a/popover/examples/confirm/theme.go b/popover/examples/confirm/theme.go new file mode 100644 index 0000000..dbf7eb1 --- /dev/null +++ b/popover/examples/confirm/theme.go @@ -0,0 +1,43 @@ +package main + +import ( + "charm.land/lipgloss/v2" + "github.com/felipeospina21/tuishell/style" +) + +func defaultTheme() style.Theme { + return style.Theme{ + Primary: lipgloss.Color("#b8a6ff"), + PrimaryBright: lipgloss.Color("#9673ff"), + PrimaryFg: lipgloss.Color("#f2f0ff"), + PrimaryDim: lipgloss.Color("#4c01d6"), + + Info: lipgloss.Color("#3ac4d9"), + InfoBright: lipgloss.Color("#1ca7be"), + Success: lipgloss.Color("#6beaaf"), + SuccessBright: lipgloss.Color("#3ad994"), + Danger: lipgloss.Color("#f9a8a8"), + DangerBright: lipgloss.Color("#f47575"), + Warning: lipgloss.Color("#ffe043"), + WarningBright: lipgloss.Color("#ffcc14"), + Caution: lipgloss.Color("#ff8237"), + + Text: lipgloss.Color("#C4C4C4"), + TextInverse: lipgloss.Color("#111"), + TextDimmed: lipgloss.Color("#777777"), + Muted: lipgloss.Color("#999999"), + Dim: lipgloss.Color("#444444"), + Border: lipgloss.Color("#3f4145"), + ModalBorder: lipgloss.Color("#666666"), + SurfaceDim: lipgloss.Color("#1e1e24"), + SelectionBorder: lipgloss.Color("#AD58B4"), + + StatusText: lipgloss.Color("#FFFDF5"), + StatusNormal: lipgloss.Color("#6914ff"), + StatusLoading: lipgloss.Color("#1A7A94"), + StatusError: lipgloss.Color("#CE3060"), + StatusDev: lipgloss.Color("#4E8212"), + StatusAccent1: lipgloss.Color("#A550DF"), + StatusAccent2: lipgloss.Color("#6124DF"), + } +} diff --git a/popover/examples/input/main.go b/popover/examples/input/main.go index 7a6f034..ca40185 100644 --- a/popover/examples/input/main.go +++ b/popover/examples/input/main.go @@ -21,7 +21,7 @@ type model struct { } func newModel() model { - t := style.DefaultTheme() + t := defaultTheme() return model{theme: t, input: popover.NewInput(t)} } diff --git a/popover/examples/input/theme.go b/popover/examples/input/theme.go new file mode 100644 index 0000000..dbf7eb1 --- /dev/null +++ b/popover/examples/input/theme.go @@ -0,0 +1,43 @@ +package main + +import ( + "charm.land/lipgloss/v2" + "github.com/felipeospina21/tuishell/style" +) + +func defaultTheme() style.Theme { + return style.Theme{ + Primary: lipgloss.Color("#b8a6ff"), + PrimaryBright: lipgloss.Color("#9673ff"), + PrimaryFg: lipgloss.Color("#f2f0ff"), + PrimaryDim: lipgloss.Color("#4c01d6"), + + Info: lipgloss.Color("#3ac4d9"), + InfoBright: lipgloss.Color("#1ca7be"), + Success: lipgloss.Color("#6beaaf"), + SuccessBright: lipgloss.Color("#3ad994"), + Danger: lipgloss.Color("#f9a8a8"), + DangerBright: lipgloss.Color("#f47575"), + Warning: lipgloss.Color("#ffe043"), + WarningBright: lipgloss.Color("#ffcc14"), + Caution: lipgloss.Color("#ff8237"), + + Text: lipgloss.Color("#C4C4C4"), + TextInverse: lipgloss.Color("#111"), + TextDimmed: lipgloss.Color("#777777"), + Muted: lipgloss.Color("#999999"), + Dim: lipgloss.Color("#444444"), + Border: lipgloss.Color("#3f4145"), + ModalBorder: lipgloss.Color("#666666"), + SurfaceDim: lipgloss.Color("#1e1e24"), + SelectionBorder: lipgloss.Color("#AD58B4"), + + StatusText: lipgloss.Color("#FFFDF5"), + StatusNormal: lipgloss.Color("#6914ff"), + StatusLoading: lipgloss.Color("#1A7A94"), + StatusError: lipgloss.Color("#CE3060"), + StatusDev: lipgloss.Color("#4E8212"), + StatusAccent1: lipgloss.Color("#A550DF"), + StatusAccent2: lipgloss.Color("#6124DF"), + } +} diff --git a/popover/examples/list/main.go b/popover/examples/list/main.go index 5abc75f..385a334 100644 --- a/popover/examples/list/main.go +++ b/popover/examples/list/main.go @@ -21,7 +21,7 @@ type model struct { } func newModel() model { - t := style.DefaultTheme() + t := defaultTheme() return model{theme: t, list: popover.NewList(t)} } diff --git a/popover/examples/list/theme.go b/popover/examples/list/theme.go new file mode 100644 index 0000000..dbf7eb1 --- /dev/null +++ b/popover/examples/list/theme.go @@ -0,0 +1,43 @@ +package main + +import ( + "charm.land/lipgloss/v2" + "github.com/felipeospina21/tuishell/style" +) + +func defaultTheme() style.Theme { + return style.Theme{ + Primary: lipgloss.Color("#b8a6ff"), + PrimaryBright: lipgloss.Color("#9673ff"), + PrimaryFg: lipgloss.Color("#f2f0ff"), + PrimaryDim: lipgloss.Color("#4c01d6"), + + Info: lipgloss.Color("#3ac4d9"), + InfoBright: lipgloss.Color("#1ca7be"), + Success: lipgloss.Color("#6beaaf"), + SuccessBright: lipgloss.Color("#3ad994"), + Danger: lipgloss.Color("#f9a8a8"), + DangerBright: lipgloss.Color("#f47575"), + Warning: lipgloss.Color("#ffe043"), + WarningBright: lipgloss.Color("#ffcc14"), + Caution: lipgloss.Color("#ff8237"), + + Text: lipgloss.Color("#C4C4C4"), + TextInverse: lipgloss.Color("#111"), + TextDimmed: lipgloss.Color("#777777"), + Muted: lipgloss.Color("#999999"), + Dim: lipgloss.Color("#444444"), + Border: lipgloss.Color("#3f4145"), + ModalBorder: lipgloss.Color("#666666"), + SurfaceDim: lipgloss.Color("#1e1e24"), + SelectionBorder: lipgloss.Color("#AD58B4"), + + StatusText: lipgloss.Color("#FFFDF5"), + StatusNormal: lipgloss.Color("#6914ff"), + StatusLoading: lipgloss.Color("#1A7A94"), + StatusError: lipgloss.Color("#CE3060"), + StatusDev: lipgloss.Color("#4E8212"), + StatusAccent1: lipgloss.Color("#A550DF"), + StatusAccent2: lipgloss.Color("#6124DF"), + } +} diff --git a/shell/example/main.go b/shell/example/main.go index 132c3ab..b552eb4 100644 --- a/shell/example/main.go +++ b/shell/example/main.go @@ -15,11 +15,10 @@ import ( "charm.land/lipgloss/v2" "github.com/felipeospina21/tuishell" "github.com/felipeospina21/tuishell/shell" - "github.com/felipeospina21/tuishell/style" "github.com/felipeospina21/tuishell/table" ) -var theme = style.DefaultTheme() +var theme = defaultTheme() func main() { p := tea.NewProgram(newApp()) diff --git a/shell/example/theme.go b/shell/example/theme.go new file mode 100644 index 0000000..dbf7eb1 --- /dev/null +++ b/shell/example/theme.go @@ -0,0 +1,43 @@ +package main + +import ( + "charm.land/lipgloss/v2" + "github.com/felipeospina21/tuishell/style" +) + +func defaultTheme() style.Theme { + return style.Theme{ + Primary: lipgloss.Color("#b8a6ff"), + PrimaryBright: lipgloss.Color("#9673ff"), + PrimaryFg: lipgloss.Color("#f2f0ff"), + PrimaryDim: lipgloss.Color("#4c01d6"), + + Info: lipgloss.Color("#3ac4d9"), + InfoBright: lipgloss.Color("#1ca7be"), + Success: lipgloss.Color("#6beaaf"), + SuccessBright: lipgloss.Color("#3ad994"), + Danger: lipgloss.Color("#f9a8a8"), + DangerBright: lipgloss.Color("#f47575"), + Warning: lipgloss.Color("#ffe043"), + WarningBright: lipgloss.Color("#ffcc14"), + Caution: lipgloss.Color("#ff8237"), + + Text: lipgloss.Color("#C4C4C4"), + TextInverse: lipgloss.Color("#111"), + TextDimmed: lipgloss.Color("#777777"), + Muted: lipgloss.Color("#999999"), + Dim: lipgloss.Color("#444444"), + Border: lipgloss.Color("#3f4145"), + ModalBorder: lipgloss.Color("#666666"), + SurfaceDim: lipgloss.Color("#1e1e24"), + SelectionBorder: lipgloss.Color("#AD58B4"), + + StatusText: lipgloss.Color("#FFFDF5"), + StatusNormal: lipgloss.Color("#6914ff"), + StatusLoading: lipgloss.Color("#1A7A94"), + StatusError: lipgloss.Color("#CE3060"), + StatusDev: lipgloss.Color("#4E8212"), + StatusAccent1: lipgloss.Color("#A550DF"), + StatusAccent2: lipgloss.Color("#6124DF"), + } +} diff --git a/shell/shell.go b/shell/shell.go index 53ed147..30765de 100644 --- a/shell/shell.go +++ b/shell/shell.go @@ -72,7 +72,9 @@ func New(cfg Config) Model { cfg.LeftPanelWidth = 30 } if cfg.MainFrameStyle.GetWidth() == 0 { - cfg.MainFrameStyle = style.MainFrameStyle(t) + cfg.MainFrameStyle = lipgloss.NewStyle(). + Border(lipgloss.NormalBorder()). + BorderForeground(t.Border) } ctx := tuishell.AppContext{FocusedPanel: tuishell.LeftPanel, DevMode: cfg.DevMode} diff --git a/style/colors.go b/style/colors.go deleted file mode 100644 index a852abe..0000000 --- a/style/colors.go +++ /dev/null @@ -1,47 +0,0 @@ -// Package style provides color palettes and a Theme struct for tuishell components. -package style - -// ColorShades maps shade numbers (50–950) to hex color strings. -type ColorShades = map[uint]string - -// Blue is a Tailwind-style blue color palette with shades 50–950. -var Blue = ColorShades{ - 50: "#eefcfd", 100: "#d4f6f9", 200: "#aeecf3", 300: "#76dcea", - 400: "#3ac4d9", 500: "#1ca7be", 600: "#1a86a0", 700: "#1c6c82", - 800: "#1f596b", 900: "#1e4a5b", 950: "#0e303e", -} - -// Red is a Tailwind-style red color palette with shades 50–950. -var Red = ColorShades{ - 50: "#fef2f2", 100: "#fde3e3", 200: "#fccccc", 300: "#f9a8a8", - 400: "#f47575", 500: "#ea4949", 600: "#d93a3a", 700: "#b42121", - 800: "#951f1f", 900: "#7c2020", 950: "#430c0c", -} - -// Green is a Tailwind-style green color palette with shades 50–950. -var Green = ColorShades{ - 50: "#ecfdf4", 100: "#d0fbe2", 200: "#a5f5ca", 300: "#6beaaf", - 400: "#3ad994", 500: "#0cbd76", 600: "#019a5f", 700: "#017b50", - 800: "#046141", 900: "#045037", 950: "#012d20", -} - -// Yellow is a Tailwind-style yellow color palette with shades 50–950. -var Yellow = ColorShades{ - 50: "#fefce8", 100: "#fff9c2", 200: "#fff087", 300: "#ffe043", - 400: "#ffcc14", 500: "#efb203", 600: "#ce8900", 700: "#a46004", - 800: "#884b0b", 900: "#733d10", 950: "#431f05", -} - -// Violet is a Tailwind-style violet color palette with shades 50–950. -var Violet = ColorShades{ - 50: "#f2f0ff", 100: "#e9e4ff", 200: "#d5cdff", 300: "#b8a6ff", - 400: "#9673ff", 500: "#773bff", 600: "#6914ff", 700: "#6714ff", - 800: "#4c01d6", 900: "#4003af", 950: "#250077", -} - -// Orange is a Tailwind-style orange color palette with shades 50–950. -var Orange = ColorShades{ - 50: "#fff6ed", 100: "#ffead4", 200: "#ffd0a8", 300: "#ffaf70", - 400: "#ff8237", 500: "#ff5c0a", 600: "#f04406", 700: "#c73107", - 800: "#9e270e", 900: "#7f240f", 950: "#450e05", -} diff --git a/style/theme.go b/style/theme.go index 5927ba1..7a08360 100644 --- a/style/theme.go +++ b/style/theme.go @@ -1,10 +1,7 @@ +// Package style provides the Theme struct for tuishell components. package style -import ( - "image/color" - - "charm.land/lipgloss/v2" -) +import "image/color" // Theme defines the color tokens used across all tuishell components. type Theme struct { @@ -41,48 +38,3 @@ type Theme struct { StatusAccent1 color.Color StatusAccent2 color.Color } - -// DefaultTheme returns the default (mrglab) color scheme. -func DefaultTheme() Theme { - return Theme{ - Primary: lipgloss.Color(Violet[300]), - PrimaryBright: lipgloss.Color(Violet[400]), - PrimaryFg: lipgloss.Color(Violet[50]), - PrimaryDim: lipgloss.Color(Violet[800]), - - Info: lipgloss.Color(Blue[400]), - InfoBright: lipgloss.Color(Blue[500]), - Success: lipgloss.Color(Green[300]), - SuccessBright: lipgloss.Color(Green[400]), - Danger: lipgloss.Color(Red[300]), - DangerBright: lipgloss.Color(Red[400]), - Warning: lipgloss.Color(Yellow[300]), - WarningBright: lipgloss.Color(Yellow[400]), - Caution: lipgloss.Color(Orange[400]), - - Text: lipgloss.Color("#C4C4C4"), - TextInverse: lipgloss.Color("#111"), - TextDimmed: lipgloss.Color("#777777"), - Muted: lipgloss.Color("#999999"), - Dim: lipgloss.Color("#444444"), - Border: lipgloss.Color("#3f4145"), - ModalBorder: lipgloss.Color("#666666"), - SurfaceDim: lipgloss.Color("#1e1e24"), - SelectionBorder: lipgloss.Color("#AD58B4"), - - StatusText: lipgloss.Color("#FFFDF5"), - StatusNormal: lipgloss.Color(Violet[600]), - StatusLoading: lipgloss.Color("#1A7A94"), - StatusError: lipgloss.Color("#CE3060"), - StatusDev: lipgloss.Color("#4E8212"), - StatusAccent1: lipgloss.Color("#A550DF"), - StatusAccent2: lipgloss.Color("#6124DF"), - } -} - -// MainFrameStyle returns the outer border style for the main application frame. -func MainFrameStyle(t Theme) lipgloss.Style { - return lipgloss.NewStyle(). - Border(lipgloss.NormalBorder()). - BorderForeground(t.Border) -}