import Elementary import Foundation public struct ResultView< V: Sendable, E: Error, ValueView: HTML, ErrorView: HTML >: HTML { let onSuccess: @Sendable (V) -> ValueView let onError: @Sendable (E) -> ErrorView let result: Result public init( result: Result, @HTMLBuilder onSuccess: @escaping @Sendable (V) -> ValueView, @HTMLBuilder onError: @escaping @Sendable (E) -> ErrorView ) { self.result = result self.onError = onError self.onSuccess = onSuccess } public var body: some HTML { switch result { case .success(let value): onSuccess(value) case .failure(let error): onError(error) } } } extension ResultView { public init( result: Result, @HTMLBuilder onSuccess: @escaping @Sendable (V) -> ValueView ) where ErrorView == Styleguide.ErrorView { self.init(result: result, onSuccess: onSuccess) { error in Styleguide.ErrorView(error: error) } } public init( catching: @escaping @Sendable () async throws(E) -> V, @HTMLBuilder onSuccess: @escaping @Sendable (V) -> ValueView ) async where ErrorView == Styleguide.ErrorView { await self.init( result: .init(catching: catching), onSuccess: onSuccess ) { error in Styleguide.ErrorView(error: error) } } public init( catching: @escaping @Sendable () async throws(E) -> V, ) async where ErrorView == Styleguide.ErrorView, V == Void, ValueView == EmptyHTML { await self.init( result: .init(catching: catching), onSuccess: { EmptyHTML() } ) { error in Styleguide.ErrorView(error: error) } } } extension ResultView where V == ValueView { public init( catching: @escaping @Sendable () async throws(E) -> V ) async where ErrorView == Styleguide.ErrorView { await self.init(result: .init(catching: catching)) { $0 } onError: { error in Styleguide.ErrorView(error: error) } } } extension ResultView: Sendable where Error: Sendable, ValueView: Sendable, ErrorView: Sendable {} public struct ErrorView: HTML, Sendable where Error: Sendable { let error: E public init(error: E) { self.error = error } public var body: some HTML { div { h1(.class("text-2xl font-bold text-error")) { "Oops: Error" } p { "\(error)" } } } }