feat: complete TUI redesign with cyberpunk theme (#1)
Some checks failed
Stable Release / stable (push) Failing after 22s
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
This commit was merged in pull request #1.
This commit is contained in:
@@ -15,16 +15,16 @@ func (m Model) renderDashboard() string {
|
||||
|
||||
var left, right strings.Builder
|
||||
|
||||
left.WriteString(renderSectionWithIcon("System", "◉"))
|
||||
left.WriteString(renderSectionHeader("SYSTEM", "[*]"))
|
||||
left.WriteString("\n")
|
||||
if m.scanResult != nil {
|
||||
sysInfo := m.scanResult.System.String()
|
||||
left.WriteString(" ")
|
||||
left.WriteString(lipgloss.NewStyle().Foreground(textColor).Render(sysInfo))
|
||||
left.WriteString(lipgloss.NewStyle().Foreground(textMain).Render(sysInfo))
|
||||
}
|
||||
left.WriteString("\n\n")
|
||||
|
||||
left.WriteString(renderSectionWithIcon("Installed Tools", "◆"))
|
||||
left.WriteString(renderSectionHeader("INSTALLED TOOLS", "[+]"))
|
||||
left.WriteString("\n")
|
||||
if m.scanResult != nil {
|
||||
installed := 0
|
||||
@@ -33,14 +33,14 @@ func (m Model) renderDashboard() string {
|
||||
if t.Installed {
|
||||
installed++
|
||||
left.WriteString(" ")
|
||||
left.WriteString(itemOKStyle.Render("✓ "))
|
||||
left.WriteString(lipgloss.NewStyle().Foreground(textColor).Render(t.Name))
|
||||
left.WriteString(lipgloss.NewStyle().Foreground(dimColor).Render(fmt.Sprintf(" %s", extractVersion(t.Version))))
|
||||
left.WriteString(itemOKStyle.Render("[OK] "))
|
||||
left.WriteString(lipgloss.NewStyle().Foreground(textMain).Render(t.Name))
|
||||
left.WriteString(lipgloss.NewStyle().Foreground(dimRed).Render(fmt.Sprintf(" %s", extractVersion(t.Version))))
|
||||
left.WriteString("\n")
|
||||
} else {
|
||||
left.WriteString(" ")
|
||||
left.WriteString(itemMissingStyle.Render("✗ "))
|
||||
left.WriteString(lipgloss.NewStyle().Foreground(mutedColor).Render(t.Name))
|
||||
left.WriteString(itemMissingStyle.Render("[--] "))
|
||||
left.WriteString(lipgloss.NewStyle().Foreground(textMuted).Render(t.Name))
|
||||
left.WriteString(itemPendingStyle.Render(" (missing)"))
|
||||
left.WriteString("\n")
|
||||
}
|
||||
@@ -51,14 +51,14 @@ func (m Model) renderDashboard() string {
|
||||
if total > 0 {
|
||||
pct = (installed * barWidth) / total
|
||||
}
|
||||
bar := lipgloss.NewStyle().Foreground(primaryColor).Render(strings.Repeat("█", pct)) +
|
||||
lipgloss.NewStyle().Foreground(dimColor).Render(strings.Repeat("░", barWidth-pct))
|
||||
bar := lipgloss.NewStyle().Foreground(cyberRed).Bold(true).Render(strings.Repeat("█", pct)) +
|
||||
lipgloss.NewStyle().Foreground(dimRed).Render(strings.Repeat("░", barWidth-pct))
|
||||
left.WriteString(fmt.Sprintf("\n %s %d/%d\n", bar, installed, total))
|
||||
}
|
||||
left.WriteString("\n")
|
||||
|
||||
if m.installing {
|
||||
left.WriteString(renderSectionWithIcon("Installing", "⏳"))
|
||||
left.WriteString(renderSectionHeader("INSTALLING", "[~]"))
|
||||
left.WriteString("\n")
|
||||
progBar := m.progressBar.View()
|
||||
label := ""
|
||||
@@ -72,7 +72,7 @@ func (m Model) renderDashboard() string {
|
||||
}
|
||||
|
||||
if len(m.installLog) > 0 {
|
||||
left.WriteString(renderSectionWithIcon("Install Log", "📋"))
|
||||
left.WriteString(renderSectionHeader("INSTALL LOG", "[#]"))
|
||||
left.WriteString("\n")
|
||||
for _, l := range m.installLog {
|
||||
left.WriteString(l + "\n")
|
||||
@@ -80,27 +80,27 @@ func (m Model) renderDashboard() string {
|
||||
left.WriteString("\n")
|
||||
}
|
||||
|
||||
right.WriteString(renderSectionWithIcon("Quick Actions", "⚡"))
|
||||
right.WriteString(renderSectionHeader("QUICK ACTIONS", "[!]"))
|
||||
right.WriteString("\n")
|
||||
actions := []struct {
|
||||
key string
|
||||
desc string
|
||||
color lipgloss.Color
|
||||
}{
|
||||
{"i", "Install missing tools", primaryColor},
|
||||
{"u", "Check for updates", warmColor},
|
||||
{"s", "Rescan system", roseColor},
|
||||
{"l", "Scan LSP servers", accentColor},
|
||||
{"m", "Configure MCP servers", roseLightColor},
|
||||
{"i", "Install missing tools", cyberRed},
|
||||
{"u", "Check for updates", neonRed},
|
||||
{"s", "Rescan system", cyberPink},
|
||||
{"l", "Scan LSP servers", cyberRose},
|
||||
{"m", "Configure MCP servers", brightRed},
|
||||
}
|
||||
for _, a := range actions {
|
||||
right.WriteString(fmt.Sprintf(" %s %s\n",
|
||||
lipgloss.NewStyle().Foreground(a.color).Bold(true).Render("["+a.key+"]"),
|
||||
lipgloss.NewStyle().Foreground(textColor).Render(a.desc)))
|
||||
lipgloss.NewStyle().Foreground(textMain).Render(a.desc)))
|
||||
}
|
||||
right.WriteString("\n")
|
||||
|
||||
right.WriteString(renderSectionWithIcon("Active Agents", "◉"))
|
||||
right.WriteString(renderSectionHeader("ACTIVE AGENTS", "[*]"))
|
||||
right.WriteString("\n")
|
||||
|
||||
agents := []struct {
|
||||
@@ -111,24 +111,24 @@ func (m Model) renderDashboard() string {
|
||||
}
|
||||
for _, a := range agents {
|
||||
right.WriteString(" ")
|
||||
right.WriteString(lipgloss.NewStyle().Foreground(dimColor).Render("● "))
|
||||
right.WriteString(lipgloss.NewStyle().Foreground(mutedColor).Render(a.name + " "))
|
||||
right.WriteString(itemPendingStyle.Render("stopped"))
|
||||
right.WriteString(lipgloss.NewStyle().Foreground(dimRed).Render(">> "))
|
||||
right.WriteString(lipgloss.NewStyle().Foreground(textMuted).Render(a.name + " "))
|
||||
right.WriteString(itemPendingStyle.Render("[stopped]"))
|
||||
right.WriteString("\n")
|
||||
}
|
||||
right.WriteString("\n")
|
||||
|
||||
if len(m.updateStatus) > 0 {
|
||||
right.WriteString(renderSectionWithIcon("Updates", "↻"))
|
||||
right.WriteString(renderSectionHeader("UPDATES", "[^]"))
|
||||
right.WriteString("\n")
|
||||
for _, s := range m.updateStatus {
|
||||
if s.NeedsUpdate {
|
||||
right.WriteString(" ")
|
||||
right.WriteString(itemWarnStyle.Render("⚠ "))
|
||||
right.WriteString(fmt.Sprintf("%s: %s → %s\n", s.Tool, s.Current, s.Latest))
|
||||
right.WriteString(itemWarnStyle.Render("[!!] "))
|
||||
right.WriteString(fmt.Sprintf("%s: %s -> %s\n", s.Tool, s.Current, s.Latest))
|
||||
} else if s.Error == "" {
|
||||
right.WriteString(" ")
|
||||
right.WriteString(itemOKStyle.Render("✓ "))
|
||||
right.WriteString(itemOKStyle.Render("[OK] "))
|
||||
right.WriteString(fmt.Sprintf("%s: up to date\n", s.Tool))
|
||||
}
|
||||
}
|
||||
@@ -136,18 +136,18 @@ func (m Model) renderDashboard() string {
|
||||
}
|
||||
|
||||
if len(m.lspServers) > 0 {
|
||||
right.WriteString(renderSectionWithIcon("LSP Servers", "§"))
|
||||
right.WriteString(renderSectionHeader("LSP SERVERS", "[L]"))
|
||||
right.WriteString("\n")
|
||||
lspInstalled := 0
|
||||
for _, s := range m.lspServers {
|
||||
if s.Installed {
|
||||
lspInstalled++
|
||||
right.WriteString(" ")
|
||||
right.WriteString(itemOKStyle.Render("✓ "))
|
||||
right.WriteString(itemOKStyle.Render("[OK] "))
|
||||
right.WriteString(fmt.Sprintf("%-22s (%s)\n", s.Name, s.Language))
|
||||
} else {
|
||||
right.WriteString(" ")
|
||||
right.WriteString(itemPendingStyle.Render("○ "))
|
||||
right.WriteString(itemPendingStyle.Render("[ ] "))
|
||||
right.WriteString(fmt.Sprintf("%-22s (%s)\n", s.Name, s.Language))
|
||||
}
|
||||
}
|
||||
@@ -155,16 +155,16 @@ func (m Model) renderDashboard() string {
|
||||
right.WriteString("\n")
|
||||
}
|
||||
|
||||
mcpStatus := itemPendingStyle.Render("○ not configured")
|
||||
mcpStatus := itemPendingStyle.Render("[ ] not configured")
|
||||
if m.mcpConfigured {
|
||||
mcpStatus = itemOKStyle.Render("✓ configured")
|
||||
mcpStatus = itemOKStyle.Render("[OK] configured")
|
||||
}
|
||||
right.WriteString(fmt.Sprintf(" MCP: %s\n", mcpStatus))
|
||||
|
||||
if m.daemon != nil {
|
||||
daemonStatus := itemPendingStyle.Render("○ stopped")
|
||||
daemonStatus := itemPendingStyle.Render("[ ] stopped")
|
||||
if m.daemon.IsRunning() {
|
||||
daemonStatus = itemOKStyle.Render("✓ running")
|
||||
daemonStatus = itemOKStyle.Render("[OK] running")
|
||||
}
|
||||
right.WriteString(fmt.Sprintf(" Daemon: %s\n", daemonStatus))
|
||||
}
|
||||
@@ -174,8 +174,3 @@ func (m Model) renderDashboard() string {
|
||||
|
||||
return lipgloss.JoinHorizontal(lipgloss.Top, leftCol, rightCol)
|
||||
}
|
||||
|
||||
func renderSectionWithIcon(title string, icon string) string {
|
||||
return lipgloss.NewStyle().Foreground(primaryColor).Render(icon+" ") +
|
||||
sectionStyle.Render(title)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user