initial commit
This commit is contained in:
commit
8de962eeb8
44 changed files with 4843 additions and 0 deletions
126
Components.swift
Normal file
126
Components.swift
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
import SwiftUI
|
||||
|
||||
/// Simple load state for screen view models.
|
||||
enum LoadPhase: Equatable {
|
||||
case idle
|
||||
case loading
|
||||
case loaded
|
||||
case failed(String)
|
||||
}
|
||||
|
||||
// MARK: - State / severity badges
|
||||
|
||||
struct StateBadge: View {
|
||||
let text: String
|
||||
let color: Color
|
||||
|
||||
var body: some View {
|
||||
Text(text)
|
||||
.font(.caption2.weight(.semibold))
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 3)
|
||||
.background(color.opacity(0.18))
|
||||
.foregroundStyle(color)
|
||||
.clipShape(Capsule())
|
||||
}
|
||||
}
|
||||
|
||||
extension ONULifecycleState {
|
||||
var color: Color {
|
||||
switch self {
|
||||
case .registered: return .green
|
||||
case .unspecified: return .mint // also "online" (dev guide Procedure 2)
|
||||
case .unprovisioned: return .blue
|
||||
case .deregistered: return .gray
|
||||
case .dyingGasp, .disallowedError: return .red
|
||||
case .disabled, .disallowedAdmin, .disallowedRegID: return .orange
|
||||
case .unknown: return .secondary
|
||||
}
|
||||
}
|
||||
var label: String { self == .unknown ? "Unknown" : rawValue }
|
||||
}
|
||||
|
||||
extension DeviceState {
|
||||
var color: Color {
|
||||
switch self {
|
||||
case .online: return .green
|
||||
case .offline: return .gray
|
||||
case .unattached: return .orange
|
||||
case .preProvisioned: return .blue
|
||||
case .unknown: return .secondary
|
||||
}
|
||||
}
|
||||
var label: String { self == .unknown ? "Unknown" : rawValue }
|
||||
}
|
||||
|
||||
extension AlarmSeverity {
|
||||
var color: Color {
|
||||
switch self {
|
||||
case .emergency, .alert, .critical: return .red
|
||||
case .error: return .orange
|
||||
case .warning: return .yellow
|
||||
case .notice, .info: return .blue
|
||||
case .debug: return .gray
|
||||
case .unknown: return .secondary
|
||||
}
|
||||
}
|
||||
var label: String { self == .unknown ? "unknown" : rawValue }
|
||||
}
|
||||
|
||||
struct SeverityBadge: View {
|
||||
let severity: AlarmSeverity
|
||||
var body: some View { StateBadge(text: severity.label, color: severity.color) }
|
||||
}
|
||||
|
||||
// MARK: - Count tile (dashboard)
|
||||
|
||||
struct CountTile: View {
|
||||
let title: String
|
||||
let value: Int
|
||||
var systemImage: String? = nil
|
||||
var tint: Color = .accentColor
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
HStack(spacing: 6) {
|
||||
if let systemImage { Image(systemName: systemImage).foregroundStyle(tint) }
|
||||
Text(title).font(.caption).foregroundStyle(.secondary)
|
||||
}
|
||||
Text("\(value)").font(.system(.title, design: .rounded).weight(.semibold))
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding()
|
||||
.background(Color(.secondarySystemBackground))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 14, style: .continuous))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Loading / error
|
||||
|
||||
struct LoadingView: View {
|
||||
var label: String = "Loading…"
|
||||
var body: some View {
|
||||
VStack(spacing: 12) {
|
||||
ProgressView()
|
||||
Text(label).font(.subheadline).foregroundStyle(.secondary)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
}
|
||||
|
||||
struct ErrorStateView: View {
|
||||
let message: String
|
||||
var retry: (() -> Void)? = nil
|
||||
|
||||
var body: some View {
|
||||
ContentUnavailableView {
|
||||
Label("Something went wrong", systemImage: "exclamationmark.triangle")
|
||||
} description: {
|
||||
Text(message)
|
||||
} actions: {
|
||||
if let retry {
|
||||
Button("Retry", action: retry).buttonStyle(.borderedProminent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue