WIP: Begins effective length views.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import Dependencies
|
||||
import Foundation
|
||||
|
||||
// TODO: Not sure how to model effective length groups in the database.
|
||||
@@ -85,3 +86,40 @@ extension EffectiveLength {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
extension EffectiveLength {
|
||||
public static let mocks: [Self] = [
|
||||
.init(
|
||||
id: UUID(0),
|
||||
projectID: UUID(0),
|
||||
name: "Test Supply - 1",
|
||||
type: .supply,
|
||||
straightLengths: [10, 20, 25],
|
||||
groups: [
|
||||
.init(group: 1, letter: "a", value: 20),
|
||||
.init(group: 2, letter: "b", value: 15, quantity: 2),
|
||||
.init(group: 3, letter: "c", value: 10, quantity: 1),
|
||||
],
|
||||
createdAt: Date(),
|
||||
updatedAt: Date()
|
||||
),
|
||||
.init(
|
||||
id: UUID(1),
|
||||
projectID: UUID(0),
|
||||
name: "Test Return - 1",
|
||||
type: .return,
|
||||
straightLengths: [10, 20, 25],
|
||||
groups: [
|
||||
.init(group: 1, letter: "a", value: 20),
|
||||
.init(group: 2, letter: "b", value: 15, quantity: 2),
|
||||
.init(group: 3, letter: "c", value: 10, quantity: 1),
|
||||
],
|
||||
createdAt: Date(),
|
||||
updatedAt: Date()
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,7 @@ extension SiteRoute {
|
||||
case project(ProjectRoute)
|
||||
case room(RoomRoute)
|
||||
case frictionRate(FrictionRateRoute)
|
||||
case effectiveLength(EffectiveLengthRoute)
|
||||
|
||||
public static let router = OneOf {
|
||||
Route(.case(Self.project)) {
|
||||
@@ -21,6 +22,9 @@ extension SiteRoute {
|
||||
Route(.case(Self.frictionRate)) {
|
||||
SiteRoute.View.FrictionRateRoute.router
|
||||
}
|
||||
Route(.case(Self.effectiveLength)) {
|
||||
SiteRoute.View.EffectiveLengthRoute.router
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,3 +129,29 @@ extension SiteRoute.View.FrictionRateRoute {
|
||||
case componentPressureLoss
|
||||
}
|
||||
}
|
||||
|
||||
extension SiteRoute.View {
|
||||
public enum EffectiveLengthRoute: Equatable, Sendable {
|
||||
case form(dismiss: Bool = false)
|
||||
case index
|
||||
|
||||
static let rootPath = "effective-lengths"
|
||||
|
||||
public static let router = OneOf {
|
||||
Route(.case(Self.index)) {
|
||||
Path { rootPath }
|
||||
Method.get
|
||||
}
|
||||
Route(.case(Self.form(dismiss:))) {
|
||||
Path {
|
||||
rootPath
|
||||
"create"
|
||||
}
|
||||
Method.get
|
||||
Query {
|
||||
Field("dismiss", default: false) { Bool.parser() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ extension ViewController.Request {
|
||||
return try await route.renderView(isHtmxRequest: isHtmxRequest)
|
||||
case .frictionRate(let route):
|
||||
return try await route.renderView(isHtmxRequest: isHtmxRequest)
|
||||
case .effectiveLength(let route):
|
||||
return try await route.renderView(isHtmxRequest: isHtmxRequest)
|
||||
default:
|
||||
// FIX: FIX
|
||||
return mainPage
|
||||
@@ -86,6 +88,23 @@ extension SiteRoute.View.FrictionRateRoute.FormType {
|
||||
}
|
||||
}
|
||||
|
||||
extension SiteRoute.View.EffectiveLengthRoute {
|
||||
|
||||
func renderView(isHtmxRequest: Bool) async throws -> AnySendableHTML {
|
||||
switch self {
|
||||
case .index:
|
||||
return MainPage {
|
||||
EffectiveLengthsView(effectiveLengths: EffectiveLength.mocks)
|
||||
}
|
||||
case .form(let dismiss):
|
||||
guard !dismiss else {
|
||||
return div(.id("effectiveLengthForm")) {}
|
||||
}
|
||||
return EffectiveLengthForm()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let mainPage: AnySendableHTML = {
|
||||
MainPage {
|
||||
div {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import Elementary
|
||||
import ElementaryHTMX
|
||||
import ManualDCore
|
||||
import Styleguide
|
||||
|
||||
struct EffectiveLengthForm: HTML, Sendable {
|
||||
|
||||
var body: some HTML {
|
||||
div(
|
||||
.id("effectiveLengthForm"),
|
||||
.class(
|
||||
"""
|
||||
fixed top-40 left-[25vw] w-1/2 z-50 text-gray-800
|
||||
bg-gray-200 border border-gray-400
|
||||
rounded-lg shadow-lg mx-10
|
||||
"""
|
||||
)
|
||||
) {
|
||||
h1(.class("text-2xl font-bold")) { "Effective Length" }
|
||||
form(.class("space-y-4 p-4")) {
|
||||
// FIX: Add fields
|
||||
|
||||
Row {
|
||||
div {}
|
||||
div {
|
||||
CancelButton()
|
||||
.attributes(
|
||||
.hx.get(route: .effectiveLength(.form(dismiss: true))),
|
||||
.hx.target("#effectiveLengthForm"),
|
||||
.hx.swap(.outerHTML)
|
||||
)
|
||||
SubmitButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import Elementary
|
||||
import ElementaryHTMX
|
||||
import ManualDCore
|
||||
import Styleguide
|
||||
|
||||
struct EffectiveLengthsView: HTML, Sendable {
|
||||
|
||||
let effectiveLengths: [EffectiveLength]
|
||||
|
||||
var body: some HTML {
|
||||
div(
|
||||
.class(
|
||||
"""
|
||||
m-4
|
||||
"""
|
||||
)
|
||||
) {
|
||||
Row {
|
||||
h1(.class("text-2xl font-bold")) { "Effective Lengths" }
|
||||
button(
|
||||
.hx.get(route: .effectiveLength(.form(dismiss: false))),
|
||||
.hx.target("#effectiveLengthForm"),
|
||||
.hx.swap(.outerHTML)
|
||||
) {
|
||||
Icon(.circlePlus)
|
||||
}
|
||||
}
|
||||
.attributes(.class("pb-6"))
|
||||
|
||||
div(
|
||||
.id("effectiveLengths"),
|
||||
.class(
|
||||
"""
|
||||
border border-gray-200 rounded-lg shadow-lg
|
||||
"""
|
||||
)
|
||||
) {
|
||||
for row in effectiveLengths {
|
||||
EffectiveLengthView(effectiveLength: row)
|
||||
}
|
||||
}
|
||||
|
||||
div(.id("effectiveLengthForm")) {}
|
||||
}
|
||||
}
|
||||
|
||||
private struct EffectiveLengthView: HTML, Sendable {
|
||||
|
||||
let effectiveLength: EffectiveLength
|
||||
|
||||
var straightLengthsTotal: Int {
|
||||
effectiveLength.straightLengths
|
||||
.reduce(into: 0) { $0 += $1 }
|
||||
}
|
||||
|
||||
var groupsTotal: Double {
|
||||
effectiveLength.groups.reduce(into: 0) {
|
||||
$0 += ($1.value * Double($1.quantity))
|
||||
}
|
||||
}
|
||||
|
||||
var body: some HTML<HTMLTag.div> {
|
||||
div(
|
||||
.class(
|
||||
"""
|
||||
pb-6
|
||||
"""
|
||||
)
|
||||
) {
|
||||
Row {
|
||||
span(.class("text-xl font-bold")) { effectiveLength.name }
|
||||
}
|
||||
Row {
|
||||
Label("Straight Lengths")
|
||||
}
|
||||
for length in effectiveLength.straightLengths {
|
||||
Row {
|
||||
div {}
|
||||
Number(length)
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Label("Groups")
|
||||
Label("Equivalent Length")
|
||||
Label("Quantity")
|
||||
}
|
||||
.attributes(.class("border-b border-gray-200"))
|
||||
|
||||
for group in effectiveLength.groups {
|
||||
Row {
|
||||
span { "\(group.group)-\(group.letter)" }
|
||||
Number(group.value)
|
||||
Number(group.quantity)
|
||||
}
|
||||
}
|
||||
Row {
|
||||
Label("Total")
|
||||
Number(Double(straightLengthsTotal) + groupsTotal, digits: 0)
|
||||
.attributes(.class("text-xl font-bold"))
|
||||
}
|
||||
.attributes(.class("border border-gray-200"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,13 +16,14 @@ struct Sidebar: HTML {
|
||||
) {
|
||||
row(title: "Project", icon: .mapPin, href: "/projects")
|
||||
row(title: "Rooms", icon: .doorClosed, href: "/rooms")
|
||||
row(title: "Equivalent Lengths", icon: .rulerDimensionLine, href: "#")
|
||||
row(title: "Equivalent Lengths", icon: .rulerDimensionLine, href: "/effective-lengths")
|
||||
row(title: "Friction Rate", icon: .squareFunction, href: "/friction-rate")
|
||||
.attributes(.data("active", value: "true"))
|
||||
row(title: "Duct Sizes", icon: .wind, href: "#")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use SiteRoute.View routes as href.
|
||||
private func row(
|
||||
title: String,
|
||||
icon: Icon.Key,
|
||||
|
||||
Reference in New Issue
Block a user