WIP: Adds a modal form view and integrates into current forms.
This commit is contained in:
37
Sources/Styleguide/ModalForm.swift
Normal file
37
Sources/Styleguide/ModalForm.swift
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import Elementary
|
||||||
|
|
||||||
|
public struct ModalForm<T: HTML>: HTML, Sendable where T: Sendable {
|
||||||
|
|
||||||
|
let dismiss: Bool
|
||||||
|
let id: String
|
||||||
|
let inner: T
|
||||||
|
|
||||||
|
public init(
|
||||||
|
id: String,
|
||||||
|
dismiss: Bool,
|
||||||
|
@HTMLBuilder inner: () -> T
|
||||||
|
) {
|
||||||
|
self.dismiss = dismiss
|
||||||
|
self.id = id
|
||||||
|
self.inner = inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
public var body: some HTML {
|
||||||
|
if dismiss {
|
||||||
|
div(.id(id)) {}
|
||||||
|
} else {
|
||||||
|
div(
|
||||||
|
.id(id),
|
||||||
|
.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
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,14 +24,11 @@ extension SiteRoute.View.ProjectRoute {
|
|||||||
func renderView(isHtmxRequest: Bool) async throws -> AnySendableHTML {
|
func renderView(isHtmxRequest: Bool) async throws -> AnySendableHTML {
|
||||||
switch self {
|
switch self {
|
||||||
case .index:
|
case .index:
|
||||||
return MainPage {
|
return MainPage(active: .projects) {
|
||||||
ProjectView(project: .mock)
|
ProjectView(project: .mock)
|
||||||
}
|
}
|
||||||
case .form(let dismiss):
|
case .form(let dismiss):
|
||||||
guard !dismiss else {
|
return ProjectForm(dismiss: dismiss)
|
||||||
return div(.id("projectForm")) {}
|
|
||||||
}
|
|
||||||
return ProjectForm()
|
|
||||||
|
|
||||||
case .create:
|
case .create:
|
||||||
return mainPage
|
return mainPage
|
||||||
@@ -48,7 +45,7 @@ extension SiteRoute.View.RoomRoute {
|
|||||||
}
|
}
|
||||||
return RoomForm()
|
return RoomForm()
|
||||||
case .index:
|
case .index:
|
||||||
return MainPage {
|
return MainPage(active: .rooms) {
|
||||||
RoomsView(rooms: Room.mocks)
|
RoomsView(rooms: Room.mocks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,19 +56,16 @@ extension SiteRoute.View.FrictionRateRoute {
|
|||||||
func renderView(isHtmxRequest: Bool) async throws -> AnySendableHTML {
|
func renderView(isHtmxRequest: Bool) async throws -> AnySendableHTML {
|
||||||
switch self {
|
switch self {
|
||||||
case .index:
|
case .index:
|
||||||
return MainPage {
|
return MainPage(active: .frictionRate) {
|
||||||
FrictionRateView()
|
FrictionRateView()
|
||||||
}
|
}
|
||||||
case .form(let type, let dismiss):
|
case .form(let type, let dismiss):
|
||||||
guard !dismiss else {
|
|
||||||
return div(.id(type.id)) {}
|
|
||||||
}
|
|
||||||
// FIX: Forms need to reference existing items.
|
// FIX: Forms need to reference existing items.
|
||||||
switch type {
|
switch type {
|
||||||
case .equipmentInfo:
|
case .equipmentInfo:
|
||||||
return EquipmentForm()
|
return EquipmentForm(dismiss: dismiss)
|
||||||
case .componentPressureLoss:
|
case .componentPressureLoss:
|
||||||
return ComponentLossForm()
|
return ComponentLossForm(dismiss: dismiss)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,14 +87,11 @@ extension SiteRoute.View.EffectiveLengthRoute {
|
|||||||
func renderView(isHtmxRequest: Bool) async throws -> AnySendableHTML {
|
func renderView(isHtmxRequest: Bool) async throws -> AnySendableHTML {
|
||||||
switch self {
|
switch self {
|
||||||
case .index:
|
case .index:
|
||||||
return MainPage {
|
return MainPage(active: .effectiveLength) {
|
||||||
EffectiveLengthsView(effectiveLengths: EffectiveLength.mocks)
|
EffectiveLengthsView(effectiveLengths: EffectiveLength.mocks)
|
||||||
}
|
}
|
||||||
case .form(let dismiss):
|
case .form(let dismiss):
|
||||||
guard !dismiss else {
|
return EffectiveLengthForm(dismiss: dismiss)
|
||||||
return div(.id("effectiveLengthForm")) {}
|
|
||||||
}
|
|
||||||
return EffectiveLengthForm()
|
|
||||||
|
|
||||||
case .field(let type):
|
case .field(let type):
|
||||||
switch type {
|
switch type {
|
||||||
@@ -114,7 +105,7 @@ extension SiteRoute.View.EffectiveLengthRoute {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private let mainPage: AnySendableHTML = {
|
private let mainPage: AnySendableHTML = {
|
||||||
MainPage {
|
MainPage(active: .projects) {
|
||||||
div {
|
div {
|
||||||
h1 { "It works!" }
|
h1 { "It works!" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,20 @@ import ManualDCore
|
|||||||
import Styleguide
|
import Styleguide
|
||||||
|
|
||||||
struct EffectiveLengthForm: HTML, Sendable {
|
struct EffectiveLengthForm: HTML, Sendable {
|
||||||
|
let dismiss: Bool
|
||||||
|
|
||||||
var body: some HTML {
|
var body: some HTML {
|
||||||
div(
|
// div(
|
||||||
.id("effectiveLengthForm"),
|
// .id("effectiveLengthForm"),
|
||||||
.class(
|
// .class(
|
||||||
"""
|
// """
|
||||||
fixed top-40 left-[25vw] w-1/2 z-50 text-gray-800
|
// fixed top-40 left-[25vw] w-1/2 z-50 text-gray-800
|
||||||
bg-gray-200 border border-gray-400
|
// bg-gray-200 border border-gray-400
|
||||||
rounded-lg shadow-lg mx-10
|
// rounded-lg shadow-lg mx-10
|
||||||
"""
|
// """
|
||||||
)
|
// )
|
||||||
) {
|
// ) {
|
||||||
|
ModalForm(id: "effectiveLengthForm", dismiss: dismiss) {
|
||||||
h1(.class("text-2xl font-bold")) { "Effective Length" }
|
h1(.class("text-2xl font-bold")) { "Effective Length" }
|
||||||
form(.class("space-y-4 p-4")) {
|
form(.class("space-y-4 p-4")) {
|
||||||
div {
|
div {
|
||||||
@@ -25,7 +27,6 @@ struct EffectiveLengthForm: HTML, Sendable {
|
|||||||
}
|
}
|
||||||
div {
|
div {
|
||||||
label(.for("type")) { "Type" }
|
label(.for("type")) { "Type" }
|
||||||
// FIX: Add select field.
|
|
||||||
select(
|
select(
|
||||||
.id("type"), .name("type"),
|
.id("type"), .name("type"),
|
||||||
.class("w-full border rounded-md")
|
.class("w-full border rounded-md")
|
||||||
|
|||||||
@@ -4,17 +4,10 @@ import ManualDCore
|
|||||||
import Styleguide
|
import Styleguide
|
||||||
|
|
||||||
struct ComponentLossForm: HTML, Sendable {
|
struct ComponentLossForm: HTML, Sendable {
|
||||||
|
let dismiss: Bool
|
||||||
|
|
||||||
var body: some HTML {
|
var body: some HTML {
|
||||||
div(
|
ModalForm(id: "componentLossForm", dismiss: dismiss) {
|
||||||
.id("componentLossForm"),
|
|
||||||
.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")) { "Component Loss" }
|
h1(.class("text-2xl font-bold")) { "Component Loss" }
|
||||||
form(.class("space-y-4 p-4")) {
|
form(.class("space-y-4 p-4")) {
|
||||||
div {
|
div {
|
||||||
|
|||||||
@@ -5,17 +5,10 @@ import Styleguide
|
|||||||
// TODO: Have form hold onto equipment info model to edit.
|
// TODO: Have form hold onto equipment info model to edit.
|
||||||
struct EquipmentForm: HTML, Sendable {
|
struct EquipmentForm: HTML, Sendable {
|
||||||
|
|
||||||
|
let dismiss: Bool
|
||||||
|
|
||||||
var body: some HTML {
|
var body: some HTML {
|
||||||
div(
|
ModalForm(id: "equipmentForm", dismiss: dismiss) {
|
||||||
.id("equipmentForm"),
|
|
||||||
.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-3xl font-bold pb-6 ps-2")) { "Equipment Info" }
|
h1(.class("text-3xl font-bold pb-6 ps-2")) { "Equipment Info" }
|
||||||
form(.class("space-y-4 p-4")) {
|
form(.class("space-y-4 p-4")) {
|
||||||
div {
|
div {
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ public struct MainPage<Inner: HTML>: SendableHTMLDocument where Inner: Sendable
|
|||||||
public var title: String { "Manual-D" }
|
public var title: String { "Manual-D" }
|
||||||
public var lang: String { "en" }
|
public var lang: String { "en" }
|
||||||
let inner: Inner
|
let inner: Inner
|
||||||
|
let activeTab: Sidebar.ActiveTab
|
||||||
|
|
||||||
init(_ inner: () -> Inner) {
|
init(active activeTab: Sidebar.ActiveTab, _ inner: () -> Inner) {
|
||||||
|
self.activeTab = activeTab
|
||||||
self.inner = inner()
|
self.inner = inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ public struct MainPage<Inner: HTML>: SendableHTMLDocument where Inner: Sendable
|
|||||||
public var body: some HTML {
|
public var body: some HTML {
|
||||||
div(.class("bg-white dark:bg-gray-800 dark:text-white")) {
|
div(.class("bg-white dark:bg-gray-800 dark:text-white")) {
|
||||||
div(.class("flex flex-row")) {
|
div(.class("flex flex-row")) {
|
||||||
Sidebar()
|
Sidebar(active: activeTab)
|
||||||
main(.class("flex flex-col h-screen w-full")) {
|
main(.class("flex flex-col h-screen w-full")) {
|
||||||
inner
|
inner
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,24 +6,18 @@ import Styleguide
|
|||||||
struct ProjectForm: HTML, Sendable {
|
struct ProjectForm: HTML, Sendable {
|
||||||
|
|
||||||
let project: Project?
|
let project: Project?
|
||||||
|
let dismiss: Bool
|
||||||
|
|
||||||
init(
|
init(
|
||||||
|
dismiss: Bool,
|
||||||
project: Project? = nil
|
project: Project? = nil
|
||||||
) {
|
) {
|
||||||
|
self.dismiss = dismiss
|
||||||
self.project = project
|
self.project = project
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some HTML {
|
var body: some HTML {
|
||||||
div(
|
ModalForm(id: "projectForm", dismiss: dismiss) {
|
||||||
.id("projectForm"),
|
|
||||||
.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-3xl font-bold pb-6 ps-2")) { "Project" }
|
h1(.class("text-3xl font-bold pb-6 ps-2")) { "Project" }
|
||||||
form(.class("space-y-4 p-4")) {
|
form(.class("space-y-4 p-4")) {
|
||||||
div {
|
div {
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import Elementary
|
import Elementary
|
||||||
|
import ManualDCore
|
||||||
import Styleguide
|
import Styleguide
|
||||||
|
|
||||||
// TODO: Need to add active to sidebar links.
|
// TODO: Need to add active to sidebar links.
|
||||||
struct Sidebar: HTML {
|
struct Sidebar: HTML {
|
||||||
|
|
||||||
|
let active: ActiveTab
|
||||||
|
|
||||||
var body: some HTML {
|
var body: some HTML {
|
||||||
aside(
|
aside(
|
||||||
.class(
|
.class(
|
||||||
@@ -14,12 +17,20 @@ struct Sidebar: HTML {
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
row(title: "Project", icon: .mapPin, href: "/projects")
|
row(title: "Project", icon: .mapPin, route: .project(.index))
|
||||||
row(title: "Rooms", icon: .doorClosed, href: "/rooms")
|
.attributes(.data("active", value: active == .projects ? "true" : "false"))
|
||||||
row(title: "Equivalent Lengths", icon: .rulerDimensionLine, href: "/effective-lengths")
|
|
||||||
row(title: "Friction Rate", icon: .squareFunction, href: "/friction-rate")
|
row(title: "Rooms", icon: .doorClosed, route: .room(.index))
|
||||||
.attributes(.data("active", value: "true"))
|
.attributes(.data("active", value: active == .rooms ? "true" : "false"))
|
||||||
|
|
||||||
|
row(title: "Equivalent Lengths", icon: .rulerDimensionLine, route: .effectiveLength(.index))
|
||||||
|
.attributes(.data("active", value: active == .effectiveLength ? "true" : "false"))
|
||||||
|
|
||||||
|
row(title: "Friction Rate", icon: .squareFunction, route: .frictionRate(.index))
|
||||||
|
.attributes(.data("active", value: active == .frictionRate ? "true" : "false"))
|
||||||
|
|
||||||
row(title: "Duct Sizes", icon: .wind, href: "#")
|
row(title: "Duct Sizes", icon: .wind, href: "#")
|
||||||
|
.attributes(.data("active", value: active == .ductSizing ? "true" : "false"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,4 +57,22 @@ struct Sidebar: HTML {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func row(
|
||||||
|
title: String,
|
||||||
|
icon: Icon.Key,
|
||||||
|
route: SiteRoute.View
|
||||||
|
) -> some HTML<HTMLTag.a> {
|
||||||
|
row(title: title, icon: icon, href: SiteRoute.View.router.path(for: route))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Sidebar {
|
||||||
|
enum ActiveTab: Equatable, Sendable {
|
||||||
|
case projects
|
||||||
|
case rooms
|
||||||
|
case effectiveLength
|
||||||
|
case frictionRate
|
||||||
|
case ductSizing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user