PadXcode-iPad/Editor/EditorTabBar.swift
2026-04-12 00:46:30 -07:00

71 lines
2.6 KiB
Swift

import SwiftUI
struct EditorTabBar: View {
@ObservedObject var editorState: EditorState
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 0) {
ForEach(editorState.tabs) { tab in
EditorTabCell(
tab: tab,
isActive: tab.id == editorState.activeTabId,
onSelect: { editorState.activeTabId = tab.id },
onClose: { editorState.closeTab(id: tab.id) }
)
}
}
}
.frame(height: 36)
.background(Color(.secondarySystemBackground))
.overlay(alignment: .bottom) { Divider() }
}
}
struct EditorTabCell: View {
let tab: EditorTab
let isActive: Bool
let onSelect: () -> Void
let onClose: () -> Void
@State private var isHovered = false
var body: some View {
HStack(spacing: 6) {
if tab.isDirty {
Circle().fill(Color.accentColor).frame(width: 6, height: 6)
} else {
Button(action: onClose) {
Image(systemName: "xmark").font(.system(size: 9, weight: .semibold))
.frame(width: 14, height: 14).contentShape(Circle())
}
.buttonStyle(.plain)
.opacity((isActive || isHovered) ? 1 : 0)
}
Image(systemName: fileIcon(for: tab.fileName))
.font(.system(size: 11)).foregroundStyle(iconColor(for: tab.fileName))
Text(tab.fileName)
.font(.system(.caption, design: .monospaced)).lineLimit(1)
}
.padding(.horizontal, 10).frame(height: 36)
.background(isActive ? Color(.systemBackground) : .clear)
.overlay(alignment: .bottom) {
if isActive { Rectangle().fill(Color.accentColor).frame(height: 2) }
}
.contentShape(Rectangle())
.onTapGesture(perform: onSelect)
.onHover { isHovered = $0 }
}
private func fileIcon(for name: String) -> String {
switch (name as NSString).pathExtension.lowercased() {
case "swift": return "swift"; case "json": return "curlybraces"
case "md": return "doc.text"; case "sh": return "terminal"; default: return "doc"
}
}
private func iconColor(for name: String) -> Color {
switch (name as NSString).pathExtension.lowercased() {
case "swift": return .orange; case "json": return .yellow
case "md": return .blue; default: return .secondary
}
}
}