feat: Begins thermal balance point
This commit is contained in:
143
Sources/ViewController/Views/HeatingBalancePoint.swift
Normal file
143
Sources/ViewController/Views/HeatingBalancePoint.swift
Normal file
@@ -0,0 +1,143 @@
|
||||
import Elementary
|
||||
import ElementaryHTMX
|
||||
import Routes
|
||||
import Styleguide
|
||||
|
||||
struct HeatingBalancePointForm: HTML, Sendable {
|
||||
let mode: HeatingBalancePoint.Mode
|
||||
let heatLossMode: HeatingBalancePoint.HeatLoss.Mode
|
||||
let response: HeatingBalancePoint.Response?
|
||||
|
||||
init(
|
||||
mode: HeatingBalancePoint.Mode?,
|
||||
heatLossMode: HeatingBalancePoint.HeatLoss.Mode? = nil,
|
||||
response: HeatingBalancePoint.Response? = nil
|
||||
) {
|
||||
self.mode = mode ?? .thermal
|
||||
self.heatLossMode = heatLossMode ?? .estimated
|
||||
self.response = response
|
||||
}
|
||||
|
||||
var content: some HTML {
|
||||
FormHeader(label: "Balance Point - \(mode.label)", svg: .scale)
|
||||
// TODO: Toggle button
|
||||
|
||||
form(
|
||||
.hx.post(route: .heatingBalancePoint(.index)),
|
||||
.hx.target("#result")
|
||||
) {
|
||||
div(.class("space-y-6")) {
|
||||
switch mode {
|
||||
case .thermal:
|
||||
ThermalFields(heatLossMode: heatLossMode)
|
||||
case .economic:
|
||||
div {}
|
||||
}
|
||||
|
||||
div {
|
||||
SubmitButton(label: "Calculate Balance Point")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div(.id("result")) {
|
||||
if let response {
|
||||
HeatingBalancePointResponse(response: response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ThermalFields: HTML, Sendable {
|
||||
let heatLossMode: HeatingBalancePoint.HeatLoss.Mode
|
||||
|
||||
var content: some HTML {
|
||||
LabeledContent(label: "System Size (Tons)") {
|
||||
Input(id: "systemSize", placeholder: "System size")
|
||||
.attributes(.type(.number), .min("1"), .step("0.5"), .autofocus, .required)
|
||||
}
|
||||
div {
|
||||
div(.class("mb-4")) {
|
||||
h4(.class("text-lg font-bold")) { "Capacities" }
|
||||
p(.class("text-sm")) {
|
||||
"Entering known capacities gives better results, otherwise capacities will be estimated."
|
||||
}
|
||||
}
|
||||
div(.class("grid grid-cols-1 lg:grid-cols-2 gap-4")) {
|
||||
LabeledContent(label: "Capacity @ 47° (BTU/h)") {
|
||||
Input(id: "capacityAt47", placeholder: "Capacity @ 47° (optional)")
|
||||
.attributes(.type(.number), .min("1"), .step("0.5"))
|
||||
}
|
||||
LabeledContent(label: "Capacity @ 17° (BTU/h)") {
|
||||
Input(id: "capacityAt17", placeholder: "Capacity @ 17° (optional)")
|
||||
.attributes(.type(.number), .min("1"), .step("0.5"))
|
||||
}
|
||||
}
|
||||
}
|
||||
HeatLossFields(mode: heatLossMode)
|
||||
}
|
||||
}
|
||||
|
||||
struct HeatLossFields: HTML, Sendable {
|
||||
let mode: HeatingBalancePoint.HeatLoss.Mode
|
||||
|
||||
var content: some HTML {
|
||||
div(.id("heatLossFields")) {
|
||||
div(.class("flex flex-wrap justify-between")) {
|
||||
h4(.class("text-lg font-bold")) { "Heat Loss - \(mode.label)" }
|
||||
Toggle(
|
||||
isOn: mode == .estimated,
|
||||
onLabel: HeatingBalancePoint.HeatLoss.Mode.estimated.label,
|
||||
onAttributes: [
|
||||
.hx.get(route: .heatingBalancePoint(.heatLossFields(mode: .estimated))),
|
||||
.hx.target("#heatLossFields")
|
||||
],
|
||||
offLabel: HeatingBalancePoint.HeatLoss.Mode.known.label,
|
||||
offAttributes: [
|
||||
.hx.get(route: .heatingBalancePoint(.heatLossFields(mode: .known))),
|
||||
.hx.target("#heatLossFields")
|
||||
]
|
||||
)
|
||||
.attributes(.class("mb-6"))
|
||||
}
|
||||
switch mode {
|
||||
case .known:
|
||||
knownFields
|
||||
case .estimated:
|
||||
simplifiedFields
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var simplifiedFields: some HTML {
|
||||
LabeledContent(label: "Building Size (ft²)") {
|
||||
Input(id: "simplifiedHeatLoss", placeholder: "Square feet")
|
||||
.attributes(.type(.number), .min("1"), .step("0.5"), .required)
|
||||
}
|
||||
}
|
||||
|
||||
private var knownFields: some HTML {
|
||||
LabeledContent(label: "Heat Loss (BTU/h)") {
|
||||
Input(id: "knownHeatLoss", placeholder: "Heat loss")
|
||||
.attributes(.type(.number), .min("1"), .step("0.5"), .required)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct HeatingBalancePointResponse: HTML, Sendable {
|
||||
|
||||
let response: HeatingBalancePoint.Response
|
||||
|
||||
}
|
||||
|
||||
private extension HeatingBalancePoint.Mode {
|
||||
|
||||
var label: String { rawValue.capitalized }
|
||||
|
||||
}
|
||||
|
||||
private extension HeatingBalancePoint.HeatLoss.Mode {
|
||||
var label: String { rawValue.capitalized }
|
||||
}
|
||||
Reference in New Issue
Block a user