Some checks failed
Stable Release / stable (push) Failing after 22s
- Dark theme with red accents (cyberpunk aesthetic) - Epuré cyberpunk style: clean dark backgrounds, sharp red highlights - Full cyberpunk animations: glitch effect, scan line, typewriter - Mixed Unicode + ASCII icons - Rounded borders (╭ ╮ ╯ ╰) on cards and panels - ASCII art block titles (■) with red styling - Header: MUYUE branding, status indicators, live clock - Footer: shortcuts, version, update indicator - Tab transitions: glitch → scan → typewriter sequence - Extracted header.go, footer.go, animations.go as new files Controls unchanged: ctrl+t tabs, ctrl+s sidebar, ctrl+a AI panel file changes: - styles.go: new color palette (cyberRed, bgVoid, dimRed), block titles - types.go: added transition state, clock tick, glitch/scan/done messages - animations.go: new file with glitch, scan, typewriter, hex stream effects - header.go: new file with logo, tabs, status dots, live clock - footer.go: new file with shortcuts, version, update indicator - model.go: integrated transition state machine, clock updates - dashboard.go, studio.go, terminal.go, config_tab.go: updated icons/styles Generated with Crush Assisted-by: GLM-5.1 via Crush <crush@charm.land> Co-authored-by: Augustin <muyue@legion-muyue.fr> Reviewed-on: #1
197 lines
6.2 KiB
Go
197 lines
6.2 KiB
Go
package tui
|
|
|
|
import (
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
var (
|
|
cyberRed = lipgloss.Color("#FF0033")
|
|
cyberRedDark = lipgloss.Color("#8B0020")
|
|
cyberRedDeep = lipgloss.Color("#5C0015")
|
|
cyberPink = lipgloss.Color("#FF1A5E")
|
|
cyberRose = lipgloss.Color("#FF4D6D")
|
|
neonRed = lipgloss.Color("#FF1744")
|
|
brightRed = lipgloss.Color("#FF5252")
|
|
dimRed = lipgloss.Color("#6B2033")
|
|
mutedRed = lipgloss.Color("#4A1525")
|
|
|
|
textBright = lipgloss.Color("#EAE0E2")
|
|
textMain = lipgloss.Color("#D4C4C8")
|
|
textDim = lipgloss.Color("#8A7A7E")
|
|
textMuted = lipgloss.Color("#5A4F52")
|
|
|
|
successGreen = lipgloss.Color("#00E676")
|
|
warnAmber = lipgloss.Color("#FFD740")
|
|
errorRed = lipgloss.Color("#FF1744")
|
|
|
|
bgVoid = lipgloss.Color("#0A0A0C")
|
|
bgBase = lipgloss.Color("#0F0D10")
|
|
bgSurface = lipgloss.Color("#161218")
|
|
bgPanel = lipgloss.Color("#1C1719")
|
|
bgCard = lipgloss.Color("#221B1E")
|
|
bgInput = lipgloss.Color("#2A2225")
|
|
|
|
borderDim = lipgloss.Color("#2A1F22")
|
|
borderRed = lipgloss.Color("#FF003344")
|
|
borderRedFull = lipgloss.Color("#FF0033")
|
|
)
|
|
|
|
var (
|
|
baseStyle = lipgloss.NewStyle()
|
|
|
|
titleBlockStyle = lipgloss.NewStyle().
|
|
Foreground(cyberRed).
|
|
Bold(true)
|
|
|
|
sectionTitleStyle = lipgloss.NewStyle().
|
|
Foreground(cyberRed).
|
|
Bold(true)
|
|
|
|
labelStyle = lipgloss.NewStyle().
|
|
Foreground(textDim).
|
|
Width(14)
|
|
|
|
valueStyle = lipgloss.NewStyle().
|
|
Foreground(textMain)
|
|
|
|
cardStyle = lipgloss.NewStyle().
|
|
Background(bgCard).
|
|
Border(lipgloss.RoundedBorder()).
|
|
BorderForeground(borderDim).
|
|
Padding(0, 1)
|
|
|
|
cardActiveStyle = lipgloss.NewStyle().
|
|
Background(bgCard).
|
|
Border(lipgloss.RoundedBorder()).
|
|
BorderForeground(cyberRed).
|
|
Padding(0, 1)
|
|
|
|
sidebarStyle = lipgloss.NewStyle().
|
|
Background(bgSurface).
|
|
Border(lipgloss.Border{Right: "│"}).
|
|
BorderForeground(borderDim).
|
|
Padding(0, 1)
|
|
|
|
statusBarStyle = lipgloss.NewStyle().
|
|
Background(bgSurface).
|
|
Foreground(textDim).
|
|
Padding(0, 1)
|
|
|
|
inputStyle = lipgloss.NewStyle().
|
|
Foreground(cyberRed)
|
|
|
|
userMsgStyle = lipgloss.NewStyle().
|
|
Foreground(cyberRose)
|
|
|
|
aiMsgStyle = lipgloss.NewStyle().
|
|
Foreground(textMain)
|
|
|
|
errMsgStyle = lipgloss.NewStyle().
|
|
Foreground(errorRed)
|
|
|
|
itemOKStyle = lipgloss.NewStyle().Foreground(successGreen)
|
|
itemMissingStyle = lipgloss.NewStyle().Foreground(errorRed)
|
|
itemWarnStyle = lipgloss.NewStyle().Foreground(warnAmber)
|
|
itemPendingStyle = lipgloss.NewStyle().Foreground(textMuted)
|
|
|
|
confirmBoxStyle = lipgloss.NewStyle().
|
|
Border(lipgloss.RoundedBorder()).
|
|
BorderForeground(cyberRed).
|
|
Background(bgCard).
|
|
Foreground(textBright).
|
|
Padding(1, 3).
|
|
Bold(true)
|
|
|
|
confirmYesStyle = lipgloss.NewStyle().Foreground(successGreen).Bold(true)
|
|
confirmNoStyle = lipgloss.NewStyle().Foreground(textMuted)
|
|
|
|
badgeStyle = lipgloss.NewStyle().
|
|
Background(cyberRed).
|
|
Foreground(lipgloss.Color("#FFFFFF")).
|
|
Padding(0, 1).
|
|
Bold(true)
|
|
|
|
tabBarStyle = lipgloss.NewStyle().Background(bgSurface)
|
|
|
|
stepDoneStyle = lipgloss.NewStyle().Foreground(successGreen)
|
|
stepPendingStyle = lipgloss.NewStyle().Foreground(textMuted)
|
|
stepCurrentStyle = lipgloss.NewStyle().Foreground(cyberRed).Bold(true)
|
|
stepErrorStyle = lipgloss.NewStyle().Foreground(errorRed)
|
|
)
|
|
|
|
var logoLines = []string{
|
|
"███╗ ███╗██╗ ██╗ █████╗ ███╗ ██╗███████╗",
|
|
"████╗ ████║╚██╗ ██╔╝██╔══██╗████╗ ██║██╔════╝",
|
|
"██╔████╔██║ ╚████╔╝ ███████║██╔██╗ ██║███████╗",
|
|
"██║╚██╔╝██║ ╚██╔╝ ██╔══██║██║╚██╗██║╚════██║",
|
|
"██║ ╚═╝ ██║ ██║ ██║ ██║██║ ╚████║███████║",
|
|
"╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝",
|
|
}
|
|
|
|
var scanFrames = []string{
|
|
"─────────────────────────── ───",
|
|
" ─────────────────────────── ─── ",
|
|
"── ──────────────────────────── ",
|
|
"─ ─── ────────────────────────────",
|
|
"─── ─────────────────────────── ─",
|
|
" ──── ─────────────────────────────",
|
|
}
|
|
|
|
func getAnimFrame(frame int) string {
|
|
frames := []string{
|
|
"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏",
|
|
}
|
|
return frames[frame%len(frames)]
|
|
}
|
|
|
|
func getScanFrame(frame int) string {
|
|
return scanFrames[frame%len(scanFrames)]
|
|
}
|
|
|
|
func renderLogo() string {
|
|
styled := make([]string, len(logoLines))
|
|
for i, line := range logoLines {
|
|
styled[i] = lipgloss.NewStyle().Foreground(cyberRed).Bold(true).Render(line)
|
|
}
|
|
return lipgloss.JoinVertical(lipgloss.Left, styled...)
|
|
}
|
|
|
|
func renderBlockTitle(text string) string {
|
|
width := len(text) + 6
|
|
top := lipgloss.NewStyle().Foreground(dimRed).Render(
|
|
"╭" + repeatStr("─", width) + "╮",
|
|
)
|
|
content := lipgloss.NewStyle().Foreground(cyberRed).Bold(true).Render(
|
|
"│ ■ " + text + " ■ │",
|
|
)
|
|
bottom := lipgloss.NewStyle().Foreground(dimRed).Render(
|
|
"╰" + repeatStr("─", width) + "╯",
|
|
)
|
|
return lipgloss.JoinVertical(lipgloss.Left, top, content, bottom)
|
|
}
|
|
|
|
func renderSectionHeader(title string, icon string) string {
|
|
return lipgloss.NewStyle().Foreground(cyberRed).Bold(true).Render(
|
|
"■ "+icon+" "+title+" ■",
|
|
)
|
|
}
|
|
|
|
func renderProgressBar(pct float64, width int) string {
|
|
filled := int(float64(width) * pct)
|
|
empty := width - filled
|
|
bar := lipgloss.NewStyle().Foreground(cyberRed).Bold(true).Render(
|
|
repeatStr("█", filled),
|
|
) + lipgloss.NewStyle().Foreground(dimRed).Render(
|
|
repeatStr("░", empty),
|
|
)
|
|
return bar
|
|
}
|
|
|
|
func repeatStr(s string, n int) string {
|
|
result := ""
|
|
for i := 0; i < n; i++ {
|
|
result += s
|
|
}
|
|
return result
|
|
}
|