import SwiftUI struct RootView: View { @StateObject private var model = WebModel() @State private var showSplash = true var body: some View { ZStack { Ka.bg.ignoresSafeArea() WebView(model: model).opacity(model.loaded ? 1 : 0) if !model.loaded && !model.failed { VStack(spacing: 0) { GeometryReader { geo in Rectangle().fill(Ka.orange) .frame(width: geo.size.width * max(0.04, model.progress), height: 3) .animation(.easeOut(duration: 0.25), value: model.progress) }.frame(height: 3) Spacer() } } if showSplash { splash.transition(.opacity) } if model.failed { offline } } .onChange(of: model.loaded) { loaded in if loaded { DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { withAnimation(.easeInOut(duration: 0.4)) { showSplash = false } } } } } private var splash: some View { ZStack { Ka.bg.ignoresSafeArea() VStack(spacing: 16) { KaMark(size: 88) Text("Admin-Ka").font(.system(size: 24, weight: .heavy, design: .rounded)).foregroundColor(Ka.ink) Text("Console Claude Code · Groupe KA") .font(.system(size: 13, weight: .semibold, design: .rounded)).foregroundColor(Ka.muted) if !model.failed { ProgressView().controlSize(.small).padding(.top, 4) } } } } private var offline: some View { ZStack { Ka.bg.ignoresSafeArea() VStack(spacing: 14) { KaMark(size: 68) Text("Hors ligne").font(.system(size: 20, weight: .heavy, design: .rounded)).foregroundColor(Ka.ink) Text("Impossible de joindre administration-ka.com") .font(.system(size: 13, weight: .medium, design: .rounded)).foregroundColor(Ka.muted) Button { showSplash = true; model.reload() } label: { Text("Réessayer").font(.system(size: 14, weight: .heavy, design: .rounded)) .foregroundColor(Ka.ink).padding(.horizontal, 22).padding(.vertical, 10) .background(Capsule().fill(Ka.orange).overlay(Capsule().strokeBorder(Ka.ink, lineWidth: 2))) }.buttonStyle(.plain).padding(.top, 4) } } } }