mirror of
https://github.com/phranck/TUIkit.git
synced 2026-05-21 09:50:35 +00:00
84fdb7ace2
- TableColumn: Column definition with title, alignment, width modes - Key path and closure-based value extraction - Width modes: .fixed(Int), .flexible, .ratio(Double) - Alignment: .leading, .center, .trailing - Chainable modifiers: .alignment(), .width() - Table: SwiftUI-compatible table with column headers - Single selection: Table(data, selection: Binding<ID?>) - Multi-selection: Table(data, selection: Binding<Set<ID>>) - Reuses ItemListHandler for navigation/selection - ANSI-aware column alignment - Header row with column titles - Space-only separators (no vertical lines) - Scroll indicators when content overflows - Empty state placeholder - .disabled() modifier support - TableColumnBuilder: Result builder for column DSL - TablePage: Example with file browser style demo - 21 new tests for Table and TableColumn Completes Phase 2 of List & Table plan.
125 lines
4.3 KiB
Swift
125 lines
4.3 KiB
Swift
// 🖥️ TUIKit — Terminal UI Kit for Swift
|
||
// ListPage.swift
|
||
//
|
||
// Created by LAYERED.work
|
||
// License: MIT
|
||
|
||
import TUIkit
|
||
|
||
// MARK: - Demo Item
|
||
|
||
/// A simple item for list demos.
|
||
private struct FileItem: Identifiable {
|
||
let id: String
|
||
let name: String
|
||
let size: String
|
||
let icon: String
|
||
|
||
static let sampleFiles: [Self] = [
|
||
Self(id: "1", name: "README.md", size: "4.2 KB", icon: "📄"),
|
||
Self(id: "2", name: "Package.swift", size: "1.8 KB", icon: "📦"),
|
||
Self(id: "3", name: "Sources", size: "128 KB", icon: "📁"),
|
||
Self(id: "4", name: "Tests", size: "64 KB", icon: "📁"),
|
||
Self(id: "5", name: ".gitignore", size: "0.5 KB", icon: "📄"),
|
||
Self(id: "6", name: "LICENSE", size: "1.1 KB", icon: "📄"),
|
||
Self(id: "7", name: "docs", size: "256 KB", icon: "📁"),
|
||
Self(id: "8", name: "plans", size: "32 KB", icon: "📁"),
|
||
Self(id: "9", name: ".swiftlint.yml", size: "1.2 KB", icon: "⚙️"),
|
||
Self(id: "10", name: ".github", size: "8 KB", icon: "📁"),
|
||
Self(id: "11", name: "Makefile", size: "0.8 KB", icon: "📄"),
|
||
Self(id: "12", name: ".claude", size: "16 KB", icon: "📁"),
|
||
]
|
||
}
|
||
|
||
// MARK: - List Page
|
||
|
||
/// List component demo page.
|
||
///
|
||
/// Shows interactive list features including:
|
||
/// - Single selection with binding
|
||
/// - Multi-selection with binding
|
||
/// - Keyboard navigation (Up/Down/Home/End/PageUp/PageDown)
|
||
/// - Scroll indicators
|
||
/// - Empty state placeholder
|
||
struct ListPage: View {
|
||
@State var singleSelection: String?
|
||
@State var multiSelection: Set<String> = []
|
||
|
||
var body: some View {
|
||
VStack(spacing: 1) {
|
||
|
||
HStack(spacing: 2) {
|
||
DemoSection("Single Selection") {
|
||
List(
|
||
selection: $singleSelection,
|
||
maxVisibleRows: 6
|
||
) {
|
||
ForEach(FileItem.sampleFiles) { file in
|
||
HStack(spacing: 1) {
|
||
Text(file.icon)
|
||
Text(file.name)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
DemoSection("Multi Selection") {
|
||
List(
|
||
selection: $multiSelection,
|
||
maxVisibleRows: 6
|
||
) {
|
||
ForEach(FileItem.sampleFiles) { file in
|
||
HStack(spacing: 1) {
|
||
Text(file.icon)
|
||
Text(file.name)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
DemoSection("Current Selections") {
|
||
VStack(spacing: 1) {
|
||
HStack(spacing: 1) {
|
||
Text("Single:").foregroundColor(.palette.foregroundSecondary)
|
||
Text(singleSelection ?? "(none)")
|
||
.bold()
|
||
.foregroundColor(.palette.accent)
|
||
}
|
||
HStack(spacing: 1) {
|
||
Text("Multi:").foregroundColor(.palette.foregroundSecondary)
|
||
Text(multiSelection.isEmpty ? "(none)" : multiSelection.sorted().joined(separator: ", "))
|
||
.bold()
|
||
.foregroundColor(.palette.accent)
|
||
}
|
||
}
|
||
}
|
||
|
||
DemoSection("Empty List") {
|
||
List(selection: Binding<String?>(get: { nil }, set: { _ in })) {
|
||
EmptyView()
|
||
}
|
||
}
|
||
|
||
DemoSection("Navigation") {
|
||
VStack {
|
||
Text("Use [↑/↓] to navigate items").dim()
|
||
Text("Use [Home/End] to jump to first/last").dim()
|
||
Text("Use [PageUp/PageDown] for fast scrolling").dim()
|
||
Text("Use [Enter/Space] to select/deselect").dim()
|
||
Text("Use [Tab] to switch between lists").dim()
|
||
}
|
||
}
|
||
|
||
Spacer()
|
||
}
|
||
.appHeader {
|
||
HStack {
|
||
Text("List Demo").bold().foregroundColor(.palette.accent)
|
||
Spacer()
|
||
Text("TUIkit v\(tuiKitVersion)").foregroundColor(.palette.foregroundTertiary)
|
||
}
|
||
}
|
||
}
|
||
}
|