feat: Style updates.

This commit is contained in:
2026-01-11 20:57:06 -05:00
parent f7c6373255
commit 0a68177aa8
19 changed files with 410 additions and 141 deletions

View File

@@ -5581,6 +5581,9 @@
.ms-4 { .ms-4 {
margin-inline-start: calc(var(--spacing) * 4); margin-inline-start: calc(var(--spacing) * 4);
} }
.me-4 {
margin-inline-end: calc(var(--spacing) * 4);
}
.modal-action { .modal-action {
@layer daisyui.l1.l2.l3 { @layer daisyui.l1.l2.l3 {
margin-top: calc(0.25rem * 6); margin-top: calc(0.25rem * 6);
@@ -6444,6 +6447,9 @@
.h-\[50px\] { .h-\[50px\] {
height: 50px; height: 50px;
} }
.h-auto {
height: auto;
}
.h-fit { .h-fit {
height: fit-content; height: fit-content;
} }
@@ -6599,6 +6605,9 @@
.w-\[80px\] { .w-\[80px\] {
width: 80px; width: 80px;
} }
.w-auto {
width: auto;
}
.w-fit { .w-fit {
width: fit-content; width: fit-content;
} }
@@ -6798,12 +6807,18 @@
.grid-cols-1 { .grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr)); grid-template-columns: repeat(1, minmax(0, 1fr));
} }
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-cols-5 { .grid-cols-5 {
grid-template-columns: repeat(5, minmax(0, 1fr)); grid-template-columns: repeat(5, minmax(0, 1fr));
} }
.flex-col { .flex-col {
flex-direction: column; flex-direction: column;
} }
.flex-row {
flex-direction: row;
}
.flex-wrap { .flex-wrap {
flex-wrap: wrap; flex-wrap: wrap;
} }
@@ -6828,6 +6843,9 @@
.justify-end { .justify-end {
justify-content: flex-end; justify-content: flex-end;
} }
.justify-start {
justify-content: flex-start;
}
.gap-1 { .gap-1 {
gap: calc(var(--spacing) * 1); gap: calc(var(--spacing) * 1);
} }
@@ -7280,6 +7298,12 @@
border-color: currentColor; border-color: currentColor;
} }
} }
.border-base-100 {
border-color: var(--color-base-100);
}
.border-base-200 {
border-color: var(--color-base-200);
}
.border-gray-200 { .border-gray-200 {
border-color: var(--color-gray-200); border-color: var(--color-gray-200);
} }
@@ -7872,6 +7896,9 @@
} }
} }
} }
.px-2 {
padding-inline: calc(var(--spacing) * 2);
}
.px-3 { .px-3 {
padding-inline: calc(var(--spacing) * 3); padding-inline: calc(var(--spacing) * 3);
} }
@@ -9443,6 +9470,13 @@
border-color: var(--color-red-500); border-color: var(--color-red-500);
} }
} }
.hover\:rounded-lg {
&:hover {
@media (hover: hover) {
border-radius: var(--radius-lg);
}
}
}
.hover\:bg-gray-900 { .hover\:bg-gray-900 {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
@@ -9471,6 +9505,13 @@
} }
} }
} }
.hover\:bg-success {
&:hover {
@media (hover: hover) {
background-color: var(--color-success);
}
}
}
.hover\:text-black { .hover\:text-black {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
@@ -9485,6 +9526,16 @@
} }
} }
} }
.hover\:btn-success {
&:hover {
@media (hover: hover) {
@layer daisyui.l1.l2.l3 {
--btn-color: var(--color-success);
--btn-fg: var(--color-success-content);
}
}
}
}
.focus\:outline { .focus\:outline {
&:focus { &:focus {
outline-style: var(--tw-outline-style); outline-style: var(--tw-outline-style);
@@ -9806,6 +9857,11 @@
display: flex; display: flex;
} }
} }
.is-drawer-open\:hidden {
&:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) {
display: none;
}
}
.is-drawer-open\:w-64 { .is-drawer-open\:w-64 {
&:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) { &:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) {
width: calc(var(--spacing) * 64); width: calc(var(--spacing) * 64);

View File

@@ -66,9 +66,10 @@ extension DatabaseClient.Projects: TestDependencyKey {
.first() .first()
return .init( return .init(
equipmentInfo: equipmentInfo != nil,
rooms: roomsCount > 0, rooms: roomsCount > 0,
equivalentLength: equivalentLengthsCompleted, equivalentLength: equivalentLengthsCompleted,
frictionRate: equipmentInfo != nil && componentLosses > 0 frictionRate: componentLosses > 0
) )
}, },
getSensibleHeatRatio: { id in getSensibleHeatRatio: { id in

View File

@@ -66,11 +66,18 @@ extension Project {
public struct CompletedSteps: Codable, Equatable, Sendable { public struct CompletedSteps: Codable, Equatable, Sendable {
public let equipmentInfo: Bool
public let rooms: Bool public let rooms: Bool
public let equivalentLength: Bool public let equivalentLength: Bool
public let frictionRate: Bool public let frictionRate: Bool
public init(rooms: Bool, equivalentLength: Bool, frictionRate: Bool) { public init(
equipmentInfo: Bool,
rooms: Bool,
equivalentLength: Bool,
frictionRate: Bool
) {
self.equipmentInfo = equipmentInfo
self.rooms = rooms self.rooms = rooms
self.equivalentLength = equivalentLength self.equivalentLength = equivalentLength
self.frictionRate = frictionRate self.frictionRate = frictionRate

View File

@@ -189,6 +189,7 @@ extension SiteRoute.View.ProjectRoute {
public enum Tab: String, CaseIterable, Equatable, Sendable { public enum Tab: String, CaseIterable, Equatable, Sendable {
case project case project
case equipment
case rooms case rooms
case equivalentLength case equivalentLength
case frictionRate case frictionRate

View File

@@ -0,0 +1,28 @@
import Elementary
public struct Badge<Inner: HTML>: HTML, Sendable where Inner: Sendable {
let inner: Inner
public init(
@HTMLBuilder inner: () -> Inner
) {
self.inner = inner()
}
public var body: some HTML<HTMLTag.div> {
div(.class("badge badge-lg badge-outline font-bold")) {
inner
}
}
}
extension Badge where Inner == Number {
public init(number: Int) {
self.inner = Number(number)
}
public init(number: Double, digits: Int = 2) {
self.inner = Number(number, digits: digits)
}
}

View File

@@ -65,7 +65,7 @@ public struct EditButton: HTML, Sendable {
} }
public var body: some HTML<HTMLTag.button> { public var body: some HTML<HTMLTag.button> {
button(.class("btn btn-success btn-circle"), .type(type)) { button(.class("btn hover:btn-success"), .type(type)) {
div(.class("flex")) { div(.class("flex")) {
if let title { if let title {
span(.class("pe-2")) { title } span(.class("pe-2")) { title }

View File

@@ -40,3 +40,9 @@ extension HTMLAttribute where Tag == HTMLTag.button {
.on(.click, "\(id).showModal()") .on(.click, "\(id).showModal()")
} }
} }
extension HTML where Tag: HTMLTrait.Attributes.Global {
public func badge() -> _AttributedElement<Self> {
attributes(.class("badge badge-lg badge-outline font-bold"))
}
}

View File

@@ -0,0 +1,72 @@
import Elementary
public struct LabeledContent<Label: HTML, Content: HTML>: HTML {
let label: @Sendable () -> Label
let content: @Sendable () -> Content
let position: LabelPosition
public init(
position: LabelPosition = .default,
@HTMLBuilder label: @escaping @Sendable () -> Label,
@HTMLBuilder content: @escaping @Sendable () -> Content
) {
self.position = position
self.label = label
self.content = content
}
public var body: some HTML<HTMLTag.div> {
div {
switch position {
case .leading:
label()
content()
case .trailing:
content()
label()
case .top:
label()
content()
case .bottom:
content()
label()
}
}
.attributes(.class("flex space-x-4"), when: position.isHorizontal)
.attributes(.class("space-y-4"), when: position.isVertical)
}
}
// TODO: Merge / use TooltipPosition
public enum LabelPosition: String, CaseIterable, Equatable, Sendable {
case leading
case trailing
case top
case bottom
var isHorizontal: Bool {
self == .leading || self == .trailing
}
var isVertical: Bool {
self == .top || self == .bottom
}
public static let `default` = Self.leading
}
extension LabeledContent: Sendable where Label: Sendable, Content: Sendable {}
extension LabeledContent where Label == Styleguide.Label {
public init(
_ label: String, position: LabelPosition = .default,
@HTMLBuilder content: @escaping @Sendable () -> Content
) {
self.init(
position: position,
label: { Label(label) },
content: content
)
}
}

View File

@@ -23,6 +23,7 @@ extension SVG {
case close case close
case doorClosed case doorClosed
case email case email
case fan
case key case key
case mapPin case mapPin
case rulerDimensionLine case rulerDimensionLine
@@ -78,6 +79,10 @@ extension SVG {
</g> </g>
</svg> </svg>
""" """
case .fan:
return """
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-fan-icon lucide-fan"><path d="M10.827 16.379a6.082 6.082 0 0 1-8.618-7.002l5.412 1.45a6.082 6.082 0 0 1 7.002-8.618l-1.45 5.412a6.082 6.082 0 0 1 8.618 7.002l-5.412-1.45a6.082 6.082 0 0 1-7.002 8.618l1.45-5.412Z"/><path d="M12 12v.01"/></svg>
"""
case .key: case .key:
return """ return """
<svg class="h-[1em] opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <svg class="h-[1em] opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">

View File

@@ -188,10 +188,8 @@ extension SiteRoute.View.ProjectRoute.EquipmentInfoRoute {
switch self { switch self {
case .index: case .index:
return await ResultView { return request.view {
try await database.equipment.fetch(projectID) ProjectView(projectID: projectID, activeTab: .equipment)
} onSuccess: { equipment in
EquipmentInfoView(equipmentInfo: equipment, projectID: projectID)
} }
case .form(let dismiss): case .form(let dismiss):
return await ResultView { return await ResultView {

View File

@@ -15,37 +15,31 @@ struct ComponentPressureLossesView: HTML, Sendable {
} }
var body: some HTML { var body: some HTML {
div( div(.class("space-y-4")) {
.class(
"""
border border-gray-200 rounded-lg shadow-lg space-y-4 p-4
"""
)
) {
Row { Row {
div(.class("flex space-x-4 items-center")) { h1(.class("text-2xl font-bold")) { "Component Pressure Losses" }
h1(.class("text-2xl font-bold")) { "Component Pressure Losses" } LabeledContent("Total") {
div(.class("flex text-primary space-x-2 items-baseline")) { Badge(number: total)
Number(total)
.attributes(.class("text-xl font-bold badge badge-outline badge-primary"))
span(.class("text-sm italic")) { "Total" }
}
}
Tooltip("Add Component Loss") {
PlusButton()
.attributes(
.class("btn-ghost text-2xl"),
.showModal(id: ComponentLossForm.id())
)
} }
} }
.attributes(.class("px-4"))
table(.class("table table-zebra")) { table(.class("table table-zebra")) {
thead { thead {
tr(.class("text-xl font-bold")) { tr(.class("text-xl font-bold")) {
th { "Name" } th { "Name" }
th { "Value" } th { "Value" }
th {} th {
div(.class("flex justify-end mx-auto")) {
Tooltip("Add Component Loss") {
PlusButton()
.attributes(
.class("btn-ghost text-2xl"),
.showModal(id: ComponentLossForm.id())
)
}
}
}
} }
} }
tbody { tbody {

View File

@@ -41,7 +41,7 @@ struct DuctSizingView: HTML, Sendable {
th(.class("hidden 2xl:table-cell")) { "Htg CFM" } th(.class("hidden 2xl:table-cell")) { "Htg CFM" }
th(.class("hidden 2xl:table-cell")) { "Clg CFM" } th(.class("hidden 2xl:table-cell")) { "Clg CFM" }
th { "Dsn CFM" } th { "Dsn CFM" }
th(.class("hidden xl:table-cell")) { "Round Size" } th(.class("hidden 2xl:table-cell")) { "Round Size" }
th { "Velocity" } th { "Velocity" }
th { "Final Size" } th { "Final Size" }
th { "Flex Size" } th { "Flex Size" }
@@ -84,7 +84,7 @@ struct DuctSizingView: HTML, Sendable {
.attributes( .attributes(
.class("badge badge-outline badge-\(room.designCFM.color) text-xl font-bold")) .class("badge badge-outline badge-\(room.designCFM.color) text-xl font-bold"))
} }
td(.class("hidden xl:table-cell")) { Number(room.roundSize, digits: 0) } td(.class("hidden 2xl:table-cell")) { Number(room.roundSize, digits: 0) }
td { Number(room.velocity) } td { Number(room.velocity) }
td { td {
Number(room.finalSize) Number(room.finalSize)
@@ -131,7 +131,7 @@ struct DuctSizingView: HTML, Sendable {
EditButton() EditButton()
.attributes( .attributes(
.class("join-item btn-ghost text-success hover:text-white"), .class("join-item btn-ghost"),
.showModal(id: RectangularSizeForm.id(room)) .showModal(id: RectangularSizeForm.id(room))
) )
} }

View File

@@ -8,7 +8,7 @@ struct EquipmentInfoView: HTML, Sendable {
var body: some HTML { var body: some HTML {
div( div(
.class("space-y-4 border border-gray-200 rounded-lg shadow-lg p-4"), .class("space-y-4 p-4"),
.id("equipmentInfo") .id("equipmentInfo")
) { ) {
@@ -27,23 +27,17 @@ struct EquipmentInfoView: HTML, Sendable {
if let equipmentInfo { if let equipmentInfo {
table(.class("table table-zebra")) { table(.class("table table-zebra")) {
thead {
tr {
th { Label("Name") }
th { Label("Value") }
}
}
tbody(.class("text-lg")) { tbody(.class("text-lg")) {
tr { tr {
td { "Static Pressure" } td { Label("Static Pressure") }
td { Number(equipmentInfo.staticPressure) } td { Number(equipmentInfo.staticPressure) }
} }
tr { tr {
td { "Heating CFM" } td { Label("Heating CFM") }
td { Number(equipmentInfo.heatingCFM) } td { Number(equipmentInfo.heatingCFM) }
} }
tr { tr {
td { "Cooling CFM" } td { Label("Cooling CFM") }
td { Number(equipmentInfo.coolingCFM) } td { Number(equipmentInfo.coolingCFM) }
} }
} }

View File

@@ -43,24 +43,26 @@ struct FrictionRateView: HTML, Sendable {
} }
var body: some HTML { var body: some HTML {
div(.class("p-4 space-y-6")) { div(.class("space-y-6")) {
Row { div(.class("grid grid-cols-2 px-4")) {
h1(.class("text-4xl font-bold pb-6")) { "Friction Rate" }
div(.class("space-y-4")) { h1(.class("text-4xl font-bold items-end my-auto")) { "Friction Rate" }
div(.class("flex space-x-4 justify-end")) {
if let availableStaticPressure { div(.class("space-y-4 justify-end")) {
Label("Available Static Pressure")
Number(availableStaticPressure, digits: 2) if let frictionRateDesignValue {
.attributes(.class("badge badge-lg badge-outline font-bold ms-4")) LabeledContent("Friction Rate Design Value") {
Badge(number: frictionRateDesignValue, digits: 2)
.attributes(.class("\(badgeColor)"))
} }
.attributes(.class("justify-end"))
} }
div(.class("flex space-x-4 justify-end")) { if let availableStaticPressure {
if let frictionRateDesignValue { LabeledContent("Available Static Pressure") {
Label("Friction Rate Design Value") Badge(number: availableStaticPressure, digits: 2)
Number(frictionRateDesignValue, digits: 2)
.attributes(.class("badge badge-lg badge-outline \(badgeColor) font-bold"))
} }
.attributes(.class("justify-end"))
} }
} }
} }
@@ -94,12 +96,14 @@ struct FrictionRateView: HTML, Sendable {
.attributes(.class("hidden"), when: !showHighErrors) .attributes(.class("hidden"), when: !showHighErrors)
} }
div(.class("grid grid-cols-1 lg:grid-cols-2 gap-4")) { div(.class("divider")) {}
EquipmentInfoView(equipmentInfo: equipmentInfo, projectID: projectID)
ComponentPressureLossesView( // div(.class("grid grid-cols-1 lg:grid-cols-2 gap-4")) {
componentPressureLosses: componentLosses, projectID: projectID // EquipmentInfoView(equipmentInfo: equipmentInfo, projectID: projectID)
) ComponentPressureLossesView(
} componentPressureLosses: componentLosses, projectID: projectID
)
// }
} }
} }
} }

View File

@@ -5,7 +5,7 @@ import Styleguide
public struct MainPage<Inner: HTML>: SendableHTMLDocument where Inner: Sendable { public struct MainPage<Inner: HTML>: SendableHTMLDocument where Inner: Sendable {
public var title: String { "Manual-D" } public var title: String { "Duct Calc" }
public var lang: String { "en" } public var lang: String { "en" }
let inner: Inner let inner: Inner
@@ -22,7 +22,11 @@ public struct MainPage<Inner: HTML>: SendableHTMLDocument where Inner: Sendable
script(.src("https://unpkg.com/htmx.org@2.0.8")) {} script(.src("https://unpkg.com/htmx.org@2.0.8")) {}
script(.src("/js/main.js")) {} script(.src("/js/main.js")) {}
link(.rel(.stylesheet), .href("/css/output.css")) link(.rel(.stylesheet), .href("/css/output.css"))
link(.rel(.icon), .href("/images/favicon.ico"), .custom(name: "type", value: "image/x-icon")) link(
.rel(.icon),
.href("/images/favicon.ico"),
.init(name: "type", value: "image/x-icon")
)
link( link(
.rel(.icon), .rel(.icon),
.href("/images/favicon-32x32.png"), .href("/images/favicon-32x32.png"),

View File

@@ -25,6 +25,7 @@ struct Navbar: HTML, Sendable {
} }
.navButton() .navButton()
} }
} }
Tooltip("Home", position: .right) { Tooltip("Home", position: .right) {
@@ -35,7 +36,7 @@ struct Navbar: HTML, Sendable {
img( img(
.src("/images/mand_logo_sm.webp"), .src("/images/mand_logo_sm.webp"),
) )
span { "Manual-D" } span { "Duct Calc" }
} }
.navButton() .navButton()
} }

View File

@@ -7,51 +7,95 @@ struct ProjectDetail: HTML, Sendable {
let project: Project let project: Project
var body: some HTML { var body: some HTML {
div( div {
.class(
"""
border border-gray-200 rounded-lg shadow-lg space-y-4 p-4 m-4
"""
)
) {
Row { Row {
h1(.class("text-2xl font-bold")) { "Project" } h1(.class("text-2xl font-bold")) { "Project" }
EditButton() EditButton()
.attributes( .attributes(
.class("btn-ghost"),
.on(.click, "projectForm.showModal()") .on(.click, "projectForm.showModal()")
) )
} }
Row { div(.class("overflow-x-auto")) {
Label("Name") table(.class("table table-zebra text-lg")) {
span { project.name } tbody {
tr {
td { Label("Name") }
td { project.name }
}
tr {
td { Label("Street Address") }
td { project.streetAddress }
}
tr {
td { Label("City") }
td { project.city }
}
tr {
td { Label("State") }
td { project.state }
}
tr {
td { Label("Zip") }
td { project.zipCode }
}
}
}
} }
.attributes(.class("border-b border-gray-200"))
Row { ProjectForm(dismiss: true, project: project)
Label("Address")
span { project.streetAddress }
}
.attributes(.class("border-b border-gray-200"))
Row {
Label("City")
span { project.city }
}
.attributes(.class("border-b border-gray-200"))
Row {
Label("State")
span { project.state }
}
.attributes(.class("border-b border-gray-200"))
Row {
Label("Zip")
span { project.zipCode }
}
} }
ProjectForm(dismiss: true, project: project)
} }
// var body: some HTML {
// div(
// .class(
// """
// space-y-4 p-4 m-4
// """
// )
// ) {
// Row {
// h1(.class("text-2xl font-bold")) { "Project" }
// EditButton()
// .attributes(
// .class("btn-ghost"),
// .on(.click, "projectForm.showModal()")
// )
// }
//
// Row {
// Label("Name")
// span { project.name }
// }
// .attributes(.class("border-b border-gray-200"))
//
// Row {
// Label("Address")
// span { project.streetAddress }
// }
// .attributes(.class("border-b border-gray-200"))
//
// Row {
// Label("City")
// span { project.city }
// }
// .attributes(.class("border-b border-gray-200"))
//
// Row {
// Label("State")
// span { project.state }
// }
// .attributes(.class("border-b border-gray-200"))
//
// Row {
// Label("Zip")
// span { project.zipCode }
// }
// }
//
// ProjectForm(dismiss: true, project: project)
// }
} }

View File

@@ -48,6 +48,14 @@ struct ProjectView: HTML, Sendable {
} onSuccess: { project in } onSuccess: { project in
ProjectDetail(project: project) ProjectDetail(project: project)
} }
case .equipment:
await resultView(projectID) {
try await database.equipment.fetch(projectID)
} onSuccess: { equipment in
EquipmentInfoView(equipmentInfo: equipment, projectID: projectID)
}
// FIX:
// div { "Fix Me" }
case .rooms: case .rooms:
await resultView(projectID) { await resultView(projectID) {
try await ( try await (
@@ -179,6 +187,16 @@ extension ProjectView {
.attributes(.data("active", value: "true"), when: active == .rooms) .attributes(.data("active", value: "true"), when: active == .rooms)
} }
li(.class("flex w-full")) {
row(
title: "Equipment",
icon: .fan,
route: .project(.detail(projectID, .equipment(.index))),
isComplete: completedSteps.equipmentInfo
)
.attributes(.data("active", value: "true"), when: active == .equipment)
}
li(.class("w-full")) { li(.class("w-full")) {
// Tooltip("Equivalent Lengths", position: .right) { // Tooltip("Equivalent Lengths", position: .right) {
row( row(
@@ -235,6 +253,7 @@ extension ProjectView {
""" """
), ),
.hx.get(href), .hx.get(href),
.hx.pushURL(true),
.hx.target("body"), .hx.target("body"),
.hx.swap(.outerHTML) .hx.swap(.outerHTML)
) { ) {

View File

@@ -12,44 +12,65 @@ struct RoomsView: HTML, Sendable {
let sensibleHeatRatio: Double? let sensibleHeatRatio: Double?
var body: some HTML { var body: some HTML {
div { div(.class("flex w-full flex-col")) {
h1(.class("text-2xl font-bold pb-6")) { "Room Loads" } Row {
h1(
.class("flex flex-row text-2xl font-bold pb-6 h-full items-center")
) { "Room Loads" }
div(.class("border rounded-lg mb-6")) { div(.class("flex justify-end")) {
Row { Tooltip("Project wide sensible heat ratio", position: .left) {
div { button(
div(.class("space-x-6 my-2 items-center")) { .class(
Label("Sensible Heat Ratio") """
.attributes(.class("my-auto")) grid grid-cols-1 gap-2 p-4 justify-end
if let sensibleHeatRatio { hover:bg-neutral hover:text-white hover:rounded-lg
Number(sensibleHeatRatio) """
.attributes(.class("badge badge-outline")) ),
.showModal(id: SHRForm.id)
) {
LabeledContent("Sensible Heat Ratio") {
if let sensibleHeatRatio {
Badge(number: sensibleHeatRatio)
}
}
div(.class("flex justify-end")) {
SVG(.squarePen)
} }
} }
p(.class("text-sm italic")) {
"Project wide sensible heat ratio"
}
}
Tooltip("Edit SHR") {
EditButton()
.attributes(.class("btn-ghost"), .showModal(id: SHRForm.id))
} }
} }
.attributes(.class("m-4"))
SHRForm(projectID: projectID, sensibleHeatRatio: sensibleHeatRatio)
} }
div(.class("overflow-x-auto rounded-box border")) { 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"), .id("roomsTable")) {
thead { thead {
tr { tr {
th { Label("Name") } th { Label("Name") }
th { Label("Heating Load") } th {
th { Label("Cooling Total") } div(.class("flex justify-center")) {
th { Label("Cooling Sensible") } Label("Heating Load")
th { Label("Register Count") } }
}
th {
div(.class("flex justify-center")) {
Label("Cooling Total")
}
}
th {
div(.class("flex justify-center")) {
Label("Cooling Sensible")
}
}
th {
div(.class("flex justify-center")) {
Label("Register Count")
}
}
th { th {
div(.class("flex justify-end")) { div(.class("flex justify-end")) {
Tooltip("Add Room") { Tooltip("Add Room") {
@@ -58,8 +79,8 @@ struct RoomsView: HTML, Sendable {
.class("btn-ghost mx-auto"), .class("btn-ghost mx-auto"),
.showModal(id: RoomForm.id()) .showModal(id: RoomForm.id())
) )
.attributes(.class("tooltip-left"))
} }
.attributes(.class("tooltip-left"))
} }
} }
} }
@@ -72,16 +93,22 @@ struct RoomsView: HTML, Sendable {
tr(.class("font-bold text-xl")) { tr(.class("font-bold text-xl")) {
td { Label("Total") } td { Label("Total") }
td { td {
Number(rooms.heatingTotal, digits: 0) div(.class("flex justify-center")) {
.attributes(.class("badge badge-outline badge-error badge-xl")) Badge(number: rooms.heatingTotal)
.attributes(.class("badge-error badge-xl"))
}
} }
td { td {
Number(rooms.coolingTotal, digits: 0) div(.class("flex justify-center")) {
.attributes(.class("badge badge-outline badge-success badge-xl")) Badge(number: rooms.coolingTotal, digits: 0)
.attributes(.class("badge-success badge-xl"))
}
} }
td { td {
Number(rooms.coolingSensible(shr: sensibleHeatRatio), digits: 0) div(.class("flex justify-center")) {
.attributes(.class("badge badge-outline badge-info badge-xl")) Badge(number: rooms.coolingSensible(shr: sensibleHeatRatio), digits: 0)
.attributes(.class("badge-info badge-xl"))
}
} }
td {} td {}
td {} td {}
@@ -113,19 +140,27 @@ struct RoomsView: HTML, Sendable {
tr(.id("roomRow_\(room.name)")) { tr(.id("roomRow_\(room.name)")) {
td { room.name } td { room.name }
td { td {
Number(room.heatingLoad, digits: 0) div(.class("flex justify-center")) {
.attributes(.class("text-error")) Number(room.heatingLoad, digits: 0)
.attributes(.class("text-error"))
}
} }
td { td {
Number(room.coolingTotal, digits: 0) div(.class("flex justify-center")) {
.attributes(.class("text-success")) Number(room.coolingTotal, digits: 0)
.attributes(.class("text-success"))
}
} }
td { td {
Number(coolingSensible, digits: 0) div(.class("flex justify-center")) {
.attributes(.class("text-info")) Number(coolingSensible, digits: 0)
.attributes(.class("text-info"))
}
} }
td { td {
Number(room.registerCount) div(.class("flex justify-center")) {
Number(room.registerCount)
}
} }
td { td {
div(.class("flex justify-end")) { div(.class("flex justify-end")) {