115 lines · 4.3 KB · Swift
RawDownload
import SwiftUI extension ProviderStatusIndicator {    /// Traffic-light color used for the per-component dot in the status submenu.    fileprivate var dotColor: Color {        switch self {        case .none: Color(red: 0.20, green: 0.78, blue: 0.35)        case .minor, .maintenance: Color(red: 0.96, green: 0.77, blue: 0.13)        case .major, .critical: Color(red: 0.91, green: 0.30, blue: 0.24)        case .unknown: Color.secondary        }    }} /// Renders the list of statuspage.io component rows inside the provider's status submenu./// Each leaf row is: colored dot (far left) · service name · right-aligned status text./// A component group renders as an expandable dropdown: the parent shows the group's own/// status, and a chevron reveals the individual child statuses indented beneath it/// (modeled on the "Other" disclosure in StorageBreakdownMenuView).struct StatusComponentsMenuView: View {    let components: [ProviderStatusComponent]    let width: CGFloat    /// Invoked after a group expands or collapses so the host can re-measure the row height.    let onToggle: (() -> Void)?     @State private var expandedGroupIDs: Set<String> = []     init(        components: [ProviderStatusComponent],        width: CGFloat,        onToggle: (() -> Void)? = nil)    {        self.components = components        self.width = width        self.onToggle = onToggle    }     var body: some View {        VStack(alignment: .leading, spacing: 6) {            ForEach(self.components) { component in                if component.isGroup {                    self.groupRow(component)                } else {                    self.statusRow(component)                }            }        }        .padding(.horizontal, 14)        .padding(.vertical, 8)        .frame(width: self.width, alignment: .leading)        .fixedSize(horizontal: false, vertical: true)    }     /// A single leaf row: dot · name · right-aligned status.    private func statusRow(_ component: ProviderStatusComponent, indented: Bool = false) -> some View {        HStack(spacing: 8) {            Circle()                .fill(component.indicator.dotColor)                .frame(width: 8, height: 8)            Text(component.name)                .font(.system(size: 13))                .foregroundStyle(.primary)                .lineLimit(1)            Spacer(minLength: 16)            Text(component.statusLabel)                .font(.system(size: 12))                .foregroundStyle(.secondary)                .lineLimit(1)        }        .padding(.leading, indented ? 17 : 0)    }     /// An expandable group: parent status row with a chevron, revealing children when expanded.    private func groupRow(_ group: ProviderStatusComponent) -> some View {        let isExpanded = self.expandedGroupIDs.contains(group.id)        return VStack(alignment: .leading, spacing: 6) {            Button {                if isExpanded {                    self.expandedGroupIDs.remove(group.id)                } else {                    self.expandedGroupIDs.insert(group.id)                }                self.onToggle?()            } label: {                HStack(spacing: 8) {                    Circle()                        .fill(group.indicator.dotColor)                        .frame(width: 8, height: 8)                    Text(group.name)                        .font(.system(size: 13))                        .foregroundStyle(.primary)                        .lineLimit(1)                    Image(systemName: isExpanded ? "chevron.down" : "chevron.right")                        .font(.system(size: 9, weight: .semibold))                        .foregroundStyle(.secondary)                    Spacer(minLength: 16)                    Text(group.statusLabel)                        .font(.system(size: 12))                        .foregroundStyle(.secondary)                        .lineLimit(1)                }                .contentShape(Rectangle())            }            .buttonStyle(.plain)             if isExpanded {                VStack(alignment: .leading, spacing: 6) {                    ForEach(group.children) { child in                        self.statusRow(child, indented: true)                    }                }            }        }    }}