mirror of
https://github.com/phranck/TUIkit.git
synced 2026-05-21 09:50:35 +00:00
Feat: AppHeader — framework-managed header bar rendered outside the view tree
AppHeader is rendered at the top of the terminal by RenderLoop, similar to
StatusBar at the bottom. Views declare header content via .appHeader { }
ViewBuilder modifier. Supports standard (thin divider) and block (half-block
with appHeaderBackground) appearance. Hidden when no content is set.
Diff cache invalidates on header height changes to prevent ghosting.
This commit is contained in:
@@ -1,49 +0,0 @@
|
||||
// 🖥️ TUIKit — Terminal UI Kit for Swift
|
||||
// HeaderView.swift
|
||||
//
|
||||
// Created by LAYERED.work
|
||||
// CC BY-NC-SA 4.0
|
||||
|
||||
import TUIkit
|
||||
|
||||
/// A styled header with title on the left and version on the right.
|
||||
///
|
||||
/// Used at the top of each demo page to provide consistent branding
|
||||
/// and optional subtitle.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```swift
|
||||
/// HeaderView(
|
||||
/// title: "My Demo",
|
||||
/// subtitle: "An optional description"
|
||||
/// )
|
||||
/// ```
|
||||
struct HeaderView: View {
|
||||
let title: String
|
||||
let subtitle: String?
|
||||
|
||||
init(title: String, subtitle: String? = nil) {
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
Text(title)
|
||||
.bold()
|
||||
.foregroundColor(.palette.accent)
|
||||
Spacer()
|
||||
Text("TUIkit v\(tuiKitVersion)")
|
||||
.foregroundColor(.palette.foregroundTertiary)
|
||||
}
|
||||
if let subtitleText = subtitle {
|
||||
Text(subtitleText)
|
||||
.foregroundColor(.palette.foregroundSecondary)
|
||||
.italic()
|
||||
}
|
||||
Divider(character: "═")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import TUIkit
|
||||
struct BlockThemePage: View {
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
HeaderView(title: "Block Theme Colors")
|
||||
|
||||
Text("Switch to block appearance (press 'a') and violet theme (press 't').")
|
||||
.foregroundColor(.palette.foregroundSecondary)
|
||||
@@ -76,5 +75,12 @@ struct BlockThemePage: View {
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.appHeader {
|
||||
HStack {
|
||||
Text("Block Theme Colors").bold().foregroundColor(.palette.accent)
|
||||
Spacer()
|
||||
Text("TUIkit v\(tuiKitVersion)").foregroundColor(.palette.foregroundTertiary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ struct ButtonsPage: View {
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
HeaderView(title: "Buttons & Focus Demo")
|
||||
|
||||
DemoSection("Interactive Counter (@State)") {
|
||||
HStack(spacing: 2) {
|
||||
@@ -88,5 +87,12 @@ struct ButtonsPage: View {
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.appHeader {
|
||||
HStack {
|
||||
Text("Buttons & Focus Demo").bold().foregroundColor(.palette.accent)
|
||||
Spacer()
|
||||
Text("TUIkit v\(tuiKitVersion)").foregroundColor(.palette.foregroundTertiary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import TUIkit
|
||||
struct ColorsPage: View {
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
HeaderView(title: "Colors Demo")
|
||||
|
||||
DemoSection("Standard ANSI Colors") {
|
||||
HStack(spacing: 2) {
|
||||
@@ -62,5 +61,12 @@ struct ColorsPage: View {
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.appHeader {
|
||||
HStack {
|
||||
Text("Colors Demo").bold().foregroundColor(.palette.accent)
|
||||
Spacer()
|
||||
Text("TUIkit v\(tuiKitVersion)").foregroundColor(.palette.foregroundTertiary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ struct ContainersPage: View {
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
HeaderView(title: "Container Views Demo")
|
||||
|
||||
HStack(spacing: 2) {
|
||||
// Card example
|
||||
@@ -121,5 +120,12 @@ struct ContainersPage: View {
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.appHeader {
|
||||
HStack {
|
||||
Text("Container Views Demo").bold().foregroundColor(.palette.accent)
|
||||
Spacer()
|
||||
Text("TUIkit v\(tuiKitVersion)").foregroundColor(.palette.foregroundTertiary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import TUIkit
|
||||
struct LayoutPage: View {
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
HeaderView(title: "Layout System Demo")
|
||||
|
||||
DemoSection("VStack (Vertical)") {
|
||||
// Box uses appearance default borderStyle
|
||||
@@ -68,5 +67,12 @@ struct LayoutPage: View {
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.appHeader {
|
||||
HStack {
|
||||
Text("Layout System Demo").bold().foregroundColor(.palette.accent)
|
||||
Spacer()
|
||||
Text("TUIkit v\(tuiKitVersion)").foregroundColor(.palette.foregroundTertiary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,6 @@ struct MainMenuPage: View {
|
||||
|
||||
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 {
|
||||
@@ -66,6 +61,18 @@ struct MainMenuPage: View {
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.appHeader {
|
||||
VStack {
|
||||
HStack {
|
||||
Text("TUIkit Example App").bold().foregroundColor(.palette.accent)
|
||||
Spacer()
|
||||
Text("TUIkit v\(tuiKitVersion)").foregroundColor(.palette.foregroundTertiary)
|
||||
}
|
||||
Text("A SwiftUI-like framework for Terminal User Interfaces")
|
||||
.foregroundColor(.palette.foregroundSecondary)
|
||||
.italic()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a small feature highlight box.
|
||||
|
||||
@@ -131,8 +131,6 @@ struct OverlaysPage: View {
|
||||
/// The main background content with menu and description.
|
||||
private var backgroundContent: some View {
|
||||
VStack(spacing: 1) {
|
||||
HeaderView(title: "Overlays & Modals Demo")
|
||||
|
||||
HStack(spacing: 3) {
|
||||
// Left: Demo menu
|
||||
Menu(
|
||||
@@ -166,6 +164,13 @@ struct OverlaysPage: View {
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.appHeader {
|
||||
HStack {
|
||||
Text("Overlays & Modals Demo").bold().foregroundColor(.palette.accent)
|
||||
Spacer()
|
||||
Text("TUIkit v\(tuiKitVersion)").foregroundColor(.palette.foregroundTertiary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Description Panel
|
||||
|
||||
@@ -10,7 +10,6 @@ import TUIkit
|
||||
struct SpinnersPage: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 1) {
|
||||
HeaderView(title: "Spinners")
|
||||
|
||||
DemoSection("Dots (Braille Rotation)") {
|
||||
Spinner("Loading data...")
|
||||
@@ -30,5 +29,12 @@ struct SpinnersPage: View {
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.appHeader {
|
||||
HStack {
|
||||
Text("Spinners").bold().foregroundColor(.palette.accent)
|
||||
Spacer()
|
||||
Text("TUIkit v\(tuiKitVersion)").foregroundColor(.palette.foregroundTertiary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@ import TUIkit
|
||||
struct TextStylesPage: View {
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
HeaderView(title: "Text Styles Demo")
|
||||
|
||||
DemoSection("Basic Styles") {
|
||||
Text("Normal text - no styling applied")
|
||||
Text("Bold text").bold()
|
||||
@@ -41,5 +39,12 @@ struct TextStylesPage: View {
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.appHeader {
|
||||
HStack {
|
||||
Text("Text Styles Demo").bold().foregroundColor(.palette.accent)
|
||||
Spacer()
|
||||
Text("TUIkit v\(tuiKitVersion)").foregroundColor(.palette.foregroundTertiary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user