import Elementary import ElementaryHTMX import SharedModels struct MainPage: SendableHTMLDocument where Inner: Sendable { var title: String { "Purchase Orders" } var lang: String { "en" } let inner: Inner let displayNav: Bool let routeHeader: RouteHeaderView init( displayNav: Bool = false, route: RouteHeaderView.ViewRoute, _ inner: () -> Inner ) { self.displayNav = displayNav self.routeHeader = .init(route: route) self.inner = inner() } var head: some HTML { meta(.charset(.utf8)) script(.src("https://unpkg.com/htmx.org@2.0.4")) {} script(.src("/js/main.js")) {} link(.rel(.stylesheet), .href("/css/main.css")) link(.rel(.icon), .href("/images/favicon.ico"), .custom(name: "type", value: "image/x-icon")) } var body: some HTML { header(.class("header")) { Logo() if displayNav { Navbar() } } routeHeader inner } } extension MainPage where Inner == LoggedIn { static func loggedIn(next: String?) -> Self { MainPage(displayNav: true, route: .purchaseOrders) { LoggedIn(next: next) } } } struct LoggedIn: HTML, Sendable { let next: String? var content: some HTML { div( .hx.get(nextRoute ?? ViewRoute.router.path(for: .purchaseOrder(.index))), .hx.pushURL(true), .hx.target(.body), .hx.trigger(.event(.revealed)), .hx.indicator(".hx-indicator") ) { Img.spinner().attributes(.class("hx-indicator")) } } // HACK: to get search route to work after login. var nextRoute: String? { if let next, next.contains("search") { return ViewRoute.router.path(for: .purchaseOrder(.search(.index(context: .employee, table: true)))) } return next } } struct RouteHeaderView: HTML, Sendable { let title: String let description: String init(title: String, description: String) { self.title = title self.description = description } init(route: ViewRoute) { self.init(title: route.title, description: route.description) } var content: some HTML { div(.class("container"), .style("padding: 20px 20px;")) { h1 { title } br() p(.class("secondary")) { i { description } } br() } } enum ViewRoute: String, Sendable { case employees case login case purchaseOrders case users case vendors var title: String { switch self { case .purchaseOrders: return "Purchase Orders" default: return rawValue.capitalized } } var description: String { switch self { case .employees: return "Employees are who purchase orders can be issued to." case .purchaseOrders, .login: return "" case .users: return "Users are who can login and issue purchase orders for employees." case .vendors: return "Vendors are where purchase orders can be issued to." } } } } struct Logo: HTML, Sendable { var content: some HTML { div(.id("logo")) { "HHE - Purchase Orders" } } } protocol SendableHTMLDocument: HTMLDocument, Sendable {}