diff --git a/Public/css/output.css b/Public/css/output.css index ec3a096..fbc6f47 100644 --- a/Public/css/output.css +++ b/Public/css/output.css @@ -20,6 +20,8 @@ --spacing: 0.25rem; --text-sm: 0.875rem; --text-sm--line-height: calc(1.25 / 0.875); + --text-base: 1rem; + --text-base--line-height: calc(1.5 / 1); --text-lg: 1.125rem; --text-lg--line-height: calc(1.75 / 1.125); --text-xl: 1.25rem; @@ -5366,6 +5368,12 @@ } } } + .-my-2 { + margin-block: calc(var(--spacing) * -2); + } + .-my-4 { + margin-block: calc(var(--spacing) * -4); + } .my-1 { margin-block: calc(var(--spacing) * 1); } @@ -5581,6 +5589,12 @@ border-width: var(--border, 1px) 0 var(--border, 1px) var(--border, 1px); } } + .me-4 { + margin-inline-end: calc(var(--spacing) * 4); + } + .me-6 { + margin-inline-end: calc(var(--spacing) * 6); + } .modal-action { @layer daisyui.l1.l2.l3 { margin-top: calc(0.25rem * 6); @@ -5620,6 +5634,12 @@ } } } + .mt-1 { + margin-top: calc(var(--spacing) * 1); + } + .mt-2 { + margin-top: calc(var(--spacing) * 2); + } .mt-4 { margin-top: calc(var(--spacing) * 4); } @@ -6768,6 +6788,9 @@ .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } .grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } @@ -7922,6 +7945,10 @@ font-size: var(--text-4xl); line-height: var(--tw-leading, var(--text-4xl--line-height)); } + .text-base { + font-size: var(--text-base); + line-height: var(--tw-leading, var(--text-base--line-height)); + } .text-lg { font-size: var(--text-lg); line-height: var(--tw-leading, var(--text-lg--line-height)); diff --git a/Sources/ManualDCore/Theme.swift b/Sources/ManualDCore/Theme.swift index 691f6fa..798e0ff 100644 --- a/Sources/ManualDCore/Theme.swift +++ b/Sources/ManualDCore/Theme.swift @@ -15,6 +15,7 @@ public enum Theme: String, CaseIterable, Codable, Equatable, Sendable { public static let darkThemes = [ Self.aqua, + Self.cyberpunk, Self.dark, Self.dracula, Self.night, @@ -23,7 +24,6 @@ public enum Theme: String, CaseIterable, Codable, Equatable, Sendable { public static let lightThemes = [ Self.cupcake, - Self.cyberpunk, Self.light, Self.nord, Self.retro, diff --git a/Sources/Styleguide/Label.swift b/Sources/Styleguide/Label.swift index 96e8c44..5492c46 100644 --- a/Sources/Styleguide/Label.swift +++ b/Sources/Styleguide/Label.swift @@ -13,7 +13,7 @@ public struct Label: HTML, Sendable { } public var body: some HTML { - span(.class("text-xl text-secondary font-bold")) { + span(.class("text-lg text-secondary font-bold")) { title } } diff --git a/Sources/Styleguide/PageTitle.swift b/Sources/Styleguide/PageTitle.swift new file mode 100644 index 0000000..9d42013 --- /dev/null +++ b/Sources/Styleguide/PageTitle.swift @@ -0,0 +1,18 @@ +import Elementary + +public struct PageTitle: HTML, Sendable { + + let title: String + + public init(_ title: String) { + self.title = title + } + + public init(_ title: () -> String) { + self.title = title() + } + + public var body: some HTML { + h1(.class("text-3xl font-bold")) { title } + } +} diff --git a/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift b/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift index 0789013..21ef93f 100644 --- a/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift +++ b/Sources/ViewController/Views/DuctSizing/DuctSizingView.swift @@ -14,7 +14,7 @@ struct DuctSizingView: HTML, Sendable { var body: some HTML { div { - h1(.class("text-2xl py-4")) { "Duct Sizes" } + PageTitle { "Duct Sizes" } if rooms.count == 0 { p(.class("text-error italic")) { "Must complete all the previous sections to display duct sizing calculations." diff --git a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift index c235c8d..e8ef378 100644 --- a/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift +++ b/Sources/ViewController/Views/EffectiveLength/EffectiveLengthsView.swift @@ -23,11 +23,9 @@ struct EffectiveLengthsView: HTML, Sendable { } var body: some HTML { - div( - .class("m-4 space-y-4") - ) { + div(.class("space-y-4")) { Row { - h1(.class("text-2xl font-bold")) { "Equivalent Lengths" } + PageTitle { "Equivalent Lengths" } PlusButton() .attributes( .class("btn-ghost"), @@ -40,6 +38,8 @@ struct EffectiveLengthsView: HTML, Sendable { 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 (n, row) in supplies.enumerated() { EffectiveLengthView(effectiveLength: row) @@ -50,6 +50,7 @@ struct EffectiveLengthsView: HTML, Sendable { 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 (n, row) in returns.enumerated() { EffectiveLengthView(effectiveLength: row) diff --git a/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoForm.swift b/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoForm.swift index 34bbaf0..444a835 100644 --- a/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoForm.swift +++ b/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoForm.swift @@ -29,7 +29,7 @@ struct EquipmentInfoForm: HTML, Sendable { ModalForm(id: Self.id, dismiss: dismiss) { h1(.class("text-3xl font-bold pb-6 ps-2")) { "Equipment Info" } form( - .class("space-y-4 p-4"), + .class("grid grid-cols-1 gap-4"), equipmentInfo != nil ? .hx.patch(route) : .hx.post(route), @@ -42,27 +42,40 @@ struct EquipmentInfoForm: HTML, Sendable { input(.class("hidden"), .name("id"), .value("\(equipmentInfo.id)")) } - div { - label(.for("staticPressure")) { "Static Pressure" } - Input(id: "staticPressure", placeholder: "Static pressure") - .attributes( - .type(.number), .value(staticPressure), .min("0"), .max("1.0"), .step("0.1") - ) - } - div { - label(.for("heatingCFM")) { "Heating CFM" } - Input(id: "heatingCFM", placeholder: "CFM") - .attributes(.type(.number), .min("0"), .value(equipmentInfo?.heatingCFM)) - } - div { - label(.for("coolingCFM")) { "Cooling CFM" } - Input(id: "coolingCFM", placeholder: "CFM") - .attributes(.type(.number), .min("0"), .value(equipmentInfo?.coolingCFM)) - } - div { - SubmitButton(title: "Save") - .attributes(.class("btn-block")) - } + LabeledInput( + "Static Pressure", + .name("staticPressure"), + .type(.number), + .value(staticPressure), + .min("0"), + .max("1.0"), + .step("0.1"), + .required + ) + + LabeledInput( + "Heating CFM", + .name("heatingCFM"), + .type(.number), + .value(equipmentInfo?.heatingCFM), + .placeholder("1000"), + .min("0"), + .required, + .autofocus + ) + + LabeledInput( + "Cooling CFM", + .name("coolingCFM"), + .type(.number), + .value(equipmentInfo?.coolingCFM), + .placeholder("1000"), + .min("0"), + .required + ) + + SubmitButton(title: "Save") + .attributes(.class("btn-block my-6")) } } } diff --git a/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoView.swift b/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoView.swift index 12fbf4f..8422c5c 100644 --- a/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoView.swift +++ b/Sources/ViewController/Views/EquipmentInfo/EquipmentInfoView.swift @@ -8,12 +8,12 @@ struct EquipmentInfoView: HTML, Sendable { var body: some HTML { div( - .class("space-y-4 p-4"), + .class("space-y-4"), .id("equipmentInfo") ) { Row { - h1(.class("text-2xl font-bold")) { "Equipment Info" } + PageTitle { "Equipment Info" } Tooltip("Edit equipment info") { EditButton() @@ -29,16 +29,28 @@ struct EquipmentInfoView: HTML, Sendable { table(.class("table table-zebra")) { tbody(.class("text-lg")) { tr { - td { Label("Static Pressure") } - td { Number(equipmentInfo.staticPressure) } + td { span { "Static Pressure" } } + td { + div(.class("flex justify-end")) { + Number(equipmentInfo.staticPressure) + } + } } tr { - td { Label("Heating CFM") } - td { Number(equipmentInfo.heatingCFM) } + td { span { "Heating CFM" } } + td { + div(.class("flex justify-end")) { + Number(equipmentInfo.heatingCFM) + } + } } tr { - td { Label("Cooling CFM") } - td { Number(equipmentInfo.coolingCFM) } + td { span { "Cooling CFM" } } + td { + div(.class("flex justify-end")) { + Number(equipmentInfo.coolingCFM) + } + } } } } diff --git a/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift b/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift index d047315..93f92f8 100644 --- a/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift +++ b/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift @@ -44,7 +44,7 @@ struct FrictionRateView: HTML, Sendable { div(.class("space-y-6")) { div(.class("grid grid-cols-2 px-4")) { - h1(.class("text-4xl font-bold items-end my-auto")) { "Friction Rate" } + PageTitle { "Friction Rate" } div(.class("space-y-4 justify-end")) { diff --git a/Sources/ViewController/Views/Project/ProjectDetail.swift b/Sources/ViewController/Views/Project/ProjectDetail.swift index 27e5a14..99f9d14 100644 --- a/Sources/ViewController/Views/Project/ProjectDetail.swift +++ b/Sources/ViewController/Views/Project/ProjectDetail.swift @@ -9,7 +9,7 @@ struct ProjectDetail: HTML, Sendable { var body: some HTML { div { Row { - h1(.class("text-2xl font-bold")) { "Project" } + h1(.class("text-3xl font-bold")) { "Project" } EditButton() .attributes( .class("btn-ghost"), @@ -21,24 +21,44 @@ struct ProjectDetail: HTML, Sendable { table(.class("table table-zebra text-lg")) { tbody { tr { - td { Label("Name") } - td { project.name } + td { "Name" } + td { + div(.class("flex justify-end")) { + project.name + } + } } tr { - td { Label("Street Address") } - td { project.streetAddress } + td { "Street Address" } + td { + div(.class("flex justify-end")) { + project.streetAddress + } + } } tr { - td { Label("City") } - td { project.city } + td { "City" } + td { + div(.class("flex justify-end")) { + project.city + } + } } tr { - td { Label("State") } - td { project.state } + td { "State" } + td { + div(.class("flex justify-end")) { + project.state + } + } } tr { - td { Label("Zip") } - td { project.zipCode } + td { "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 8711333..028880a 100644 --- a/Sources/ViewController/Views/Project/ProjectsTable.swift +++ b/Sources/ViewController/Views/Project/ProjectsTable.swift @@ -20,7 +20,7 @@ struct ProjectsTable: HTML, Sendable { Navbar(sidebarToggle: false) div(.class("m-6")) { Row { - h1(.class("text-2xl font-bold")) { "Projects" } + PageTitle { "Projects" } Tooltip("Add project") { PlusButton() .attributes( @@ -31,7 +31,7 @@ struct ProjectsTable: HTML, Sendable { } .attributes(.class("pb-6")) - div(.class("overflow-x-auto rounded-box border")) { + div(.class("overflow-x-auto")) { table(.class("table table-zebra")) { thead { tr { diff --git a/Sources/ViewController/Views/Rooms/RoomForm.swift b/Sources/ViewController/Views/Rooms/RoomForm.swift index 206aa78..398b98d 100644 --- a/Sources/ViewController/Views/Rooms/RoomForm.swift +++ b/Sources/ViewController/Views/Rooms/RoomForm.swift @@ -39,8 +39,7 @@ struct RoomForm: HTML, Sendable { ModalForm(id: Self.id(room), dismiss: dismiss) { h1(.class("text-3xl font-bold pb-6")) { "Room" } form( - .class("modal-backdrop"), - .init(name: "method", value: "dialog"), + .class("grid grid-cols-1 gap-4"), room == nil ? .hx.post(route) : .hx.patch(route), @@ -54,34 +53,54 @@ struct RoomForm: HTML, Sendable { input(.class("hidden"), .name("id"), .value("\(id)")) } - div { - label(.for("name")) { "Name:" } - Input(id: "name", placeholder: "Room Name") - .attributes(.type(.text), .required, .autofocus, .value(room?.name)) - } - div { - label(.for("heatingLoad")) { "Heating Load:" } - Input(id: "heatingLoad", placeholder: "Heating Load") - .attributes(.type(.number), .required, .min("0"), .value(room?.heatingLoad)) - } - div { - label(.for("coolingTotal")) { "Cooling Total:" } - Input(id: "coolingTotal", placeholder: "Cooling Total") - .attributes(.type(.number), .required, .min("0"), .value(room?.coolingTotal)) - } - div { - label(.for("coolingSensible")) { "Cooling Sensible:" } - Input(id: "coolingSensible", placeholder: "Cooling Sensible (Optional)") - .attributes(.type(.number), .min("0"), .value(room?.coolingSensible)) - } - div(.class("pb-6")) { - label(.for("registerCount")) { "Registers:" } - Input(id: "registerCount", placeholder: "Register Count") - .attributes( - .type(.number), .required, .min("0"), - .value("\(room != nil ? room!.registerCount : 1)"), - ) - } + LabeledInput( + "Name", + .name("name"), + .type(.text), + .placeholder("Name"), + .required, + .autofocus, + .value(room?.name) + ) + + LabeledInput( + "Heating Load", + .name("heatingLoad"), + .type(.number), + .placeholder("1234"), + .required, + .min("0"), + .value(room?.heatingLoad) + ) + + LabeledInput( + "Cooling Total", + .name("coolingTotal"), + .type(.number), + .placeholder("1234"), + .required, + .min("0"), + .value(room?.coolingTotal) + ) + + LabeledInput( + "Cooling Sensible", + .name("coolingSensible"), + .type(.number), + .placeholder("1234 (Optional)"), + .min("0"), + .value(room?.coolingSensible) + ) + + LabeledInput( + "Registers", + .name("registerCount"), + .type(.number), + .min("1"), + .required, + .value(room?.registerCount ?? 1) + ) + SubmitButton() .attributes(.class("btn-block")) } diff --git a/Sources/ViewController/Views/Rooms/RoomsView.swift b/Sources/ViewController/Views/Rooms/RoomsView.swift index 248e06e..b7cb56e 100644 --- a/Sources/ViewController/Views/Rooms/RoomsView.swift +++ b/Sources/ViewController/Views/Rooms/RoomsView.swift @@ -14,61 +14,84 @@ struct RoomsView: HTML, Sendable { var body: some HTML { div(.class("flex w-full flex-col")) { Row { - h1( - .class("flex flex-row text-2xl font-bold pb-6 h-full items-center") - ) { "Room Loads" } + PageTitle { "Room Loads" } - div(.class("flex justify-end")) { + div(.class("flex justify-end items-end -my-2")) { Tooltip("Project wide sensible heat ratio", position: .left) { button( .class( """ - grid grid-cols-1 gap-2 p-4 justify-end + justify-end items-end p-4 hover:bg-neutral hover:text-white hover:rounded-lg """ ), .showModal(id: SHRForm.id) ) { - LabeledContent("Sensible Heat Ratio") { + LabeledContent { + div(.class("flex justify-end items-end space-x-4")) { + // SVG(.squarePen) + span(.class("font-bold")) { + "Sensible Heat Ratio" + } + } + } content: { if let sensibleHeatRatio { Badge(number: sensibleHeatRatio) } } - div(.class("flex justify-end")) { - SVG(.squarePen) - } } } } } + div(.class("flex flex-wrap justify-between mt-6")) { + div(.class("flex items-end space-x-4")) { + span(.class("font-bold")) { "Heating Total" } + Badge(number: rooms.heatingTotal, digits: 0) + .attributes(.class("badge-error")) + } + + div(.class("flex items-end space-x-4")) { + span(.class("font-bold")) { "Cooling Total" } + Badge(number: rooms.coolingTotal, digits: 0) + .attributes(.class("badge-success")) + } + + div(.class("flex justify-end items-end space-x-4 me-4")) { + span(.class("font-bold")) { "Cooling Sensible" } + Badge(number: rooms.coolingSensible(shr: sensibleHeatRatio), digits: 0) + .attributes(.class("badge-info")) + } + } + // .attributes(.class("mt-6 me-4")) + div(.class("divider")) {} SHRForm(projectID: projectID, sensibleHeatRatio: sensibleHeatRatio) div(.class("overflow-x-auto")) { - table(.class("table table-zebra"), .id("roomsTable")) { + table(.class("table table-zebra text-lg"), .id("roomsTable")) { thead { - tr { - th { Label("Name") } + tr(.class("text-lg font-bold")) { + th { "Name" } th { div(.class("flex justify-center")) { - Label("Heating Load") + "Heating Load" } } th { div(.class("flex justify-center")) { - Label("Cooling Total") + "Cooling Total" } } th { div(.class("flex justify-center")) { - Label("Cooling Sensible") + "Cooling Sensible" } } th { div(.class("flex justify-center")) { - Label("Register Count") + "Register Count" } } th { @@ -89,30 +112,6 @@ struct RoomsView: HTML, Sendable { for room in rooms { RoomRow(room: room, shr: sensibleHeatRatio) } - // TOTALS - tr(.class("font-bold text-xl")) { - td { Label("Total") } - td { - div(.class("flex justify-center")) { - Badge(number: rooms.heatingTotal) - .attributes(.class("badge-error badge-xl")) - } - } - td { - div(.class("flex justify-center")) { - Badge(number: rooms.coolingTotal, digits: 0) - .attributes(.class("badge-success badge-xl")) - } - } - td { - div(.class("flex justify-center")) { - Badge(number: rooms.coolingSensible(shr: sensibleHeatRatio), digits: 0) - .attributes(.class("badge-info badge-xl")) - } - } - td {} - td {} - } } } } @@ -143,19 +142,19 @@ struct RoomsView: HTML, Sendable { td { div(.class("flex justify-center")) { Number(room.heatingLoad, digits: 0) - .attributes(.class("text-error")) + // .attributes(.class("text-error")) } } td { div(.class("flex justify-center")) { Number(room.coolingTotal, digits: 0) - .attributes(.class("text-success")) + // .attributes(.class("text-success")) } } td { div(.class("flex justify-center")) { Number(coolingSensible, digits: 0) - .attributes(.class("text-info")) + // .attributes(.class("text-info")) } } td { @@ -204,22 +203,28 @@ struct RoomsView: HTML, Sendable { var body: some HTML { ModalForm(id: Self.id, dismiss: true) { + h1(.class("text-xl font-bold mb-6")) { + "Sensible Heat Ratio" + } form( - .class("space-y-6"), + .class("grid grid-cols-1 gap-4"), .hx.patch("/projects/\(projectID)/rooms/update-shr"), .hx.target("body"), .hx.swap(.outerHTML) ) { input(.class("hidden"), .name("projectID"), .value("\(projectID)")) - div { - label(.for("sensibleHeatRatio")) { "Sensible Heat Ratio" } - Input(id: "sensibleHeatRatio", placeholder: "Sensible Heat Ratio") - .attributes(.min("0"), .max("1"), .step("0.01"), .value(sensibleHeatRatio)) - } - div { - SubmitButton() - .attributes(.class("btn-block")) - } + LabeledInput( + "SHR", + .type(.number), + .placeholder("0.83"), + .min("0"), + .max("1"), + .step("0.01"), + .value(sensibleHeatRatio), + .autofocus + ) + SubmitButton() + .attributes(.class("btn-block my-6")) } } }