diff --git a/Public/css/output.css b/Public/css/output.css index 6432e8f..6f47cc5 100644 --- a/Public/css/output.css +++ b/Public/css/output.css @@ -5360,9 +5360,6 @@ } } } - .my-1 { - margin-block: calc(var(--spacing) * 1); - } .my-1\.5 { margin-block: calc(var(--spacing) * 1.5); } @@ -5578,9 +5575,6 @@ .ms-4 { margin-inline-start: calc(var(--spacing) * 4); } - .me-4 { - margin-inline-end: calc(var(--spacing) * 4); - } .modal-action { @layer daisyui.l1.l2.l3 { margin-top: calc(0.25rem * 6); @@ -5620,15 +5614,6 @@ } } } - .mt-1 { - margin-top: calc(var(--spacing) * 1); - } - .mt-1\.5 { - margin-top: calc(var(--spacing) * 1.5); - } - .mt-2 { - margin-top: calc(var(--spacing) * 2); - } .mt-4 { margin-top: calc(var(--spacing) * 4); } @@ -7811,9 +7796,6 @@ .px-4 { padding-inline: calc(var(--spacing) * 4); } - .py-1 { - padding-block: calc(var(--spacing) * 1); - } .py-1\.5 { padding-block: calc(var(--spacing) * 1.5); } @@ -7840,9 +7822,6 @@ .pe-2 { padding-inline-end: calc(var(--spacing) * 2); } - .pt-4 { - padding-top: calc(var(--spacing) * 4); - } .pt-6 { padding-top: calc(var(--spacing) * 6); } @@ -7852,9 +7831,6 @@ .pb-6 { padding-bottom: calc(var(--spacing) * 6); } - .align-baseline { - vertical-align: baseline; - } .file-input-lg { @layer daisyui.l1.l2 { --size: calc(var(--size-field, 0.25rem) * 12); diff --git a/Sources/DatabaseClient/Errors.swift b/Sources/DatabaseClient/Errors.swift index 6c0a0f4..0995825 100644 --- a/Sources/DatabaseClient/Errors.swift +++ b/Sources/DatabaseClient/Errors.swift @@ -9,4 +9,6 @@ public struct ValidationError: Error { } } -public struct NotFoundError: Error {} +public struct NotFoundError: Error { + public init() {} +} diff --git a/Sources/ManualDClient/Helpers.swift b/Sources/ManualDClient/Helpers.swift index 89b8561..71f048e 100644 --- a/Sources/ManualDClient/Helpers.swift +++ b/Sources/ManualDClient/Helpers.swift @@ -4,6 +4,7 @@ import ManualDCore extension Room { var heatingLoadPerRegister: Double { + heatingLoad / Double(registerCount) } diff --git a/Sources/ManualDClient/Live.swift b/Sources/ManualDClient/Live.swift index b323131..3b7768f 100644 --- a/Sources/ManualDClient/Live.swift +++ b/Sources/ManualDClient/Live.swift @@ -25,7 +25,7 @@ extension ManualDClient: DependencyKey { throw ManualDError(message: "Total Effective Length should be greater than 0.") } - let totalComponentLosses = request.componentPressureLosses.totalLosses + let totalComponentLosses = request.componentPressureLosses.totalComponentPressureLoss let availableStaticPressure = request.externalStaticPressure - totalComponentLosses let frictionRate = availableStaticPressure * 100.0 / Double(request.totalEffectiveLength) return .init(availableStaticPressure: availableStaticPressure, frictionRate: frictionRate) diff --git a/Sources/ManualDClient/ManualDClient.swift b/Sources/ManualDClient/ManualDClient.swift index 4a411d6..e7ee433 100644 --- a/Sources/ManualDClient/ManualDClient.swift +++ b/Sources/ManualDClient/ManualDClient.swift @@ -130,12 +130,12 @@ extension ManualDClient { public struct FrictionRateRequest: Codable, Equatable, Sendable { public let externalStaticPressure: Double - public let componentPressureLosses: ComponentPressureLosses + public let componentPressureLosses: [ComponentPressureLoss] public let totalEffectiveLength: Int public init( externalStaticPressure: Double, - componentPressureLosses: ComponentPressureLosses, + componentPressureLosses: [ComponentPressureLoss], totalEffectiveLength: Int ) { self.externalStaticPressure = externalStaticPressure diff --git a/Sources/ManualDCore/Routes/ViewRoute.swift b/Sources/ManualDCore/Routes/ViewRoute.swift index 659f6f7..dbbd3ec 100644 --- a/Sources/ManualDCore/Routes/ViewRoute.swift +++ b/Sources/ManualDCore/Routes/ViewRoute.swift @@ -707,6 +707,9 @@ extension SiteRoute.View.ProjectRoute { Method.post Body { FormData { + Optionally { + Field("id") { DuctSizing.RectangularDuct.ID.parser() } + } Field("register") { Int.parser() } Field("height") { Int.parser() } } @@ -716,6 +719,7 @@ extension SiteRoute.View.ProjectRoute { } public struct RoomRectangularForm: Equatable, Sendable { + public let id: DuctSizing.RectangularDuct.ID? public let register: Int public let height: Int } diff --git a/Sources/Styleguide/Buttons.swift b/Sources/Styleguide/Buttons.swift index 98a2139..ca6b558 100644 --- a/Sources/Styleguide/Buttons.swift +++ b/Sources/Styleguide/Buttons.swift @@ -65,7 +65,7 @@ public struct EditButton: HTML, Sendable { } public var body: some HTML { - button(.class("btn btn-success btn-circle dark:text-white"), .type(type)) { + button(.class("btn btn-success btn-circle"), .type(type)) { div(.class("flex")) { if let title { span(.class("pe-2")) { title } diff --git a/Sources/Styleguide/ResultView.swift b/Sources/Styleguide/ResultView.swift new file mode 100644 index 0000000..a735228 --- /dev/null +++ b/Sources/Styleguide/ResultView.swift @@ -0,0 +1,78 @@ +import Elementary +import Foundation + +public struct ResultView< + V: Sendable, + E: Error, + ValueView: HTML, + ErrorView: HTML +>: HTML { + + let onSuccess: @Sendable (V) -> ValueView + let onError: @Sendable (E) -> ErrorView + let result: Result + + public init( + result: Result, + @HTMLBuilder onSuccess: @escaping @Sendable (V) -> ValueView, + @HTMLBuilder onError: @escaping @Sendable (E) -> ErrorView + ) { + self.result = result + self.onError = onError + self.onSuccess = onSuccess + } + + public var body: some HTML { + switch result { + case .success(let value): + onSuccess(value) + case .failure(let error): + onError(error) + } + } +} + +extension ResultView { + + public init( + result: Result, + @HTMLBuilder onSuccess: @escaping @Sendable (V) -> ValueView + ) where ErrorView == Styleguide.ErrorView { + self.init(result: result, onSuccess: onSuccess) { error in + Styleguide.ErrorView(error: error) + } + } + + public init( + catching: @escaping @Sendable () async throws(E) -> V, + @HTMLBuilder onSuccess: @escaping @Sendable (V) -> ValueView + ) async where ErrorView == Styleguide.ErrorView { + await self.init( + result: .init(catching: catching), + onSuccess: onSuccess + ) { error in + Styleguide.ErrorView(error: error) + } + } +} + +extension ResultView: Sendable where Error: Sendable, ValueView: Sendable, ErrorView: Sendable {} + +public struct ErrorView: HTML, Sendable where Error: Sendable { + + let error: E + + public init(error: E) { + self.error = error + } + + public var body: some HTML { + div { + h1(.class("text-2xl font-bold text-error")) { "Oops: Error" } + p { + "\(error)" + } + } + } + +} diff --git a/Sources/Styleguide/Tooltip.swift b/Sources/Styleguide/Tooltip.swift index a47f50d..503c134 100644 --- a/Sources/Styleguide/Tooltip.swift +++ b/Sources/Styleguide/Tooltip.swift @@ -3,22 +3,35 @@ import Elementary public struct Tooltip: HTML, Sendable { let tooltip: String + let position: TooltipPosition let inner: Inner public init( _ tooltip: String, + position: TooltipPosition = .default, @HTMLBuilder inner: () -> Inner ) { self.tooltip = tooltip + self.position = position self.inner = inner() } public var body: some HTML { div( - .class("tooltip"), + .class("tooltip tooltip-\(position.rawValue)"), .data("tip", value: tooltip) ) { inner } } } + +public enum TooltipPosition: String, CaseIterable, Sendable { + + public static let `default` = Self.left + + case bottom + case left + case right + case top +} diff --git a/Sources/ViewController/Extensions/DatabaseExtensions.swift b/Sources/ViewController/Extensions/DatabaseExtensions.swift index da8171b..1546f9a 100644 --- a/Sources/ViewController/Extensions/DatabaseExtensions.swift +++ b/Sources/ViewController/Extensions/DatabaseExtensions.swift @@ -1,5 +1,7 @@ import DatabaseClient +import Dependencies import Fluent +import ManualDClient import ManualDCore import Vapor @@ -24,6 +26,16 @@ extension DatabaseClient.Projects { extension DatabaseClient { + func calculateDuctSizes(projectID: Project.ID) async throws -> [DuctSizing.RoomContainer] { + @Dependency(\.manualD) var manualD + + return try await manualD.calculate( + rooms: rooms.fetch(projectID), + designFrictionRateResult: designFrictionRate(projectID: projectID), + projectSHR: projects.getSensibleHeatRatio(projectID) + ) + } + func designFrictionRate( projectID: Project.ID ) async throws -> (EquipmentInfo, EffectiveLength.MaxContainer, Double)? { diff --git a/Sources/ViewController/Live.swift b/Sources/ViewController/Live.swift index 1a7e798..bebe018 100644 --- a/Sources/ViewController/Live.swift +++ b/Sources/ViewController/Live.swift @@ -353,30 +353,24 @@ extension SiteRoute.View.ProjectRoute.DuctSizingRoute { case .deleteRectangularSize(let roomID, let rectangularSizeID): let room = try await database.rooms.deleteRectangularSize(roomID, rectangularSizeID) - let container = try await manualD.calculate( - rooms: [room], - designFrictionRateResult: database.designFrictionRate(projectID: projectID), - projectSHR: database.projects.getSensibleHeatRatio(projectID) - ).first! + let container = try await database.calculateDuctSizes(projectID: projectID) + .filter({ $0.roomID == room.id }) + .first! return DuctSizingView.RoomRow(projectID: projectID, room: container) case .roomRectangularForm(let roomID, let form): - let _ = try await database.rooms.update( + let room = try await database.rooms.update( roomID, - .init(rectangularSizes: [.init(register: form.register, height: form.height)]) + .init( + rectangularSizes: [ + .init(id: form.id ?? .init(), register: form.register, height: form.height) + ] + ) ) - // request.logger.debug("Got room rectangular form: \(roomID)") - // - // let containers = try await manualD.calculate( - // rooms: [room], - // designFrictionRateResult: database.designFrictionRate(projectID: projectID), - // projectSHR: database.projects.getSensibleHeatRatio(projectID) - // ) - // request.logger.debug("Room Containers: \(containers)") - // let container = containers.first(where: { $0.roomName == "\(room.name)-\(form.register)" })! - // request.logger.debug("Room Container: \(container)") - // return DuctSizingView.RoomRow(projectID: projectID, room: container) - return ProjectView(projectID: projectID, activeTab: .ductSizing, logger: request.logger) + let container = try await database.calculateDuctSizes(projectID: projectID) + .filter({ $0.roomID == room.id }) + .first! + return DuctSizingView.RoomRow(projectID: projectID, room: container) } } } diff --git a/Sources/ViewController/Views/ComponentLoss/ComponentLossesView.swift b/Sources/ViewController/Views/ComponentLoss/ComponentLossesView.swift index 43714a9..3ec8627 100644 --- a/Sources/ViewController/Views/ComponentLoss/ComponentLossesView.swift +++ b/Sources/ViewController/Views/ComponentLoss/ComponentLossesView.swift @@ -31,10 +31,13 @@ struct ComponentPressureLossesView: HTML, Sendable { span(.class("text-sm italic")) { "Total" } } } - PlusButton() - .attributes( - .showModal(id: ComponentLossForm.id()) - ) + Tooltip("Add Component Loss") { + PlusButton() + .attributes( + .class("btn-ghost text-2xl"), + .showModal(id: ComponentLossForm.id()) + ) + } } table(.class("table table-zebra")) { @@ -65,24 +68,28 @@ struct ComponentPressureLossesView: HTML, Sendable { td { Number(row.value) } td { div(.class("flex join items-end justify-end mx-auto")) { - TrashButton() - .attributes( - .class("join-item"), - .hx.delete( - route: .project( - .detail(row.projectID, .componentLoss(.delete(row.id))) - ) - ), - .hx.target("body"), - .hx.swap(.outerHTML), - .hx.confirm("Are your sure?") + Tooltip("Delete", position: .bottom) { + TrashButton() + .attributes( + .class("join-item btn-ghost"), + .hx.delete( + route: .project( + .detail(row.projectID, .componentLoss(.delete(row.id))) + ) + ), + .hx.target("body"), + .hx.swap(.outerHTML), + .hx.confirm("Are your sure?") - ) - EditButton() - .attributes( - .class("join-item"), - .showModal(id: ComponentLossForm.id(row)) - ) + ) + } + Tooltip("Edit", position: .bottom) { + EditButton() + .attributes( + .class("join-item btn-ghost"), + .showModal(id: ComponentLossForm.id(row)) + ) + } } ComponentLossForm(dismiss: true, projectID: row.projectID, componentLoss: row) diff --git a/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift b/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift index 8352d44..b1ff561 100644 --- a/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift +++ b/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift @@ -7,7 +7,9 @@ import Styleguide struct DuctSizingView: HTML, Sendable { - let projectID: Project.ID + @Environment(ProjectViewValue.$projectID) var projectID + + // let projectID: Project.ID let rooms: [DuctSizing.RoomContainer] var body: some HTML { diff --git a/Sources/ViewController/Views/DuctSizing/RectangularSizeForm.swift b/Sources/ViewController/Views/DuctSizing/RectangularSizeForm.swift index d3e8ef7..4cae986 100644 --- a/Sources/ViewController/Views/DuctSizing/RectangularSizeForm.swift +++ b/Sources/ViewController/Views/DuctSizing/RectangularSizeForm.swift @@ -74,7 +74,7 @@ struct RectangularSizeForm: HTML, Sendable { form( .class("space-y-4"), .hx.post(route), - .hx.target("body"), + .hx.target("closest tr"), .hx.swap(.outerHTML) ) { input(.class("hidden"), .name("register"), .value(register)) diff --git a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthForm.swift b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthForm.swift index d8b1037..7e310ce 100644 --- a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthForm.swift +++ b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthForm.swift @@ -3,16 +3,8 @@ import ElementaryHTMX import ManualDCore import Styleguide -// TODO: May need a multi-step form were the the effective length type is -// determined before groups selections are made in order to use the -// appropriate select field values when the type is supply vs. return. -// Currently when the select field is changed it doesn't change the group -// I can get it to add a new one. - // TODO: Add back buttons / capability?? -// TODO: Add patch / update capability - struct EffectiveLengthForm: HTML, Sendable { static func id(_ equivalentLength: EffectiveLength?) -> String { diff --git a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift index f89f3ae..7266092 100644 --- a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift +++ b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift @@ -7,7 +7,9 @@ import Styleguide struct EffectiveLengthsView: HTML, Sendable { - let projectID: Project.ID + @Environment(ProjectViewValue.$projectID) var projectID + + // let projectID: Project.ID let effectiveLengths: [EffectiveLength] var supplies: [EffectiveLength] { diff --git a/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoView.swift b/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoView.swift index 3fc1073..68405a5 100644 --- a/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoView.swift +++ b/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoView.swift @@ -15,10 +15,13 @@ struct EquipmentInfoView: HTML, Sendable { Row { h1(.class("text-2xl font-bold")) { "Equipment Info" } - EditButton() - .attributes( - .on(.click, "\(EquipmentInfoForm.id).showModal()") - ) + Tooltip("Edit equipment info") { + EditButton() + .attributes( + .class("btn-ghost"), + .showModal(id: EquipmentInfoForm.id) + ) + } } if let equipmentInfo { diff --git a/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift b/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift index 4c0b02e..48f0d66 100644 --- a/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift +++ b/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift @@ -1,4 +1,5 @@ import Elementary +import ManualDClient import ManualDCore import Styleguide @@ -6,23 +7,20 @@ import Styleguide struct FrictionRateView: HTML, Sendable { + @Environment(ProjectViewValue.$projectID) var projectID + let equipmentInfo: EquipmentInfo? let componentLosses: [ComponentPressureLoss] let equivalentLengths: EffectiveLength.MaxContainer - let projectID: Project.ID + // let projectID: Project.ID + let frictionRateResponse: ManualDClient.FrictionRateResponse? var availableStaticPressure: Double? { - guard let staticPressure = equipmentInfo?.staticPressure else { - return nil - } - return staticPressure - componentLosses.totalComponentPressureLoss + frictionRateResponse?.availableStaticPressure } var frictionRateDesignValue: Double? { - guard let availableStaticPressure, let tel = equivalentLengths.total else { - return nil - } - return (((availableStaticPressure * 100) / tel) * 100) / 100 + frictionRateResponse?.frictionRate } var badgeColor: String { diff --git a/Sources/ViewController/Views/Project/ProjectView.swift b/Sources/ViewController/Views/Project/ProjectView.swift index 083f9e6..ee00464 100644 --- a/Sources/ViewController/Views/Project/ProjectView.swift +++ b/Sources/ViewController/Views/Project/ProjectView.swift @@ -7,6 +7,10 @@ import ManualDClient import ManualDCore import Styleguide +enum ProjectViewValue { + @TaskLocal static var projectID = Project.ID(0) +} + struct ProjectView: HTML, Sendable { @Dependency(\.database) var database @Dependency(\.manualD) var manualD @@ -34,50 +38,65 @@ struct ProjectView: HTML, Sendable { div(.class("drawer-content p-4")) { label( .for("my-drawer-1"), - .class("btn btn-square btn-ghost drawer-button size-7") + .class("btn btn-square btn-ghost drawer-button size-7 pb-6") ) { SVG(.sidebarToggle) } switch self.activeTab { case .project: - if let project = try await database.projects.get(projectID) { - ProjectDetail(project: project) - } else { - div { - "FIX ME!" + await resultView(projectID) { + guard let project = try await database.projects.get(projectID) else { + throw NotFoundError() } + return project + } onSuccess: { project in + ProjectDetail(project: project) } case .rooms: - try await RoomsView( - projectID: projectID, - rooms: database.rooms.fetch(projectID), - sensibleHeatRatio: database.projects.getSensibleHeatRatio(projectID) - ) + await resultView(projectID) { + try await ( + database.rooms.fetch(projectID), + database.projects.getSensibleHeatRatio(projectID) + ) + } onSuccess: { (rooms, shr) in + RoomsView(rooms: rooms, sensibleHeatRatio: shr) + } case .equivalentLength: - try await EffectiveLengthsView( - projectID: projectID, - effectiveLengths: database.effectiveLength.fetch(projectID) - ) + await resultView(projectID) { + try await database.effectiveLength.fetch(projectID) + } onSuccess: { + EffectiveLengthsView(effectiveLengths: $0) + } case .frictionRate: - try await FrictionRateView( - equipmentInfo: database.equipment.fetch(projectID), - componentLosses: database.componentLoss.fetch(projectID), - equivalentLengths: database.effectiveLength.fetchMax(projectID), - projectID: projectID - ) - case .ductSizing: - try await DuctSizingView( - projectID: projectID, - rooms: manualD.calculate( - rooms: database.rooms.fetch(projectID), - designFrictionRateResult: database.designFrictionRate(projectID: projectID), - projectSHR: database.projects.getSensibleHeatRatio(projectID), - logger: logger - ) - ) - // div { "FIX ME!" } + await resultView(projectID) { + + let equipmentInfo = try await database.equipment.fetch(projectID) + let componentLosses = try await database.componentLoss.fetch(projectID) + let equivalentLengths = try await database.effectiveLength.fetchMax(projectID) + let frictionRateResponse = try await manualD.frictionRate( + equipmentInfo: equipmentInfo, + componentLosses: componentLosses, + effectiveLength: equivalentLengths + ) + return ( + equipmentInfo, componentLosses, equivalentLengths, frictionRateResponse + ) + } onSuccess: { + FrictionRateView( + equipmentInfo: $0.0, + componentLosses: $0.1, + equivalentLengths: $0.2, + frictionRateResponse: $0.3 + ) + } + case .ductSizing: + await resultView(projectID) { + try await database.calculateDuctSizes(projectID: projectID) + } onSuccess: { + DuctSizingView(rooms: $0) + } } } @@ -89,8 +108,77 @@ struct ProjectView: HTML, Sendable { } } } + + func resultView( + _ projectID: Project.ID, + catching: @escaping @Sendable () async throws(E) -> V, + onSuccess: @escaping @Sendable (V) -> ValueView + ) async -> ResultView, ErrorView> + where + ValueView: Sendable, E: Sendable + { + await .init( + result: .init(catching: catching), + onSuccess: { result in + onSuccess(result) + .environment(ProjectViewValue.$projectID, projectID) + } + ) + } } +// extension SiteRoute.View.ProjectRoute.DetailRoute.Tab { +// +// func view(projectID: Project.ID) async throws -> AnySendableHTML { +// @Dependency(\.database) var database +// @Dependency(\.manualD) var manualD +// +// switch self { +// case .project: +// if let project = try await database.projects.get(projectID) { +// return ProjectDetail(project: project) +// } else { +// return div { +// "FIX ME!" +// } +// } +// case .rooms: +// return try await RoomsView( +// projectID: projectID, +// rooms: database.rooms.fetch(projectID), +// sensibleHeatRatio: database.projects.getSensibleHeatRatio(projectID) +// ) +// +// case .equivalentLength: +// return try await EffectiveLengthsView( +// projectID: projectID, +// effectiveLengths: database.effectiveLength.fetch(projectID) +// ) +// case .frictionRate: +// let equipmentInfo = try await database.equipment.fetch(projectID) +// let componentLosses = try await database.componentLoss.fetch(projectID) +// let equivalentLengths = try await database.effectiveLength.fetchMax(projectID) +// +// return try await FrictionRateView( +// equipmentInfo: equipmentInfo, +// componentLosses: componentLosses, +// equivalentLengths: equivalentLengths, +// projectID: projectID, +// frictionRateResponse: manualD.frictionRate( +// equipmentInfo: equipmentInfo, +// componentLosses: componentLosses, +// effectiveLength: equivalentLengths +// ) +// ) +// case .ductSizing: +// return try await DuctSizingView( +// projectID: projectID, +// rooms: database.calculateDuctSizes(projectID: projectID) +// ) +// } +// } +// } + extension ProjectView { struct Sidebar: HTML { @@ -261,3 +349,27 @@ extension ProjectView { } } } + +extension ManualDClient { + + func frictionRate( + equipmentInfo: EquipmentInfo?, + componentLosses: [ComponentPressureLoss], + effectiveLength: EffectiveLength.MaxContainer + ) async throws -> FrictionRateResponse? { + guard let staticPressure = equipmentInfo?.staticPressure else { + return nil + } + guard let totalEquivalentLength = effectiveLength.total else { + return nil + } + return try await self.frictionRate( + .init( + externalStaticPressure: staticPressure, + componentPressureLosses: componentLosses, + totalEffectiveLength: Int(totalEquivalentLength) + ) + ) + } + +} diff --git a/Sources/ViewController/Views/Rooms/RoomsView.swift b/Sources/ViewController/Views/Rooms/RoomsView.swift index 76200d7..0d33391 100644 --- a/Sources/ViewController/Views/Rooms/RoomsView.swift +++ b/Sources/ViewController/Views/Rooms/RoomsView.swift @@ -5,40 +5,36 @@ import Foundation import ManualDCore import Styleguide -// TODO: Calculate rooms sensible based on project wide SHR. - struct RoomsView: HTML, Sendable { - let projectID: Project.ID + @Environment(ProjectViewValue.$projectID) var projectID + // let projectID: Project.ID let rooms: [Room] let sensibleHeatRatio: Double? var body: some HTML { div { - Row { - h1(.class("text-2xl font-bold")) { "Room Loads" } - // div( - // .class("tooltip tooltip-left"), - // .data("tip", value: "Add room") - // ) { - // div(.class("flex me-4")) { - // PlusButton() - // .attributes(.showModal(id: RoomForm.id())) - // } - // } - } - .attributes(.class("pb-6")) + h1(.class("text-2xl font-bold pb-6")) { "Room Loads" } div(.class("border rounded-lg mb-6")) { Row { - div(.class("space-x-6 my-2")) { - Label("Sensible Heat Ratio") - if let sensibleHeatRatio { - Number(sensibleHeatRatio) + div { + div(.class("space-x-6 my-2 items-center")) { + Label("Sensible Heat Ratio") + .attributes(.class("my-auto")) + if let sensibleHeatRatio { + Number(sensibleHeatRatio) + .attributes(.class("badge badge-outline")) + } + } + p(.class("text-sm italic")) { + "Project wide sensible heat ratio" } } - EditButton() - .attributes(.showModal(id: SHRForm.id)) + Tooltip("Edit SHR") { + EditButton() + .attributes(.showModal(id: SHRForm.id)) + } } .attributes(.class("m-4")) @@ -134,7 +130,7 @@ struct RoomsView: HTML, Sendable { td { div(.class("flex justify-end")) { div(.class("join")) { - Tooltip("Delete room") { + Tooltip("Delete room", position: .bottom) { TrashButton() .attributes( .class("join-item btn-ghost"), @@ -144,16 +140,14 @@ struct RoomsView: HTML, Sendable { .hx.confirm("Are you sure?") ) } - .attributes(.class("tooltip-bottom")) - Tooltip("Edit room") { + Tooltip("Edit room", position: .bottom) { EditButton() .attributes( .class("join-item btn-ghost"), .showModal(id: RoomForm.id(room)) ) } - .attributes(.class("tooltip-bottom")) } } RoomForm(