205 lines
5.5 KiB
Go
205 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
// ============================================================================
|
|
// STYLING DEFINITIONS (Lipgloss)
|
|
// ============================================================================
|
|
var (
|
|
// Colors
|
|
skyBlue = lipgloss.Color("117")
|
|
neonPink = lipgloss.Color("205")
|
|
moneyGreen = lipgloss.Color("85")
|
|
gray = lipgloss.Color("240")
|
|
|
|
// Component Styles
|
|
titleStyle = lipgloss.NewStyle().
|
|
Foreground(skyBlue).
|
|
Bold(true).
|
|
MarginTop(1).
|
|
MarginBottom(1)
|
|
|
|
headerBoxStyle = lipgloss.NewStyle().
|
|
Border(lipgloss.RoundedBorder()).
|
|
BorderForeground(skyBlue).
|
|
Padding(0, 2).
|
|
MarginBottom(1)
|
|
|
|
listStyle = lipgloss.NewStyle().MarginLeft(2)
|
|
|
|
itemStyle = lipgloss.NewStyle().
|
|
PaddingLeft(2).
|
|
Foreground(lipgloss.Color("252"))
|
|
|
|
selectedItemStyle = lipgloss.NewStyle().
|
|
PaddingLeft(2).
|
|
Foreground(neonPink).
|
|
Bold(true).
|
|
Background(lipgloss.Color("236")) // Slight background highlight
|
|
|
|
footerStyle = lipgloss.NewStyle().
|
|
Foreground(gray).
|
|
MarginTop(2)
|
|
)
|
|
|
|
// ============================================================================
|
|
// 1. THE MODEL
|
|
// ============================================================================
|
|
type homepageModel struct {
|
|
cursor int
|
|
choices []string
|
|
selected string
|
|
|
|
// Mock Player Data (In a real app, pass this in via initialModel)
|
|
playerName string
|
|
cash int
|
|
fleetCount int
|
|
}
|
|
|
|
func initialHomepageModel() homepageModel {
|
|
return homepageModel{
|
|
// Our interactive menu options
|
|
choices: []string{
|
|
"🗄️ Manage Hangar Fleet",
|
|
"🏢 View Airport Infrastructure",
|
|
"🏁 Active Runways & Service Loop",
|
|
"🚪 Logout / Quit",
|
|
},
|
|
playerName: "CaptainGo",
|
|
cash: 14500,
|
|
fleetCount: 12,
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// 2. THE INIT FUNCTION
|
|
// ============================================================================
|
|
func (m homepageModel) Init() tea.Cmd {
|
|
return nil // No background tasks to start immediately
|
|
}
|
|
|
|
// ============================================================================
|
|
// 3. THE UPDATE FUNCTION (Handles inputs)
|
|
// ============================================================================
|
|
func (m homepageModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
|
|
// Handle keyboard events
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
|
|
// Quit commands
|
|
case "ctrl+c", "q", "esc":
|
|
m.selected = "quit"
|
|
return m, tea.Quit
|
|
|
|
// Move up the menu
|
|
case "up", "k":
|
|
if m.cursor > 0 {
|
|
m.cursor--
|
|
} else {
|
|
m.cursor = len(m.choices) - 1 // Wrap around to bottom
|
|
}
|
|
|
|
// Move down the menu
|
|
case "down", "j":
|
|
if m.cursor < len(m.choices)-1 {
|
|
m.cursor++
|
|
} else {
|
|
m.cursor = 0 // Wrap around to top
|
|
}
|
|
|
|
// Select an option
|
|
case "enter", " ":
|
|
m.selected = m.choices[m.cursor]
|
|
return m, tea.Quit
|
|
}
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
// ============================================================================
|
|
// 4. THE VIEW FUNCTION (Renders the UI)
|
|
// ============================================================================
|
|
func (m homepageModel) View() string {
|
|
var b strings.Builder
|
|
|
|
// --- 1. TITLE ---
|
|
b.WriteString(titleStyle.Render("✈️ SKYRAMA COMMAND CENTER"))
|
|
b.WriteString("\n")
|
|
|
|
// --- 2. HEADER BAR (Player Stats) ---
|
|
statsLine := fmt.Sprintf("[ 🔑 Player: %s ] [ 💰 Cash: %s ] [ 🛩️ Fleet: %d ]",
|
|
lipgloss.NewStyle().Foreground(lipgloss.Color("252")).Bold(true).Render(m.playerName),
|
|
lipgloss.NewStyle().Foreground(moneyGreen).Render(fmt.Sprintf("%d €", m.cash)),
|
|
m.fleetCount,
|
|
)
|
|
b.WriteString(headerBoxStyle.Render(statsLine))
|
|
b.WriteString("\n\n")
|
|
|
|
// --- 3. INTERACTIVE MENU ---
|
|
b.WriteString(" Main Operations Menu:\n\n")
|
|
|
|
for i, choice := range m.choices {
|
|
// Is the cursor pointing at this choice?
|
|
cursorStr := " " // no cursor
|
|
if m.cursor == i {
|
|
cursorStr = lipgloss.NewStyle().Foreground(neonPink).Render(">")
|
|
b.WriteString(fmt.Sprintf("%s %s\n", cursorStr, selectedItemStyle.Render(choice)))
|
|
} else {
|
|
b.WriteString(fmt.Sprintf("%s %s\n", cursorStr, itemStyle.Render(choice)))
|
|
}
|
|
}
|
|
|
|
// --- 4. FOOTER ---
|
|
b.WriteString(footerStyle.Render("\n ↑/↓: Navigate • Enter: Select • q/esc: Quit"))
|
|
|
|
// Return the final drawn screen with a little left margin padding
|
|
return lipgloss.NewStyle().MarginLeft(2).Render(b.String()) + "\n"
|
|
}
|
|
|
|
// ============================================================================
|
|
// THE WRAPPER FUNCTION
|
|
// ============================================================================
|
|
// RunHomepageScreen starts the TUI and returns the menu string the user selected.
|
|
func RunHomepageScreen() string {
|
|
p := tea.NewProgram(initialHomepageModel(), tea.WithAltScreen()) // AltScreen creates a full-screen view
|
|
|
|
finalModel, err := p.Run()
|
|
if err != nil {
|
|
fmt.Printf("Error running dashboard: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if m, ok := finalModel.(homepageModel); ok {
|
|
return m.selected
|
|
}
|
|
|
|
return "quit"
|
|
}
|
|
|
|
/*
|
|
// Optional Main function to test it directly
|
|
func main() {
|
|
selection := RunHomepageScreen()
|
|
|
|
// Clear the screen on exit to print standard output
|
|
fmt.Print("\033[H\033[2J")
|
|
|
|
if selection == "quit" || selection == "🚪 Logout / Quit" {
|
|
fmt.Println("Gracefully disconnected from SkyRama servers. Goodbye!")
|
|
os.Exit(0)
|
|
}
|
|
|
|
fmt.Printf("You selected: %s\n", selection)
|
|
fmt.Println("Here is where you would load the next Bubble Tea model for that screen!")
|
|
}
|
|
*/
|