style: apply cyberpunk theme to TUI components for enhanced visual appeal

This commit is contained in:
taorye 2026-03-20 17:04:57 +08:00
parent 119cc2e8e1
commit 74a145c291
No known key found for this signature in database
GPG key ID: EDFFE0AD344F5FE0
5 changed files with 129 additions and 124 deletions

View file

@ -102,17 +102,23 @@ func (a *App) refreshModelCache(onDone func()) {
// New creates and wires up the TUI application. // New creates and wires up the TUI application.
func New(cfg *tuicfg.TUIConfig, configPath string) *App { func New(cfg *tuicfg.TUIConfig, configPath string) *App {
tview.Styles.PrimitiveBackgroundColor = tcell.ColorBlack // Cyberpunk Theme Colors
tview.Styles.ContrastBackgroundColor = tcell.ColorTeal // Dark background
tview.Styles.MoreContrastBackgroundColor = tcell.ColorLime tview.Styles.PrimitiveBackgroundColor = tcell.NewHexColor(0x050510) // Deep Void
tview.Styles.BorderColor = tcell.ColorDarkCyan tview.Styles.ContrastBackgroundColor = tcell.NewHexColor(0x1a1a2e) // Dark Indigo
tview.Styles.TitleColor = tcell.ColorAqua tview.Styles.MoreContrastBackgroundColor = tcell.NewHexColor(0x2a2a40)
tview.Styles.GraphicsColor = tcell.ColorDarkCyan
tview.Styles.PrimaryTextColor = tcell.ColorWhite // Borders and Titles
tview.Styles.SecondaryTextColor = tcell.ColorSilver tview.Styles.BorderColor = tcell.NewHexColor(0x00f0ff) // Neon Cyan
tview.Styles.TertiaryTextColor = tcell.ColorAqua tview.Styles.TitleColor = tcell.NewHexColor(0x00f0ff) // Neon Cyan
tview.Styles.InverseTextColor = tcell.ColorBlack tview.Styles.GraphicsColor = tcell.NewHexColor(0xff00ff) // Neon Magenta
tview.Styles.ContrastSecondaryTextColor = tcell.ColorNavy
// Text
tview.Styles.PrimaryTextColor = tcell.NewHexColor(0xe0e0e0) // Off-white
tview.Styles.SecondaryTextColor = tcell.NewHexColor(0x00f0ff) // Neon Cyan
tview.Styles.TertiaryTextColor = tcell.NewHexColor(0x39ff14) // Neon Lime
tview.Styles.InverseTextColor = tcell.NewHexColor(0x000000) // Black
tview.Styles.ContrastSecondaryTextColor = tcell.NewHexColor(0xff00ff) // Neon Magenta
a := &App{ a := &App{
tapp: tview.NewApplication(), tapp: tview.NewApplication(),
@ -127,7 +133,7 @@ func New(cfg *tuicfg.TUIConfig, configPath string) *App {
a.tapp.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { a.tapp.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyEscape { if event.Key() == tcell.KeyEscape {
if len(a.modalOpen) > 0 { if len(a.modalOpen) > 0 {
return nil return event
} }
return a.goBack() return a.goBack()
} }
@ -192,21 +198,22 @@ func (a *App) save() {
func (a *App) showError(msg string) { func (a *App) showError(msg string) {
modal := tview.NewModal(). modal := tview.NewModal().
SetText("Error: " + msg). SetText(" [red::b]ERROR[-::-]\n\n" + msg).
AddButtons([]string{"OK"}). AddButtons([]string{"OK"}).
SetDoneFunc(func(_ int, _ string) { SetDoneFunc(func(_ int, _ string) {
a.hideModal("error") a.hideModal("error")
}) })
modal.SetBackgroundColor(tcell.ColorNavy) // Cyberpunk Modal Style
modal.SetTextColor(tcell.ColorWhite) modal.SetBackgroundColor(tcell.NewHexColor(0x1a1a2e)) // Deep Indigo
modal.SetButtonBackgroundColor(tcell.ColorDarkCyan) modal.SetTextColor(tcell.NewHexColor(0xffffff)) // White
modal.SetButtonTextColor(tcell.ColorWhite) modal.SetButtonBackgroundColor(tcell.NewHexColor(0xff2a2a)) // Neon Red
modal.SetButtonTextColor(tcell.NewHexColor(0xffffff)) // White
a.showModal("error", modal) a.showModal("error", modal)
} }
func (a *App) confirmDelete(label string, onConfirm func()) { func (a *App) confirmDelete(label string, onConfirm func()) {
modal := tview.NewModal(). modal := tview.NewModal().
SetText("Delete " + label + "?\nThis cannot be undone."). SetText(" [red::b]DELETE WARNING[-::-]\n\nDelete " + label + "?\n[gray]This action cannot be undone.[-]").
AddButtons([]string{"Delete", "Cancel"}). AddButtons([]string{"Delete", "Cancel"}).
SetDoneFunc(func(_ int, buttonLabel string) { SetDoneFunc(func(_ int, buttonLabel string) {
a.hideModal("confirm-delete") a.hideModal("confirm-delete")
@ -214,10 +221,11 @@ func (a *App) confirmDelete(label string, onConfirm func()) {
onConfirm() onConfirm()
} }
}) })
modal.SetBackgroundColor(tcell.ColorNavy) // Cyberpunk Modal Style
modal.SetTextColor(tcell.ColorWhite) modal.SetBackgroundColor(tcell.NewHexColor(0x1a1a2e)) // Deep Indigo
modal.SetButtonBackgroundColor(tcell.ColorDarkCyan) modal.SetTextColor(tcell.NewHexColor(0xffffff)) // White
modal.SetButtonTextColor(tcell.ColorWhite) modal.SetButtonBackgroundColor(tcell.NewHexColor(0xff2a2a)) // Neon Red for danger
modal.SetButtonTextColor(tcell.NewHexColor(0xffffff)) // White
a.showModal("confirm-delete", modal) a.showModal("confirm-delete", modal)
} }
@ -234,9 +242,10 @@ func centeredForm(form *tview.Form, widthPct, height int) tview.Primitive {
func hintBar(text string) *tview.TextView { func hintBar(text string) *tview.TextView {
tv := tview.NewTextView(). tv := tview.NewTextView().
SetText(text). SetText(text).
SetDynamicColors(true).
SetTextAlign(tview.AlignCenter). SetTextAlign(tview.AlignCenter).
SetTextColor(tcell.ColorAqua) SetTextColor(tcell.NewHexColor(0x00f0ff)) // Neon Cyan
tv.SetBackgroundColor(tcell.ColorMidnightBlue) tv.SetBackgroundColor(tcell.NewHexColor(0x2a2a40)) // Darker Indigo
return tv return tv
} }
@ -246,21 +255,21 @@ func (a *App) buildShell(pageID string, content tview.Primitive, hint string) tv
if a.headerModelTV == nil { if a.headerModelTV == nil {
a.headerModelTV = tview.NewTextView() a.headerModelTV = tview.NewTextView()
a.headerModelTV.SetTextAlign(tview.AlignRight). a.headerModelTV.SetTextAlign(tview.AlignRight).
SetTextColor(tcell.ColorYellow). SetTextColor(tcell.NewHexColor(0x39ff14)). // Neon Lime
SetDynamicColors(true). SetDynamicColors(true).
SetBackgroundColor(tcell.ColorBlack) SetBackgroundColor(tcell.NewHexColor(0x050510))
} }
modelTV = a.headerModelTV modelTV = a.headerModelTV
modelTV.SetText(a.cfg.CurrentModelLabel() + " ") modelTV.SetText("MODEL: " + a.cfg.CurrentModelLabel() + " ")
} else { } else {
modelTV = tview.NewTextView() modelTV = tview.NewTextView()
modelTV.SetBackgroundColor(tcell.ColorBlack) modelTV.SetBackgroundColor(tcell.NewHexColor(0x050510))
} }
headerLeft := tview.NewTextView(). headerLeft := tview.NewTextView().
SetText(" ▓▓ PICOCLAW LAUNCHER ▓▓"). SetText(" [#ff00ff::b]///[#00f0ff] PICOCLAW LAUNCHER [#ff00ff]///").
SetTextColor(tcell.ColorAqua). SetDynamicColors(true).
SetBackgroundColor(tcell.ColorBlack) SetBackgroundColor(tcell.NewHexColor(0x050510))
header := tview.NewFlex(). header := tview.NewFlex().
AddItem(headerLeft, 0, 1, false). AddItem(headerLeft, 0, 1, false).
@ -269,44 +278,42 @@ func (a *App) buildShell(pageID string, content tview.Primitive, hint string) tv
sidebar := tview.NewTextView(). sidebar := tview.NewTextView().
SetDynamicColors(true). SetDynamicColors(true).
SetWrap(false) SetWrap(false)
sidebar.SetBackgroundColor(tcell.ColorNavy) sidebar.SetBackgroundColor(tcell.NewHexColor(0x1a1a2e)) // Deep Indigo
activeColor := "[lime]▶ " // Cyberpunk Sidebar Styling
inactiveColor := "[gray] " activePrefix := "[#39ff14::b]>> " // Neon Lime arrow
activeSuffix := "[-]"
inactivePrefix := "[#808080] "
inactiveSuffix := "[-]"
sbText := "\n" sbText := "\n\n" // Top padding
if pageID == "home" {
sbText += activeColor + "HOME[-]\n" menuItem := func(id, label string) string {
} else { if pageID == id {
sbText += inactiveColor + "HOME[-]\n" return activePrefix + label + activeSuffix + "\n\n"
} }
if pageID == "schemes" { return inactivePrefix + label + inactiveSuffix + "\n\n"
sbText += activeColor + "SCHEMES[-]\n"
} else {
sbText += inactiveColor + "SCHEMES[-]\n"
}
if pageID == "users" {
sbText += activeColor + "USERS[-]\n"
} else {
sbText += inactiveColor + "USERS[-]\n"
}
if pageID == "models" {
sbText += activeColor + "MODELS[-]\n"
} else {
sbText += inactiveColor + "MODELS[-]\n"
} }
sbText += menuItem("home", "HOME")
sbText += menuItem("schemes", "SCHEMES")
sbText += menuItem("users", "USERS")
sbText += menuItem("models", "MODELS")
sidebar.SetText(sbText) sidebar.SetText(sbText)
footer := hintBar(hint) footer := hintBar(hint)
grid := tview.NewGrid(). grid := tview.NewGrid().
SetRows(1, 0, 1). SetRows(1, 0, 1).
SetColumns(16, 0). SetColumns(20, 0). // Slightly wider sidebar
AddItem(header, 0, 0, 1, 2, 0, 0, false). AddItem(header, 0, 0, 1, 2, 0, 0, false).
AddItem(sidebar, 1, 0, 1, 1, 0, 0, false). AddItem(sidebar, 1, 0, 1, 1, 0, 0, false).
AddItem(content, 1, 1, 1, 1, 0, 0, true). AddItem(content, 1, 1, 1, 1, 0, 0, true).
AddItem(footer, 2, 0, 1, 2, 0, 0, false) AddItem(footer, 2, 0, 1, 2, 0, 0, false)
// Add a border around the content area if possible, or ensure content has its own border
// grid.SetBorders(false) // Grid borders usually look bad, handled by components
return grid return grid
} }

View file

@ -12,20 +12,20 @@ import (
func (a *App) newHomePage() tview.Primitive { func (a *App) newHomePage() tview.Primitive {
list := tview.NewList() list := tview.NewList()
list.SetBorder(true).SetTitle(" Active Configuration ").SetTitleColor(tcell.ColorAqua).SetBorderColor(tcell.ColorDarkCyan) list.SetBorder(true).SetTitle(" [#00f0ff::b] ACTIVE CONFIGURATION ").SetTitleColor(tcell.NewHexColor(0x00f0ff)).SetBorderColor(tcell.NewHexColor(0x00f0ff))
list.SetMainTextColor(tcell.ColorWhite) list.SetMainTextColor(tcell.NewHexColor(0xe0e0e0))
list.SetSecondaryTextColor(tcell.ColorDarkGray) list.SetSecondaryTextColor(tcell.NewHexColor(0x808080))
list.SetSelectedStyle(tcell.StyleDefault.Background(tcell.ColorTeal).Foreground(tcell.ColorWhite)) list.SetSelectedStyle(tcell.StyleDefault.Background(tcell.NewHexColor(0x39ff14)).Foreground(tcell.NewHexColor(0x050510)))
list.SetSelectedBackgroundColor(tcell.ColorTeal) list.SetHighlightFullLine(true)
list.SetSelectedTextColor(tcell.ColorWhite) list.SetBackgroundColor(tcell.NewHexColor(0x050510))
rebuildList := func() { rebuildList := func() {
sel := list.GetCurrentItem() sel := list.GetCurrentItem()
list.Clear() list.Clear()
list.AddItem("model: "+a.cfg.CurrentModelLabel(), "Enter to configure", 'm', func() { list.AddItem("MODEL: "+a.cfg.CurrentModelLabel(), "Select to configure AI model", 'm', func() {
a.navigateTo("schemes", a.newSchemesPage()) a.navigateTo("schemes", a.newSchemesPage())
}) })
list.AddItem("Quit", "", 'q', func() { a.tapp.Stop() }) list.AddItem("QUIT SYSTEM", "Exit PicoClaw Launcher", 'q', func() { a.tapp.Stop() })
if sel >= 0 && sel < list.GetItemCount() { if sel >= 0 && sel < list.GetItemCount() {
list.SetCurrentItem(sel) list.SetCurrentItem(sel)
} }
@ -34,5 +34,5 @@ func (a *App) newHomePage() tview.Primitive {
a.pageRefreshFns["home"] = rebuildList a.pageRefreshFns["home"] = rebuildList
return a.buildShell("home", list, " m: configure model q: quit ") return a.buildShell("home", list, " [#00f0ff]m:[-] configure model [#ff2a2a]q:[-] quit ")
} }

View file

@ -33,17 +33,17 @@ func (a *App) newModelsPage(schemeName, userName, baseURL string) tview.Primitiv
SetBorders(false). SetBorders(false).
SetSelectable(true, false). SetSelectable(true, false).
SetFixed(0, 0) SetFixed(0, 0)
table.SetBorder(true).SetTitle(fmt.Sprintf(" Models · %s / %s ", schemeName, userName)) table.SetBorder(true).SetTitle(fmt.Sprintf(" [#00f0ff::b] MODELS · %s / %s ", schemeName, userName)).SetTitleColor(tcell.NewHexColor(0x00f0ff)).SetBorderColor(tcell.NewHexColor(0x00f0ff))
table.SetTitleColor(tcell.ColorAqua).SetBorderColor(tcell.ColorDarkCyan) table.SetSelectedStyle(tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0xffffff)))
table.SetSelectedStyle(tcell.StyleDefault.Background(tcell.ColorTeal).Foreground(tcell.ColorWhite)) table.SetBackgroundColor(tcell.NewHexColor(0x050510))
var modelIDs []string var modelIDs []string
status := tview.NewTextView(). status := tview.NewTextView().
SetTextAlign(tview.AlignCenter). SetTextAlign(tview.AlignCenter).
SetDynamicColors(true). SetDynamicColors(true).
SetText("[yellow]Fetching models…[-]") SetText("[#ffff00]FETCHING MODELS...[-]")
status.SetBackgroundColor(tcell.ColorBlack) status.SetBackgroundColor(tcell.NewHexColor(0x050510))
flex := tview.NewFlex(). flex := tview.NewFlex().
SetDirection(tview.FlexRow). SetDirection(tview.FlexRow).
@ -74,32 +74,32 @@ func (a *App) newModelsPage(schemeName, userName, baseURL string) tview.Primitiv
a.tapp.QueueUpdateDraw(func() { a.tapp.QueueUpdateDraw(func() {
if err != nil { if err != nil {
status.SetText(fmt.Sprintf("[red]Error: %s[-]", err.Error())) status.SetText(fmt.Sprintf("[#ff2a2a]ERROR: %s[-]", err.Error()))
table.SetCell(0, 0, tview.NewTableCell("(failed to load models)")) table.SetCell(0, 0, tview.NewTableCell(" (failed to load models)"))
a.tapp.SetFocus(table) a.tapp.SetFocus(table)
return return
} }
if len(entries) == 0 { if len(entries) == 0 {
status.SetText("[yellow]No models returned[-]") status.SetText("[#ff2a2a]NO MODELS RETURNED[-]")
table.SetCell(0, 0, tview.NewTableCell("(no models available)")) table.SetCell(0, 0, tview.NewTableCell(" (no models available)"))
a.tapp.SetFocus(table) a.tapp.SetFocus(table)
return return
} }
status.SetText(fmt.Sprintf("[lime]%d model(s) loaded[-]", len(entries))) status.SetText(fmt.Sprintf("[#39ff14]%d MODEL(S) LOADED[-]", len(entries)))
for i, m := range entries { for i, m := range entries {
modelIDs = append(modelIDs, m.ID) modelIDs = append(modelIDs, m.ID)
table.SetCell(i, 0, table.SetCell(i, 0,
tview.NewTableCell(fmt.Sprintf("%3d", i+1)). tview.NewTableCell(fmt.Sprintf("%3d", i+1)).
SetAlign(tview.AlignRight). SetAlign(tview.AlignRight).
SetTextColor(tcell.ColorGray). SetTextColor(tcell.NewHexColor(0x808080)).
SetSelectable(false), SetSelectable(false),
) )
table.SetCell(i, 1, table.SetCell(i, 1,
tview.NewTableCell(" "+m.ID). tview.NewTableCell(" "+m.ID).
SetAlign(tview.AlignLeft). SetAlign(tview.AlignLeft).
SetExpansion(1). SetExpansion(1).
SetTextColor(tcell.ColorWhite), SetTextColor(tcell.NewHexColor(0xe0e0e0)),
) )
} }
a.tapp.SetFocus(table) a.tapp.SetFocus(table)
@ -119,7 +119,7 @@ func (a *App) newModelsPage(schemeName, userName, baseURL string) tview.Primitiv
a.goBack() a.goBack()
}) })
return a.buildShell("models", flex, " Enter: select ESC: back ") return a.buildShell("models", flex, " [#39ff14]Enter:[-] select [#ff00ff]ESC:[-] back ")
} }
func (a *App) resolveKey(schemeName, userName string) string { func (a *App) resolveKey(schemeName, userName string) string {

View file

@ -17,9 +17,9 @@ func (a *App) newSchemesPage() tview.Primitive {
table := tview.NewTable(). table := tview.NewTable().
SetBorders(false). SetBorders(false).
SetSelectable(true, false) SetSelectable(true, false)
table.SetBorder(true).SetTitle(" Provider Schemes ") table.SetBorder(true).SetTitle(" [#00f0ff::b] PROVIDER SCHEMES ").SetTitleColor(tcell.NewHexColor(0x00f0ff)).SetBorderColor(tcell.NewHexColor(0x00f0ff))
table.SetTitleColor(tcell.ColorAqua).SetBorderColor(tcell.ColorDarkCyan) table.SetSelectedStyle(tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0xffffff)))
table.SetSelectedStyle(tcell.StyleDefault.Background(tcell.ColorTeal).Foreground(tcell.ColorWhite)) table.SetBackgroundColor(tcell.NewHexColor(0x050510))
rowToIdx := func(row int) int { return row / 2 } rowToIdx := func(row int) int { return row / 2 }
@ -43,7 +43,7 @@ func (a *App) newSchemesPage() tview.Primitive {
table.SetCell(nameRow, 0, table.SetCell(nameRow, 0,
tview.NewTableCell(" "+s.Name). tview.NewTableCell(" "+s.Name).
SetTextColor(tcell.ColorWhite). SetTextColor(tcell.NewHexColor(0xe0e0e0)).
SetExpansion(1). SetExpansion(1).
SetSelectable(true), SetSelectable(true),
) )
@ -57,14 +57,13 @@ func (a *App) newSchemesPage() tview.Primitive {
} }
} }
table.SetCell(detailRow, 0, table.SetCell(detailRow, 0,
tview.NewTableCell(fmt.Sprintf(" (%d/%d)%s", m, n, s.BaseURL)). tview.NewTableCell(fmt.Sprintf(" [#808080](%d/%d) %s", m, n, s.BaseURL)).
SetTextColor(tcell.ColorDarkGray). SetTextColor(tcell.NewHexColor(0x808080)).
SetExpansion(1). SetExpansion(1).
SetSelectable(false), SetSelectable(false),
) )
table.SetCell(detailRow, 1, table.SetCell(detailRow, 1,
tview.NewTableCell(s.Type+" "). tview.NewTableCell("[#00f0ff]"+s.Type+" ").
SetTextColor(tcell.ColorDarkGray).
SetAlign(tview.AlignRight). SetAlign(tview.AlignRight).
SetSelectable(false), SetSelectable(false),
) )
@ -166,20 +165,20 @@ func (a *App) newSchemesPage() tview.Primitive {
return event return event
}) })
return a.buildShell("schemes", table, " a: add e: edit d: delete Enter: open ESC: back ") return a.buildShell("schemes", table, " [#00f0ff]a:[-] add [#00f0ff]e:[-] edit [#ff2a2a]d:[-] delete [#39ff14]Enter:[-] open [#ff00ff]ESC:[-] back ")
} }
func (a *App) showSchemeForm(existing *tuicfg.Scheme, onSave func(tuicfg.Scheme)) { func (a *App) showSchemeForm(existing *tuicfg.Scheme, onSave func(tuicfg.Scheme)) {
name := "" name := ""
baseURL := "" baseURL := ""
schemeType := "openai-compatible" schemeType := "openai-compatible"
title := " Add Scheme " title := " ADD SCHEME "
if existing != nil { if existing != nil {
name = existing.Name name = existing.Name
baseURL = existing.BaseURL baseURL = existing.BaseURL
schemeType = existing.Type schemeType = existing.Type
title = " Edit Scheme " title = " EDIT SCHEME "
} }
typeOptions := []string{"openai-compatible", "anthropic"} typeOptions := []string{"openai-compatible", "anthropic"}
@ -194,10 +193,10 @@ func (a *App) showSchemeForm(existing *tuicfg.Scheme, onSave func(tuicfg.Scheme)
form := tview.NewForm() form := tview.NewForm()
form. form.
AddInputField("Name", name, 32, nil, func(text string) { name = text }). AddInputField("Name", name, 20, nil, func(text string) { name = text }).
AddInputField("Base URL", baseURL, 32, nil, func(text string) { baseURL = text }). AddInputField("Base URL", baseURL, 28, nil, func(text string) { baseURL = text }).
AddDropDown("Type", typeOptions, typeIdx, func(option string, _ int) { schemeType = option }). AddDropDown("Type", typeOptions, typeIdx, func(option string, _ int) { schemeType = option }).
AddButton("Save", func() { AddButton("SAVE", func() {
if name == "" { if name == "" {
a.showError("Name is required") a.showError("Name is required")
return return
@ -217,17 +216,17 @@ func (a *App) showSchemeForm(existing *tuicfg.Scheme, onSave func(tuicfg.Scheme)
a.hideModal("scheme-form") a.hideModal("scheme-form")
onSave(tuicfg.Scheme{Name: name, BaseURL: baseURL, Type: schemeType}) onSave(tuicfg.Scheme{Name: name, BaseURL: baseURL, Type: schemeType})
}). }).
AddButton("Cancel", func() { AddButton("CANCEL", func() {
a.hideModal("scheme-form") a.hideModal("scheme-form")
}) })
form.SetBorder(true).SetTitle(title).SetTitleColor(tcell.ColorLime) form.SetBorder(true).SetTitle(" [::b]" + title + " ").SetTitleColor(tcell.NewHexColor(0x39ff14)).SetBorderColor(tcell.NewHexColor(0x00f0ff))
form.SetBorderColor(tcell.ColorDarkCyan) form.SetBackgroundColor(tcell.NewHexColor(0x1a1a2e))
form.SetFieldBackgroundColor(tcell.ColorBlack) form.SetFieldBackgroundColor(tcell.NewHexColor(0x050510))
form.SetFieldTextColor(tcell.ColorWhite) form.SetFieldTextColor(tcell.NewHexColor(0x00f0ff))
form.SetLabelColor(tcell.ColorAqua) form.SetLabelColor(tcell.NewHexColor(0xe0e0e0))
form.SetButtonBackgroundColor(tcell.ColorDarkCyan) form.SetButtonBackgroundColor(tcell.NewHexColor(0xff00ff))
form.SetButtonTextColor(tcell.ColorWhite) form.SetButtonTextColor(tcell.NewHexColor(0xffffff))
form.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { form.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyEscape { if event.Key() == tcell.KeyEscape {
a.hideModal("scheme-form") a.hideModal("scheme-form")
@ -236,5 +235,5 @@ func (a *App) showSchemeForm(existing *tuicfg.Scheme, onSave func(tuicfg.Scheme)
return event return event
}) })
a.showModal("scheme-form", centeredForm(form, 6, 12)) a.showModal("scheme-form", centeredForm(form, 4, 12))
} }

View file

@ -17,9 +17,9 @@ func (a *App) newUsersPage(schemeName string) tview.Primitive {
table := tview.NewTable(). table := tview.NewTable().
SetBorders(false). SetBorders(false).
SetSelectable(true, false) SetSelectable(true, false)
table.SetBorder(true).SetTitle(fmt.Sprintf(" Users · %s ", schemeName)) table.SetBorder(true).SetTitle(fmt.Sprintf(" [#00f0ff::b] USERS · %s ", schemeName)).SetTitleColor(tcell.NewHexColor(0x00f0ff)).SetBorderColor(tcell.NewHexColor(0x00f0ff))
table.SetTitleColor(tcell.ColorAqua).SetBorderColor(tcell.ColorDarkCyan) table.SetSelectedStyle(tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0xffffff)))
table.SetSelectedStyle(tcell.StyleDefault.Background(tcell.ColorTeal).Foreground(tcell.ColorWhite)) table.SetBackgroundColor(tcell.NewHexColor(0x050510))
visibleUsers := func() []tuicfg.User { visibleUsers := func() []tuicfg.User {
var out []tuicfg.User var out []tuicfg.User
@ -62,7 +62,7 @@ func (a *App) newUsersPage(schemeName string) tview.Primitive {
table.SetCell(nameRow, 0, table.SetCell(nameRow, 0,
tview.NewTableCell(" "+u.Name). tview.NewTableCell(" "+u.Name).
SetTextColor(tcell.ColorWhite). SetTextColor(tcell.NewHexColor(0xe0e0e0)).
SetExpansion(1). SetExpansion(1).
SetSelectable(true), SetSelectable(true),
) )
@ -74,19 +74,18 @@ func (a *App) newUsersPage(schemeName string) tview.Primitive {
models := a.cachedModels(schemeName, u.Name) models := a.cachedModels(schemeName, u.Name)
var detailText string var detailText string
if len(models) > 0 { if len(models) > 0 {
detailText = fmt.Sprintf(" %d models", len(models)) detailText = fmt.Sprintf(" [#39ff14]%d models available[-]", len(models))
} else { } else {
detailText = " [red]Inactive[-]" detailText = " [#ff2a2a]Inactive / No Access[-]"
} }
table.SetCell(detailRow, 0, table.SetCell(detailRow, 0,
tview.NewTableCell(detailText). tview.NewTableCell(detailText).
SetTextColor(tcell.ColorDarkGray). SetTextColor(tcell.NewHexColor(0x808080)).
SetExpansion(1). SetExpansion(1).
SetSelectable(false), SetSelectable(false),
) )
table.SetCell(detailRow, 1, table.SetCell(detailRow, 1,
tview.NewTableCell(u.Type+" "). tview.NewTableCell("[#00f0ff]"+u.Type+" ").
SetTextColor(tcell.ColorDarkGray).
SetAlign(tview.AlignRight). SetAlign(tview.AlignRight).
SetSelectable(false), SetSelectable(false),
) )
@ -180,20 +179,20 @@ func (a *App) newUsersPage(schemeName string) tview.Primitive {
return event return event
}) })
return a.buildShell("users", table, " a: add e: edit d: delete Enter: models ESC: back ") return a.buildShell("users", table, " [#00f0ff]a:[-] add [#00f0ff]e:[-] edit [#ff2a2a]d:[-] delete [#39ff14]Enter:[-] models [#ff00ff]ESC:[-] back ")
} }
func (a *App) showUserForm(schemeName string, existing *tuicfg.User, onSave func(tuicfg.User)) { func (a *App) showUserForm(schemeName string, existing *tuicfg.User, onSave func(tuicfg.User)) {
name := "" name := ""
userType := "key" userType := "key"
key := "" key := ""
title := " Add User " title := " ADD USER "
if existing != nil { if existing != nil {
name = existing.Name name = existing.Name
userType = existing.Type userType = existing.Type
key = existing.Key key = existing.Key
title = " Edit User " title = " EDIT USER "
} }
typeOptions := []string{"key", "OAuth"} typeOptions := []string{"key", "OAuth"}
@ -207,10 +206,10 @@ func (a *App) showUserForm(schemeName string, existing *tuicfg.User, onSave func
form := tview.NewForm() form := tview.NewForm()
form. form.
AddInputField("Name", name, 32, nil, func(text string) { name = text }). AddInputField("Name", name, 20, nil, func(text string) { name = text }).
AddDropDown("Type", typeOptions, typeIdx, func(option string, _ int) { userType = option }). AddDropDown("Type", typeOptions, typeIdx, func(option string, _ int) { userType = option }).
AddPasswordField("Key", key, 32, '*', func(text string) { key = text }). AddPasswordField("Key", key, 28, '*', func(text string) { key = text }).
AddButton("Save", func() { AddButton("SAVE", func() {
if name == "" { if name == "" {
a.showError("Name is required") a.showError("Name is required")
return return
@ -226,17 +225,17 @@ func (a *App) showUserForm(schemeName string, existing *tuicfg.User, onSave func
a.hideModal("user-form") a.hideModal("user-form")
onSave(tuicfg.User{Name: name, Scheme: schemeName, Type: userType, Key: key}) onSave(tuicfg.User{Name: name, Scheme: schemeName, Type: userType, Key: key})
}). }).
AddButton("Cancel", func() { AddButton("CANCEL", func() {
a.hideModal("user-form") a.hideModal("user-form")
}) })
form.SetBorder(true).SetTitle(title).SetTitleColor(tcell.ColorLime) form.SetBorder(true).SetTitle(" [::b]" + title + " ").SetTitleColor(tcell.NewHexColor(0x39ff14)).SetBorderColor(tcell.NewHexColor(0x00f0ff))
form.SetBorderColor(tcell.ColorDarkCyan) form.SetBackgroundColor(tcell.NewHexColor(0x1a1a2e))
form.SetFieldBackgroundColor(tcell.ColorBlack) form.SetFieldBackgroundColor(tcell.NewHexColor(0x050510))
form.SetFieldTextColor(tcell.ColorWhite) form.SetFieldTextColor(tcell.NewHexColor(0x00f0ff))
form.SetLabelColor(tcell.ColorAqua) form.SetLabelColor(tcell.NewHexColor(0xe0e0e0))
form.SetButtonBackgroundColor(tcell.ColorDarkCyan) form.SetButtonBackgroundColor(tcell.NewHexColor(0xff00ff))
form.SetButtonTextColor(tcell.ColorWhite) form.SetButtonTextColor(tcell.NewHexColor(0xffffff))
form.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { form.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyEscape { if event.Key() == tcell.KeyEscape {
a.hideModal("user-form") a.hideModal("user-form")
@ -245,5 +244,5 @@ func (a *App) showUserForm(schemeName string, existing *tuicfg.User, onSave func
return event return event
}) })
a.showModal("user-form", centeredForm(form, 6, 13)) a.showModal("user-form", centeredForm(form, 4, 13))
} }