feat: Adds snapshot tests and updates Dockerfile.dev for docker tests.
This commit is contained in:
@@ -3,6 +3,7 @@ import Elementary
|
||||
import HTMLSnapshotTesting
|
||||
import Logging
|
||||
import OrderedCollections
|
||||
import PsychrometricClientLive
|
||||
import Routes
|
||||
import SnapshotTesting
|
||||
import Testing
|
||||
@@ -14,11 +15,13 @@ struct ViewControllerTests {
|
||||
let record = SnapshotTestingConfiguration.Record.missing
|
||||
let logger = Logger(label: "ViewControllerTests")
|
||||
|
||||
// swiftlint:disable function_body_length
|
||||
@Test
|
||||
func snapShotTests() async throws {
|
||||
try await withSnapshotTesting(record: record) {
|
||||
try await withDependencies {
|
||||
$0.viewController = .liveValue
|
||||
$0.psychrometricClient = .liveValue
|
||||
} operation: {
|
||||
@Dependency(\.viewController) var viewController
|
||||
|
||||
@@ -33,15 +36,18 @@ struct ViewControllerTests {
|
||||
atticDewpoint: 76,
|
||||
atticFloorArea: 1234
|
||||
))),
|
||||
|
||||
// Capacitor
|
||||
.capacitor(.index),
|
||||
.capacitor(.index(mode: .size)),
|
||||
.capacitor(.index(mode: .test)),
|
||||
.capacitor(.submit(.size(.init(runningAmps: 10.7, lineVoltage: 243, powerFactor: 0.86)))),
|
||||
.capacitor(.submit(.test(.init(startWindingAmps: 4.3, runToCommonVoltage: 343)))),
|
||||
|
||||
// Dehumidifier Sizing
|
||||
.dehumidifierSize(.index),
|
||||
.dehumidifierSize(.submit(.init(latentLoad: 3443, temperature: 76, humidity: 67))),
|
||||
|
||||
// Filter Pressure Drop
|
||||
.filterPressureDrop(.index),
|
||||
.filterPressureDrop(.index(mode: .basic)),
|
||||
@@ -60,7 +66,66 @@ struct ViewControllerTests {
|
||||
ratedAirflow: 800,
|
||||
ratedPressureDrop: 0.1,
|
||||
designAirflow: 900
|
||||
)))),
|
||||
|
||||
// Heating Balance Point
|
||||
.heatingBalancePoint(.index),
|
||||
.heatingBalancePoint(.heatLossFields(mode: .estimated)),
|
||||
.heatingBalancePoint(.heatLossFields(mode: .known)),
|
||||
.heatingBalancePoint(.submit(.economic(.init(
|
||||
fuelType: .propane,
|
||||
fuelCostPerUnit: 2.43,
|
||||
fuelAFUE: 90,
|
||||
costPerKW: 0.13
|
||||
)))),
|
||||
.heatingBalancePoint(.submit(.thermal(.init(
|
||||
systemSize: 2,
|
||||
capacityAt47: 24600,
|
||||
capacityAt17: 15100,
|
||||
heatingDesignTemperature: 5,
|
||||
buildingHeatLoss: .known(btu: 45667),
|
||||
climateZone: .five
|
||||
)))),
|
||||
|
||||
// HVAC System Performance
|
||||
.hvacSystemPerformance(.index),
|
||||
.hvacSystemPerformance(.submit(.init(
|
||||
altitude: 800,
|
||||
airflow: 800,
|
||||
returnAirTemperature: 76,
|
||||
returnAirHumidity: 67,
|
||||
supplyAirTemperature: 56,
|
||||
supplyAirHumidity: 89,
|
||||
systemSize: 2
|
||||
))),
|
||||
|
||||
// Mold risk
|
||||
.moldRisk(.index),
|
||||
.moldRisk(.submit(.init(temperature: 76, humidity: 67))),
|
||||
|
||||
// Psychrometrics
|
||||
.psychrometrics(.index),
|
||||
.psychrometrics(.submit(.init(temperature: 76, humidity: 67, altitude: 800))),
|
||||
|
||||
// Room pressures
|
||||
.roomPressure(.index),
|
||||
.roomPressure(.index(mode: .measuredPressure)),
|
||||
.roomPressure(.submit(.knownAirflow(.init(
|
||||
targetRoomPressure: 3,
|
||||
doorWidth: 30,
|
||||
doorHeight: 86,
|
||||
doorUndercut: 1,
|
||||
supplyAirflow: 200,
|
||||
preferredGrilleHeight: .fourteen
|
||||
)))),
|
||||
.roomPressure(.submit(.measuredPressure(.init(
|
||||
measuredRoomPressure: 4,
|
||||
doorWidth: 30,
|
||||
doorHeight: 86,
|
||||
doorUndercut: 1,
|
||||
preferredGrilleHeight: .fourteen
|
||||
))))
|
||||
|
||||
])
|
||||
|
||||
for route in arguments {
|
||||
@@ -71,6 +136,8 @@ struct ViewControllerTests {
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:enable function_body_length
|
||||
|
||||
}
|
||||
|
||||
private extension ViewController {
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
<div class="flex flex-wrap justify-between">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="block text-blue-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-scale">
|
||||
<path d="m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"/>
|
||||
<path d="m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"/>
|
||||
<path d="M7 21h10"/><path d="M12 3v18"/>
|
||||
<path d="M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="text-2xl font-extrabold">Balance Point - Thermal</h2>
|
||||
</div>
|
||||
<div class="flex items-center gap-x-0 mb-6">
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-yellow-300 enabled:hover:bg-yellow-400
|
||||
text-blue-600 rounded-s-lg" disabled type="button">Thermal</button>
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-blue-500 enabled:hover:bg-blue-600
|
||||
text-yellow-300 rounded-e-lg" hx-target="#content" hx-push-url="true" hx-get="/balance-point?mode=economic&heatLossMode=estimated" type="button">Economic</button>
|
||||
</div>
|
||||
</div>
|
||||
<form hx-post="/balance-point" hx-target="#result">
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<label for="systemSize" class="block text-sm font-medium mb-2">System Size (Tons)</label>
|
||||
<input id="systemSize" placeholder="System size" name="systemSize" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="1" step="0.5" autofocus required>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-4">
|
||||
<h4 class="text-lg font-bold">Capacities</h4>
|
||||
<p class="text-xs text-blue-500">Entering known capacities gives better results, otherwise capacities will be estimated.</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label for="capacityAt47" class="block text-sm font-medium mb-2">Capacity @ 47° (BTU/h)</label>
|
||||
<input id="capacityAt47" placeholder="Capacity @ 47° (optional)" name="capacityAt47" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="1" step="0.5">
|
||||
</div>
|
||||
<div>
|
||||
<label for="capacityAt17" class="block text-sm font-medium mb-2">Capacity @ 17° (BTU/h)</label>
|
||||
<input id="capacityAt17" placeholder="Capacity @ 17° (optional)" name="capacityAt17" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="1" step="0.5">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="heatLossFields">
|
||||
<div class="flex flex-wrap justify-between">
|
||||
<h4 class="text-lg font-bold">Heat Loss - Estimated</h4>
|
||||
<div class="flex items-center gap-x-0 mb-6">
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-yellow-300 enabled:hover:bg-yellow-400
|
||||
text-blue-600 rounded-s-lg" disabled type="button">Estimated</button>
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-blue-500 enabled:hover:bg-blue-600
|
||||
text-yellow-300 rounded-e-lg" hx-get="/balance-point/heat-loss?mode=known" hx-target="#heatLossFields" type="button">Known</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label for="simplifiedHeatLoss" class="block text-sm font-medium mb-2">Building Size (ft²)</label>
|
||||
<input id="simplifiedHeatLoss" placeholder="Square feet" name="simplifiedHeatLoss" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="1" step="0.5" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="climateZone" class="block text-sm font-medium mb-2">Climate Zone</label>
|
||||
<select id="climateZone" name="climateZone" class="w-full rounded-md border px-4 py-2 min-h-11">
|
||||
<option value="CZ1">CZ1</option>
|
||||
<option value="CZ2">CZ2</option>
|
||||
<option value="CZ3">CZ3</option>
|
||||
<option value="CZ4">CZ4</option>
|
||||
<option value="CZ5">CZ5</option>
|
||||
<option value="CZ6">CZ6</option>
|
||||
<option value="CZ7">CZ7</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="heatingDesignTemperature" class="block text-sm font-medium mb-2">Outdoor Design Temperature (°F)</label>
|
||||
<input id="heatingDesignTemperature" placeholder="Design temperature (optional)" name="heatingDesignTemperature" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.5">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class=" w-full font-bold py-3 rounded-md transition-colors
|
||||
bg-yellow-300 dark:bg-blue-500
|
||||
hover:bg-yellow-400 hover:dark:bg-blue-600
|
||||
text-blue-500 dark:text-yellow-300">Calculate Balance Point</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="result"></div>
|
||||
@@ -0,0 +1,41 @@
|
||||
<div id="heatLossFields">
|
||||
<div class="flex flex-wrap justify-between">
|
||||
<h4 class="text-lg font-bold">Heat Loss - Estimated</h4>
|
||||
<div class="flex items-center gap-x-0 mb-6">
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-yellow-300 enabled:hover:bg-yellow-400
|
||||
text-blue-600 rounded-s-lg" disabled type="button">Estimated</button>
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-blue-500 enabled:hover:bg-blue-600
|
||||
text-yellow-300 rounded-e-lg" hx-get="/balance-point/heat-loss?mode=known" hx-target="#heatLossFields" type="button">Known</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label for="simplifiedHeatLoss" class="block text-sm font-medium mb-2">Building Size (ft²)</label>
|
||||
<input id="simplifiedHeatLoss" placeholder="Square feet" name="simplifiedHeatLoss" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="1" step="0.5" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="climateZone" class="block text-sm font-medium mb-2">Climate Zone</label>
|
||||
<select id="climateZone" name="climateZone" class="w-full rounded-md border px-4 py-2 min-h-11">
|
||||
<option value="CZ1">CZ1</option>
|
||||
<option value="CZ2">CZ2</option>
|
||||
<option value="CZ3">CZ3</option>
|
||||
<option value="CZ4">CZ4</option>
|
||||
<option value="CZ5">CZ5</option>
|
||||
<option value="CZ6">CZ6</option>
|
||||
<option value="CZ7">CZ7</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="heatingDesignTemperature" class="block text-sm font-medium mb-2">Outdoor Design Temperature (°F)</label>
|
||||
<input id="heatingDesignTemperature" placeholder="Design temperature (optional)" name="heatingDesignTemperature" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.5">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,29 @@
|
||||
<div id="heatLossFields">
|
||||
<div class="flex flex-wrap justify-between">
|
||||
<h4 class="text-lg font-bold">Heat Loss - Known</h4>
|
||||
<div class="flex items-center gap-x-0 mb-6">
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-blue-500 enabled:hover:bg-blue-600
|
||||
text-yellow-300 rounded-s-lg" hx-get="/balance-point/heat-loss?mode=estimated" hx-target="#heatLossFields" type="button">Estimated</button>
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-yellow-300 enabled:hover:bg-yellow-400
|
||||
text-blue-600 rounded-e-lg" disabled type="button">Known</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label for="knownHeatLoss" class="block text-sm font-medium mb-2">Heat Loss (BTU/h)</label>
|
||||
<input id="knownHeatLoss" placeholder="Heat loss" name="knownHeatLoss" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="1" step="0.5" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="heatingDesignTemperature" class="block text-sm font-medium mb-2">Outdoor Design Temperature (°F)</label>
|
||||
<input id="heatingDesignTemperature" placeholder="Design temperature" name="heatingDesignTemperature" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.5" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,51 @@
|
||||
<div class=" mt-6 p-6 rounded-lg border border-blue-500
|
||||
bg-blue-50 dark:bg-slate-600
|
||||
text-blue-500 dark:text-slate-200">
|
||||
<div class="relative">
|
||||
<h3 class="text-xl font-semibold mb-4">Results</h3>
|
||||
<button class=" font-bold px-4 py-2 rounded-md transition-colors
|
||||
bg-blue-500 dark:bg-yellow-300
|
||||
hover:bg-blue-600 hover:dark:bg-yellow-400
|
||||
text-yellow-300 dark:text-blue-500 absolute bottom-0 right-0" hx-get="/balance-point?mode=economic" hx-target="#content">Reset</button>
|
||||
</div>
|
||||
<div class="w-full rounded-xl shadow-xl bg-blue-100 text-blue-600 border border-blue-600 py-4">
|
||||
<div class="flex">
|
||||
<div class="block text-blue-600 px-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-scale">
|
||||
<path d="m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"/>
|
||||
<path d="m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"/>
|
||||
<path d="M7 21h10"/><path d="M12 3v18"/>
|
||||
<path d="M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2"/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="font-medium">Economic Balance Point</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="grid grid-cols-1 justify-items-center mb-8">
|
||||
<p class="font-medium">Balance Point</p>
|
||||
<h3 class="text-3xl font-extrabold">-13<span class="text-lg ms-2">°F</span></h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 space-y-6">
|
||||
<div>
|
||||
<div class="grid grid-cols-1 justify-items-center">
|
||||
<p class="font-medium">Electric Cost</p>
|
||||
<h3 class="text-3xl font-extrabold">$38.1<span class="text-lg ms-2">/ MMBTU</span></h3>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="grid grid-cols-1 justify-items-center">
|
||||
<p class="font-medium">Fuel Cost</p>
|
||||
<h3 class="text-3xl font-extrabold">$29.56<span class="text-lg ms-2">/ MMBTU</span></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="grid grid-cols-1 justify-items-center">
|
||||
<p class="font-medium">COP at Balance Point</p>
|
||||
<h3 class="text-3xl font-extrabold">1.29</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="warnings"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,57 @@
|
||||
<div class=" mt-6 p-6 rounded-lg border border-blue-500
|
||||
bg-blue-50 dark:bg-slate-600
|
||||
text-blue-500 dark:text-slate-200">
|
||||
<div class="relative">
|
||||
<h3 class="text-xl font-semibold mb-4">Results</h3>
|
||||
<button class=" font-bold px-4 py-2 rounded-md transition-colors
|
||||
bg-blue-500 dark:bg-yellow-300
|
||||
hover:bg-blue-600 hover:dark:bg-yellow-400
|
||||
text-yellow-300 dark:text-blue-500 absolute bottom-0 right-0" hx-get="/balance-point?mode=thermal" hx-target="#content">Reset</button>
|
||||
</div>
|
||||
<div class="w-full rounded-xl shadow-xl bg-blue-100 text-blue-600 border border-blue-600 py-4">
|
||||
<div class="flex">
|
||||
<div class="block text-blue-600 px-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-scale">
|
||||
<path d="m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"/>
|
||||
<path d="m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"/>
|
||||
<path d="M7 21h10"/><path d="M12 3v18"/>
|
||||
<path d="M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2"/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="font-medium">Thermal Balance Point</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="grid grid-cols-1 justify-items-center mb-8">
|
||||
<p class="font-medium">Balance Point</p>
|
||||
<h3 class="text-3xl font-extrabold">36.9<span class="text-lg ms-2">°F</span></h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 space-y-6">
|
||||
<div>
|
||||
<div class="grid grid-cols-1 justify-items-center">
|
||||
<p class="font-medium">Heat Loss - Known</p>
|
||||
<h3 class="text-3xl font-extrabold">45,667<span class="text-lg ms-2">BTU/h</span></h3>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="grid grid-cols-1 justify-items-center">
|
||||
<p class="font-medium">Heating Design Temperature</p>
|
||||
<h3 class="text-3xl font-extrabold">5<span class="text-lg ms-2">°F</span></h3>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="grid grid-cols-1 justify-items-center">
|
||||
<p class="font-medium">Capacity @ 47°</p>
|
||||
<h3 class="text-3xl font-extrabold">24,600<span class="text-lg ms-2">BTU/h</span></h3>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="grid grid-cols-1 justify-items-center">
|
||||
<p class="font-medium">Capacity @ 17°</p>
|
||||
<h3 class="text-3xl font-extrabold">15,100<span class="text-lg ms-2">BTU/h</span></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="warnings"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,82 @@
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="block text-blue-500">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path stroke="currentColor" d="M12 9C11.1077 8.98562 10.2363 9.27003 9.52424 9.808C8.81222 10.346 8.30055 11.1066 8.07061 11.9688C7.84068 12.8311 7.90568 13.7455 8.25529 14.5665C8.6049 15.3876 9.21904 16.0682 10 16.5M12 3V5M6.6 18.4L5.2 19.8M4 13H2M6.6 7.6L5.2 6.2M20 14.5351V4C20 2.89543 19.1046 2 18 2C16.8954 2 16 2.89543 16 4V14.5351C14.8044 15.2267 14 16.5194 14 18C14 20.2091 15.7909 22 18 22C20.2091 22 22 20.2091 22 18C22 16.5194 21.1956 15.2267 20 14.5351Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="text-2xl font-extrabold">HVAC System Performance</h2>
|
||||
</div>
|
||||
<form hx-post="/hvac-system-performance" hx-target="#result">
|
||||
<div class="space-y-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label for="systemSize" class="block text-sm font-medium mb-2">System Size (Tons)</label>
|
||||
<input id="systemSize" placeholder="System size" name="systemSize" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="1" step="0.5" autofocus required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="airflow" class="block text-sm font-medium mb-2">Airflow (CFM)</label>
|
||||
<input id="airflow" placeholder="Airflow" name="airflow" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="1" step="0.5" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="altitude" class="block text-sm font-medium mb-2">Altitude (ft.)</label>
|
||||
<input id="altitude" placeholder="Project altitude (Optional)" name="altitude" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="1" step="0.5">
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium">Return Air</h3>
|
||||
<div>
|
||||
<label for="returnAirTemperature" class="block text-sm font-medium mb-2">Dry Bulb (°F)</label>
|
||||
<input id="returnAirTemperature" placeholder="Return temperature" name="returnAirTemperature" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500">
|
||||
</div>
|
||||
<div>
|
||||
<label for="returnAirHumidity" class="block text-sm font-medium mb-2">Indoor Humdity (%)</label>
|
||||
<input id="returnAirHumidity" placeholder="Return humidity" name="returnAirHumidity" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium">Supply Air</h3>
|
||||
<div>
|
||||
<label for="supplyAirTemperature" class="block text-sm font-medium mb-2">Dry Bulb (°F)</label>
|
||||
<input id="supplyAirTemperature" placeholder="Supply temperature" name="supplyAirTemperature" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500">
|
||||
</div>
|
||||
<div>
|
||||
<label for="supplyAirHumidity" class="block text-sm font-medium mb-2">Indoor Humdity (%)</label>
|
||||
<input id="supplyAirHumidity" placeholder="Supply humidity" name="supplyAirHumidity" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class=" w-full font-bold py-3 rounded-md transition-colors
|
||||
bg-yellow-300 dark:bg-blue-500
|
||||
hover:bg-yellow-400 hover:dark:bg-blue-600
|
||||
text-blue-500 dark:text-yellow-300">Calculate Performance</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="result"></div>
|
||||
@@ -0,0 +1,95 @@
|
||||
<div class=" mt-6 p-6 rounded-lg border border-blue-500
|
||||
bg-blue-50 dark:bg-slate-600
|
||||
text-blue-500 dark:text-slate-200">
|
||||
<div class="relative">
|
||||
<h3 class="text-xl font-semibold mb-4">Results</h3>
|
||||
<button class=" font-bold px-4 py-2 rounded-md transition-colors
|
||||
bg-blue-500 dark:bg-yellow-300
|
||||
hover:bg-blue-600 hover:dark:bg-yellow-400
|
||||
text-yellow-300 dark:text-blue-500 absolute bottom-0 right-0" hx-get="/hvac-system-performance" hx-target="#content">Reset</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||
<div class="rounded-xl text-blue-600 bg-blue-100 border border-blue-600 p-6">
|
||||
<h4 class="text-lg font-semibold mb-2">Total Capacity</h4>
|
||||
<div class="text-3xl font-bold">2.9<span class="text-xl ps-2">Tons</span></div>
|
||||
<div class="text-sm mt-1">35,396.9 BTU/h</div>
|
||||
</div>
|
||||
<div class="rounded-xl text-green-600 bg-green-100 border border-green-600 p-6">
|
||||
<h4 class="text-lg font-semibold mb-2">Sensible Capacity</h4>
|
||||
<div class="text-3xl font-bold">1.4<span class="text-xl ps-2">Tons</span></div>
|
||||
<div class="text-sm mt-1">17,280 BTU/h</div>
|
||||
</div>
|
||||
<div class="rounded-xl text-purple-600 bg-purple-100 border border-purple-600 p-6">
|
||||
<h4 class="text-lg font-semibold mb-2">Latent Capacity</h4>
|
||||
<div class="text-3xl font-bold">1.5<span class="text-xl ps-2">Tons</span></div>
|
||||
<div class="text-sm mt-1">18,116.9 BTU/h</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8 border rounded-xl shadow-lg">
|
||||
<h4 class="text-lg font-semibold flex justify-center py-2 mb-4 text-blue-600 dark:text-slate-300">System Performance Metrics</h4>
|
||||
<div class="flex justify-between items-center p-4">
|
||||
<div class="space-y-3">
|
||||
<div class="mb-8">
|
||||
<span class="text-sm">Airflow per Ton</span>
|
||||
<p class="text-2xl font-semibold">400<span class="text-base font-normal ps-2">CFM/ton</span></p>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<span class="text-sm">Temperature Split</span>
|
||||
<p class="text-2xl font-semibold">20<span class="text-base font-normal ps-2">°F</span></p>
|
||||
</div>
|
||||
<p class="text-xs">Target: 20.83 °F</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="mb-8">
|
||||
<span class="text-sm">Moisture Removal</span>
|
||||
<p class="text-2xl font-semibold">2<span class="text-base font-normal ps-2">gal/h</span></p>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-sm">Sensible Heat Ratio</span>
|
||||
<p class="text-2xl font-semibold">0.5<span class="text-base font-normal ps-2">%</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="warnings" class=" mt-6 p-4 rounded-lg shadow-lg
|
||||
text-amber-500
|
||||
bg-amber-100 dark:bg-amber-200
|
||||
border border-amber-500 mb-4 mx-8">
|
||||
<span class="font-semibold mb-4 border-b border-amber-500">Warning:</span>
|
||||
<ul class="list-disc mx-10 mt-4">
|
||||
<li>Low sensible heat ratio may indicate excessive dehumidification or low airflow.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-8">
|
||||
<div class="rounded-xl border border-blue-600 dark:border-gray-400 bg-blue-100 dark:bg-slate-700 p-4">
|
||||
<h4 class=" text-lg font-semibold flex justify-center py-2 mb-4 text-blue-600 dark:text-slate-300">Return Air Properties</h4>
|
||||
<div class="w-full grid grid-cols-1 gap-4">
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Dew Point: </span><span class="font-light">64.3 °F</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Wet Bulb: </span><span class="font-light">67.64 °F</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Enthalpy: </span><span class="font-light">32.75 Btu/lb</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Density: </span><span class="font-light">0.07 lb/ft³</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Vapor Pressure: </span><span class="font-light">0.3 psi</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Specific Volume: </span><span class="font-light">14.2</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Absolute Humidity: </span><span class="font-light">94.18 gr/ft³</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Humidity Ratio: </span><span class="font-light">0.01</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Degree of Saturation: </span><span class="font-light">0.66</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-xl border border-blue-600 dark:border-gray-400 bg-blue-100 dark:bg-slate-700 p-4">
|
||||
<h4 class=" text-lg font-semibold flex justify-center py-2 mb-4 text-blue-600 dark:text-slate-300">Supply Air Properties</h4>
|
||||
<div class="w-full grid grid-cols-1 gap-4">
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Dew Point: </span><span class="font-light">52.87 °F</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Wet Bulb: </span><span class="font-light">54.01 °F</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Enthalpy: </span><span class="font-light">22.92 Btu/lb</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Density: </span><span class="font-light">0.07 lb/ft³</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Vapor Pressure: </span><span class="font-light">0.2 psi</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Specific Volume: </span><span class="font-light">13.57</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Absolute Humidity: </span><span class="font-light">61.47 gr/ft³</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Humidity Ratio: </span><span class="font-light">0.01</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Degree of Saturation: </span><span class="font-light">0.89</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,35 @@
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="block text-blue-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="w-8 h-8">
|
||||
<path d="M14 4v10.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0Z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="text-2xl font-extrabold">Mold Risk Calculator</h2>
|
||||
</div>
|
||||
<form hx-post="/mold-risk" hx-target="#result">
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<label for="temperature" class="block text-sm font-medium mb-2">Indoor Temperature (°F)</label>
|
||||
<input id="temperature" placeholder="Dry bulb temperature" name="temperature" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" autofocus required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="humidity" class="block text-sm font-medium mb-2">Indoor Humdity (%)</label>
|
||||
<input id="humidity" placeholder="Relative humidity" name="humidity" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" required>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class=" w-full font-bold py-3 rounded-md transition-colors
|
||||
bg-yellow-300 dark:bg-blue-500
|
||||
hover:bg-yellow-400 hover:dark:bg-blue-600
|
||||
text-blue-500 dark:text-yellow-300">Calculate Mold Risk</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="result"></div>
|
||||
@@ -0,0 +1,60 @@
|
||||
<div class=" mt-6 p-6 rounded-lg border border-blue-500
|
||||
bg-blue-50 dark:bg-slate-600
|
||||
text-blue-500 dark:text-slate-200">
|
||||
<div class="relative">
|
||||
<h3 class="text-xl font-semibold mb-4">Results</h3>
|
||||
<button class=" font-bold px-4 py-2 rounded-md transition-colors
|
||||
bg-blue-500 dark:bg-yellow-300
|
||||
hover:bg-blue-600 hover:dark:bg-yellow-400
|
||||
text-yellow-300 dark:text-blue-500 absolute bottom-0 right-0" hx-get="/mold-risk" hx-target="#content">Reset</button>
|
||||
</div>
|
||||
<div class="p-2 rounded-lg shadow-lg bg-amber-200 border-2 border border-amber-500">
|
||||
<div class="text-amber-500">
|
||||
<div class="flex flex-wrap mt-2">
|
||||
<div class="w-full sm:w-1/2 flex gap-2">
|
||||
<div class="block text-amber-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-6 h-6">
|
||||
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path>
|
||||
<path d="M12 9v4"></path>
|
||||
<path d="M12 17h.01"></path>
|
||||
</svg>
|
||||
</div>
|
||||
Risk Level: Moderate<span class="text-lg font-extrabold"></span>
|
||||
</div>
|
||||
<div class="w-full sm:w-1/2 gap-2"><span class="font-semibold">Estimated Days to Mold Growth: </span><span>30 days</span></div>
|
||||
</div>
|
||||
<div class="mt-6 pb-4">
|
||||
<p class="font-semibold mb-4">
|
||||
<u>Recommendations:</u>
|
||||
</p>
|
||||
<ul class="list-disc mx-10">
|
||||
<li>Improve ventilation to reduce moisture accumulation</li>
|
||||
<li>Inspect for and repair any water leaks or intrusion</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full rounded-lg border mt-8">
|
||||
<h3 class="flex justify-center text-xl font-semibold mb-6 mt-2">Psychrometric Properties</h3>
|
||||
<div class="w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-6 gap-y-2 px-4 pb-4">
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Dew Point: </span><span class="font-light">64.3 °F</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Wet Bulb: </span><span class="font-light">67.7 °F</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Enthalpy: </span><span class="font-light">32.33 Btu/lb</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Density: </span><span class="font-light">0.07 lb/ft³</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Vapor Pressure: </span><span class="font-light">0.3 psi</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Specific Volume: </span><span class="font-light">13.78</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Absolute Humidity: </span><span class="font-light">91.4 gr/ft³</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Humidity Ratio: </span><span class="font-light">0.01</span></div>
|
||||
<div class="flex items-center justify-between text-blue-500 dark:text-slate-200"><span class="font-semibold">Degree of Saturation: </span><span class="font-light">0.66</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8 p-4 bg-gray-100 dark:bg-gray-700 rounded-md shadow-md
|
||||
border border-blue-500 text-blue-500 text-sm">
|
||||
<p class="font-extrabold mb-3">Note:</p>
|
||||
<p class="px-6">
|
||||
These calculations are based on typical indoor conditions and common mold species. Actual mold growth can
|
||||
vary based on surface materials, air movement, and other environmental factors. Always address moisture
|
||||
issues promptly and consult professionals for severe cases.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,47 @@
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="block text-blue-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path d="M7 16.3c2.2 0 4-1.83 4-4.05 0-1.16-.57-2.26-1.71-3.19S7.29 6.75 7 5.3c-.29 1.45-1.14 2.84-2.29 3.76S3 11.1 3 12.25c0 2.22 1.8 4.05 4 4.05z"></path>
|
||||
<path d="M12.56 6.6A10.97 10.97 0 0014 3.02c.5 2.5 2 4.9 4 6.5s3 3.5 3 5.5a6.98 6.98 0 01-11.91 4.97"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="text-2xl font-extrabold">Psychrometric Properties</h2>
|
||||
</div>
|
||||
<form hx-post="/psychrometric-properties" hx-target="#result">
|
||||
<div class="space-y-6">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label for="temperature" class="block text-sm font-medium mb-2">Temperature (°F)</label>
|
||||
<input id="temperature" placeholder="Dry bulb temperature" name="temperature" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="0.1" step="0.1" autofocus required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="humidity" class="block text-sm font-medium mb-2">Relative Humidity (%)</label>
|
||||
<input id="humidity" placeholder="Relative humidity" name="humidity" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="0.1" step="0.1" max="100" required>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="altitude" class="block text-sm font-medium mb-2">Altitude (ft.)</label>
|
||||
<input id="altitude" placeholder="Altitude (optional)" name="altitude" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" min="0.1" step="0.1">
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class=" w-full font-bold py-3 rounded-md transition-colors
|
||||
bg-yellow-300 dark:bg-blue-500
|
||||
hover:bg-yellow-400 hover:dark:bg-blue-600
|
||||
text-blue-500 dark:text-yellow-300">Calculate Psychrometrics</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="result"></div>
|
||||
@@ -0,0 +1,58 @@
|
||||
<div class=" mt-6 p-6 rounded-lg border border-blue-500
|
||||
bg-blue-50 dark:bg-slate-600
|
||||
text-blue-500 dark:text-slate-200">
|
||||
<div class="relative">
|
||||
<h3 class="text-xl font-semibold mb-4">Results</h3>
|
||||
<button class=" font-bold px-4 py-2 rounded-md transition-colors
|
||||
bg-blue-500 dark:bg-yellow-300
|
||||
hover:bg-blue-600 hover:dark:bg-yellow-400
|
||||
text-yellow-300 dark:text-blue-500 absolute bottom-0 right-0" hx-get="/psychrometric-properties" hx-target="#content">Reset</button>
|
||||
</div>
|
||||
<div class="w-full rounded-lg shadow-lg bg-blue-100 border border-blue-600 text-blue-600 p-6">
|
||||
<div class="flex mb-8">
|
||||
<div class="block text-blue-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path d="M7 16.3c2.2 0 4-1.83 4-4.05 0-1.16-.57-2.26-1.71-3.19S7.29 6.75 7 5.3c-.29 1.45-1.14 2.84-2.29 3.76S3 11.1 3 12.25c0 2.22 1.8 4.05 4 4.05z"></path>
|
||||
<path d="M12.56 6.6A10.97 10.97 0 0014 3.02c.5 2.5 2 4.9 4 6.5s3 3.5 3 5.5a6.98 6.98 0 01-11.91 4.97"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl px-2 font-semibold">Psychrometrics</h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div class="rounded-lg bg-purple-200 border border-purple-600 text-purple-600">
|
||||
<div class="grid grid-cols-1 justify-items-center my-8">
|
||||
<p class="font-medium">Dew Point</p>
|
||||
<h3 class="text-3xl font-extrabold">64.3<span class="text-lg ms-2">°F</span></h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-lg bg-orange-200 border border-orange-600 text-orange-600">
|
||||
<div class="grid grid-cols-1 justify-items-center my-8">
|
||||
<p class="font-medium">Enthalpy</p>
|
||||
<h3 class="text-3xl font-extrabold">32.8<span class="text-lg ms-2">Btu/lb</span></h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-lg bg-green-200 border border-green-600 text-green-600">
|
||||
<div class="grid grid-cols-1 justify-items-center my-8">
|
||||
<p class="font-medium">Wet Bulb</p>
|
||||
<h3 class="text-3xl font-extrabold">67.6<span class="text-lg ms-2">°F</span></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8">
|
||||
<h4 class="text-lg font-semibold">Other Properties</h4>
|
||||
<div class="rounded-lg border border-blue-300">
|
||||
<div class="flex items-center justify-between border-b border-blue-300 p-2"><span class="font-semibold">Density: </span><span class="font-light">0.07 lb/ft³</span></div>
|
||||
<div class="flex items-center justify-between border-b border-blue-300 p-2"><span class="font-semibold">Vapor Pressure: </span><span class="font-light">0.3 psi</span></div>
|
||||
<div class="flex items-center justify-between border-b border-blue-300 p-2"><span class="font-semibold">Specific Volume: </span><span class="font-light">14.2</span></div>
|
||||
<div class="flex items-center justify-between border-b border-blue-300 p-2"><span class="font-semibold">Absolute Humidity: </span><span class="font-light">94.18 gr/ft³</span></div>
|
||||
<div class="flex items-center justify-between border-b border-blue-300 p-2"><span class="font-semibold">Humidity Ratio: </span><span class="font-light">0.01</span></div>
|
||||
<div class="flex items-center justify-between border-b border-blue-300 p-2"><span class="font-semibold">Degree of Saturation: </span><span class="font-light">0.66</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="warnings"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,80 @@
|
||||
<div class="relative">
|
||||
<div class="flex flex-wrap justify-between">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="block text-blue-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-left-right">
|
||||
<path d="M8 3 4 7l4 4"/>
|
||||
<path d="M4 7h16"/>
|
||||
<path d="m16 21 4-4-4-4"/>
|
||||
<path d="M20 17H4"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="text-2xl font-extrabold">Room Pressure Calculator - Known Airflow</h2>
|
||||
</div>
|
||||
<div class="flex items-center gap-x-0 mb-6">
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-yellow-300 enabled:hover:bg-yellow-400
|
||||
text-blue-600 rounded-s-lg" disabled type="button">Known Airflow</button>
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-blue-500 enabled:hover:bg-blue-600
|
||||
text-yellow-300 rounded-e-lg" hx-target="#content" hx-push-url="true" hx-get="/room-pressure?mode=measuredPressure" type="button">Measured Pressure</button>
|
||||
</div>
|
||||
</div>
|
||||
<form hx-post="/room-pressure" hx-target="#result" class="mt-6">
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<label for="targetRoomPressure" class="block text-sm font-medium mb-2">Target Room Pressure (Pascals)</label>
|
||||
<input id="targetRoomPressure" placeholder="Room pressure (max 3 pa.)" name="targetRoomPressure" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" max="3.0" autofocus required>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label for="doorWidth" class="block text-sm font-medium mb-2">Door Width (in.)</label>
|
||||
<input id="doorWidth" placeholder="Width" name="doorWidth" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="doorHeight" class="block text-sm font-medium mb-2">Door Height (in.)</label>
|
||||
<input id="doorHeight" placeholder="Height" name="doorHeight" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" required>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="doorUndercut" class="block text-sm font-medium mb-2">Door Undercut (in.)</label>
|
||||
<input id="doorUndercut" placeholder="Undercut height" name="doorUndercut" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="supplyAirflow" class="block text-sm font-medium mb-2">Supply Airflow (CFM)</label>
|
||||
<input id="supplyAirflow" placeholder="Airflow" name="supplyAirflow" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" required>
|
||||
</div>
|
||||
Preferred Grille Height<label for="preferredGrilleHeight" class="block text-sm font-medium mb-2"></label>
|
||||
<select id="preferredGrilleHeight" name="preferredGrilleHeight" class="w-full px-4 py-2 rounded-md border">
|
||||
<option value="4">4"</option>
|
||||
<option value="6">6"</option>
|
||||
<option value="8">8"</option>
|
||||
<option value="10">10"</option>
|
||||
<option value="12">12"</option>
|
||||
<option value="14">14"</option>
|
||||
</select>
|
||||
<div>
|
||||
<button type="submit" class=" w-full font-bold py-3 rounded-md transition-colors
|
||||
bg-yellow-300 dark:bg-blue-500
|
||||
hover:bg-yellow-400 hover:dark:bg-blue-600
|
||||
text-blue-500 dark:text-yellow-300">Calculate Return Path Size</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="result"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,73 @@
|
||||
<div class="relative">
|
||||
<div class="flex flex-wrap justify-between">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="block text-blue-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-left-right">
|
||||
<path d="M8 3 4 7l4 4"/>
|
||||
<path d="M4 7h16"/>
|
||||
<path d="m16 21 4-4-4-4"/>
|
||||
<path d="M20 17H4"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="text-2xl font-extrabold">Room Pressure Calculator - Measured Pressure</h2>
|
||||
</div>
|
||||
<div class="flex items-center gap-x-0 mb-6">
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-blue-500 enabled:hover:bg-blue-600
|
||||
text-yellow-300 rounded-s-lg" hx-target="#content" hx-push-url="true" hx-get="/room-pressure?mode=knownAirflow" type="button">Known Airflow</button>
|
||||
<button class=" font-bold py-2 px-4 transition-colors
|
||||
bg-yellow-300 enabled:hover:bg-yellow-400
|
||||
text-blue-600 rounded-e-lg" disabled type="button">Measured Pressure</button>
|
||||
</div>
|
||||
</div>
|
||||
<form hx-post="/room-pressure" hx-target="#result" class="mt-6">
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<label for="measuredRoomPressure" class="block text-sm font-medium mb-2">Measured Room Pressure (Pascals)</label>
|
||||
<input id="measuredRoomPressure" placeholder="Measured pressure" name="measuredRoomPressure" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" autofocus required>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label for="doorWidth" class="block text-sm font-medium mb-2">Door Width (in.)</label>
|
||||
<input id="doorWidth" placeholder="Width" name="doorWidth" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="doorHeight" class="block text-sm font-medium mb-2">Door Height (in.)</label>
|
||||
<input id="doorHeight" placeholder="Height" name="doorHeight" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" required>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="doorUndercut" class="block text-sm font-medium mb-2">Door Undercut (in.)</label>
|
||||
<input id="doorUndercut" placeholder="Undercut height" name="doorUndercut" class=" w-full px-4 py-2 border rounded-md min-h-11
|
||||
focus:ring-2 focus:ring-yellow-800 focus:border-yellow-800
|
||||
placeholder-shown:!border-gray-400
|
||||
invalid:border-red-500 out-of-range:border-red-500" type="number" step="0.1" min="0.1" required>
|
||||
</div>
|
||||
Preferred Grille Height<label for="preferredGrilleHeight" class="block text-sm font-medium mb-2"></label>
|
||||
<select id="preferredGrilleHeight" name="preferredGrilleHeight" class="w-full px-4 py-2 rounded-md border">
|
||||
<option value="4">4"</option>
|
||||
<option value="6">6"</option>
|
||||
<option value="8">8"</option>
|
||||
<option value="10">10"</option>
|
||||
<option value="12">12"</option>
|
||||
<option value="14">14"</option>
|
||||
</select>
|
||||
<div>
|
||||
<button type="submit" class=" w-full font-bold py-3 rounded-md transition-colors
|
||||
bg-yellow-300 dark:bg-blue-500
|
||||
hover:bg-yellow-400 hover:dark:bg-blue-600
|
||||
text-blue-500 dark:text-yellow-300">Calculate Return Path Size</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="result"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
<div class=" mt-6 p-6 rounded-lg border border-blue-500
|
||||
bg-blue-50 dark:bg-slate-600
|
||||
text-blue-500 dark:text-slate-200">
|
||||
<div class="relative">
|
||||
<h3 class="text-xl font-semibold mb-4">Results</h3>
|
||||
<button class=" font-bold px-4 py-2 rounded-md transition-colors
|
||||
bg-blue-500 dark:bg-yellow-300
|
||||
hover:bg-blue-600 hover:dark:bg-yellow-400
|
||||
text-yellow-300 dark:text-blue-500 absolute bottom-0 right-0" hx-get="/room-pressure?mode=knownAirflow" hx-target="#content">Reset</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<div class="rounded-xl p-6 bg-blue-100 border border-blue-600 text-blue-600">
|
||||
<h4 class="text-xl font-bold">Return / Transfer Grille</h4>
|
||||
<div class="flex justify-between mt-6"><span class="font-semibold">Standard Size:</span><span> 14" x 14"</span></div>
|
||||
<div class="flex justify-between mt-3"><span class="font-semibold">Required Net Free Area:</span><span> 0.5 in<sup>2</sup></span></div>
|
||||
<div class="mt-8 text-sm"><span class="font-semibold">Note: </span><span>Select a grille with at least 0.5 in<sup>2</sup><span> net free area.</span></span></div>
|
||||
</div>
|
||||
<div class="rounded-xl p-6 bg-purple-100 border border-purple-600 text-purple-600">
|
||||
<h4 class="text-xl font-bold">Return / Transfer Duct</h4>
|
||||
<div class="flex justify-between mt-6"><span class="font-semibold">Standard Size:</span><span>9"</span></div>
|
||||
<div class="flex justify-between mt-3"><span class="font-semibold">Air Velocity:</span><span>452.7 FPM</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="warnings"></div>
|
||||
<div class="mt-8 p-4 bg-gray-100 dark:bg-gray-700 rounded-md shadow-md
|
||||
border border-blue-500 text-blue-500 text-sm">
|
||||
<p class="font-extrabold mb-3">Note:</p>
|
||||
<p class="px-6">
|
||||
Calculations are based on a target velocity of 400 FPM for return/transfer air paths.
|
||||
The required net free area is the minimum needed - select a grille that meets or exceeds this value.
|
||||
Verify manufacturer specifications for actual net free area of selected grilles.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
<div class=" mt-6 p-6 rounded-lg border border-blue-500
|
||||
bg-blue-50 dark:bg-slate-600
|
||||
text-blue-500 dark:text-slate-200">
|
||||
<div class="relative">
|
||||
<h3 class="text-xl font-semibold mb-4">Results</h3>
|
||||
<button class=" font-bold px-4 py-2 rounded-md transition-colors
|
||||
bg-blue-500 dark:bg-yellow-300
|
||||
hover:bg-blue-600 hover:dark:bg-yellow-400
|
||||
text-yellow-300 dark:text-blue-500 absolute bottom-0 right-0" hx-get="/room-pressure?mode=measuredPressure" hx-target="#content">Reset</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<div class="rounded-xl p-6 bg-blue-100 border border-blue-600 text-blue-600">
|
||||
<h4 class="text-xl font-bold">Return / Transfer Grille</h4>
|
||||
<div class="flex justify-between mt-6"><span class="font-semibold">Standard Size:</span><span> 14" x 14"</span></div>
|
||||
<div class="flex justify-between mt-3"><span class="font-semibold">Required Net Free Area:</span><span> 0.5 in<sup>2</sup></span></div>
|
||||
<div class="mt-8 text-sm"><span class="font-semibold">Note: </span><span>Select a grille with at least 0.5 in<sup>2</sup><span> net free area.</span></span></div>
|
||||
</div>
|
||||
<div class="rounded-xl p-6 bg-purple-100 border border-purple-600 text-purple-600">
|
||||
<h4 class="text-xl font-bold">Return / Transfer Duct</h4>
|
||||
<div class="flex justify-between mt-6"><span class="font-semibold">Standard Size:</span><span>9"</span></div>
|
||||
<div class="flex justify-between mt-3"><span class="font-semibold">Air Velocity:</span><span>440.7 FPM</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="warnings"></div>
|
||||
<div class="mt-8 p-4 bg-gray-100 dark:bg-gray-700 rounded-md shadow-md
|
||||
border border-blue-500 text-blue-500 text-sm">
|
||||
<p class="font-extrabold mb-3">Note:</p>
|
||||
<p class="px-6">
|
||||
Calculations are based on a target velocity of 400 FPM for return/transfer air paths.
|
||||
The required net free area is the minimum needed - select a grille that meets or exceeds this value.
|
||||
Verify manufacturer specifications for actual net free area of selected grilles.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user