import Elementary import ElementaryHTMX import PsychrometricClient import Routes import Styleguide struct FeetOfHeadForm: HTML, Sendable { let response: FeetOfHead.Response? typealias Key = FeetOfHead.Request.FieldKey var content: some HTML { FormHeader(label: "Feet of Head", svg: .footprints) form( .hx.post(route: .feetOfHead(.index)), .hx.target("#result") ) { div(.class("space-y-6")) { div(.class("grid grid-cols-2 gap-4")) { LabeledContent(label: "Pressure (psi)") { Input(id: Key.pressure, placeholder: "Pressure") .attributes(.type(.number), .min("0.1"), .step("0.1"), .autofocus, .required) } LabeledContent(label: "Water Temperature (\(String.fahrenheit))") { Input(id: Key.waterTemperature, placeholder: "Temperature (optional)") .attributes(.type(.number), .min("32.0"), .step("0.1")) } } Note { """ If water temperature is not supplied, then calculations will be based on 60\(String.fahrenheit) water. """ } div { SubmitButton(label: "Feet of Head") } } } div(.id("result")) { if let response { FeetOfHeadResponse(response: response) } } } } struct FeetOfHeadResponse: HTML, Sendable { let response: FeetOfHead.Response var content: some HTML { ResultContainer(reset: .feetOfHead(.index)) { ResultBox { div(.class("grid grid-cols-2")) { VerticalGroup(label: "Feet of Head", value: "\(double: response.feetOfHead)", valueLabel: "ft.") VerticalGroup( label: "Water Density", value: "\(double: response.density.value)", valueLabel: response.density.units.rawValue ) } } WarningBox(warnings: response.warnings) } } }