feat: Ipad app features and Dream Weaver for Velocity WebOS

This commit is contained in:
Sayan Datta
2026-04-28 10:59:07 +05:30
parent 184bfa77f8
commit fefe8373ec
117 changed files with 19510 additions and 6383 deletions

View File

@@ -0,0 +1,224 @@
import SwiftUI
enum AppSection: String, CaseIterable, Hashable, Identifiable {
var id: String { rawValue }
case dashboard = "Dashboard"
case clients = "Clients"
case imports = "Imports"
case communications = "Communications"
case calendar = "Calendar"
case oracle = "Oracle"
case sentinel = "Sentinel"
case inventory = "Inventory"
case settings = "Settings"
var displayTitle: String {
switch self {
case .sentinel:
return SentinelScope.navigationTitle
default:
return rawValue
}
}
var systemImage: String {
switch self {
case .dashboard: return "square.grid.2x2"
case .clients: return "person.text.rectangle"
case .imports: return "tray.and.arrow.down"
case .communications: return "phone.connection"
case .calendar: return "calendar.badge.clock"
case .oracle: return "message.and.waveform"
case .sentinel: return "person.crop.rectangle"
case .inventory: return "shippingbox"
case .settings: return "gearshape"
}
}
var accentColor: Color {
switch self {
case .dashboard: return VelocityTheme.accent
case .clients: return Color(red: 0.22, green: 0.78, blue: 0.96)
case .imports: return Color(red: 0.94, green: 0.70, blue: 0.25)
case .communications: return Color(red: 0.19, green: 0.84, blue: 0.63)
case .calendar: return Color(red: 0.96, green: 0.67, blue: 0.16)
case .oracle: return Color(red: 0.13, green: 0.83, blue: 0.93) // cyan
case .sentinel: return Color(red: 0.60, green: 0.57, blue: 0.99) // indigo
case .inventory: return VelocityTheme.warning
case .settings: return VelocityTheme.mutedFg
}
}
}
struct ContentView: View {
@State private var selectedSection: AppSection? = .dashboard
@State private var session = SessionStore.shared
var body: some View {
Group {
if session.isConfigured {
NavigationSplitView(columnVisibility: .constant(.all)) {
sidebarContent
} detail: {
detailContent
}
.navigationSplitViewStyle(.balanced)
} else {
ConfigurationGateView()
}
}
}
// MARK: Sidebar
private var sidebarContent: some View {
ZStack {
VelocityTheme.sidebarBg.ignoresSafeArea()
VStack(spacing: 0) {
// App title
HStack(spacing: 10) {
ZStack {
RoundedRectangle(cornerRadius: 9)
.fill(VelocityTheme.accent.opacity(0.18))
.frame(width: 34, height: 34)
Image(systemName: "bolt.fill")
.font(.system(size: 15, weight: .semibold))
.foregroundStyle(VelocityTheme.accent)
}
VStack(alignment: .leading, spacing: 1) {
Text("Velocity")
.font(.system(size: 16, weight: .semibold))
.foregroundStyle(VelocityTheme.foreground)
Text("Project Velocity · v1.1")
.font(.system(size: 10))
.foregroundStyle(VelocityTheme.mutedFg)
}
Spacer()
}
.padding(.horizontal, 16)
.padding(.top, 20)
.padding(.bottom, 16)
Divider()
.background(VelocityTheme.borderSubtle)
.padding(.bottom, 8)
// Nav items
VStack(spacing: 2) {
ForEach(AppSection.allCases) { section in
Button {
selectedSection = section
} label: {
SidebarRow(section: section, isSelected: selectedSection == section)
}
.buttonStyle(.plain)
.accessibilityLabel(section.displayTitle)
.accessibilityAddTraits(selectedSection == section ? [.isSelected] : [])
}
}
.padding(.horizontal, 8)
Spacer()
// User footer
Divider()
.background(VelocityTheme.borderSubtle)
HStack(spacing: 10) {
ZStack {
RoundedRectangle(cornerRadius: 8)
.fill(VelocityTheme.accent)
.frame(width: 32, height: 32)
Text(operatorInitials)
.font(.system(size: 11, weight: .bold))
.foregroundStyle(.white)
}
VStack(alignment: .leading, spacing: 2) {
Text(operatorName)
.font(.system(size: 12, weight: .medium))
.foregroundStyle(VelocityTheme.foreground)
Text(session.authModeDescription)
.font(.system(size: 10))
.foregroundStyle(VelocityTheme.mutedFg)
}
Spacer()
}
.padding(16)
}
}
.navigationTitle("")
.toolbar(.hidden, for: .navigationBar)
}
// MARK: Detail
private var detailContent: some View {
ZStack {
VelocityTheme.background.ignoresSafeArea()
Group {
switch selectedSection {
case .dashboard: DashboardView()
case .clients: ClientsView()
case .imports: ImportsView()
case .communications: CommunicationsView()
case .calendar: CalendarView()
case .oracle: OracleView()
case .sentinel: SentinelView()
case .inventory: InventoryView()
case .settings: SettingsView()
case .none: DashboardView()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
private var operatorName: String {
session.operatorIdentity
}
private var operatorInitials: String {
let source = session.operatorIdentity
let parts = source
.replacingOccurrences(of: "@", with: " ")
.split(separator: ".")
.flatMap { $0.split(separator: " ") }
let initials = parts.prefix(2).compactMap(\.first)
return initials.isEmpty ? "VO" : String(initials)
}
}
// MARK: Sidebar Row
private struct SidebarRow: View {
let section: AppSection
let isSelected: Bool
var body: some View {
HStack(spacing: 11) {
Image(systemName: section.systemImage)
.font(.system(size: 14, weight: .medium))
.foregroundStyle(isSelected ? section.accentColor : VelocityTheme.mutedFg)
.frame(width: 20)
Text(section.displayTitle)
.font(.system(size: 14, weight: isSelected ? .semibold : .regular))
.foregroundStyle(isSelected ? VelocityTheme.foreground : VelocityTheme.mutedFg)
Spacer()
}
.padding(.horizontal, 12)
.padding(.vertical, 9)
.background(
RoundedRectangle(cornerRadius: 10)
.fill(isSelected ? section.accentColor.opacity(0.12) : .clear)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(isSelected ? section.accentColor.opacity(0.25) : .clear, lineWidth: 1)
)
)
.contentShape(Rectangle())
}
}
#Preview {
ContentView()
}