diff --git a/Public/css/output.css b/Public/css/output.css
index 8ec475b..2c733bb 100644
--- a/Public/css/output.css
+++ b/Public/css/output.css
@@ -9,6 +9,7 @@
monospace;
--color-amber-300: oklch(87.9% 0.169 91.605);
--color-green-400: oklch(79.2% 0.209 151.711);
+ --color-sky-300: oklch(82.8% 0.111 230.318);
--color-sky-600: oklch(58.8% 0.158 241.966);
--color-violet-600: oklch(54.1% 0.281 293.009);
--color-gray-200: oklch(92.8% 0.006 264.531);
@@ -34,8 +35,6 @@
--text-4xl--line-height: calc(2.5 / 2.25);
--text-5xl: 3rem;
--text-5xl--line-height: 1;
- --text-6xl: 3.75rem;
- --text-6xl--line-height: 1;
--text-8xl: 6rem;
--text-8xl--line-height: 1;
--font-weight-bold: 700;
@@ -4233,9 +4232,18 @@
--toast-y: 0;
}
}
+ .top-0 {
+ top: calc(var(--spacing) * 0);
+ }
.top-2 {
top: calc(var(--spacing) * 2);
}
+ .top-10 {
+ top: calc(var(--spacing) * 10);
+ }
+ .top-20 {
+ top: calc(var(--spacing) * 20);
+ }
.right-2 {
right: calc(var(--spacing) * 2);
}
@@ -4299,9 +4307,21 @@
.bottom-0 {
bottom: calc(var(--spacing) * 0);
}
+ .-left-10 {
+ left: calc(var(--spacing) * -10);
+ }
+ .-left-15 {
+ left: calc(var(--spacing) * -15);
+ }
+ .-left-20 {
+ left: calc(var(--spacing) * -20);
+ }
.left-0 {
left: calc(var(--spacing) * 0);
}
+ .left-10 {
+ left: calc(var(--spacing) * 10);
+ }
.join {
display: inline-flex;
align-items: stretch;
@@ -5243,6 +5263,9 @@
.m-1 {
margin: calc(var(--spacing) * 1);
}
+ .m-4 {
+ margin: calc(var(--spacing) * 4);
+ }
.m-6 {
margin: calc(var(--spacing) * 6);
}
@@ -5291,6 +5314,12 @@
}
}
}
+ .mx-10 {
+ margin-inline: calc(var(--spacing) * 10);
+ }
+ .mx-20 {
+ margin-inline: calc(var(--spacing) * 20);
+ }
.mx-auto {
margin-inline: auto;
}
@@ -5380,18 +5409,12 @@
}
}
}
- .-my-2 {
- margin-block: calc(var(--spacing) * -2);
- }
.my-1 {
margin-block: calc(var(--spacing) * 1);
}
.my-1\.5 {
margin-block: calc(var(--spacing) * 1.5);
}
- .my-2 {
- margin-block: calc(var(--spacing) * 2);
- }
.my-6 {
margin-block: calc(var(--spacing) * 6);
}
@@ -5601,18 +5624,12 @@
border-width: var(--border, 1px) 0 var(--border, 1px) var(--border, 1px);
}
}
- .-ms-2 {
- margin-inline-start: calc(var(--spacing) * -2);
- }
- .ms-2 {
- margin-inline-start: calc(var(--spacing) * 2);
+ .ms-10 {
+ margin-inline-start: calc(var(--spacing) * 10);
}
.me-2 {
margin-inline-end: calc(var(--spacing) * 2);
}
- .me-3 {
- margin-inline-end: calc(var(--spacing) * 3);
- }
.me-4 {
margin-inline-end: calc(var(--spacing) * 4);
}
@@ -5664,15 +5681,12 @@
.-mt-2 {
margin-top: calc(var(--spacing) * -2);
}
+ .mt-1 {
+ margin-top: calc(var(--spacing) * 1);
+ }
.mt-2 {
margin-top: calc(var(--spacing) * 2);
}
- .mt-3 {
- margin-top: calc(var(--spacing) * 3);
- }
- .mt-3\.5 {
- margin-top: calc(var(--spacing) * 3.5);
- }
.mt-4 {
margin-top: calc(var(--spacing) * 4);
}
@@ -5682,9 +5696,15 @@
.mt-8 {
margin-top: calc(var(--spacing) * 8);
}
+ .mt-10 {
+ margin-top: calc(var(--spacing) * 10);
+ }
.mt-20 {
margin-top: calc(var(--spacing) * 20);
}
+ .mt-60 {
+ margin-top: calc(var(--spacing) * 60);
+ }
.breadcrumbs {
@layer daisyui.l1.l2.l3 {
max-width: 100%;
@@ -5761,12 +5781,6 @@
font-weight: 600;
}
}
- .mb-1 {
- margin-bottom: calc(var(--spacing) * 1);
- }
- .mb-2 {
- margin-bottom: calc(var(--spacing) * 2);
- }
.mb-4 {
margin-bottom: calc(var(--spacing) * 4);
}
@@ -6634,6 +6648,12 @@
width: calc(var(--size-selector, 0.25rem) * 4);
}
}
+ .w-\[200px\] {
+ width: 200px;
+ }
+ .w-\[250px\] {
+ width: 250px;
+ }
.w-\[330px\] {
width: 330px;
}
@@ -6643,12 +6663,6 @@
.w-full {
width: 100%;
}
- .max-w-lg {
- max-width: var(--container-lg);
- }
- .max-w-md {
- max-width: var(--container-md);
- }
.min-w-\[80\%\] {
min-width: 80%;
}
@@ -6695,8 +6709,8 @@
.-rotate-45 {
rotate: calc(45deg * -1);
}
- .rotate-90 {
- rotate: 90deg;
+ .rotate-45 {
+ rotate: 45deg;
}
.rotate-180 {
rotate: 180deg;
@@ -6794,6 +6808,9 @@
}
}
}
+ .list-disc {
+ list-style-type: disc;
+ }
.alert-horizontal {
@layer daisyui.l1.l2 {
justify-content: start;
@@ -6875,6 +6892,9 @@
.flex-wrap {
flex-wrap: wrap;
}
+ .items-baseline {
+ align-items: baseline;
+ }
.items-center {
align-items: center;
}
@@ -6967,6 +6987,9 @@
.overflow-auto {
overflow: auto;
}
+ .overflow-hidden {
+ overflow: hidden;
+ }
.timeline-box {
@layer daisyui.l1.l2.l3 {
border: var(--border) solid;
@@ -7079,9 +7102,6 @@
.rounded-sm {
border-radius: var(--radius-sm);
}
- .rounded-xl {
- border-radius: var(--radius-xl);
- }
.rounded-t-box {
border-top-left-radius: var(--radius-box);
border-top-right-radius: var(--radius-box);
@@ -7258,10 +7278,18 @@
border-style: var(--tw-border-style);
border-width: 2px;
}
+ .border-3 {
+ border-style: var(--tw-border-style);
+ border-width: 3px;
+ }
.border-b-1 {
border-bottom-style: var(--tw-border-style);
border-bottom-width: 1px;
}
+ .border-b-6 {
+ border-bottom-style: var(--tw-border-style);
+ border-bottom-width: 6px;
+ }
.border-b-8 {
border-bottom-style: var(--tw-border-style);
border-bottom-width: 8px;
@@ -7375,8 +7403,8 @@
border-color: currentColor;
}
}
- .border-amber-300 {
- border-color: var(--color-amber-300);
+ .border-accent {
+ border-color: var(--color-accent);
}
.border-error {
border-color: var(--color-error);
@@ -7387,6 +7415,9 @@
.border-primary {
border-color: var(--color-primary);
}
+ .border-secondary {
+ border-color: var(--color-secondary);
+ }
.border-sky-600 {
border-color: var(--color-sky-600);
}
@@ -7550,6 +7581,9 @@
.bg-error {
background-color: var(--color-error);
}
+ .bg-primary {
+ background-color: var(--color-primary);
+ }
.bg-secondary {
background-color: var(--color-secondary);
}
@@ -7765,6 +7799,15 @@
}
}
}
+ .mask-contain {
+ mask-size: contain;
+ }
+ .mask-clip-border {
+ mask-clip: border-box;
+ }
+ .mask-clip-content {
+ mask-clip: content-box;
+ }
.mask-repeat {
mask-repeat: repeat;
}
@@ -7967,6 +8010,9 @@
.px-4 {
padding-inline: calc(var(--spacing) * 4);
}
+ .px-6 {
+ padding-inline: calc(var(--spacing) * 6);
+ }
.py-2 {
padding-block: calc(var(--spacing) * 2);
}
@@ -8629,6 +8675,9 @@
color: var(--color-warning);
}
}
+ .text-accent {
+ color: var(--color-accent);
+ }
.text-base-content {
color: var(--color-base-content);
}
@@ -8644,12 +8693,15 @@
.text-info {
color: var(--color-info);
}
+ .text-primary {
+ color: var(--color-primary);
+ }
+ .text-secondary {
+ color: var(--color-secondary);
+ }
.text-success {
color: var(--color-success);
}
- .text-violet-600 {
- color: var(--color-violet-600);
- }
.lowercase {
text-transform: lowercase;
}
@@ -8726,10 +8778,6 @@
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
- .shadow-xl {
- --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
- }
.outline {
outline-style: var(--tw-outline-style);
outline-width: 1px;
diff --git a/Public/files/ManD.Groups.pdf_original b/Public/files/ManD.Groups.pdf_original
deleted file mode 100755
index 994d241..0000000
Binary files a/Public/files/ManD.Groups.pdf_original and /dev/null differ
diff --git a/Sources/ManualDClient/Helpers.swift b/Sources/ManualDClient/Helpers.swift
index fc5b2aa..155fe81 100644
--- a/Sources/ManualDClient/Helpers.swift
+++ b/Sources/ManualDClient/Helpers.swift
@@ -1,50 +1,6 @@
import Foundation
import ManualDCore
-extension Room {
-
- public var heatingLoadPerRegister: Double {
- heatingLoad / Double(registerCount)
- }
-
- public func coolingSensiblePerRegister(projectSHR: Double) throws -> Double {
- let sensible = try coolingLoad.ensured(shr: projectSHR).sensible
- return sensible / Double(registerCount)
- }
-}
-
-extension TrunkSize.RoomProxy {
-
- // We need to make sure if registers got removed after a trunk
- // was already made / saved that we do not include registers that
- // no longer exist.
- private var actualRegisterCount: Int {
- guard registers.count <= room.registerCount else {
- return room.registerCount
- }
- return registers.count
- }
-
- var totalHeatingLoad: Double {
- room.heatingLoadPerRegister * Double(actualRegisterCount)
- }
-
- func totalCoolingSensible(projectSHR: Double) throws -> Double {
- try room.coolingSensiblePerRegister(projectSHR: projectSHR) * Double(actualRegisterCount)
- }
-}
-
-extension TrunkSize {
-
- var totalHeatingLoad: Double {
- rooms.reduce(into: 0) { $0 += $1.totalHeatingLoad }
- }
-
- func totalCoolingSensible(projectSHR: Double) throws -> Double {
- try rooms.reduce(into: 0) { $0 += try $1.totalCoolingSensible(projectSHR: projectSHR) }
- }
-}
-
extension Array where Element == EffectiveLengthGroup {
var totalEffectiveLength: Int {
reduce(0) { $0 + $1.effectiveLength }
diff --git a/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift b/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift
index 6fd3e72..859ced8 100644
--- a/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift
+++ b/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift
@@ -33,6 +33,7 @@ extension ManualDClient {
)
}
+ // FIX: Need to add the loads for rooms that get delegated to other rooms here.
func calculateRoomSizes(
rooms: [Room],
sharedRequest: DuctSizeSharedRequest,
@@ -42,10 +43,15 @@ extension ManualDClient {
var retval: [DuctSizes.RoomContainer] = []
let totalHeatingLoad = rooms.totalHeatingLoad
let totalCoolingSensible = try rooms.totalCoolingSensible(shr: sharedRequest.projectSHR)
+ let nonDelegatedRooms = rooms.filter { $0.delegatedTo == nil }
- for room in rooms {
- let heatingLoad = room.heatingLoadPerRegister
+ for room in nonDelegatedRooms {
+ // Get all the rooms that delegate their loads to this room.
+ let delegatedRooms = rooms.filter { $0.delegatedTo == room.id }
+
+ let heatingLoad = room.heatingLoadPerRegister(delegatedRooms: delegatedRooms)
let coolingLoad = try room.coolingSensiblePerRegister(projectSHR: sharedRequest.projectSHR)
+
let heatingPercent = heatingLoad / totalHeatingLoad
let coolingPercent = coolingLoad / totalCoolingSensible
let heatingCFM = heatingPercent * Double(sharedRequest.equipmentInfo.heatingCFM)
@@ -181,47 +187,34 @@ extension DuctSizes.SizeContainer {
}
}
-// extension Room {
+// extension TrunkSize.RoomProxy {
//
-// var heatingLoadPerRegister: Double {
-//
-// heatingLoad / Double(registerCount)
+// // We need to make sure if registers got removed after a trunk
+// // was already made / saved that we do not include registers that
+// // no longer exist.
+// private var actualRegisterCount: Int {
+// guard registers.count <= room.registerCount else {
+// return room.registerCount
+// }
+// return registers.count
// }
//
-// func coolingSensiblePerRegister(projectSHR: Double) -> Double {
-// let sensible = coolingSensible ?? (coolingTotal * projectSHR)
-// return sensible / Double(registerCount)
+// var totalHeatingLoad: Double {
+// room.heatingLoadPerRegister() * Double(actualRegisterCount)
+// }
+//
+// func totalCoolingSensible(projectSHR: Double) throws -> Double {
+// try room.coolingSensiblePerRegister(projectSHR: projectSHR) * Double(actualRegisterCount)
// }
// }
-extension TrunkSize.RoomProxy {
-
- // We need to make sure if registers got removed after a trunk
- // was already made / saved that we do not include registers that
- // no longer exist.
- private var actualRegisterCount: Int {
- guard registers.count <= room.registerCount else {
- return room.registerCount
- }
- return registers.count
- }
-
- var totalHeatingLoad: Double {
- room.heatingLoadPerRegister * Double(actualRegisterCount)
- }
-
- func totalCoolingSensible(projectSHR: Double) throws -> Double {
- try room.coolingSensiblePerRegister(projectSHR: projectSHR) * Double(actualRegisterCount)
- }
-}
-
-extension TrunkSize {
-
- var totalHeatingLoad: Double {
- rooms.reduce(into: 0) { $0 += $1.totalHeatingLoad }
- }
-
- func totalCoolingSensible(projectSHR: Double) throws -> Double {
- try rooms.reduce(into: 0) { $0 += try $1.totalCoolingSensible(projectSHR: projectSHR) }
- }
-}
+// extension TrunkSize {
+//
+// var totalHeatingLoad: Double {
+// rooms.reduce(into: 0) { $0 += $1.totalHeatingLoad }
+// }
+//
+// func totalCoolingSensible(projectSHR: Double) throws -> Double {
+// try rooms.reduce(into: 0) { $0 += try $1.totalCoolingSensible(projectSHR: projectSHR) }
+// }
+// }
diff --git a/Sources/ProjectClient/Internal/Room+loadPerRegister.swift b/Sources/ProjectClient/Internal/Room+loadPerRegister.swift
new file mode 100644
index 0000000..9346dbe
--- /dev/null
+++ b/Sources/ProjectClient/Internal/Room+loadPerRegister.swift
@@ -0,0 +1,20 @@
+import Foundation
+import ManualDCore
+
+extension Room {
+
+ public func heatingLoadPerRegister(delegatedRooms: [Room]? = nil) -> Double {
+ (heatingLoad + (delegatedRooms?.totalHeatingLoad ?? 0)) / Double(registerCount)
+ }
+
+ public func coolingSensiblePerRegister(
+ projectSHR: Double,
+ delegatedRooms: [Room]? = nil
+ ) throws -> Double {
+ let sensible =
+ try coolingLoad.ensured(shr: projectSHR).sensible
+ + (delegatedRooms?.totalCoolingSensible(shr: projectSHR) ?? 0)
+
+ return sensible / Double(registerCount)
+ }
+}
diff --git a/Sources/ProjectClient/Internal/TrunkSize+loads.swift b/Sources/ProjectClient/Internal/TrunkSize+loads.swift
new file mode 100644
index 0000000..2ab2bce
--- /dev/null
+++ b/Sources/ProjectClient/Internal/TrunkSize+loads.swift
@@ -0,0 +1,34 @@
+import Foundation
+import ManualDCore
+
+extension TrunkSize.RoomProxy {
+
+ // We need to make sure if registers got removed after a trunk
+ // was already made / saved that we do not include registers that
+ // no longer exist.
+ private var actualRegisterCount: Int {
+ guard registers.count <= room.registerCount else {
+ return room.registerCount
+ }
+ return registers.count
+ }
+
+ public var totalHeatingLoad: Double {
+ room.heatingLoadPerRegister() * Double(actualRegisterCount)
+ }
+
+ public func totalCoolingSensible(projectSHR: Double) throws -> Double {
+ try room.coolingSensiblePerRegister(projectSHR: projectSHR) * Double(actualRegisterCount)
+ }
+}
+
+extension TrunkSize {
+
+ public var totalHeatingLoad: Double {
+ rooms.reduce(into: 0) { $0 += $1.totalHeatingLoad }
+ }
+
+ public func totalCoolingSensible(projectSHR: Double) throws -> Double {
+ try rooms.reduce(into: 0) { $0 += try $1.totalCoolingSensible(projectSHR: projectSHR) }
+ }
+}
diff --git a/Sources/ViewController/Views/Home.swift b/Sources/ViewController/Views/Home.swift
index 7acd898..77fd88c 100644
--- a/Sources/ViewController/Views/Home.swift
+++ b/Sources/ViewController/Views/Home.swift
@@ -4,53 +4,113 @@ import ElementaryHTMX
struct HomeView: HTML, Sendable {
var body: some HTML {
- div(.class("flex justify-end me-4")) {
- button(
- .class("btn btn-ghost btn-secondary text-lg"),
- .hx.get(route: .login(.index())),
- .hx.target("body"),
- .hx.swap(.outerHTML)
- ) {
- "Login"
+ div( // Uncomment to test different theme's.
+ // .data("theme", value: "cyberpunk")
+ // NOTE: Footer background color will follow system theme, it will actually be the
+ // same as the `hero` background in reality.
+ ) {
+ div(.class("flex justify-end m-4")) {
+ button(
+ .class("btn btn-ghost btn-secondary text-lg"),
+ .hx.get(route: .login(.index())),
+ .hx.target("body"),
+ .hx.swap(.outerHTML)
+ ) {
+ "Login"
+ }
}
- }
- div(.class("hero min-h-screen")) {
- div(
- .class(
- """
- hero-content text-center bg-base-200 dark:bg-base-300
- min-w-[80%] min-h-[400px] rounded-3xl shadow-3xl
- """
- )
- ) {
- div {
- header
- a(
- .class("btn btn-ghost text-md italic"),
- .href("https://git.housh.dev/michael/swift-manual-d"),
- .target(.blank)
+ div(.class("hero")) {
+ div(
+ .class(
+ """
+ relative hero-content text-center bg-base-300
+ w-full min-h-[400px] rounded-3xl shadow-3xl overflow-hidden
+ """
+ )
+ ) {
+ div(
+ .class(
+ """
+ bg-secondary text-xl font-bold
+ absolute top-10 -left-15
+ px-6 py-2 w-[250px] -rotate-45
+ """
+ )
) {
- "Open source residential duct design program"
+ "BETA"
}
- p(.class("text-xl py-6")) {
- """
- Manual-D™ speed sheet, but on the web!
- """
- }
- button(
- .class("btn btn-xl bg-violet-600 mt-6"),
- .hx.get(route: .signup(.index)),
- .hx.target("body"),
- .hx.swap(.outerHTML)
- ) {
- "Get Started"
- }
- p(.class("text-xs italic mt-8")) {
- """
- Manual-D™ is a trademark of Air Conditioning Contractors of America (ACCA).
+ div {
+ header
+ a(
+ .class("btn btn-ghost text-md text-primary font-bold italic"),
+ .href("https://git.housh.dev/michael/swift-manual-d"),
+ .target(.blank)
+ ) {
+ "Open source residential duct design program"
+ }
+ p(.class("text-3xl py-6")) {
+ """
+ Manual-D™ speed sheet, but on the web!
+ """
+ }
+ button(
+ .class("btn btn-xl btn-primary mt-6"),
+ .hx.get(route: .signup(.index)),
+ .hx.target("body"),
+ .hx.swap(.outerHTML)
+ ) {
+ "Get Started"
+ }
+ p(.class("text-xs italic mt-8")) {
+ """
+ Manual-D™ is a trademark of Air Conditioning Contractors of America (ACCA).
- This site is not designed by or affiliated with ACCA.
- """
+ This site is not designed by or affiliated with ACCA.
+ """
+ }
+ }
+ }
+ }
+
+ div(.class("grid grid-cols-1 md:grid-cols-2 gap-4 mx-20 my-6")) {
+ div(.class("border-3 border-accent rounded-lg shadow-lg p-4")) {
+ div(.class("flex items-center space-x-4")) {
+ div(.class("text-5xl text-primary font-bold")) {
+ "Features"
+ }
+ }
+ div(.class("text-xl ms-10 mt-10")) {
+ ul(.class("list-disc")) {
+ li {
+ div(
+ .class("font-bold italic bg-secondary rounded-lg shadow-lg px-4 w-fit")
+ ) {
+ "Built by humans"
+ }
+ }
+ li { "Fully open source." }
+ li { "Great replacement for speed sheet users." }
+ li { "Great for classrooms." }
+ li { "Store your projects in one place." }
+ li { "Export final project to pdf." }
+ li { "Import room loads via CSV file." }
+ li { "Web based." }
+ li { "Self host (run on your own infrastructure)." }
+ }
+ }
+ }
+
+ div(.class("border-3 border-accent rounded-lg shadow-lg p-4")) {
+ div(.class("text-5xl text-primary font-bold")) {
+ "Coming Soon"
+ }
+ div(.class("text-xl ms-10 mt-10")) {
+ ul(.class("list-disc")) {
+ li { "API integration." }
+ li { "Command line interface." }
+ li { "Fitting selection tool." }
+ li { "Room load import from PDF." }
+ }
}
}
}
@@ -62,7 +122,7 @@ struct HomeView: HTML, Sendable {
div(
.class(
"""
- flex border-b-8 border-sky-600
+ flex border-b-6 border-accent
text-8xl font-bold my-auto space-2
"""
)
@@ -72,7 +132,7 @@ struct HomeView: HTML, Sendable {
span(
.class(
"""
- bg-violet-600 rounded-md
+ bg-secondary rounded-md
text-5xl rotate-180 p-2
"""
),
diff --git a/Tests/DatabaseClientTests/Resources/rooms.csv b/Tests/DatabaseClientTests/Resources/rooms.csv
index cf9b958..9b12eaf 100644
--- a/Tests/DatabaseClientTests/Resources/rooms.csv
+++ b/Tests/DatabaseClientTests/Resources/rooms.csv
@@ -1,5 +1,5 @@
Name,Heating Load,Cooling Total,Cooling Sensible,Register Count,Delegated To
-Bed-1,12345,1234,1321,1,
+Bed-1,2345,1234,1321,1,
Entry,3456,2345,1234,1,
Kitchen,7654,3456,2453,2,
-Bath-1,890,345,,1,Kitchen
+Bath-1,890,345,,0,Kitchen
diff --git a/Tests/DatabaseClientTests/RoomTests.swift b/Tests/DatabaseClientTests/RoomTests.swift
index 03816f4..0859872 100644
--- a/Tests/DatabaseClientTests/RoomTests.swift
+++ b/Tests/DatabaseClientTests/RoomTests.swift
@@ -77,16 +77,13 @@ struct RoomTests {
let csvPath = Bundle.module.path(forResource: "rooms", ofType: "csv")
let csvFile = Room.CSV(file: try Data(contentsOf: URL(filePath: csvPath!)))
let rows = try await csvParser.parseRooms(csvFile)
- print()
- print("ROWS: \(rows)")
- print()
-
let created = try await database.rooms.createFromCSV(project.id, rows)
-
- print()
- print("CREATED: \(created)")
- print()
#expect(created.count == rows.count)
+
+ // Check that delegating to another room works properly.
+ let bath = created.first(where: { $0.name == "Bath-1" })!
+ let kitchen = created.first(where: { $0.name == "Kitchen" })!
+ #expect(bath.delegatedTo == kitchen.id)
}
}
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/home.1.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/home.1.html
index 28155e6..ea624a0 100644
--- a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/home.1.html
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/home.1.html
@@ -30,31 +30,69 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
BETA
+
+
+
-
Duct Calc
-
-
Pro
+
Duct Calc
+
+ Pro
+
+ Open source residential duct design program
+
Manual-D™ speed sheet, but on the web!
+
+
+ Manual-D™ is a trademark of Air Conditioning Contractors of America (ACCA).
+
+ This site is not designed by or affiliated with ACCA.
+
+
+
+
+
+
+
+
+
+ -
+
Built by humans
+
+ - Fully open source.
+ - Great replacement for speed sheet users.
+ - Great for classrooms.
+ - Store your projects in one place.
+ - Export final project to pdf.
+ - Import room loads via CSV file.
+ - Web based.
+ - Self host (run on your own infrastructure).
+
+
+
+
+
Coming Soon
+
+
+ - API integration.
+ - Command line interface.
+ - Fitting selection tool.
+ - Room load import from PDF.
+
- Open source residential duct design program
-
Manual-D™ speed sheet, but on the web!
-
-
- Manual-D™ is a trademark of Air Conditioning Contractors of America (ACCA).
-
- This site is not designed by or affiliated with ACCA.
-