import SwiftUI enum SIO { static let tint = Color("SIOTint") static let laneFeed = Color("LaneFeed") static let lanePaper = Color("LanePaper") static let lanePeople = Color("LanePeople") static let cardRadius: CGFloat = 14 static let controlRadius: CGFloat = 10 static let chipRadius: CGFloat = 6 static let bodyFontSize: CGFloat = 15.5 static let bodyLineSpacing: CGFloat = 15.5 * 0.55 } enum Lane: String, CaseIterable, Codable, Hashable { case feed case paper case people var label: String { switch self { case .feed: "Feed" case .paper: "Paper" case .people: "People" } } var color: Color { switch self { case .feed: SIO.laneFeed case .paper: SIO.lanePaper case .people: SIO.lanePeople } } } extension View { @ViewBuilder func sioGlassChrome(in shape: S, tint: Color? = nil, interactive: Bool = false) -> some View { if #available(iOS 26.0, macOS 26.0, *) { self.glassEffect( Glass.regular.tint(tint).interactive(interactive), in: shape ) } else { self .background(.ultraThinMaterial, in: shape) .overlay(shape.stroke(Color.primary.opacity(0.08), lineWidth: 0.5)) } } @ViewBuilder func sioGlassChromeContainer(spacing: CGFloat? = nil) -> some View { if #available(iOS 26.0, macOS 26.0, *) { GlassEffectContainer(spacing: spacing) { self } } else { self } } } struct LaneChip: View { let lane: Lane var compact: Bool = false var body: some View { Text(lane.label) .font(.caption2.weight(.semibold)) .tracking(0.2) .foregroundStyle(lane.color) .padding(.horizontal, compact ? 6 : 8) .padding(.vertical, compact ? 2 : 3) .background( lane.color.opacity(0.14), in: RoundedRectangle(cornerRadius: SIO.chipRadius, style: .continuous) ) } } struct AvatarView: View { let name: String let size: CGFloat var tint: Color = SIO.tint var initials: String { let parts = name.split(separator: " ").prefix(2) return parts.compactMap { $0.first.map(String.init) }.joined().uppercased() } var body: some View { Text(initials) .font(.system(size: size * 0.42, weight: .semibold)) .foregroundStyle(.white) .frame(width: size, height: size) .background(tint, in: Circle()) } } struct AISummaryCard: View { let messageCount: Int let bullets: [String] var body: some View { VStack(alignment: .leading, spacing: 8) { HStack(spacing: 6) { Image(systemName: "sparkles") .font(.caption2.weight(.bold)) Text("SUMMARY · \(messageCount) messages") .font(.caption2.weight(.bold)) .tracking(0.6) } .foregroundStyle(SIO.tint) ForEach(Array(bullets.enumerated()), id: \.offset) { _, line in HStack(alignment: .firstTextBaseline, spacing: 8) { Text("·").foregroundStyle(SIO.tint) Text(line) .font(.callout) .foregroundStyle(.primary) .fixedSize(horizontal: false, vertical: true) } } } .padding(14) .frame(maxWidth: .infinity, alignment: .leading) .background(SIO.tint.opacity(0.10), in: RoundedRectangle(cornerRadius: 16, style: .continuous)) .overlay( RoundedRectangle(cornerRadius: 16, style: .continuous) .stroke(SIO.tint.opacity(0.22), lineWidth: 0.5) ) } } struct KeyboardHint: View { let label: String var body: some View { Text(label) .font(.system(size: 11, weight: .medium, design: .monospaced)) .foregroundStyle(.secondary) .padding(.horizontal, 5) .padding(.vertical, 1) .background(.secondary.opacity(0.10), in: RoundedRectangle(cornerRadius: 4, style: .continuous)) .overlay( RoundedRectangle(cornerRadius: 4, style: .continuous) .stroke(.secondary.opacity(0.20), lineWidth: 0.5) ) } } struct PrimaryActionStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label .font(.headline) .foregroundStyle(.white) .padding(.horizontal, 16) .padding(.vertical, 10) .background(SIO.tint, in: RoundedRectangle(cornerRadius: SIO.controlRadius, style: .continuous)) .opacity(configuration.isPressed ? 0.85 : 1) } } struct SecondaryActionStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label .font(.subheadline.weight(.semibold)) .foregroundStyle(.primary) .padding(.horizontal, 14) .padding(.vertical, 9) .background(.secondary.opacity(0.12), in: RoundedRectangle(cornerRadius: SIO.controlRadius, style: .continuous)) .opacity(configuration.isPressed ? 0.85 : 1) } } struct DestructiveActionStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label .font(.subheadline.weight(.semibold)) .foregroundStyle(.red) .padding(.horizontal, 14) .padding(.vertical, 9) .background(Color.red.opacity(0.12), in: RoundedRectangle(cornerRadius: SIO.controlRadius, style: .continuous)) .opacity(configuration.isPressed ? 0.85 : 1) } } extension MailPerson { var avatarTint: Color { let hash = email.unicodeScalars.reduce(0) { $0 &+ Int($1.value) } let palette: [Color] = [SIO.laneFeed, SIO.lanePaper, SIO.lanePeople, SIO.tint, .purple, .pink, .teal] return palette[abs(hash) % palette.count] } }