feat: Initial view controller dependency and snapshot tests.

This commit is contained in:
2025-01-23 10:57:20 -05:00
parent c74433c2eb
commit 5695d0e13c
49 changed files with 2802 additions and 1 deletions

View File

@@ -0,0 +1,53 @@
import Elementary
import SharedModels
import URLRouting
struct ToggleFormButton: HTML {
var content: some HTML<HTMLTag.a> {
a(.href("javascript:void(0)"), .on(.click, "toggleContent('form')"), .class("btn-add")) {
"+"
}
}
}
enum Button {
static func add() -> some HTML<HTMLTag.button> {
button(.class("btn btn-add")) { "+" }
}
static func danger<C: HTML>(@HTMLBuilder body: () -> C) -> some HTML<HTMLTag.button> {
button(.class("danger")) { body() }
}
static func close(id: String, resetURL: String? = nil) -> some HTML<HTMLTag.button> {
button(.class("btn-close"), .on(.click, makeOnClick(id, resetURL))) {
"x"
}
}
static func close(id: IDKey, resetURL route: ViewRoute? = nil) -> some HTML<HTMLTag.button> {
close(
id: id.description,
resetURL: route != nil ? ViewRoute.router.path(for: route!) : nil
)
}
static func update() -> some HTML<HTMLTag.button> {
button(.class("btn-update")) { "Update" }
}
static func detail() -> some HTML<HTMLTag.button> {
button(.class("btn-detail")) {
""
}
}
private static func makeOnClick(_ id: String, _ resetURL: String?) -> String {
let output = "toggleContent('\(id)');"
if let resetURL {
return "\(output) window.location.href='\(resetURL)';"
}
return output
}
}

View File

@@ -0,0 +1,81 @@
import Elementary
import SharedModels
struct Float<C: HTML, B: HTML>: HTML {
let id: String
let shouldDisplay: Bool
let body: C?
let closeButton: B?
init(id: String = "float") {
self.id = id
self.shouldDisplay = false
self.body = nil
self.closeButton = nil
}
init(
id: String = "float",
shouldDisplay: Bool,
@HTMLBuilder body: () -> C,
@HTMLBuilder closeButton: () -> B
) {
self.id = id
self.shouldDisplay = shouldDisplay
self.body = body()
self.closeButton = closeButton()
}
private var classString: String {
shouldDisplay ? "float" : ""
}
private var display: String {
shouldDisplay ? "block" : "hidden"
}
var content: some HTML<HTMLTag.div> {
div(.id(id), .class(classString), .style("display: \(display);")) {
if let body, shouldDisplay {
if let closeButton {
div(.class("btn-row")) {
closeButton
}
}
body
}
}
}
}
struct DefaultCloseButton: HTML {
let id: String
let resetURL: String?
var content: some HTML {
Button.close(id: id, resetURL: resetURL)
}
}
extension Float where B == DefaultCloseButton {
init(
id: String = "float",
shouldDisplay: Bool,
resetURL route: ViewRoute? = nil,
@HTMLBuilder body: () -> C
) {
self.init(
id: id,
shouldDisplay: shouldDisplay,
body: body,
closeButton: { DefaultCloseButton(
id: id,
resetURL: route != nil ? ViewRoute.router.path(for: route!) : nil
) }
)
}
}
extension Float: Sendable where C: Sendable, B: Sendable {}

View File

@@ -0,0 +1,18 @@
import Elementary
enum Img {
@Sendable
static func spinner(width: Int = 30, height: Int = 30) -> some HTML<HTMLTag.img> {
img(.src("/images/spinner.svg"), .width(width), .height(height))
}
@Sendable
static func search(width: Int = 30, height: Int = 30) -> some HTML<HTMLTag.img> {
img(.src("/images/search.svg"), .width(width), .height(height))
}
@Sendable
static func trashCan(width: Int = 30, height: Int = 30) -> some HTML<HTMLTag.img> {
img(.src("/images/trash-can.svg"), .width(width), .height(height))
}
}

View File

@@ -0,0 +1,31 @@
import Elementary
import ElementaryHTMX
struct Navbar: HTML, Sendable {
var content: some HTML {
div(.class("sidepanel"), .id("sidepanel")) {
a(.href("javascript:void(0)"), .class("closebtn"), .on(.click, "closeSidepanel()")) {
"x"
}
a(.hx.get("/purchase-orders?page=1&limit=50"), .hx.target("body"), .hx.pushURL(true)) {
"Purchase Orders"
}
a(.hx.get("/users"), .hx.target("body"), .hx.pushURL(true)) {
"Users"
}
a(.hx.get("/employees"), .hx.target("body"), .hx.pushURL(true)) {
"Employees"
}
a(.hx.get("/vendors"), .hx.target("body"), .hx.pushURL(true)) {
"Vendors"
}
div(.style("border-bottom: 1px solid grey; margin-bottom: 5px;")) {}
a(.hx.post("/logout"), .hx.target("#content"), .hx.swap(.outerHTML), .hx.trigger(.event(.click))) {
"Logout"
}
}
button(.class("openbtn"), .on(.click, "openSidepanel()")) {
img(.src("/images/menu.svg"), .style("width: 30px;, height: 30px;"))
}
}
}

View File

@@ -0,0 +1,89 @@
import Elementary
import ElementaryHTMX
import SharedModels
import Vapor
struct EmployeeSelect: HTML {
let employees: [Employee]?
let context: ViewRoute.SelectContext
var content: some HTML {
if let employees {
select(.name("createdForID"), .class(context.classString)) {
for employee in employees {
option(.value(employee.id.uuidString)) { employee.fullName }
}
}
.attributes(.style("margin-left: 15px;"), when: context == .purchaseOrderSearch)
} else {
div(
.hx.get(route: .employee(.select(context: context))),
.hx.target("this"),
.hx.swap(.outerHTML.transition(true).swap("0.5s")),
.hx.indicator("next .hx-indicator"),
.hx.trigger(.event(.revealed)),
.style("display: inline;")
) {
Img.spinner().attributes(.class("hx-indicator"))
}
}
}
static func purchaseOrderForm(employees: [Employee]? = nil) -> Self {
.init(employees: employees, context: .purchaseOrderForm)
}
static func purchaseOrderSearch(employees: [Employee]? = nil) -> Self {
.init(employees: employees, context: .purchaseOrderSearch)
}
}
struct VendorBranchSelect: HTML {
let branches: [VendorBranch.Detail]?
let context: ViewRoute.SelectContext
var content: some HTML {
if let branches {
select(.name("vendorBranchID"), .class("col-4")) {
for branch in branches {
option(.value(branch.id.uuidString)) { "\(branch.vendor.name) - \(branch.name)" }
}
}
.attributes(.style("margin-left: 15px;"), when: context == .purchaseOrderSearch)
} else {
div(
.hx.get(route: .vendorBranch(.select(context: context))),
.hx.target(.this),
.hx.swap(.outerHTML.transition(true).swap("0.5s")),
.hx.indicator("next .hx-indicator"),
.hx.trigger(.event(.revealed)),
.style("display: inline;")
) {
Img.spinner().attributes(.class("hx-indicator"))
}
}
}
static func purchaseOrderForm(branches: [VendorBranch.Detail]? = nil) -> Self {
.init(branches: branches, context: .purchaseOrderForm)
}
static func purchaseOrderSearch(branches: [VendorBranch.Detail]? = nil) -> Self {
.init(branches: branches, context: .purchaseOrderSearch)
}
}
// enum SelectContext: String, Codable, Content {
// case purchaseOrderForm
// case purchaseOrderSearch
extension ViewRoute.SelectContext {
var classString: String {
switch self {
case .purchaseOrderForm: return "col-3"
case .purchaseOrderSearch: return "col-6"
}
}
}