import Elementary import ElementaryHTMX import Routes import Styleguide struct DehumidifierSizeForm: HTML { let response: DehumidifierSize.Response? init(response: DehumidifierSize.Response? = nil) { self.response = response } var content: some HTML { FormHeader(label: "Dehumidifier Sizing Calculator", svg: .droplets) form( // Using index to get the correct path, but really uses the `submit` end-point. .hx.post(route: .dehumidifierSize(.index)), .hx.target("#result") ) { div(.class("space-y-6")) { LabeledContent(label: "Latent Load (BTU/h)") { Input(id: "latentLoad", placeholder: "Latent load from Manual-J") .attributes(.type(.number), .step("0.1"), .min("0.1"), .autofocus, .required) } LabeledContent(label: "Indoor Temperature (°F)") { Input(id: "temperature", placeholder: "Indoor dry bulb temperature") .attributes(.type(.number), .step("0.1"), .min("0.1"), .required) } LabeledContent(label: "Indoor Humdity (%)") { Input(id: "humidity", placeholder: "Relative humidity") .attributes(.type(.number), .step("0.1"), .min("0.1"), .required) } div { SubmitButton(label: "Calculate Dehumidifier Size") } } } div(.id("result")) { if let response { DehumidifierSizeResult(response: response) } } } } struct DehumidifierSizeResult: HTML { let response: DehumidifierSize.Response var content: some HTML { ResultContainer(reset: .dehumidifierSize(.index)) { div(.class("py-4 block")) { // Display calculated metrics. div(.class(""" mb-6 sm:grid sm:grid-cols-1 sm:gap-4 lg:flex items-center lg:justify-between text-blue-500 dark:text-slate-200 """)) { div { span(.class("font-semibold")) { "Base Moisture Load: " } span(.class("font-light")) { "\(double: response.pintsPerDay) pints/day" } } if response.requiredCapacity != response.pintsPerDay { div { span(.class("font-semibold")) { "Required Capacity (derated): " } span(.class("font-light")) { "\(double: response.requiredCapacity) pints/day" } } } } p(.class("font-semibold mb-4 dark:text-yellow-300")) { "Recommended Size:" } a( .target("_blank"), .href(response.recommendedUrl ?? "#"), .rel("noopener noreferrer") ) { div(.class(""" px-8 py-2 flex items-center justify-between border border-blue-700 rounded-lg shadow-lg group dark:bg-blue-400 hover:bg-blue-300 hover:dark:bg-blue-600 transition-colors """)) { div { span(.class("font-extrabold text-4xl text-blue-800")) { "\(response.recommendedSize) PPD" } p(.class("text-sm mt-1")) { "Click to view recommended model →" } } div(.class(""" w-12 h-12 rounded-full flex items-center justify-center bg-blue-500 dark:bg-blue-600 group-hover:bg-blue-600 group-hover:dark:bg-blue-700 transition-colors """)) { SVG(.droplets, color: .white) } } } } // Display warnings, if applicable if response.warnings.count > 0 { div(.class(""" w-full mt-6 p-4 rounded-lg shadow-lg text-amber-500 bg-amber-100 dark:bg-amber-200 border border-amber-500 """)) { span(.class("font-semibold mb-4 border-b")) { "Warning\(response.warnings.count > 1 ? "s:" : ":")" } ul(.class("list-disc mx-10")) { for warning in response.warnings { li { warning } } } } } Note { """ Sizing is based on continuous operation at rated conditions. Actual performance will vary based on operating conditions. Consider Energy Star rated units for better efficiency. For whole-house applications, ensure proper air distribution and drainage. """ } } } } //