Files
TUIkit/Sources/TUIkitExample/Pages/MainMenuPage.swift
T
phranck dec8c7c29f Feat: Add Spinner view with dots, line, and bouncing styles
Auto-animating loading indicator with three visual styles:
- Dots (braille rotation), Line (ASCII rotation), Bouncing (Larson scanner
  with fade trail). Time-based frame calculation ensures each spinner runs
  at its own speed independent of render triggers.

Configurable: SpinnerSpeed (.slow/.regular/.fast), BouncingTrackWidth
(.minimum/.default/.maximum/.fixed(Int)), BouncingTrailLength
(.short/.regular/.long), custom color.

Run loop upgraded from 100ms to 40ms polling (~25 FPS) to support
smooth animations.
2026-02-02 19:57:58 +01:00

86 lines
2.8 KiB
Swift

//
// MainMenuPage.swift
// TUIkitExample
//
// The main menu page with navigation to all demos.
//
import TUIkit
/// The main menu page.
///
/// Displays a centered menu with all available demos and
/// feature highlight boxes at the bottom.
struct MainMenuPage: View {
@Binding var currentPage: DemoPage
@Binding var menuSelection: Int
var body: some View {
VStack(spacing: 1) {
HeaderView(
title: "TUIkit Example App",
subtitle: "A SwiftUI-like framework for Terminal User Interfaces"
)
Spacer(minLength: 1)
HStack {
Spacer()
Menu(
title: "Select a Demo",
items: [
MenuItem(label: "Text Styles", shortcut: "1"),
MenuItem(label: "Colors", shortcut: "2"),
MenuItem(label: "Container Views", shortcut: "3"),
MenuItem(label: "Overlays & Modals", shortcut: "4"),
MenuItem(label: "Layout System", shortcut: "5"),
MenuItem(label: "Buttons & Focus", shortcut: "6"),
MenuItem(label: "Spinners", shortcut: "7"),
],
selection: $menuSelection,
onSelect: { index in
// Navigate to the selected page
if let page = DemoPage(rawValue: index + 1) {
currentPage = page
}
},
selectedColor: .palette.accent,
// borderStyle uses appearance default
borderColor: .palette.border
)
Spacer()
}
Spacer(minLength: 1)
// Feature highlights (centered)
HStack {
Spacer()
HStack(spacing: 3) {
featureBox("Pure Swift", "No ncurses")
featureBox("Declarative", "SwiftUI-like")
featureBox("Composable", "View protocol")
}
Spacer()
}
Spacer()
}
}
/// Creates a small feature highlight box.
///
/// The border style is automatically derived from the current appearance.
private func featureBox(_ title: String, _ subtitle: String) -> some View {
VStack {
Text(title)
.bold()
.foregroundColor(.palette.accent)
Text(subtitle)
.foregroundColor(.palette.foregroundSecondary)
}
.padding(EdgeInsets(horizontal: 2, vertical: 1))
.border(color: .palette.border) // Uses appearance default borderStyle
}
}