mirror of
https://github.com/lukaszraczylo/lolcathost.git
synced 2026-10-11 04:47:18 +00:00
Switch imports to the charm.land v2 modules. Return tea.View from Model.View, set alt screen and window title there, use KeyPressMsg and the "space" key name, and call SetWidth on text inputs.
182 lines
4.0 KiB
Go
182 lines
4.0 KiB
Go
// Package tui provides the terminal user interface.
|
|
package tui
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"charm.land/lipgloss/v2"
|
|
)
|
|
|
|
// Colors - matching kportal style, optimized for dark terminals
|
|
var (
|
|
colorPrimary = lipgloss.Color("205") // Pink/Magenta
|
|
colorSuccess = lipgloss.Color("42") // Green
|
|
colorWarning = lipgloss.Color("220") // Yellow
|
|
colorError = lipgloss.Color("196") // Red
|
|
colorMuted = lipgloss.Color("245") // Gray (brighter for dark terminals)
|
|
colorAccent = lipgloss.Color("141") // Light purple (brighter for dark terminals)
|
|
colorHeader = lipgloss.Color("220") // Yellow for headers
|
|
colorSelectedBg = lipgloss.Color("236") // Gray background for selection
|
|
colorSelectedFg = lipgloss.Color("255") // White foreground for selection
|
|
colorGroupHeader = lipgloss.Color("213") // Light pink for group headers
|
|
)
|
|
|
|
// Title and header styles
|
|
var (
|
|
titleStyle = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(colorHeader).
|
|
Padding(0, 1)
|
|
)
|
|
|
|
// Status indicators
|
|
var (
|
|
enabledStyle = lipgloss.NewStyle().
|
|
Foreground(colorSuccess).
|
|
Bold(true)
|
|
|
|
disabledStyle = lipgloss.NewStyle().
|
|
Foreground(colorMuted)
|
|
)
|
|
|
|
// Status bar and help
|
|
var (
|
|
statusBarStyle = lipgloss.NewStyle().
|
|
Foreground(colorMuted)
|
|
|
|
connectedStyle = lipgloss.NewStyle().
|
|
Foreground(colorSuccess).
|
|
SetString("Connected")
|
|
|
|
disconnectedStyle = lipgloss.NewStyle().
|
|
Foreground(colorError).
|
|
SetString("Disconnected")
|
|
|
|
helpBarStyle = lipgloss.NewStyle().
|
|
Foreground(colorMuted)
|
|
|
|
helpKeyStyle = lipgloss.NewStyle().
|
|
Foreground(colorHeader).
|
|
Bold(true)
|
|
|
|
helpDescStyle = lipgloss.NewStyle().
|
|
Foreground(colorMuted)
|
|
)
|
|
|
|
// Message styles
|
|
var (
|
|
errorMsgStyle = lipgloss.NewStyle().
|
|
Foreground(colorError).
|
|
Bold(true).
|
|
MarginTop(1)
|
|
|
|
successMsgStyle = lipgloss.NewStyle().
|
|
Foreground(colorSuccess).
|
|
MarginTop(1)
|
|
|
|
updateStyle = lipgloss.NewStyle().
|
|
Foreground(colorSuccess).
|
|
Bold(true)
|
|
)
|
|
|
|
// Form styles
|
|
var (
|
|
inputLabelStyle = lipgloss.NewStyle().
|
|
Foreground(colorPrimary).
|
|
Bold(true)
|
|
|
|
inputStyle = lipgloss.NewStyle().
|
|
Border(lipgloss.RoundedBorder()).
|
|
BorderForeground(colorMuted).
|
|
Padding(0, 1)
|
|
|
|
inputFocusStyle = lipgloss.NewStyle().
|
|
Border(lipgloss.RoundedBorder()).
|
|
BorderForeground(colorPrimary).
|
|
Padding(0, 1)
|
|
)
|
|
|
|
// Dialog/modal styles
|
|
var (
|
|
dialogStyle = lipgloss.NewStyle().
|
|
Border(lipgloss.RoundedBorder()).
|
|
BorderForeground(colorAccent).
|
|
Padding(1, 2)
|
|
|
|
presetItemStyle = lipgloss.NewStyle().
|
|
Padding(0, 1)
|
|
|
|
presetSelectedStyle = lipgloss.NewStyle().
|
|
Background(colorSelectedBg).
|
|
Foreground(colorSelectedFg).
|
|
Padding(0, 1)
|
|
)
|
|
|
|
// WrapHelpText wraps help text to fit within maxWidth, splitting on bullet separators.
|
|
// If maxWidth is 0 or negative, returns the original text.
|
|
func WrapHelpText(text string, maxWidth int) string {
|
|
if maxWidth <= 0 {
|
|
return helpDescStyle.Render(text)
|
|
}
|
|
|
|
separator := " • "
|
|
parts := splitOnSeparator(text, separator)
|
|
|
|
var lines []string
|
|
var currentLine string
|
|
var currentWidth int
|
|
|
|
for i, part := range parts {
|
|
partWidth := len(part)
|
|
sepWidth := 3 // len(" • ")
|
|
|
|
newWidth := currentWidth + partWidth
|
|
if currentWidth > 0 {
|
|
newWidth += sepWidth
|
|
}
|
|
|
|
if newWidth > maxWidth && currentWidth > 0 {
|
|
lines = append(lines, currentLine)
|
|
currentLine = part
|
|
currentWidth = partWidth
|
|
} else {
|
|
if currentWidth > 0 {
|
|
currentLine += separator
|
|
}
|
|
currentLine += part
|
|
if i == 0 {
|
|
currentWidth = partWidth
|
|
} else {
|
|
currentWidth = newWidth
|
|
}
|
|
}
|
|
}
|
|
|
|
if currentLine != "" {
|
|
lines = append(lines, currentLine)
|
|
}
|
|
|
|
// Apply style to each line and join
|
|
var result []string
|
|
for _, line := range lines {
|
|
result = append(result, helpDescStyle.Render(line))
|
|
}
|
|
|
|
return strings.Join(result, "\n")
|
|
}
|
|
|
|
// splitOnSeparator splits a string on the given separator.
|
|
func splitOnSeparator(s, sep string) []string {
|
|
var parts []string
|
|
for {
|
|
idx := strings.Index(s, sep)
|
|
if idx == -1 {
|
|
parts = append(parts, s)
|
|
break
|
|
}
|
|
parts = append(parts, s[:idx])
|
|
s = s[idx+len(sep):]
|
|
}
|
|
return parts
|
|
}
|