diff --git a/Public/css/output.css b/Public/css/output.css index 28e4f6a..6cd310e 100644 --- a/Public/css/output.css +++ b/Public/css/output.css @@ -4803,6 +4803,9 @@ .col-span-2 { grid-column: span 2 / span 2; } + .col-span-3 { + grid-column: span 3 / span 3; + } .col-span-5 { grid-column: span 5 / span 5; } @@ -5588,6 +5591,9 @@ .me-8 { margin-inline-end: calc(var(--spacing) * 8); } + .me-\[140px\] { + margin-inline-end: 140px; + } .modal-action { @layer daisyui.l1.l2.l3 { margin-top: calc(0.25rem * 6); @@ -6582,6 +6588,9 @@ .w-full { width: 100%; } + .min-w-\[220px\] { + min-width: 220px; + } .flex-1 { flex: 1; } @@ -6790,9 +6799,6 @@ .flex-wrap { flex-wrap: wrap; } - .items-baseline { - align-items: baseline; - } .items-center { align-items: center; } @@ -6868,6 +6874,9 @@ margin-inline-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-x-reverse))); } } + .overflow-auto { + overflow: auto; + } .overflow-x-auto { overflow-x: auto; } @@ -7869,12 +7878,12 @@ .pe-2 { padding-inline-end: calc(var(--spacing) * 2); } + .pt-2 { + padding-top: calc(var(--spacing) * 2); + } .pt-6 { padding-top: calc(var(--spacing) * 6); } - .pb-4 { - padding-bottom: calc(var(--spacing) * 4); - } .pb-6 { padding-bottom: calc(var(--spacing) * 6); } @@ -9518,16 +9527,6 @@ } } } - .lg\:grid-cols-3 { - @media (width >= 64rem) { - grid-template-columns: repeat(3, minmax(0, 1fr)); - } - } - .\32 xl\:table-cell { - @media (width >= 96rem) { - display: table-cell; - } - } .is-drawer-close\:mx-auto { &:where(.drawer-toggle:not(:checked) ~ .drawer-side, .drawer-toggle:not(:checked) ~ .drawer-side *) { margin-inline: auto; diff --git a/Public/files/ManD.Groups.pdf b/Public/files/ManD.Groups.pdf new file mode 100755 index 0000000..0a70db6 Binary files /dev/null and b/Public/files/ManD.Groups.pdf differ diff --git a/Public/files/ManD.Groups.pdf_original b/Public/files/ManD.Groups.pdf_original new file mode 100755 index 0000000..994d241 Binary files /dev/null and b/Public/files/ManD.Groups.pdf_original differ diff --git a/Sources/ManualDClient/Helpers.swift b/Sources/ManualDClient/Helpers.swift index 6b78ee2..2969d2f 100644 --- a/Sources/ManualDClient/Helpers.swift +++ b/Sources/ManualDClient/Helpers.swift @@ -16,12 +16,22 @@ extension Room { extension DuctSizing.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(registers.count) + room.heatingLoadPerRegister * Double(actualRegisterCount) } func totalCoolingSensible(projectSHR: Double) -> Double { - room.coolingSensiblePerRegister(projectSHR: projectSHR) * Double(registers.count) + room.coolingSensiblePerRegister(projectSHR: projectSHR) * Double(actualRegisterCount) } } @@ -54,6 +64,8 @@ func roundSize(_ size: Double) throws -> Int { throw ManualDError(message: "Size should be less than 24.") } + // let size = size.rounded(.toNearestOrEven) + switch size { case 0..<4: return 4 diff --git a/Sources/ManualDCore/DuctSizing.swift b/Sources/ManualDCore/DuctSizing.swift index 9b7b34f..78a514e 100644 --- a/Sources/ManualDCore/DuctSizing.swift +++ b/Sources/ManualDCore/DuctSizing.swift @@ -128,6 +128,7 @@ extension DuctSizing { // Represents the database model that the duct sizes have been calculated // for. + @dynamicMemberLookup public struct TrunkContainer: Codable, Equatable, Identifiable, Sendable { public var id: TrunkSize.ID { trunk.id } @@ -141,6 +142,14 @@ extension DuctSizing { self.trunk = trunk self.ductSize = ductSize } + + public subscript(dynamicMember keyPath: KeyPath) -> T { + trunk[keyPath: keyPath] + } + + public subscript(dynamicMember keyPath: KeyPath) -> T { + ductSize[keyPath: keyPath] + } } // Represents the database model. diff --git a/Sources/ViewController/Extensions/String+extensions.swift b/Sources/ViewController/Extensions/String+extensions.swift index 304e2e5..915778f 100644 --- a/Sources/ViewController/Extensions/String+extensions.swift +++ b/Sources/ViewController/Extensions/String+extensions.swift @@ -20,5 +20,6 @@ extension String { var idString: Self { replacing("-", with: "") + .replacing(" ", with: "") } } diff --git a/Sources/ViewController/Live.swift b/Sources/ViewController/Live.swift index 5d658c5..16f6149 100644 --- a/Sources/ViewController/Live.swift +++ b/Sources/ViewController/Live.swift @@ -13,8 +13,16 @@ extension ViewController.Request { switch route { case .test: + let projectID = UUID(uuidString: "A9C20153-E2E5-4C65-B33F-4D8A29C63A7A")! return await view { - TestPage() + await ResultView { + return ( + try await database.projects.getCompletedSteps(projectID), + try await database.calculateDuctSizes(projectID: projectID) + ) + } onSuccess: { (_, result) in + TestPage(trunks: result.trunks, rooms: result.rooms) + } } case .login(let route): switch route { diff --git a/Sources/ViewController/Views/ComponentLoss/ComponentLossesView.swift b/Sources/ViewController/Views/ComponentLoss/ComponentLossesView.swift index b97fcb8..9d4139d 100644 --- a/Sources/ViewController/Views/ComponentLoss/ComponentLossesView.swift +++ b/Sources/ViewController/Views/ComponentLoss/ComponentLossesView.swift @@ -24,31 +24,28 @@ struct ComponentPressureLossesView: HTML, Sendable { } .attributes(.class("px-4")) - div(.class("overflow-x-auto")) { - table(.class("table table-zebra")) { - thead { - tr(.class("text-xl font-bold")) { - th { "Name" } - th { "Value" } - th { - div(.class("flex justify-end mx-auto")) { - Tooltip("Add Component Loss") { - PlusButton() - .attributes( - .class("btn-ghost text-2xl me-2"), - .showModal(id: ComponentLossForm.id()) - ) - } + table(.class("table table-zebra")) { + thead { + tr(.class("text-xl font-bold")) { + th { "Name" } + th { "Value" } + th { + div(.class("flex justify-end mx-auto")) { + Tooltip("Add Component Loss") { + PlusButton() + .attributes( + .class("btn-ghost text-2xl me-2"), + .showModal(id: ComponentLossForm.id()) + ) } } } } - tbody { - for row in componentPressureLosses { - TableRow(row: row) - } + } + tbody { + for row in componentPressureLosses { + TableRow(row: row) } - } } } diff --git a/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift b/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift index 8fcaaed..466fbe9 100644 --- a/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift +++ b/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift @@ -12,23 +12,17 @@ struct DuctSizingView: HTML, Sendable { let rooms: [DuctSizing.RoomContainer] let trunks: [DuctSizing.TrunkContainer] - var supplyTrunks: [DuctSizing.TrunkContainer] { - trunks.filter { $0.trunk.type == .supply } - } - - var returnTrunks: [DuctSizing.TrunkContainer] { - trunks.filter { $0.trunk.type == .return } - } - var body: some HTML { div(.class("space-y-4")) { PageTitle { "Duct Sizes" } + if rooms.count == 0 { p(.class("text-error italic")) { "Must complete all the previous sections to display duct sizing calculations." } } else { RoomsTable(rooms: rooms) + div(.class("divider mb-6")) {} } Row { @@ -40,150 +34,14 @@ struct DuctSizingView: HTML, Sendable { .showModal(id: TrunkSizeForm.id()) ) } - .attributes(.class("mt-6")) - div(.class("divider -mt-2")) {} - - if supplyTrunks.count > 0 { - h2(.class("text-lg font-bold text-info")) { "Supply Trunks" } - TrunkTable(trunks: supplyTrunks, rooms: rooms) - } - - if returnTrunks.count > 0 { - h2(.class("text-lg font-bold text-error")) { "Return Trunks" } - TrunkTable(trunks: returnTrunks, rooms: rooms) + if trunks.count > 0 { + div(.class("divider -mt-2")) {} + TrunkTable(trunks: trunks, rooms: rooms) } TrunkSizeForm(rooms: rooms, dismiss: true) } } - struct TrunkTable: HTML, Sendable { - - let trunks: [DuctSizing.TrunkContainer] - let rooms: [DuctSizing.RoomContainer] - - var body: some HTML { - div(.class("overflow-x-auto")) { - table(.class("table table-zebra text-lg")) { - thead { - tr(.class("text-lg")) { - th { "Associated Supplies" } - th { "Dsn CFM" } - th { "Round Size" } - th { "Velocity" } - th { "Final Size" } - th { "Flex Size" } - th { "Width" } - th { "Height" } - } - } - tbody { - for trunk in trunks { - TrunkRow(trunk: trunk, rooms: rooms) - } - } - } - } - } - - } - - struct TrunkRow: HTML, Sendable { - - @Environment(ProjectViewValue.$projectID) var projectID - - let trunk: DuctSizing.TrunkContainer - let rooms: [DuctSizing.RoomContainer] - - var body: some HTML { - tr { - td(.class("space-x-2")) { - for id in registerIDS(trunk.trunk) { - Badge { id } - } - } - td { - Number(trunk.ductSize.designCFM.value, digits: 0) - } - td { - Number(trunk.ductSize.roundSize, digits: 1) - } - td { - Number(trunk.ductSize.velocity) - } - td { - Badge(number: trunk.ductSize.finalSize) - .attributes(.class("badge-secondary")) - } - td { - Badge(number: trunk.ductSize.flexSize) - .attributes(.class("badge-primary")) - } - td { - if let width = trunk.ductSize.width { - Number(width) - } - - } - td { - - div(.class("flex justify-between items-center space-x-4")) { - div { - if let height = trunk.ductSize.height { - Number(height) - } - } - - div { - div(.class("join")) { - TrashButton() - .attributes(.class("join-item btn-ghost")) - .attributes( - .hx.delete(route: deleteRoute), - .hx.target("closest tr"), - .hx.swap(.outerHTML) - ) - - EditButton() - .attributes( - .class("join-item btn-ghost"), - .showModal(id: TrunkSizeForm.id(trunk)) - ) - } - } - } - TrunkSizeForm(trunk: trunk, rooms: rooms, dismiss: true) - } - } - } - - private var deleteRoute: SiteRoute.View { - .project(.detail(projectID, .ductSizing(.trunk(.delete(trunk.id))))) - } - - private func registerIDS(_ trunk: DuctSizing.TrunkSize) -> [String] { - trunk.rooms.reduce(into: []) { array, room in - array = room.registers.reduce(into: array) { array, register in - if let room = - rooms - .first(where: { $0.roomID == room.id && $0.roomRegister == register }) - { - array.append(room.registerID) - } - } - } - .sorted() - } - - } -} - -extension DuctSizing.DesignCFM { - var color: String { - switch self { - case .heating: return "error" - case .cooling: return "info" - } - } } diff --git a/Sources/ViewController/Views/DuctSizing/RoomsTable.swift b/Sources/ViewController/Views/DuctSizing/RoomsTable.swift index 4123d18..499b2f6 100644 --- a/Sources/ViewController/Views/DuctSizing/RoomsTable.swift +++ b/Sources/ViewController/Views/DuctSizing/RoomsTable.swift @@ -11,24 +11,22 @@ extension DuctSizingView { let rooms: [DuctSizing.RoomContainer] - var body: some HTML { - div(.class("overflow-x-auto")) { + var body: some HTML { - table(.class("table table-zebra")) { - thead { - tr(.class("text-xl text-gray-400 font-bold")) { - th { "ID" } - th { "Name" } - th { "BTU" } - th { "CFM" } - th { "Velocity" } - th { "Size" } - } + table(.class("table table-zebra text-lg")) { + thead { + tr(.class("text-lg")) { + th { "ID" } + th { "Name" } + th { "BTU" } + th { "CFM" } + th { "Velocity" } + th { "Size" } } - tbody { - for room in rooms { - RoomRow(room: room) - } + } + tbody { + for room in rooms { + RoomRow(room: room) } } } @@ -66,7 +64,7 @@ extension DuctSizingView { var rowID: String { Self.id(room) } var body: some HTML { - tr(.class("text-lg items-baseline"), .id(rowID)) { + tr(.class("text-lg"), .id(rowID)) { td { room.registerID } td { room.roomName } td { @@ -107,7 +105,7 @@ extension DuctSizingView { div(.class("label")) { "Calculated" } div(.class("flex justify-center")) { - Badge(number: room.roundSize, digits: 1) + Badge(number: room.roundSize, digits: 2) } div {} diff --git a/Sources/ViewController/Views/DuctSizing/TrunksTable.swift b/Sources/ViewController/Views/DuctSizing/TrunksTable.swift new file mode 100644 index 0000000..1f17319 --- /dev/null +++ b/Sources/ViewController/Views/DuctSizing/TrunksTable.swift @@ -0,0 +1,139 @@ +import Elementary +import ElementaryHTMX +import ManualDCore +import Styleguide + +extension DuctSizingView { + + struct TrunkTable: HTML, Sendable { + + let trunks: [DuctSizing.TrunkContainer] + let rooms: [DuctSizing.RoomContainer] + + private var sortedTrunks: [DuctSizing.TrunkContainer] { + trunks.sorted(by: { $0.type.rawValue > $1.type.rawValue }) + } + + var body: some HTML { + table(.class("table table-zebra text-lg")) { + thead { + tr(.class("text-lg")) { + th { "Type" } + th { "Associated Supplies" } + th { "Dsn CFM" } + th { "Velocity" } + th { "Size" } + } + } + tbody { + for trunk in sortedTrunks { + TrunkRow(trunk: trunk, rooms: rooms) + } + } + } + } + + } + + struct TrunkRow: HTML, Sendable { + + @Environment(ProjectViewValue.$projectID) var projectID + + let trunk: DuctSizing.TrunkContainer + let rooms: [DuctSizing.RoomContainer] + + var body: some HTML { + tr { + td { + Badge { + trunk.trunk.type.rawValue + } + .attributes(.class("badge-info"), when: trunk.type == .supply) + .attributes(.class("badge-error"), when: trunk.type == .return) + } + td(.class("space-x-2")) { + for id in registerIDS { + Badge { id } + } + } + td { + Number(trunk.designCFM.value, digits: 0) + } + td { + Number(trunk.velocity) + } + td { + div(.class("grid grid-cols-3 gap-4")) { + div(.class("label")) { "Calculated" } + div(.class("flex justify-center")) { + Badge(number: trunk.roundSize, digits: 1) + } + div {} + + div(.class("label")) { "Final" } + div(.class("flex justify-center")) { + Badge(number: trunk.finalSize) + .attributes(.class("badge-secondary")) + } + div {} + + div(.class("label")) { "Flex" } + div(.class("flex justify-center")) { + Badge(number: trunk.flexSize) + .attributes(.class("badge-primary")) + } + div {} + + div(.class("label")) { "Rectangular" } + div(.class("flex justify-center")) { + if let width = trunk.width, + let height = trunk.ductSize.height + { + Badge { + span { "\(width) x \(height)" } + } + } + } + div(.class("flex justify-end")) { + div(.class("join")) { + TrashButton() + .attributes(.class("join-item btn-ghost")) + .attributes( + .hx.delete(route: deleteRoute), + .hx.target("closest tr"), + .hx.swap(.outerHTML) + ) + + EditButton() + .attributes( + .class("join-item btn-ghost"), + .showModal(id: TrunkSizeForm.id(trunk)) + ) + } + } + } + TrunkSizeForm(trunk: trunk, rooms: rooms, dismiss: true) + } + } + } + + private var deleteRoute: SiteRoute.View { + .project(.detail(projectID, .ductSizing(.trunk(.delete(trunk.id))))) + } + + private var registerIDS: [String] { + trunk.rooms.reduce(into: []) { array, room in + array = room.registers.reduce(into: array) { array, register in + if let room = + rooms + .first(where: { $0.roomID == room.id && $0.roomRegister == register }) + { + array.append(room.registerID) + } + } + } + .sorted() + } + + } +} diff --git a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthForm.swift b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthForm.swift index 9a7e509..5b53ae6 100644 --- a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthForm.swift +++ b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthForm.swift @@ -200,6 +200,14 @@ struct EffectiveLengthForm: HTML, Sendable { } } + a( + .href("/files/ManD.Groups.pdf"), + .target(.blank), + .class("btn btn-link") + ) { + "Click here for Manual-D groups reference." + } + div(.id("groups"), .class("space-y-4")) { if let effectiveLength { for group in effectiveLength.groups { @@ -346,7 +354,7 @@ extension EffectiveLength.EffectiveLengthType { case .return: return [5, 6, 7, 8, 10, 11, 12] case .supply: - return [1, 2, 4, 8, 9, 11, 12] + return [1, 2, 3, 4, 8, 9, 11, 12] } } } diff --git a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsTable.swift b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsTable.swift new file mode 100644 index 0000000..a0a61fd --- /dev/null +++ b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsTable.swift @@ -0,0 +1,136 @@ +import Elementary +import ElementaryHTMX +import ManualDCore +import Styleguide + +struct EffectiveLengthsTable: HTML, Sendable { + + let effectiveLengths: [EffectiveLength] + + private var sortedLengths: [EffectiveLength] { + effectiveLengths.sorted { + $0.totalEquivalentLength > $1.totalEquivalentLength + } + .sorted { + $0.type.rawValue > $1.type.rawValue + } + } + + var body: some HTML { + table(.class("table table-zebra text-lg")) { + thead { + tr(.class("text-lg")) { + th { "Type" } + th { "Name" } + th { "Straight Lengths" } + th { + div(.class("grid grid-cols-3 gap-2 min-w-[220px]")) { + div(.class("flex justify-center col-span-3")) { + "Groups" + } + div { "Group" } + div(.class("flex justify-center")) { + "T.E.L." + } + div(.class("flex justify-end")) { + "Quantity" + } + } + } + th { + div(.class("flex justify-end me-[140px]")) { + "T.E.L." + } + } + } + } + tbody { + for row in sortedLengths { + EffectiveLenghtRow(effectiveLength: row) + } + } + + } + } + + struct EffectiveLenghtRow: HTML, Sendable { + + let effectiveLength: EffectiveLength + + private var deleteRoute: SiteRoute.View { + .project( + .detail( + effectiveLength.projectID, + .equivalentLength(.delete(id: effectiveLength.id)) + ) + ) + } + + var body: some HTML { + tr(.id(effectiveLength.id.idString)) { + td { + // Type + Badge { + span { effectiveLength.type.rawValue } + } + .attributes(.class("badge-info"), when: effectiveLength.type == .supply) + .attributes(.class("badge-error"), when: effectiveLength.type == .return) + + } + td { effectiveLength.name } + td { + // Lengths + div(.class("grid grid-cols-1 gap-2")) { + for length in effectiveLength.straightLengths { + Number(length) + } + } + } + td { + div(.class("grid grid-cols-3 gap-2 min-w-[220px]")) { + for group in effectiveLength.groups { + span { "\(group.group)-\(group.letter)" } + div(.class("flex justify-center")) { + Number(group.value) + } + div(.class("flex justify-end")) { + Number(group.quantity) + } + } + } + + } + td { + // Total + // Row { + div(.class("flex justify-end mx-auto space-x-4")) { + Badge(number: effectiveLength.totalEquivalentLength, digits: 0) + .attributes(.class("badge-primary text-xl pt-2")) + + // Buttons + div(.class("flex justify-end -mt-2")) { + div(.class("join")) { + TrashButton() + .attributes( + .class("join-item btn-ghost"), + .hx.delete(route: deleteRoute), + .hx.confirm("Are you sure?"), + .hx.target("#\(effectiveLength.id.idString)"), + .hx.swap(.outerHTML) + ) + EditButton() + .attributes( + .class("join-item btn-ghost"), + .showModal(id: EffectiveLengthForm.id(effectiveLength)) + ) + } + } + } + + EffectiveLengthForm(effectiveLength: effectiveLength) + } + } + } + } + +} diff --git a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift index c358a56..531b945 100644 --- a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift +++ b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift @@ -25,7 +25,7 @@ struct EffectiveLengthsView: HTML, Sendable { PageTitle { "Equivalent Lengths" } PlusButton() .attributes( - .class("btn-ghost"), + .class("btn-ghost me-4"), .showModal(id: EffectiveLengthForm.id(nil)) ) } @@ -33,30 +33,12 @@ struct EffectiveLengthsView: HTML, Sendable { EffectiveLengthForm(projectID: projectID, dismiss: true) - div { - h2(.class("text-xl font-bold pb-4")) { "Supplies" } - .attributes(.class("hidden"), when: supplies.count == 0) - - div(.class("grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4")) { - for row in supplies { - EffectiveLengthView(effectiveLength: row) - } - } - } - - div { - h2(.class("text-xl font-bold pb-4")) { "Returns" } - .attributes(.class("hidden"), when: returns.count == 0) - div(.class("grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 space-x-4 space-y-4")) { - for row in returns { - EffectiveLengthView(effectiveLength: row) - } - } - } + EffectiveLengthsTable(effectiveLengths: effectiveLengths) } } + // TODO: Remove if using table view. private struct EffectiveLengthView: HTML, Sendable { let effectiveLength: EffectiveLength diff --git a/Sources/ViewController/Views/MainPage.swift b/Sources/ViewController/Views/MainPage.swift index b0a920f..e882042 100644 --- a/Sources/ViewController/Views/MainPage.swift +++ b/Sources/ViewController/Views/MainPage.swift @@ -55,7 +55,9 @@ public struct MainPage: SendableHTMLDocument where Inner: Sendable public var body: some HTML { div(.class("h-screen w-full")) { - inner + div(.class("overflow-auto")) { + inner + } } .attributes(.data("theme", value: theme?.rawValue ?? "default"), when: theme != nil) } diff --git a/Sources/ViewController/Views/Project/ProjectDetail.swift b/Sources/ViewController/Views/Project/ProjectDetail.swift index 82acaa4..cf9ec28 100644 --- a/Sources/ViewController/Views/Project/ProjectDetail.swift +++ b/Sources/ViewController/Views/Project/ProjectDetail.swift @@ -17,47 +17,45 @@ struct ProjectDetail: HTML, Sendable { ) } - div(.class("overflow-x-auto")) { - table(.class("table table-zebra text-lg")) { - tbody { - tr { - td(.class("label font-bold")) { "Name" } - td { - div(.class("flex justify-end")) { - project.name - } + table(.class("table table-zebra text-lg")) { + tbody { + tr { + td(.class("label font-bold")) { "Name" } + td { + div(.class("flex justify-end")) { + project.name } } - tr { - td(.class("label font-bold")) { "Street Address" } - td { - div(.class("flex justify-end")) { - project.streetAddress - } + } + tr { + td(.class("label font-bold")) { "Street Address" } + td { + div(.class("flex justify-end")) { + project.streetAddress } } - tr { - td(.class("label font-bold")) { "City" } - td { - div(.class("flex justify-end")) { - project.city - } + } + tr { + td(.class("label font-bold")) { "City" } + td { + div(.class("flex justify-end")) { + project.city } } - tr { - td(.class("label font-bold")) { "State" } - td { - div(.class("flex justify-end")) { - project.state - } + } + tr { + td(.class("label font-bold")) { "State" } + td { + div(.class("flex justify-end")) { + project.state } } - tr { - td(.class("label font-bold")) { "Zip" } - td { - div(.class("flex justify-end")) { - project.zipCode - } + } + tr { + td(.class("label font-bold")) { "Zip" } + td { + div(.class("flex justify-end")) { + project.zipCode } } } diff --git a/Sources/ViewController/Views/Project/ProjectsTable.swift b/Sources/ViewController/Views/Project/ProjectsTable.swift index 028880a..680c441 100644 --- a/Sources/ViewController/Views/Project/ProjectsTable.swift +++ b/Sources/ViewController/Views/Project/ProjectsTable.swift @@ -31,24 +31,22 @@ struct ProjectsTable: HTML, Sendable { } .attributes(.class("pb-6")) - div(.class("overflow-x-auto")) { - table(.class("table table-zebra")) { - thead { - tr { - th { Label("Date") } - th { Label("Name") } - th { Label("Address") } - th {} - } - } - tbody { - Rows(projects: projects) + table(.class("table table-zebra")) { + thead { + tr { + th { Label("Date") } + th { Label("Name") } + th { Label("Address") } + th {} } } + tbody { + Rows(projects: projects) + } } - - ProjectForm(dismiss: true) } + + ProjectForm(dismiss: true) } } } diff --git a/Sources/ViewController/Views/TestPage.swift b/Sources/ViewController/Views/TestPage.swift index 9aaf88f..9227c38 100644 --- a/Sources/ViewController/Views/TestPage.swift +++ b/Sources/ViewController/Views/TestPage.swift @@ -2,9 +2,30 @@ import Dependencies import Elementary import Foundation import ManualDCore +import Styleguide struct TestPage: HTML, Sendable { + let trunks: [DuctSizing.TrunkContainer] + let rooms: [DuctSizing.RoomContainer] + var body: some HTML { - UserProfileForm(userID: UUID(0), profile: nil, dismiss: false) + div(.class("overflow-auto")) { + DuctSizingView.TrunkTable(trunks: trunks, rooms: rooms) + + Row { + h2(.class("text-2xl font-bold")) { "Trunk Sizes" } + + PlusButton() + .attributes( + .class("me-6"), + .showModal(id: TrunkSizeForm.id()) + ) + } + .attributes(.class("mt-6")) + + div(.class("divider -mt-2")) {} + + DuctSizingView.TrunkTable(trunks: trunks, rooms: rooms) + } } }