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!") } */