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(" │ ") )