feat: Adds manual-d group pdf while working on better picker for groups, fixes issues with trunk table not always rendering properly with certain themes.
This commit is contained in:
@@ -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<HTMLTag.tr> {
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,24 +11,22 @@ extension DuctSizingView {
|
||||
|
||||
let rooms: [DuctSizing.RoomContainer]
|
||||
|
||||
var body: some HTML<HTMLTag.div> {
|
||||
div(.class("overflow-x-auto")) {
|
||||
var body: some HTML<HTMLTag.table> {
|
||||
|
||||
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<HTMLTag.tr> {
|
||||
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 {}
|
||||
|
||||
|
||||
139
Sources/ViewController/Views/DuctSizing/TrunksTable.swift
Normal file
139
Sources/ViewController/Views/DuctSizing/TrunksTable.swift
Normal file
@@ -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<HTMLTag.tr> {
|
||||
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()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user