fancy theme
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
// A restrained, high-contrast palette. Text always includes its meaning, so
|
||||
// colors supplement the UI rather than carrying state by themselves.
|
||||
type uiTheme struct {
|
||||
title, accent, muted, warning, success, active, selected lipgloss.Style
|
||||
border lipgloss.Style
|
||||
plain bool
|
||||
}
|
||||
|
||||
func newTheme() uiTheme {
|
||||
t := uiTheme{plain: os.Getenv("NO_COLOR") != "" || strings.EqualFold(os.Getenv("TERM"), "dumb")}
|
||||
if t.plain {
|
||||
t.title = lipgloss.NewStyle()
|
||||
t.accent = lipgloss.NewStyle()
|
||||
t.muted = lipgloss.NewStyle()
|
||||
t.warning = lipgloss.NewStyle()
|
||||
t.success = lipgloss.NewStyle()
|
||||
t.active = lipgloss.NewStyle()
|
||||
t.selected = lipgloss.NewStyle()
|
||||
t.border = lipgloss.NewStyle()
|
||||
return t
|
||||
}
|
||||
t.title = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("#D7E9EF"))
|
||||
t.accent = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("#70D6D1"))
|
||||
t.muted = lipgloss.NewStyle().Foreground(lipgloss.Color("#8FA6B2"))
|
||||
t.warning = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("#FFC078"))
|
||||
t.success = lipgloss.NewStyle().Foreground(lipgloss.Color("#A8DDA2"))
|
||||
t.active = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFC078"))
|
||||
t.selected = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("#F4FAFC")).Background(lipgloss.Color("#244553"))
|
||||
t.border = lipgloss.NewStyle().Foreground(lipgloss.Color("#426573"))
|
||||
return t
|
||||
}
|
||||
|
||||
func (t uiTheme) status(status string) string {
|
||||
label := "[" + safe(status) + "]"
|
||||
switch strings.ToLower(status) {
|
||||
case "closed", "done":
|
||||
return t.muted.Render(label)
|
||||
case "open":
|
||||
return t.success.Render(label)
|
||||
default:
|
||||
return t.active.Render(label)
|
||||
}
|
||||
}
|
||||
|
||||
func (t uiTheme) heading(section string, count string, width int) string {
|
||||
prefix := "▌ TODOAPP / "
|
||||
section = runewidth.Truncate(safe(section), max(1, width-runewidth.StringWidth(prefix)), "…")
|
||||
return t.accent.Render("▌ ") + t.title.Render("TODOAPP") + t.muted.Render(" / "+section) + "\n" +
|
||||
t.muted.Render(runewidth.Truncate(safe(count), max(1, width), "…"))
|
||||
}
|
||||
|
||||
// box frames content only when the terminal has room for a border. The width
|
||||
// argument is the terminal width, not the inner content width.
|
||||
func (t uiTheme) box(content string, width, height int) string {
|
||||
if width < 50 || height < 14 || t.plain {
|
||||
return content
|
||||
}
|
||||
return t.border.Border(lipgloss.RoundedBorder()).Padding(0, 1).Width(min(width, 100) - 2).Render(content)
|
||||
}
|
||||
|
||||
func (t uiTheme) row(label string, selected bool, width int) string {
|
||||
prefix := " "
|
||||
if selected {
|
||||
prefix = "› "
|
||||
}
|
||||
text := runewidth.Truncate(prefix+label, max(1, width), "…")
|
||||
if selected {
|
||||
return t.selected.Width(min(width, 100)).Render(text)
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
func (t uiTheme) hint(text string, width int) string {
|
||||
return t.muted.Render(runewidth.Truncate(text, max(1, width), "…"))
|
||||
}
|
||||
|
||||
func (t uiTheme) alert(text string, width int) string {
|
||||
return t.warning.Render(runewidth.Truncate("! "+safe(text), max(1, width), "…"))
|
||||
}
|
||||
Reference in New Issue
Block a user