feat: Updates to home / landing page.
All checks were successful
CI / Linux Tests (push) Successful in 6m32s
All checks were successful
CI / Linux Tests (push) Successful in 6m32s
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
monospace;
|
monospace;
|
||||||
--color-amber-300: oklch(87.9% 0.169 91.605);
|
--color-amber-300: oklch(87.9% 0.169 91.605);
|
||||||
--color-green-400: oklch(79.2% 0.209 151.711);
|
--color-green-400: oklch(79.2% 0.209 151.711);
|
||||||
|
--color-sky-300: oklch(82.8% 0.111 230.318);
|
||||||
--color-sky-600: oklch(58.8% 0.158 241.966);
|
--color-sky-600: oklch(58.8% 0.158 241.966);
|
||||||
--color-violet-600: oklch(54.1% 0.281 293.009);
|
--color-violet-600: oklch(54.1% 0.281 293.009);
|
||||||
--color-gray-200: oklch(92.8% 0.006 264.531);
|
--color-gray-200: oklch(92.8% 0.006 264.531);
|
||||||
@@ -34,8 +35,6 @@
|
|||||||
--text-4xl--line-height: calc(2.5 / 2.25);
|
--text-4xl--line-height: calc(2.5 / 2.25);
|
||||||
--text-5xl: 3rem;
|
--text-5xl: 3rem;
|
||||||
--text-5xl--line-height: 1;
|
--text-5xl--line-height: 1;
|
||||||
--text-6xl: 3.75rem;
|
|
||||||
--text-6xl--line-height: 1;
|
|
||||||
--text-8xl: 6rem;
|
--text-8xl: 6rem;
|
||||||
--text-8xl--line-height: 1;
|
--text-8xl--line-height: 1;
|
||||||
--font-weight-bold: 700;
|
--font-weight-bold: 700;
|
||||||
@@ -4233,9 +4232,18 @@
|
|||||||
--toast-y: 0;
|
--toast-y: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.top-0 {
|
||||||
|
top: calc(var(--spacing) * 0);
|
||||||
|
}
|
||||||
.top-2 {
|
.top-2 {
|
||||||
top: calc(var(--spacing) * 2);
|
top: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
|
.top-10 {
|
||||||
|
top: calc(var(--spacing) * 10);
|
||||||
|
}
|
||||||
|
.top-20 {
|
||||||
|
top: calc(var(--spacing) * 20);
|
||||||
|
}
|
||||||
.right-2 {
|
.right-2 {
|
||||||
right: calc(var(--spacing) * 2);
|
right: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
@@ -4299,9 +4307,21 @@
|
|||||||
.bottom-0 {
|
.bottom-0 {
|
||||||
bottom: calc(var(--spacing) * 0);
|
bottom: calc(var(--spacing) * 0);
|
||||||
}
|
}
|
||||||
|
.-left-10 {
|
||||||
|
left: calc(var(--spacing) * -10);
|
||||||
|
}
|
||||||
|
.-left-15 {
|
||||||
|
left: calc(var(--spacing) * -15);
|
||||||
|
}
|
||||||
|
.-left-20 {
|
||||||
|
left: calc(var(--spacing) * -20);
|
||||||
|
}
|
||||||
.left-0 {
|
.left-0 {
|
||||||
left: calc(var(--spacing) * 0);
|
left: calc(var(--spacing) * 0);
|
||||||
}
|
}
|
||||||
|
.left-10 {
|
||||||
|
left: calc(var(--spacing) * 10);
|
||||||
|
}
|
||||||
.join {
|
.join {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
@@ -5243,6 +5263,9 @@
|
|||||||
.m-1 {
|
.m-1 {
|
||||||
margin: calc(var(--spacing) * 1);
|
margin: calc(var(--spacing) * 1);
|
||||||
}
|
}
|
||||||
|
.m-4 {
|
||||||
|
margin: calc(var(--spacing) * 4);
|
||||||
|
}
|
||||||
.m-6 {
|
.m-6 {
|
||||||
margin: calc(var(--spacing) * 6);
|
margin: calc(var(--spacing) * 6);
|
||||||
}
|
}
|
||||||
@@ -5291,6 +5314,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.mx-10 {
|
||||||
|
margin-inline: calc(var(--spacing) * 10);
|
||||||
|
}
|
||||||
|
.mx-20 {
|
||||||
|
margin-inline: calc(var(--spacing) * 20);
|
||||||
|
}
|
||||||
.mx-auto {
|
.mx-auto {
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
}
|
}
|
||||||
@@ -5380,18 +5409,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.-my-2 {
|
|
||||||
margin-block: calc(var(--spacing) * -2);
|
|
||||||
}
|
|
||||||
.my-1 {
|
.my-1 {
|
||||||
margin-block: calc(var(--spacing) * 1);
|
margin-block: calc(var(--spacing) * 1);
|
||||||
}
|
}
|
||||||
.my-1\.5 {
|
.my-1\.5 {
|
||||||
margin-block: calc(var(--spacing) * 1.5);
|
margin-block: calc(var(--spacing) * 1.5);
|
||||||
}
|
}
|
||||||
.my-2 {
|
|
||||||
margin-block: calc(var(--spacing) * 2);
|
|
||||||
}
|
|
||||||
.my-6 {
|
.my-6 {
|
||||||
margin-block: calc(var(--spacing) * 6);
|
margin-block: calc(var(--spacing) * 6);
|
||||||
}
|
}
|
||||||
@@ -5601,18 +5624,12 @@
|
|||||||
border-width: var(--border, 1px) 0 var(--border, 1px) var(--border, 1px);
|
border-width: var(--border, 1px) 0 var(--border, 1px) var(--border, 1px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.-ms-2 {
|
.ms-10 {
|
||||||
margin-inline-start: calc(var(--spacing) * -2);
|
margin-inline-start: calc(var(--spacing) * 10);
|
||||||
}
|
|
||||||
.ms-2 {
|
|
||||||
margin-inline-start: calc(var(--spacing) * 2);
|
|
||||||
}
|
}
|
||||||
.me-2 {
|
.me-2 {
|
||||||
margin-inline-end: calc(var(--spacing) * 2);
|
margin-inline-end: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
.me-3 {
|
|
||||||
margin-inline-end: calc(var(--spacing) * 3);
|
|
||||||
}
|
|
||||||
.me-4 {
|
.me-4 {
|
||||||
margin-inline-end: calc(var(--spacing) * 4);
|
margin-inline-end: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
@@ -5664,15 +5681,12 @@
|
|||||||
.-mt-2 {
|
.-mt-2 {
|
||||||
margin-top: calc(var(--spacing) * -2);
|
margin-top: calc(var(--spacing) * -2);
|
||||||
}
|
}
|
||||||
|
.mt-1 {
|
||||||
|
margin-top: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
.mt-2 {
|
.mt-2 {
|
||||||
margin-top: calc(var(--spacing) * 2);
|
margin-top: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
.mt-3 {
|
|
||||||
margin-top: calc(var(--spacing) * 3);
|
|
||||||
}
|
|
||||||
.mt-3\.5 {
|
|
||||||
margin-top: calc(var(--spacing) * 3.5);
|
|
||||||
}
|
|
||||||
.mt-4 {
|
.mt-4 {
|
||||||
margin-top: calc(var(--spacing) * 4);
|
margin-top: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
@@ -5682,9 +5696,15 @@
|
|||||||
.mt-8 {
|
.mt-8 {
|
||||||
margin-top: calc(var(--spacing) * 8);
|
margin-top: calc(var(--spacing) * 8);
|
||||||
}
|
}
|
||||||
|
.mt-10 {
|
||||||
|
margin-top: calc(var(--spacing) * 10);
|
||||||
|
}
|
||||||
.mt-20 {
|
.mt-20 {
|
||||||
margin-top: calc(var(--spacing) * 20);
|
margin-top: calc(var(--spacing) * 20);
|
||||||
}
|
}
|
||||||
|
.mt-60 {
|
||||||
|
margin-top: calc(var(--spacing) * 60);
|
||||||
|
}
|
||||||
.breadcrumbs {
|
.breadcrumbs {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
@@ -5761,12 +5781,6 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.mb-1 {
|
|
||||||
margin-bottom: calc(var(--spacing) * 1);
|
|
||||||
}
|
|
||||||
.mb-2 {
|
|
||||||
margin-bottom: calc(var(--spacing) * 2);
|
|
||||||
}
|
|
||||||
.mb-4 {
|
.mb-4 {
|
||||||
margin-bottom: calc(var(--spacing) * 4);
|
margin-bottom: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
@@ -6634,6 +6648,12 @@
|
|||||||
width: calc(var(--size-selector, 0.25rem) * 4);
|
width: calc(var(--size-selector, 0.25rem) * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.w-\[200px\] {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
.w-\[250px\] {
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
.w-\[330px\] {
|
.w-\[330px\] {
|
||||||
width: 330px;
|
width: 330px;
|
||||||
}
|
}
|
||||||
@@ -6643,12 +6663,6 @@
|
|||||||
.w-full {
|
.w-full {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.max-w-lg {
|
|
||||||
max-width: var(--container-lg);
|
|
||||||
}
|
|
||||||
.max-w-md {
|
|
||||||
max-width: var(--container-md);
|
|
||||||
}
|
|
||||||
.min-w-\[80\%\] {
|
.min-w-\[80\%\] {
|
||||||
min-width: 80%;
|
min-width: 80%;
|
||||||
}
|
}
|
||||||
@@ -6695,8 +6709,8 @@
|
|||||||
.-rotate-45 {
|
.-rotate-45 {
|
||||||
rotate: calc(45deg * -1);
|
rotate: calc(45deg * -1);
|
||||||
}
|
}
|
||||||
.rotate-90 {
|
.rotate-45 {
|
||||||
rotate: 90deg;
|
rotate: 45deg;
|
||||||
}
|
}
|
||||||
.rotate-180 {
|
.rotate-180 {
|
||||||
rotate: 180deg;
|
rotate: 180deg;
|
||||||
@@ -6794,6 +6808,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.list-disc {
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
.alert-horizontal {
|
.alert-horizontal {
|
||||||
@layer daisyui.l1.l2 {
|
@layer daisyui.l1.l2 {
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
@@ -6875,6 +6892,9 @@
|
|||||||
.flex-wrap {
|
.flex-wrap {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
.items-baseline {
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
.items-center {
|
.items-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@@ -6967,6 +6987,9 @@
|
|||||||
.overflow-auto {
|
.overflow-auto {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
.overflow-hidden {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
.timeline-box {
|
.timeline-box {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
border: var(--border) solid;
|
border: var(--border) solid;
|
||||||
@@ -7079,9 +7102,6 @@
|
|||||||
.rounded-sm {
|
.rounded-sm {
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
}
|
}
|
||||||
.rounded-xl {
|
|
||||||
border-radius: var(--radius-xl);
|
|
||||||
}
|
|
||||||
.rounded-t-box {
|
.rounded-t-box {
|
||||||
border-top-left-radius: var(--radius-box);
|
border-top-left-radius: var(--radius-box);
|
||||||
border-top-right-radius: var(--radius-box);
|
border-top-right-radius: var(--radius-box);
|
||||||
@@ -7258,10 +7278,18 @@
|
|||||||
border-style: var(--tw-border-style);
|
border-style: var(--tw-border-style);
|
||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
}
|
}
|
||||||
|
.border-3 {
|
||||||
|
border-style: var(--tw-border-style);
|
||||||
|
border-width: 3px;
|
||||||
|
}
|
||||||
.border-b-1 {
|
.border-b-1 {
|
||||||
border-bottom-style: var(--tw-border-style);
|
border-bottom-style: var(--tw-border-style);
|
||||||
border-bottom-width: 1px;
|
border-bottom-width: 1px;
|
||||||
}
|
}
|
||||||
|
.border-b-6 {
|
||||||
|
border-bottom-style: var(--tw-border-style);
|
||||||
|
border-bottom-width: 6px;
|
||||||
|
}
|
||||||
.border-b-8 {
|
.border-b-8 {
|
||||||
border-bottom-style: var(--tw-border-style);
|
border-bottom-style: var(--tw-border-style);
|
||||||
border-bottom-width: 8px;
|
border-bottom-width: 8px;
|
||||||
@@ -7375,8 +7403,8 @@
|
|||||||
border-color: currentColor;
|
border-color: currentColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.border-amber-300 {
|
.border-accent {
|
||||||
border-color: var(--color-amber-300);
|
border-color: var(--color-accent);
|
||||||
}
|
}
|
||||||
.border-error {
|
.border-error {
|
||||||
border-color: var(--color-error);
|
border-color: var(--color-error);
|
||||||
@@ -7387,6 +7415,9 @@
|
|||||||
.border-primary {
|
.border-primary {
|
||||||
border-color: var(--color-primary);
|
border-color: var(--color-primary);
|
||||||
}
|
}
|
||||||
|
.border-secondary {
|
||||||
|
border-color: var(--color-secondary);
|
||||||
|
}
|
||||||
.border-sky-600 {
|
.border-sky-600 {
|
||||||
border-color: var(--color-sky-600);
|
border-color: var(--color-sky-600);
|
||||||
}
|
}
|
||||||
@@ -7550,6 +7581,9 @@
|
|||||||
.bg-error {
|
.bg-error {
|
||||||
background-color: var(--color-error);
|
background-color: var(--color-error);
|
||||||
}
|
}
|
||||||
|
.bg-primary {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
}
|
||||||
.bg-secondary {
|
.bg-secondary {
|
||||||
background-color: var(--color-secondary);
|
background-color: var(--color-secondary);
|
||||||
}
|
}
|
||||||
@@ -7765,6 +7799,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.mask-contain {
|
||||||
|
mask-size: contain;
|
||||||
|
}
|
||||||
|
.mask-clip-border {
|
||||||
|
mask-clip: border-box;
|
||||||
|
}
|
||||||
|
.mask-clip-content {
|
||||||
|
mask-clip: content-box;
|
||||||
|
}
|
||||||
.mask-repeat {
|
.mask-repeat {
|
||||||
mask-repeat: repeat;
|
mask-repeat: repeat;
|
||||||
}
|
}
|
||||||
@@ -7967,6 +8010,9 @@
|
|||||||
.px-4 {
|
.px-4 {
|
||||||
padding-inline: calc(var(--spacing) * 4);
|
padding-inline: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
|
.px-6 {
|
||||||
|
padding-inline: calc(var(--spacing) * 6);
|
||||||
|
}
|
||||||
.py-2 {
|
.py-2 {
|
||||||
padding-block: calc(var(--spacing) * 2);
|
padding-block: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
@@ -8629,6 +8675,9 @@
|
|||||||
color: var(--color-warning);
|
color: var(--color-warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.text-accent {
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
.text-base-content {
|
.text-base-content {
|
||||||
color: var(--color-base-content);
|
color: var(--color-base-content);
|
||||||
}
|
}
|
||||||
@@ -8644,12 +8693,15 @@
|
|||||||
.text-info {
|
.text-info {
|
||||||
color: var(--color-info);
|
color: var(--color-info);
|
||||||
}
|
}
|
||||||
|
.text-primary {
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
.text-secondary {
|
||||||
|
color: var(--color-secondary);
|
||||||
|
}
|
||||||
.text-success {
|
.text-success {
|
||||||
color: var(--color-success);
|
color: var(--color-success);
|
||||||
}
|
}
|
||||||
.text-violet-600 {
|
|
||||||
color: var(--color-violet-600);
|
|
||||||
}
|
|
||||||
.lowercase {
|
.lowercase {
|
||||||
text-transform: lowercase;
|
text-transform: lowercase;
|
||||||
}
|
}
|
||||||
@@ -8726,10 +8778,6 @@
|
|||||||
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||||
}
|
}
|
||||||
.shadow-xl {
|
|
||||||
--tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
||||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
||||||
}
|
|
||||||
.outline {
|
.outline {
|
||||||
outline-style: var(--tw-outline-style);
|
outline-style: var(--tw-outline-style);
|
||||||
outline-width: 1px;
|
outline-width: 1px;
|
||||||
|
|||||||
Binary file not shown.
@@ -1,50 +1,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
|
|
||||||
extension Room {
|
|
||||||
|
|
||||||
public var heatingLoadPerRegister: Double {
|
|
||||||
heatingLoad / Double(registerCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func coolingSensiblePerRegister(projectSHR: Double) throws -> Double {
|
|
||||||
let sensible = try coolingLoad.ensured(shr: projectSHR).sensible
|
|
||||||
return sensible / Double(registerCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension 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(actualRegisterCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func totalCoolingSensible(projectSHR: Double) throws -> Double {
|
|
||||||
try room.coolingSensiblePerRegister(projectSHR: projectSHR) * Double(actualRegisterCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TrunkSize {
|
|
||||||
|
|
||||||
var totalHeatingLoad: Double {
|
|
||||||
rooms.reduce(into: 0) { $0 += $1.totalHeatingLoad }
|
|
||||||
}
|
|
||||||
|
|
||||||
func totalCoolingSensible(projectSHR: Double) throws -> Double {
|
|
||||||
try rooms.reduce(into: 0) { $0 += try $1.totalCoolingSensible(projectSHR: projectSHR) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Array where Element == EffectiveLengthGroup {
|
extension Array where Element == EffectiveLengthGroup {
|
||||||
var totalEffectiveLength: Int {
|
var totalEffectiveLength: Int {
|
||||||
reduce(0) { $0 + $1.effectiveLength }
|
reduce(0) { $0 + $1.effectiveLength }
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ extension ManualDClient {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIX: Need to add the loads for rooms that get delegated to other rooms here.
|
||||||
func calculateRoomSizes(
|
func calculateRoomSizes(
|
||||||
rooms: [Room],
|
rooms: [Room],
|
||||||
sharedRequest: DuctSizeSharedRequest,
|
sharedRequest: DuctSizeSharedRequest,
|
||||||
@@ -42,10 +43,15 @@ extension ManualDClient {
|
|||||||
var retval: [DuctSizes.RoomContainer] = []
|
var retval: [DuctSizes.RoomContainer] = []
|
||||||
let totalHeatingLoad = rooms.totalHeatingLoad
|
let totalHeatingLoad = rooms.totalHeatingLoad
|
||||||
let totalCoolingSensible = try rooms.totalCoolingSensible(shr: sharedRequest.projectSHR)
|
let totalCoolingSensible = try rooms.totalCoolingSensible(shr: sharedRequest.projectSHR)
|
||||||
|
let nonDelegatedRooms = rooms.filter { $0.delegatedTo == nil }
|
||||||
|
|
||||||
for room in rooms {
|
for room in nonDelegatedRooms {
|
||||||
let heatingLoad = room.heatingLoadPerRegister
|
// Get all the rooms that delegate their loads to this room.
|
||||||
|
let delegatedRooms = rooms.filter { $0.delegatedTo == room.id }
|
||||||
|
|
||||||
|
let heatingLoad = room.heatingLoadPerRegister(delegatedRooms: delegatedRooms)
|
||||||
let coolingLoad = try room.coolingSensiblePerRegister(projectSHR: sharedRequest.projectSHR)
|
let coolingLoad = try room.coolingSensiblePerRegister(projectSHR: sharedRequest.projectSHR)
|
||||||
|
|
||||||
let heatingPercent = heatingLoad / totalHeatingLoad
|
let heatingPercent = heatingLoad / totalHeatingLoad
|
||||||
let coolingPercent = coolingLoad / totalCoolingSensible
|
let coolingPercent = coolingLoad / totalCoolingSensible
|
||||||
let heatingCFM = heatingPercent * Double(sharedRequest.equipmentInfo.heatingCFM)
|
let heatingCFM = heatingPercent * Double(sharedRequest.equipmentInfo.heatingCFM)
|
||||||
@@ -181,47 +187,34 @@ extension DuctSizes.SizeContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// extension Room {
|
// extension TrunkSize.RoomProxy {
|
||||||
//
|
//
|
||||||
// var heatingLoadPerRegister: Double {
|
// // We need to make sure if registers got removed after a trunk
|
||||||
//
|
// // was already made / saved that we do not include registers that
|
||||||
// heatingLoad / Double(registerCount)
|
// // no longer exist.
|
||||||
|
// private var actualRegisterCount: Int {
|
||||||
|
// guard registers.count <= room.registerCount else {
|
||||||
|
// return room.registerCount
|
||||||
|
// }
|
||||||
|
// return registers.count
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// func coolingSensiblePerRegister(projectSHR: Double) -> Double {
|
// var totalHeatingLoad: Double {
|
||||||
// let sensible = coolingSensible ?? (coolingTotal * projectSHR)
|
// room.heatingLoadPerRegister() * Double(actualRegisterCount)
|
||||||
// return sensible / Double(registerCount)
|
// }
|
||||||
|
//
|
||||||
|
// func totalCoolingSensible(projectSHR: Double) throws -> Double {
|
||||||
|
// try room.coolingSensiblePerRegister(projectSHR: projectSHR) * Double(actualRegisterCount)
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
extension TrunkSize.RoomProxy {
|
// extension TrunkSize {
|
||||||
|
//
|
||||||
// We need to make sure if registers got removed after a trunk
|
// var totalHeatingLoad: Double {
|
||||||
// was already made / saved that we do not include registers that
|
// rooms.reduce(into: 0) { $0 += $1.totalHeatingLoad }
|
||||||
// no longer exist.
|
// }
|
||||||
private var actualRegisterCount: Int {
|
//
|
||||||
guard registers.count <= room.registerCount else {
|
// func totalCoolingSensible(projectSHR: Double) throws -> Double {
|
||||||
return room.registerCount
|
// try rooms.reduce(into: 0) { $0 += try $1.totalCoolingSensible(projectSHR: projectSHR) }
|
||||||
}
|
// }
|
||||||
return registers.count
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
var totalHeatingLoad: Double {
|
|
||||||
room.heatingLoadPerRegister * Double(actualRegisterCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func totalCoolingSensible(projectSHR: Double) throws -> Double {
|
|
||||||
try room.coolingSensiblePerRegister(projectSHR: projectSHR) * Double(actualRegisterCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TrunkSize {
|
|
||||||
|
|
||||||
var totalHeatingLoad: Double {
|
|
||||||
rooms.reduce(into: 0) { $0 += $1.totalHeatingLoad }
|
|
||||||
}
|
|
||||||
|
|
||||||
func totalCoolingSensible(projectSHR: Double) throws -> Double {
|
|
||||||
try rooms.reduce(into: 0) { $0 += try $1.totalCoolingSensible(projectSHR: projectSHR) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
20
Sources/ProjectClient/Internal/Room+loadPerRegister.swift
Normal file
20
Sources/ProjectClient/Internal/Room+loadPerRegister.swift
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import Foundation
|
||||||
|
import ManualDCore
|
||||||
|
|
||||||
|
extension Room {
|
||||||
|
|
||||||
|
public func heatingLoadPerRegister(delegatedRooms: [Room]? = nil) -> Double {
|
||||||
|
(heatingLoad + (delegatedRooms?.totalHeatingLoad ?? 0)) / Double(registerCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func coolingSensiblePerRegister(
|
||||||
|
projectSHR: Double,
|
||||||
|
delegatedRooms: [Room]? = nil
|
||||||
|
) throws -> Double {
|
||||||
|
let sensible =
|
||||||
|
try coolingLoad.ensured(shr: projectSHR).sensible
|
||||||
|
+ (delegatedRooms?.totalCoolingSensible(shr: projectSHR) ?? 0)
|
||||||
|
|
||||||
|
return sensible / Double(registerCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Sources/ProjectClient/Internal/TrunkSize+loads.swift
Normal file
34
Sources/ProjectClient/Internal/TrunkSize+loads.swift
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import Foundation
|
||||||
|
import ManualDCore
|
||||||
|
|
||||||
|
extension 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
|
||||||
|
}
|
||||||
|
|
||||||
|
public var totalHeatingLoad: Double {
|
||||||
|
room.heatingLoadPerRegister() * Double(actualRegisterCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func totalCoolingSensible(projectSHR: Double) throws -> Double {
|
||||||
|
try room.coolingSensiblePerRegister(projectSHR: projectSHR) * Double(actualRegisterCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TrunkSize {
|
||||||
|
|
||||||
|
public var totalHeatingLoad: Double {
|
||||||
|
rooms.reduce(into: 0) { $0 += $1.totalHeatingLoad }
|
||||||
|
}
|
||||||
|
|
||||||
|
public func totalCoolingSensible(projectSHR: Double) throws -> Double {
|
||||||
|
try rooms.reduce(into: 0) { $0 += try $1.totalCoolingSensible(projectSHR: projectSHR) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,12 @@ import ElementaryHTMX
|
|||||||
struct HomeView: HTML, Sendable {
|
struct HomeView: HTML, Sendable {
|
||||||
|
|
||||||
var body: some HTML {
|
var body: some HTML {
|
||||||
div(.class("flex justify-end me-4")) {
|
div( // Uncomment to test different theme's.
|
||||||
|
// .data("theme", value: "cyberpunk")
|
||||||
|
// NOTE: Footer background color will follow system theme, it will actually be the
|
||||||
|
// same as the `hero` background in reality.
|
||||||
|
) {
|
||||||
|
div(.class("flex justify-end m-4")) {
|
||||||
button(
|
button(
|
||||||
.class("btn btn-ghost btn-secondary text-lg"),
|
.class("btn btn-ghost btn-secondary text-lg"),
|
||||||
.hx.get(route: .login(.index())),
|
.hx.get(route: .login(.index())),
|
||||||
@@ -14,31 +19,42 @@ struct HomeView: HTML, Sendable {
|
|||||||
"Login"
|
"Login"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div(.class("hero min-h-screen")) {
|
div(.class("hero")) {
|
||||||
div(
|
div(
|
||||||
.class(
|
.class(
|
||||||
"""
|
"""
|
||||||
hero-content text-center bg-base-200 dark:bg-base-300
|
relative hero-content text-center bg-base-300
|
||||||
min-w-[80%] min-h-[400px] rounded-3xl shadow-3xl
|
w-full min-h-[400px] rounded-3xl shadow-3xl overflow-hidden
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
div(
|
||||||
|
.class(
|
||||||
|
"""
|
||||||
|
bg-secondary text-xl font-bold
|
||||||
|
absolute top-10 -left-15
|
||||||
|
px-6 py-2 w-[250px] -rotate-45
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
"BETA"
|
||||||
|
}
|
||||||
div {
|
div {
|
||||||
header
|
header
|
||||||
a(
|
a(
|
||||||
.class("btn btn-ghost text-md italic"),
|
.class("btn btn-ghost text-md text-primary font-bold italic"),
|
||||||
.href("https://git.housh.dev/michael/swift-manual-d"),
|
.href("https://git.housh.dev/michael/swift-manual-d"),
|
||||||
.target(.blank)
|
.target(.blank)
|
||||||
) {
|
) {
|
||||||
"Open source residential duct design program"
|
"Open source residential duct design program"
|
||||||
}
|
}
|
||||||
p(.class("text-xl py-6")) {
|
p(.class("text-3xl py-6")) {
|
||||||
"""
|
"""
|
||||||
Manual-D™ speed sheet, but on the web!
|
Manual-D™ speed sheet, but on the web!
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
button(
|
button(
|
||||||
.class("btn btn-xl bg-violet-600 mt-6"),
|
.class("btn btn-xl btn-primary mt-6"),
|
||||||
.hx.get(route: .signup(.index)),
|
.hx.get(route: .signup(.index)),
|
||||||
.hx.target("body"),
|
.hx.target("body"),
|
||||||
.hx.swap(.outerHTML)
|
.hx.swap(.outerHTML)
|
||||||
@@ -55,6 +71,50 @@ struct HomeView: HTML, Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div(.class("grid grid-cols-1 md:grid-cols-2 gap-4 mx-20 my-6")) {
|
||||||
|
div(.class("border-3 border-accent rounded-lg shadow-lg p-4")) {
|
||||||
|
div(.class("flex items-center space-x-4")) {
|
||||||
|
div(.class("text-5xl text-primary font-bold")) {
|
||||||
|
"Features"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div(.class("text-xl ms-10 mt-10")) {
|
||||||
|
ul(.class("list-disc")) {
|
||||||
|
li {
|
||||||
|
div(
|
||||||
|
.class("font-bold italic bg-secondary rounded-lg shadow-lg px-4 w-fit")
|
||||||
|
) {
|
||||||
|
"Built by humans"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
li { "Fully open source." }
|
||||||
|
li { "Great replacement for speed sheet users." }
|
||||||
|
li { "Great for classrooms." }
|
||||||
|
li { "Store your projects in one place." }
|
||||||
|
li { "Export final project to pdf." }
|
||||||
|
li { "Import room loads via CSV file." }
|
||||||
|
li { "Web based." }
|
||||||
|
li { "Self host (run on your own infrastructure)." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div(.class("border-3 border-accent rounded-lg shadow-lg p-4")) {
|
||||||
|
div(.class("text-5xl text-primary font-bold")) {
|
||||||
|
"Coming Soon"
|
||||||
|
}
|
||||||
|
div(.class("text-xl ms-10 mt-10")) {
|
||||||
|
ul(.class("list-disc")) {
|
||||||
|
li { "API integration." }
|
||||||
|
li { "Command line interface." }
|
||||||
|
li { "Fitting selection tool." }
|
||||||
|
li { "Room load import from PDF." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var header: some HTML<HTMLTag.div> {
|
var header: some HTML<HTMLTag.div> {
|
||||||
@@ -62,7 +122,7 @@ struct HomeView: HTML, Sendable {
|
|||||||
div(
|
div(
|
||||||
.class(
|
.class(
|
||||||
"""
|
"""
|
||||||
flex border-b-8 border-sky-600
|
flex border-b-6 border-accent
|
||||||
text-8xl font-bold my-auto space-2
|
text-8xl font-bold my-auto space-2
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
@@ -72,7 +132,7 @@ struct HomeView: HTML, Sendable {
|
|||||||
span(
|
span(
|
||||||
.class(
|
.class(
|
||||||
"""
|
"""
|
||||||
bg-violet-600 rounded-md
|
bg-secondary rounded-md
|
||||||
text-5xl rotate-180 p-2
|
text-5xl rotate-180 p-2
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Name,Heating Load,Cooling Total,Cooling Sensible,Register Count,Delegated To
|
Name,Heating Load,Cooling Total,Cooling Sensible,Register Count,Delegated To
|
||||||
Bed-1,12345,1234,1321,1,
|
Bed-1,2345,1234,1321,1,
|
||||||
Entry,3456,2345,1234,1,
|
Entry,3456,2345,1234,1,
|
||||||
Kitchen,7654,3456,2453,2,
|
Kitchen,7654,3456,2453,2,
|
||||||
Bath-1,890,345,,1,Kitchen
|
Bath-1,890,345,,0,Kitchen
|
||||||
|
|||||||
|
@@ -77,16 +77,13 @@ struct RoomTests {
|
|||||||
let csvPath = Bundle.module.path(forResource: "rooms", ofType: "csv")
|
let csvPath = Bundle.module.path(forResource: "rooms", ofType: "csv")
|
||||||
let csvFile = Room.CSV(file: try Data(contentsOf: URL(filePath: csvPath!)))
|
let csvFile = Room.CSV(file: try Data(contentsOf: URL(filePath: csvPath!)))
|
||||||
let rows = try await csvParser.parseRooms(csvFile)
|
let rows = try await csvParser.parseRooms(csvFile)
|
||||||
print()
|
|
||||||
print("ROWS: \(rows)")
|
|
||||||
print()
|
|
||||||
|
|
||||||
let created = try await database.rooms.createFromCSV(project.id, rows)
|
let created = try await database.rooms.createFromCSV(project.id, rows)
|
||||||
|
|
||||||
print()
|
|
||||||
print("CREATED: \(created)")
|
|
||||||
print()
|
|
||||||
#expect(created.count == rows.count)
|
#expect(created.count == rows.count)
|
||||||
|
|
||||||
|
// Check that delegating to another room works properly.
|
||||||
|
let bath = created.first(where: { $0.name == "Bath-1" })!
|
||||||
|
let kitchen = created.first(where: { $0.name == "Kitchen" })!
|
||||||
|
#expect(bath.delegatedTo == kitchen.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,26 +30,30 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="flex flex-col min-h-screen min-w-full justify-between">
|
<div class="flex flex-col min-h-screen min-w-full justify-between">
|
||||||
<main class="flex flex-col min-h-screen min-w-full grow mb-auto">
|
<main class="flex flex-col min-h-screen min-w-full grow mb-auto">
|
||||||
<div class="flex justify-end me-4">
|
<div>
|
||||||
|
<div class="flex justify-end m-4">
|
||||||
<button class="btn btn-ghost btn-secondary text-lg" hx-get="/login" hx-target="body" hx-swap="outerHTML">Login</button>
|
<button class="btn btn-ghost btn-secondary text-lg" hx-get="/login" hx-target="body" hx-swap="outerHTML">Login</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="hero min-h-screen">
|
<div class="hero">
|
||||||
<div class="hero-content text-center bg-base-200 dark:bg-base-300
|
<div class="relative hero-content text-center bg-base-300
|
||||||
min-w-[80%] min-h-[400px] rounded-3xl shadow-3xl">
|
w-full min-h-[400px] rounded-3xl shadow-3xl overflow-hidden">
|
||||||
|
<div class="bg-secondary text-xl font-bold
|
||||||
|
absolute top-10 -left-15
|
||||||
|
px-6 py-2 w-[250px] -rotate-45">BETA</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-center items-center">
|
<div class="flex justify-center items-center">
|
||||||
<div class="flex border-b-8 border-sky-600
|
<div class="flex border-b-6 border-accent
|
||||||
text-8xl font-bold my-auto space-2">
|
text-8xl font-bold my-auto space-2">
|
||||||
<h1 class="me-2">Duct Calc</h1>
|
<h1 class="me-2">Duct Calc</h1>
|
||||||
<div class="">
|
<div class="">
|
||||||
<span class="bg-violet-600 rounded-md
|
<span class="bg-secondary rounded-md
|
||||||
text-5xl rotate-180 p-2" style="writing-mode: vertical-rl">Pro</span>
|
text-5xl rotate-180 p-2" style="writing-mode: vertical-rl">Pro</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Open source residential duct design program<a class="btn btn-ghost text-md italic" href="https://git.housh.dev/michael/swift-manual-d" target="_blank"></a>
|
Open source residential duct design program<a class="btn btn-ghost text-md text-primary font-bold italic" href="https://git.housh.dev/michael/swift-manual-d" target="_blank"></a>
|
||||||
<p class="text-xl py-6">Manual-D™ speed sheet, but on the web!</p>
|
<p class="text-3xl py-6">Manual-D™ speed sheet, but on the web!</p>
|
||||||
<button class="btn btn-xl bg-violet-600 mt-6" hx-get="/signup" hx-target="body" hx-swap="outerHTML">Get Started</button>
|
<button class="btn btn-xl btn-primary mt-6" hx-get="/signup" hx-target="body" hx-swap="outerHTML">Get Started</button>
|
||||||
<p class="text-xs italic mt-8">
|
<p class="text-xs italic mt-8">
|
||||||
Manual-D™ is a trademark of Air Conditioning Contractors of America (ACCA).
|
Manual-D™ is a trademark of Air Conditioning Contractors of America (ACCA).
|
||||||
|
|
||||||
@@ -58,6 +62,40 @@ text-8xl font-bold my-auto space-2">
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mx-20 my-6">
|
||||||
|
<div class="border-3 border-accent rounded-lg shadow-lg p-4">
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<div class="text-5xl text-primary font-bold">Features</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-xl ms-10 mt-10">
|
||||||
|
<ul class="list-disc">
|
||||||
|
<li>
|
||||||
|
<div class="font-bold italic bg-secondary rounded-lg shadow-lg px-4 w-fit">Built by humans</div>
|
||||||
|
</li>
|
||||||
|
<li>Fully open source.</li>
|
||||||
|
<li>Great replacement for speed sheet users.</li>
|
||||||
|
<li>Great for classrooms.</li>
|
||||||
|
<li>Store your projects in one place.</li>
|
||||||
|
<li>Export final project to pdf.</li>
|
||||||
|
<li>Import room loads via CSV file.</li>
|
||||||
|
<li>Web based.</li>
|
||||||
|
<li>Self host (run on your own infrastructure).</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-3 border-accent rounded-lg shadow-lg p-4">
|
||||||
|
<div class="text-5xl text-primary font-bold">Coming Soon</div>
|
||||||
|
<div class="text-xl ms-10 mt-10">
|
||||||
|
<ul class="list-disc">
|
||||||
|
<li>API integration.</li>
|
||||||
|
<li>Command line interface.</li>
|
||||||
|
<li>Fitting selection tool.</li>
|
||||||
|
<li>Room load import from PDF.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<div class="bottom-0 left-0 bg-error">
|
<div class="bottom-0 left-0 bg-error">
|
||||||
<footer class="footer sm:footer-horizontal footer-center
|
<footer class="footer sm:footer-horizontal footer-center
|
||||||
|
|||||||
Reference in New Issue
Block a user