feat: fix proxy compatibility and establish TUI foundation
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/muesli/termenv"
|
||||
|
||||
"proxyctl/internal/target"
|
||||
)
|
||||
|
||||
type semanticTheme struct {
|
||||
title lipgloss.Style
|
||||
section lipgloss.Style
|
||||
selected lipgloss.Style
|
||||
status lipgloss.Style
|
||||
warning lipgloss.Style
|
||||
enabled lipgloss.Style
|
||||
disabled lipgloss.Style
|
||||
external lipgloss.Style
|
||||
drifted lipgloss.Style
|
||||
applying lipgloss.Style
|
||||
}
|
||||
|
||||
func newSemanticTheme(mode themeMode, output io.Writer) semanticTheme {
|
||||
if output == nil {
|
||||
output = os.Stdout
|
||||
}
|
||||
renderer := lipgloss.NewRenderer(output)
|
||||
explicit := mode != themeModeAuto
|
||||
if _, noColor := os.LookupEnv("NO_COLOR"); noColor && mode == themeModeAuto {
|
||||
mode = themeModeNoColor
|
||||
explicit = true
|
||||
}
|
||||
if mode == themeModeAuto {
|
||||
if renderer.ColorProfile() == termenv.Ascii {
|
||||
mode = themeModeNoColor
|
||||
} else if renderer.HasDarkBackground() {
|
||||
mode = themeModeDark
|
||||
} else {
|
||||
mode = themeModeLight
|
||||
}
|
||||
}
|
||||
if mode == themeModeNoColor {
|
||||
renderer.SetColorProfile(termenv.Ascii)
|
||||
} else if explicit {
|
||||
// Explicit modes make fixed-size render tests deterministic. Production
|
||||
// auto mode retains capabilities detected from the injected output.
|
||||
renderer.SetColorProfile(termenv.ANSI256)
|
||||
}
|
||||
|
||||
foreground, subtle, accent := "252", "245", "75"
|
||||
if mode == themeModeLight {
|
||||
foreground, subtle, accent = "235", "242", "25"
|
||||
}
|
||||
style := renderer.NewStyle
|
||||
return semanticTheme{
|
||||
title: style().Bold(true).Foreground(lipgloss.Color(accent)),
|
||||
section: style().Bold(true).Foreground(lipgloss.Color(foreground)),
|
||||
selected: style().Bold(true).Underline(true).Foreground(lipgloss.Color(accent)),
|
||||
status: style().Foreground(lipgloss.Color(foreground)),
|
||||
warning: style().Bold(true).Foreground(lipgloss.Color("172")),
|
||||
enabled: style().Foreground(lipgloss.Color("34")),
|
||||
disabled: style().Foreground(lipgloss.Color(subtle)),
|
||||
external: style().Foreground(lipgloss.Color("172")),
|
||||
drifted: style().Bold(true).Foreground(lipgloss.Color("160")),
|
||||
applying: style().Foreground(lipgloss.Color(accent)),
|
||||
}
|
||||
}
|
||||
|
||||
func (t semanticTheme) renderTargetState(state target.State, applying bool) string {
|
||||
if applying {
|
||||
return t.applying.Render("Applying…")
|
||||
}
|
||||
label := string(state)
|
||||
switch state {
|
||||
case target.Enabled:
|
||||
return t.enabled.Render(paddedState(label))
|
||||
case target.Disabled:
|
||||
return t.disabled.Render(paddedState(label))
|
||||
case target.External:
|
||||
return t.external.Render(paddedState(label))
|
||||
case target.Drifted:
|
||||
return t.drifted.Render(paddedState(label))
|
||||
default:
|
||||
return paddedState(label)
|
||||
}
|
||||
}
|
||||
|
||||
func paddedState(label string) string {
|
||||
return lipgloss.NewStyle().Width(9).Render(label)
|
||||
}
|
||||
Reference in New Issue
Block a user