I have attached the screenshots of the native SwiftUI app. <img width="1705" alt="image.png" src="attachments/59fec2f3-0ae2-4b58-9349-457618ea0678"> <img width="1699" alt="image.png" src="attachments/0bf7c4f9-c883-4929-be36-774685b82fc4"> <img width="1698" alt="image.png" src="attachments/e3407e84-aaf2-45c0-9325-247d4020bace"> <img width="1694" alt="image.png" src="attachments/ee2cd47d-800d-4a40-855c-d54856680e79"> <img width="1694" alt="image.png" src="attachments/a2c902f1-9bc9-4427-8cae-b5801527c1ff"> Co-authored-by: Sayan Datta <sayan@Sayans-MacBook-Air.local> Reviewed-on: #2 Co-authored-by: sayan <sayan@desineuron.in> Co-committed-by: sayan <sayan@desineuron.in>
174 lines
5.9 KiB
Swift
174 lines
5.9 KiB
Swift
import SwiftUI
|
||
|
||
enum AppSection: String, CaseIterable, Hashable, Identifiable {
|
||
var id: String { rawValue }
|
||
case dashboard = "Dashboard"
|
||
case oracle = "Oracle"
|
||
case sentinel = "Sentinel"
|
||
case inventory = "Inventory"
|
||
case settings = "Settings"
|
||
|
||
var systemImage: String {
|
||
switch self {
|
||
case .dashboard: return "square.grid.2x2"
|
||
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 .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
|
||
|
||
var body: some View {
|
||
NavigationSplitView(columnVisibility: .constant(.all)) {
|
||
sidebarContent
|
||
} detail: {
|
||
detailContent
|
||
}
|
||
.navigationSplitViewStyle(.balanced)
|
||
}
|
||
|
||
// 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
|
||
SidebarRow(section: section,
|
||
isSelected: selectedSection == section)
|
||
.onTapGesture { selectedSection = section }
|
||
}
|
||
}
|
||
.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("AF")
|
||
.font(.system(size: 11, weight: .bold))
|
||
.foregroundStyle(.white)
|
||
}
|
||
VStack(alignment: .leading, spacing: 2) {
|
||
Text("Ahmed Al-Farsi")
|
||
.font(.system(size: 12, weight: .medium))
|
||
.foregroundStyle(VelocityTheme.foreground)
|
||
Text("Sales Director")
|
||
.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 .oracle: OracleView()
|
||
case .sentinel: SentinelView()
|
||
case .inventory: InventoryView()
|
||
case .settings: SettingsView()
|
||
case .none: DashboardView()
|
||
}
|
||
}
|
||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 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.rawValue)
|
||
.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()
|
||
}
|