265 lines
11 KiB
Go
265 lines
11 KiB
Go
package ui
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
// Color definitions (Hex palette)
|
|
const (
|
|
ColorBg = "#0b1017" // Dark slate background
|
|
ColorCardBg = "#121a24" // Dark grey cards
|
|
ColorBorder = "#2e3b4e" // Dark slate borders
|
|
ColorText = "#e0ecf6" // Light grey text
|
|
ColorSubdued = "#8c9ba5" // Subdued slate text
|
|
ColorCyan = "#00ffd2" // Bright teal/cyan accent
|
|
ColorPink = "#ff2a85" // Hot pink accent
|
|
ColorGreen = "#3cd58c" // Vibrant green (completed)
|
|
ColorYellow = "#f4b942" // Amber/yellow (downloading)
|
|
ColorRed = "#ff5555" // Bright red (error/missing)
|
|
ColorBlue = "#00aeff" // Vibrant blue (dht)
|
|
)
|
|
|
|
var (
|
|
// Base styles
|
|
StyleBg = lipgloss.NewStyle().
|
|
Background(lipgloss.Color(ColorBg)).
|
|
Foreground(lipgloss.Color(ColorText))
|
|
|
|
StyleTitle = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorCyan)).
|
|
Border(lipgloss.DoubleBorder(), true).
|
|
BorderForeground(lipgloss.Color(ColorCyan)).
|
|
Padding(0, 2).
|
|
MarginBottom(1)
|
|
|
|
StyleHeader = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorPink)).
|
|
MarginBottom(1)
|
|
|
|
// Status states
|
|
StyleStatusIdle = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorSubdued))
|
|
|
|
StyleStatusActive = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorYellow))
|
|
|
|
StyleStatusDone = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorGreen))
|
|
|
|
StyleStatusError = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorRed))
|
|
|
|
// KPI Cards
|
|
StyleCard = lipgloss.NewStyle().
|
|
Background(lipgloss.Color(ColorCardBg)).
|
|
Border(lipgloss.RoundedBorder()).
|
|
BorderForeground(lipgloss.Color(ColorBorder)).
|
|
Padding(0, 1).
|
|
Align(lipgloss.Left)
|
|
|
|
StyleCardActive = StyleCard.
|
|
BorderForeground(lipgloss.Color(ColorCyan))
|
|
|
|
StyleCardTitle = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorSubdued))
|
|
|
|
StyleCardValue = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorText))
|
|
|
|
// Tabs
|
|
StyleTab = lipgloss.NewStyle().
|
|
Padding(0, 2).
|
|
Background(lipgloss.Color(ColorCardBg)).
|
|
Foreground(lipgloss.Color(ColorSubdued)).
|
|
Border(lipgloss.NormalBorder(), false, true, false, false).
|
|
BorderForeground(lipgloss.Color(ColorBorder))
|
|
|
|
StyleActiveTab = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Padding(0, 2).
|
|
Background(lipgloss.Color(ColorCardBg)).
|
|
Foreground(lipgloss.Color(ColorCyan)).
|
|
Border(lipgloss.NormalBorder(), true, true, false, true).
|
|
BorderForeground(lipgloss.Color(ColorCyan))
|
|
|
|
StyleTabsRow = lipgloss.NewStyle().
|
|
Border(lipgloss.NormalBorder(), false, false, true, false).
|
|
BorderForeground(lipgloss.Color(ColorBorder)).
|
|
MarginBottom(1)
|
|
|
|
// Input form
|
|
StyleInputLabel = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorCyan)).
|
|
Width(15)
|
|
|
|
StyleInputFocused = lipgloss.NewStyle().
|
|
Foreground(lipgloss.Color(ColorCyan)).
|
|
BorderForeground(lipgloss.Color(ColorCyan))
|
|
|
|
StyleInputUnfocused = lipgloss.NewStyle().
|
|
Foreground(lipgloss.Color(ColorSubdued)).
|
|
BorderForeground(lipgloss.Color(ColorBorder))
|
|
|
|
// Help bar
|
|
StyleHelp = lipgloss.NewStyle().
|
|
Foreground(lipgloss.Color(ColorSubdued)).
|
|
MarginTop(1)
|
|
|
|
StyleKey = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorPink))
|
|
|
|
// Tables
|
|
StyleTableHeader = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color(ColorCyan))
|
|
|
|
StyleTableRowSelected = lipgloss.NewStyle().
|
|
Background(lipgloss.Color(ColorBorder)).
|
|
Foreground(lipgloss.Color(ColorCyan)).
|
|
Bold(true)
|
|
|
|
// Grid colors
|
|
StylePieceCompleted = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorGreen))
|
|
StylePieceDownloading = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorYellow))
|
|
StylePieceMissing = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorBorder))
|
|
|
|
// ── Кэшированные стили для горячих путей рендеринга ──────────────────────
|
|
|
|
// Dashboard header
|
|
StyleHeaderBrand = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorPink)).Bold(true)
|
|
StyleHeaderSep = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorBorder))
|
|
StyleHeaderName = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorText))
|
|
StyleHeaderIcon = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorSubdued))
|
|
StyleHeaderLine = lipgloss.NewStyle().
|
|
Border(lipgloss.NormalBorder(), false, false, true, false).
|
|
BorderForeground(lipgloss.Color(ColorBorder)).
|
|
PaddingBottom(0)
|
|
|
|
// Phase status styles
|
|
StylePhaseStopped = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorSubdued)).Bold(true)
|
|
StylePhaseFailed = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorRed)).Bold(true)
|
|
StylePhaseSeeding = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorGreen)).Bold(true)
|
|
StylePhaseDownload = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorCyan)).Bold(true)
|
|
StylePhaseDefault = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorYellow)).Bold(true)
|
|
|
|
// KPI cards
|
|
StyleKPIProgress = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(ColorCyan))
|
|
StyleKPIDown = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(ColorGreen))
|
|
StyleKPIUp = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(ColorYellow))
|
|
StyleKPIEta = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(ColorPink))
|
|
StyleKPIPeers = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(ColorText))
|
|
StyleKPIBarFill = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorCyan))
|
|
StyleKPIBarEmpty = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorBorder))
|
|
|
|
// Menu styles
|
|
StyleMenuText = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorText))
|
|
StyleMenuDesc = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorSubdued))
|
|
StyleMenuActive = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorCyan)).Bold(true)
|
|
StyleMenuCursor = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorPink))
|
|
StyleMenuHelp = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorSubdued)).MarginTop(2)
|
|
StyleMenuBorder = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorBorder))
|
|
StyleMenuPadding = lipgloss.NewStyle().Padding(2, 4)
|
|
StyleMenuBox = lipgloss.NewStyle().Padding(2, 0)
|
|
|
|
// Log overlay styles
|
|
StyleLogTime = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorSubdued))
|
|
StyleLogEngine = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorPink)).Bold(true)
|
|
StyleLogDHT = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorBlue)).Bold(true)
|
|
StyleLogPeer = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorGreen)).Bold(true)
|
|
StyleLogSys = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorCyan)).Bold(true)
|
|
StyleLogDefault = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorText)).Bold(true)
|
|
StyleLogError = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorRed)).Bold(true)
|
|
StyleLogWarn = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorYellow)).Bold(true)
|
|
StyleLogInfo = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorCyan))
|
|
StyleLogDebug = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorSubdued))
|
|
StyleLogMsg = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorText))
|
|
StyleLogMsgError = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorRed))
|
|
|
|
// Overview styles
|
|
StyleSectionTitle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(ColorCyan))
|
|
StyleDim = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorSubdued))
|
|
StyleVal = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorText))
|
|
StyleSpeedDown = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorGreen)).Bold(true)
|
|
StyleSpeedUp = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorYellow)).Bold(true)
|
|
StyleETA = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorPink)).Bold(true)
|
|
StyleErrText = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorRed)).Bold(true)
|
|
|
|
// HelpBar
|
|
StyleHelpKey = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorPink)).Bold(true)
|
|
StyleHelpDesc = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorSubdued))
|
|
StyleHelpSep = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorBorder))
|
|
StyleHelpBar = lipgloss.NewStyle().
|
|
Foreground(lipgloss.Color(ColorSubdued)).
|
|
Border(lipgloss.NormalBorder(), true, false, false, false).
|
|
BorderForeground(lipgloss.Color(ColorBorder)).
|
|
MarginTop(1).
|
|
PaddingTop(0)
|
|
|
|
// Logo
|
|
StyleLogoTorrent = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorText)).Bold(true)
|
|
StyleLogoZ = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorGreen)).Bold(true)
|
|
|
|
// Settings indicator
|
|
StyleSettingsCursor = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorPink))
|
|
StyleSettingsActive = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorCyan)).Bold(true)
|
|
StyleSettingsLabel = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorSubdued)).Width(26)
|
|
|
|
// Additional menu
|
|
StyleAdditCyan = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(ColorCyan))
|
|
StyleAdditPink = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorPink)).Bold(true)
|
|
StyleAdditVal = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorText))
|
|
StyleAdditShort = lipgloss.NewStyle().Foreground(lipgloss.Color(ColorYellow))
|
|
)
|
|
|
|
// Статичные строки, вычисляемые один раз
|
|
var (
|
|
// Статичный "torrent" ASCII-арт (не меняется никогда)
|
|
cachedTorrentArt = StyleLogoTorrent.Render(strings.Join([]string{
|
|
"████████╗ ██████╗ ██████╗ ██████╗ ███████╗███╗ ██╗████████╗",
|
|
"╚══██╔══╝██╔═══██╗██╔══██╗██╔══██╗██╔════╝████╗ ██║╚══██╔══╝",
|
|
" ██║ ██║ ██║██████╔╝██████╔╝█████╗ ██╔██╗ ██║ ██║ ",
|
|
" ██║ ██║ ██║██╔══██╗██╔══██╗██╔══╝ ██║╚████║ ██║ ",
|
|
" ██║ ╚██████╔╝██║ ██║██║ ██║███████╗██║ ╚███║ ██║ ",
|
|
" ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚══╝ ╚═╝ ",
|
|
}, "\n"))
|
|
|
|
// Статичный Z-логотип (при отключённых анимациях)
|
|
cachedStaticZArt = StyleLogoZ.Render(strings.Join([]string{
|
|
" ",
|
|
" ",
|
|
"███████╗",
|
|
"╚════██║",
|
|
" ██╔╝",
|
|
" ██╔╝ ",
|
|
" ██╔╝ ",
|
|
" ███████╗",
|
|
" ╚══════╝",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
}, "\n"))
|
|
|
|
// Статичный help bar главного меню
|
|
cachedMenuHelp = StyleMenuHelp.Render(" ↓↑ — выбор Enter — подтвердить Q — выход")
|
|
|
|
// Статичные строки рамки меню (зависят от boxWidth=85, не меняются)
|
|
cachedMenuTopBorder = StyleMenuBorder.Render("╭" + strings.Repeat("─", 85) + "╮")
|
|
cachedMenuBottomBorder = StyleMenuBorder.Render("╰" + strings.Repeat("─", 85) + "╯")
|
|
cachedMenuLeftEdge = StyleMenuBorder.Render("│")
|
|
cachedMenuRightEdge = StyleMenuBorder.Render("│")
|
|
|
|
// Help bar dashboard
|
|
cachedHelpSep = StyleHelpSep.Render(" │ ")
|
|
)
|