feat: Better modal form using dialog, some forms still need updated to use it effectively.

This commit is contained in:
2026-01-06 10:12:48 -05:00
parent fc12e47b5c
commit 5fcc5b88fa
14 changed files with 161 additions and 130 deletions

View File

@@ -26,7 +26,7 @@ public struct MainPage<Inner: HTML>: SendableHTMLDocument where Inner: Sendable
}
public var body: some HTML {
div {
div(.class("h-screen w-full")) {
inner
}
script(.src("https://unpkg.com/lucide@latest")) {}

View File

@@ -18,9 +18,7 @@ struct ProjectDetail: HTML, Sendable {
h1(.class("text-2xl font-bold")) { "Project" }
EditButton()
.attributes(
.hx.get(route: .project(.form(id: project.id, dismiss: false))),
.hx.target("#projectForm"),
.hx.swap(.outerHTML)
.on(.click, "projectForm.showModal()")
)
}
@@ -54,6 +52,6 @@ struct ProjectDetail: HTML, Sendable {
}
}
ProjectForm(dismiss: true)
ProjectForm(dismiss: true, project: project)
}
}

View File

@@ -34,7 +34,7 @@ struct ProjectForm: HTML, Sendable {
div {
label(.for("name")) { "Name" }
Input(id: "name", placeholder: "Name")
.attributes(.type(.text), .required, .autofocus)
.attributes(.type(.text), .required, .autofocus, .value(project?.name))
}
div {
label(.for("streetAddress")) { "Address" }
@@ -57,14 +57,9 @@ struct ProjectForm: HTML, Sendable {
.attributes(.type(.text), .required, .value(project?.zipCode))
}
div(.class("flex justify-end space-x-6")) {
CancelButton()
.attributes(
.hx.get(route: .project(.form(dismiss: true))),
.hx.target("#projectForm"),
.hx.swap(.outerHTML)
)
div(.class("flex mt-6")) {
SubmitButton()
.attributes(.class("btn-block"))
}
}
}

View File

@@ -67,8 +67,7 @@ extension ProjectsTable {
td { "\(project.name)" }
td { "\(project.streetAddress)" }
td {
Row {
div {}
div(.class("flex justify-end space-x-6")) {
TrashButton()
.attributes(
.hx.delete(route: .project(.delete(id: project.id))),

View File

@@ -17,6 +17,8 @@ struct RoomForm: HTML, Sendable {
h1(.class("text-3xl font-bold pb-6")) { "Room" }
// TODO: Use htmx here.
form(
.class("modal-backdrop"),
.init(name: "method", value: "dialog"),
room == nil
? .hx.post(route: .project(.detail(projectID, .rooms(.index))))
: .hx.patch(route: .project(.detail(projectID, .rooms(.index)))),
@@ -41,11 +43,16 @@ struct RoomForm: HTML, Sendable {
.attributes(.type(.number), .required, .min("0"), .value(room?.heatingLoad))
}
div {
label(.for("coolingLoad")) { "Cooling Load:" }
Input(id: "coolingLoad", placeholder: "Cooling Load")
.attributes(.type(.number), .required, .min("0"), .value(room?.coolingLoad))
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(
@@ -53,20 +60,9 @@ struct RoomForm: HTML, Sendable {
.value("\(room != nil ? room!.registerCount : 1)"),
)
}
Row {
// Force button to the right, probably a better way.
div {}
div(.class("space-x-4")) {
CancelButton()
.attributes(
.hx.get(route: .project(.detail(projectID, .rooms(.form(dismiss: true))))),
.hx.target("#roomForm"),
.hx.swap(.outerHTML)
)
SubmitButton()
}
div(.class("flex justify-end space-x-4")) {
SubmitButton()
}
.attributes(.class("py-4"))
}
}
}

View File

@@ -20,9 +20,10 @@ struct RoomsView: HTML, Sendable {
.data("tip", value: "Add room")
) {
button(
.hx.get(route: .project(.detail(projectID, .rooms(.form(dismiss: false))))),
.hx.target("#roomForm"),
.hx.swap(.outerHTML),
// .hx.get(route: .project(.detail(projectID, .rooms(.form(dismiss: false))))),
// .hx.target("#roomForm"),
// .hx.swap(.outerHTML),
.on(.click, "roomForm.showModal()"),
.class("btn btn-primary w-[40px] text-2xl")
) {
"+"
@@ -81,9 +82,10 @@ struct RoomsView: HTML, Sendable {
.attributes(.class("text-error"))
}
td {
Number(room.coolingLoad)
Number(room.coolingTotal)
.attributes(.class("text-success"))
}
// FIX: Add cooling sensible.
td {
Number(room.registerCount)
}
@@ -120,6 +122,6 @@ extension Array where Element == Room {
}
var coolingTotal: Double {
reduce(into: 0) { $0 += $1.coolingLoad }
reduce(into: 0) { $0 += $1.coolingTotal }
}
}

View File

@@ -13,22 +13,20 @@ struct LoginForm: HTML, Sendable {
}
var body: some HTML {
div(
.id("loginForm"),
.class("flex items-center justify-center")
) {
ModalForm(id: "loginForm", closeButton: false, dismiss: false) {
h1(.class("text-2xl font-bold mb-6")) { style.title }
form(
.method(.post)
.method(.post),
.class("space-y-4")
) {
if let next {
input(.class("hidden"), .name("next"), .value(next))
}
fieldset(.class("fieldset bg-base-200 border-base-300 rounded-box w-xl border p-4")) {
legend(.class("fieldset-legend")) { style.title }
if style == .signup {
if style == .signup {
div {
label(.class("input validator w-full")) {
SVG(.user)
input(
@@ -43,7 +41,9 @@ struct LoginForm: HTML, Sendable {
"Must be at least 3 characters"
}
}
}
div {
label(.class("input validator w-full")) {
SVG(.email)
input(
@@ -52,7 +52,9 @@ struct LoginForm: HTML, Sendable {
)
}
div(.class("validator-hint hidden")) { "Enter valid email address." }
}
div {
label(.class("input validator w-full")) {
SVG(.key)
input(
@@ -61,8 +63,10 @@ struct LoginForm: HTML, Sendable {
.name("password"), .id("password"),
)
}
}
if style == .signup {
if style == .signup {
div {
label(.class("input validator w-full")) {
SVG(.key)
input(
@@ -84,10 +88,15 @@ struct LoginForm: HTML, Sendable {
"At least one uppercase letter"
}
}
}
button(.class("btn btn-secondary mt-4")) { style.title }
div(.class("flex")) {
button(.class("btn btn-secondary mt-4 w-full")) { style.title }
}
div(.class("flex justify-center")) {
a(
.class("btn btn-link mt-4"),
.class("btn btn-link"),
.href(route: style == .signup ? .login(.index(next: next)) : .signup(.index))
) {
style == .login ? "Sign Up" : "Login"