Standardize TUI formatting and styling across all screens

This commit is contained in:
Calmcacil
2026-01-12 23:41:07 +01:00
parent 0476f1e227
commit f154c7ff69
8 changed files with 159 additions and 152 deletions

View File

@@ -3,6 +3,7 @@ package components
import (
"fmt"
"github.com/calmcacil/wg-admin/internal/tui/theme"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
@@ -18,37 +19,12 @@ type DeleteConfirmModel struct {
showErrorMessage bool
}
// Styles
// Local styles for modal
var (
deleteModalStyle = lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("196")).
Padding(1, 3).
Background(lipgloss.Color("235"))
deleteTitleStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("226")).
Bold(true)
deleteMessageStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("255")).
Width(60)
deleteWarningStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("196")).
Bold(true).
MarginTop(1)
deleteInputStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("255")).
Width(60)
deleteHelpStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("241")).
MarginTop(1)
deleteErrorStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("196")).
Bold(true).
MarginTop(1)
deleteSuccessStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("46")).
Bold(true).
MarginTop(1)
modalBaseStyle = lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("196")).Background(lipgloss.Color("235"))
modalTitleStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("226")).Bold(true)
modalMessageStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("255"))
modalHelpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241"))
)
// NewDeleteConfirm creates a new deletion confirmation modal
@@ -108,12 +84,12 @@ func (m *DeleteConfirmModel) View() string {
matches := m.input.Value() == m.clientName
// Build warning section
warningText := deleteWarningStyle.Render(
warningText := theme.StyleError.Bold(true).MarginTop(1).Render(
fmt.Sprintf("⚠️ This will permanently delete client '%s'", m.clientName),
)
// Build message section
messageText := deleteMessageStyle.Render(
messageText := modalMessageStyle.Width(60).Render(
fmt.Sprintf("This action cannot be undone. Please type the client name to confirm deletion."),
)
@@ -121,29 +97,29 @@ func (m *DeleteConfirmModel) View() string {
inputSection := lipgloss.JoinVertical(
lipgloss.Left,
"",
deleteInputStyle.Render("Client name:"),
theme.StyleValue.Width(60).Render("Client name:"),
m.input.View(),
)
// Build status section
var statusText string
if matches {
statusText = deleteSuccessStyle.Render("✓ Client name matches. Press Enter to confirm deletion.")
statusText = theme.StyleSuccess.Bold(true).MarginTop(1).Render("✓ Client name matches. Press Enter to confirm deletion.")
} else if m.showErrorMessage {
statusText = deleteErrorStyle.Render("✗ Client name does not match. Please try again.")
statusText = theme.StyleError.Bold(true).MarginTop(1).Render("✗ Client name does not match. Please try again.")
} else if m.input.Value() != "" {
statusText = deleteHelpStyle.Render("Client name does not match yet...")
statusText = modalHelpStyle.Render("Client name does not match yet...")
} else {
statusText = deleteHelpStyle.Render("Type the client name to enable confirmation.")
statusText = modalHelpStyle.Render("Type the client name to enable confirmation.")
}
// Build help section
helpText := deleteHelpStyle.Render("Esc to cancel • Enter to confirm (when name matches)")
helpText := modalHelpStyle.Render("Esc to cancel • Enter to confirm (when name matches)")
// Build modal content
content := lipgloss.JoinVertical(
lipgloss.Left,
deleteTitleStyle.Render("🗑️ Delete Client"),
modalTitleStyle.Render("🗑️ Delete Client"),
"",
warningText,
"",
@@ -155,7 +131,7 @@ func (m *DeleteConfirmModel) View() string {
)
// Apply modal style
modal := deleteModalStyle.Render(content)
modal := modalBaseStyle.Padding(1, 3).Render(content)
// Center modal on screen
modalWidth := lipgloss.Width(modal)
@@ -174,7 +150,7 @@ func (m *DeleteConfirmModel) View() string {
lipgloss.Left, lipgloss.Top,
modal,
lipgloss.WithWhitespaceChars(" "),
lipgloss.WithWhitespaceForeground(lipgloss.Color("235")),
lipgloss.WithWhitespaceForeground(theme.StyleBackground),
)
}

View File

@@ -1,6 +1,7 @@
package components
import (
"github.com/calmcacil/wg-admin/internal/tui/theme"
"strconv"
"strings"
@@ -30,22 +31,24 @@ type SearchModel struct {
}
// Styles
// Styles (using theme package)
var (
searchBarStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("255")).
Background(lipgloss.Color("235")).
Padding(0, 1).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("240"))
Foreground(lipgloss.Color("255")).
Background(theme.StyleBackground).
Padding(0, 1).
Border(lipgloss.RoundedBorder()).
BorderForeground(theme.StyleBorder)
searchPromptStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("226")).
Bold(true)
Foreground(lipgloss.Color("226")).
Bold(true)
searchFilterStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("147"))
Foreground(lipgloss.Color("147"))
searchCountStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("241"))
Foreground(lipgloss.Color("241"))
searchHelpStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("243"))
Foreground(lipgloss.Color("243"))
)
// NewSearch creates a new search component