feat(theme): token semantik Catppuccin (Mocha/Latte/terminal) + mode auto via tea.BackgroundColorMsg + tombol T
CI / test (push) Successful in 11s
CI / test (push) Successful in 11s
This commit is contained in:
1 parent
c65d2cb75d
commit
8b2a86877e
13 files changed
+428
-37
No files matched your search
+38
-22
@@ -17,6 +17,7 @@ import (
|
||||
"gitea.oxpoe.qzz.io/oxpoe/tia-love/internal/sysinfo"
|
||||
"gitea.oxpoe.qzz.io/oxpoe/tia-love/internal/ui/animation"
|
||||
"gitea.oxpoe.qzz.io/oxpoe/tia-love/internal/ui/components"
|
||||
"gitea.oxpoe.qzz.io/oxpoe/tia-love/internal/ui/theme"
|
||||
)
|
||||
|
||||
type viewKind int
|
||||
@@ -72,6 +73,7 @@ func New() Model {
|
||||
cfg.UI.Language = l
|
||||
}
|
||||
i18n.SetLang(cfg.UI.Language)
|
||||
theme.Init(theme.Mode(cfg.UI.ThemeMode), cfg.UI.ThemeAccent)
|
||||
|
||||
cl, err := docker.New()
|
||||
host, _ := os.Hostname()
|
||||
@@ -91,7 +93,7 @@ func New() Model {
|
||||
loading: true,
|
||||
}
|
||||
if cfgErr != nil {
|
||||
m.toast.Show(i18n.T("toast.configError"), cfgErr.Error())
|
||||
m.toast.Show(components.LevelWarning, i18n.T("toast.configError"), cfgErr.Error())
|
||||
}
|
||||
if err != nil {
|
||||
m.loadErr = err
|
||||
@@ -102,7 +104,7 @@ func New() Model {
|
||||
}
|
||||
|
||||
func (m Model) Init() tea.Cmd {
|
||||
var cmds []tea.Cmd
|
||||
cmds := []tea.Cmd{tea.RequestBackgroundColor} // untuk mode tema "auto"
|
||||
if m.animating {
|
||||
cmds = append(cmds, animation.Next(m.tickID))
|
||||
}
|
||||
@@ -154,7 +156,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.loading = false
|
||||
if msg.err != nil {
|
||||
m.loadErr = msg.err
|
||||
m.toast.Show(i18n.T("toast.dockerError"), msg.err.Error())
|
||||
m.toast.Show(components.LevelError, i18n.T("toast.dockerError"), msg.err.Error())
|
||||
m.sound.Play(audio.NotifyError)
|
||||
} else {
|
||||
m.loadErr = nil
|
||||
@@ -175,6 +177,11 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
return m, nil
|
||||
|
||||
case tea.BackgroundColorMsg:
|
||||
// Mode tema "auto": Mocha vs Latte sesuai background terminal.
|
||||
theme.SetDetectedDark(msg.IsDark())
|
||||
return m, nil
|
||||
|
||||
case tea.WindowSizeMsg:
|
||||
m.width, m.height = msg.Width, msg.Height
|
||||
|
||||
@@ -209,8 +216,16 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.loading = true
|
||||
m.sound.Play(audio.Click)
|
||||
return m, tea.Batch(loadContainers(m.cl), loadInfo(m.cl))
|
||||
case "T": // tombol cepat tema (PRD §5.4): auto → dark → light → terminal
|
||||
cur := theme.Current()
|
||||
next := theme.CycleMode(cur.Mode)
|
||||
theme.Set(next, cur.AccentName)
|
||||
m.toast.Show(components.LevelInfo,
|
||||
i18n.Tf("toast.themeMode", i18n.T("theme."+string(next))),
|
||||
i18n.T("theme.switchHint"))
|
||||
m.sound.Play(audio.Click)
|
||||
case "t": // demo toast (sampai modal asli datang)
|
||||
m.toast.Show(i18n.T("toast.demoTitle"), i18n.T("toast.demoBody"))
|
||||
m.toast.Show(components.LevelSuccess, i18n.T("toast.demoTitle"), i18n.T("toast.demoBody"))
|
||||
m.sound.Play(audio.NotifySuccess)
|
||||
case "j", "down":
|
||||
if len(m.containers) > 0 && m.cursor < len(m.containers)-1 {
|
||||
@@ -285,37 +300,38 @@ func (m Model) scrollStart() int {
|
||||
return m.cursor - rows + 1
|
||||
}
|
||||
|
||||
func stateStyle(state string) (glyph, color string) {
|
||||
func stateStyle(state string) (glyph string, c theme.Color) {
|
||||
th := theme.Current()
|
||||
switch state {
|
||||
case "running":
|
||||
return "●", "#a6e3a1"
|
||||
return "●", th.Success
|
||||
case "paused":
|
||||
return "⏸", "#f9e2af"
|
||||
return "⏸", th.Warning
|
||||
case "restarting", "created":
|
||||
return "◌", "#89b4fa"
|
||||
return "◌", th.Info
|
||||
case "exited", "dead":
|
||||
return "○", "#f38ba8"
|
||||
return "○", th.Danger
|
||||
default:
|
||||
return "○", "#6c7086"
|
||||
return "○", th.Overlay
|
||||
}
|
||||
}
|
||||
|
||||
// --- styling helpers ---
|
||||
// --- styling helpers (semua via token tema — F-asi §5.4) ---
|
||||
|
||||
func dim(s string) string {
|
||||
return lipgloss.NewStyle().Foreground(lipgloss.Color("#6c7086")).Render(s)
|
||||
return theme.Style(theme.Current().Subtext).Render(s)
|
||||
}
|
||||
|
||||
func text(s string) string {
|
||||
return lipgloss.NewStyle().Foreground(lipgloss.Color("#cdd6f4")).Render(s)
|
||||
return theme.Style(theme.Current().Text).Render(s)
|
||||
}
|
||||
|
||||
func red(s string) string {
|
||||
return lipgloss.NewStyle().Foreground(lipgloss.Color("#f38ba8")).Render(s)
|
||||
return theme.Style(theme.Current().Danger).Render(s)
|
||||
}
|
||||
|
||||
func styled(color, s string) string {
|
||||
return lipgloss.NewStyle().Foreground(lipgloss.Color(color)).Render(s)
|
||||
func styled(c theme.Color, s string) string {
|
||||
return theme.Style(c).Render(s)
|
||||
}
|
||||
|
||||
func truncate(s string, w int) string {
|
||||
@@ -339,11 +355,12 @@ func panel(title, meta string, lines []string, w, h int, focused bool) string {
|
||||
if w < 6 || h < 2 {
|
||||
return ""
|
||||
}
|
||||
bc := "#6c7086"
|
||||
th := theme.Current()
|
||||
bc := th.Overlay
|
||||
if focused {
|
||||
bc = "#cba6f7"
|
||||
bc = th.Accent
|
||||
}
|
||||
border := lipgloss.NewStyle().Foreground(lipgloss.Color(bc))
|
||||
border := lipgloss.NewStyle().Foreground(lipgloss.Color(string(bc)))
|
||||
titleS := text(title)
|
||||
|
||||
left := border.Render("╭─ ") + titleS
|
||||
@@ -382,8 +399,7 @@ func panel(title, meta string, lines []string, w, h int, focused bool) string {
|
||||
// --- views ---
|
||||
|
||||
func (m Model) View() tea.View {
|
||||
header := lipgloss.NewStyle().Bold(true).
|
||||
Foreground(lipgloss.Color("#cba6f7")).
|
||||
header := theme.Style(theme.Current().Accent).Bold(true).
|
||||
Render("tia — Terminal Is A My Way")
|
||||
|
||||
var body, footer string
|
||||
@@ -442,7 +458,7 @@ func (m Model) sidebarView() string {
|
||||
glyph, color := stateStyle(c.State)
|
||||
mark := " "
|
||||
if i == m.cursor {
|
||||
mark = styled("#cba6f7", "▶ ")
|
||||
mark = styled(theme.Current().Accent, "▶ ")
|
||||
}
|
||||
lines = append(lines, mark+styled(color, glyph)+" "+text(truncate(c.Name, innerW-4)))
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user