All checks were successful
PR Check / check (pull_request) Successful in 18s
- 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>
75 lines
1.9 KiB
Go
75 lines
1.9 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
"github.com/muyue/muyue/internal/version"
|
|
)
|
|
|
|
func (m Model) renderFooter() string {
|
|
profile := "unknown"
|
|
if m.config != nil && m.config.Profile.Pseudo != "" {
|
|
profile = m.config.Profile.Pseudo
|
|
}
|
|
|
|
left := fmt.Sprintf(" %s@%s",
|
|
lipgloss.NewStyle().Foreground(cyberRed).Bold(true).Render(profile),
|
|
lipgloss.NewStyle().Foreground(dimRed).Render(version.Name))
|
|
leftR := statusBarStyle.Render(left)
|
|
|
|
var helpText string
|
|
switch m.activeTab {
|
|
case tabDashboard:
|
|
helpText = "[i] install [u] update [s] scan [ctrl+t] tabs"
|
|
case tabStudio:
|
|
helpText = "[enter] send [ctrl+s] sidebar [ctrl+t] tabs"
|
|
case tabShell:
|
|
helpText = "[enter] run [ctrl+a] AI panel [ctrl+c] kill"
|
|
case tabConfig:
|
|
helpText = "[up/down] sections [ctrl+t] tabs"
|
|
default:
|
|
helpText = "[ctrl+t] tabs [ctrl+c] quit"
|
|
}
|
|
rightR := statusBarStyle.Render(helpText)
|
|
|
|
updateIndicator := ""
|
|
if len(m.updateStatus) > 0 {
|
|
needsUpdate := false
|
|
for _, s := range m.updateStatus {
|
|
if s.NeedsUpdate {
|
|
needsUpdate = true
|
|
break
|
|
}
|
|
}
|
|
if needsUpdate {
|
|
updateIndicator = lipgloss.NewStyle().Foreground(warnAmber).Render(" [UPD] ")
|
|
} else {
|
|
updateIndicator = lipgloss.NewStyle().Foreground(successGreen).Render(" [OK] ")
|
|
}
|
|
}
|
|
|
|
verStr := lipgloss.NewStyle().Foreground(dimRed).Render("v" + version.Version)
|
|
midContent := lipgloss.NewStyle().Background(bgSurface).Padding(0, 1).Render(
|
|
updateIndicator + verStr,
|
|
)
|
|
|
|
gap := m.width - lipgloss.Width(leftR) - lipgloss.Width(rightR) - lipgloss.Width(midContent)
|
|
if gap < 0 {
|
|
gap = 0
|
|
}
|
|
|
|
statusLine := lipgloss.JoinHorizontal(lipgloss.Bottom,
|
|
leftR,
|
|
strings.Repeat(" ", gap),
|
|
midContent,
|
|
rightR,
|
|
)
|
|
|
|
helpLine := lipgloss.NewStyle().Background(bgSurface).Foreground(textMuted).Render(
|
|
lipgloss.NewStyle().Padding(0, 1).Render(m.helpModel.View(keys)))
|
|
|
|
return lipgloss.JoinVertical(lipgloss.Left, statusLine, helpLine)
|
|
}
|