feat: Initial navbar
This commit is contained in:
@@ -5363,6 +5363,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.my-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);
|
||||||
}
|
}
|
||||||
@@ -5702,6 +5705,9 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.mb-4 {
|
||||||
|
margin-bottom: calc(var(--spacing) * 4);
|
||||||
|
}
|
||||||
.mb-6 {
|
.mb-6 {
|
||||||
margin-bottom: calc(var(--spacing) * 6);
|
margin-bottom: calc(var(--spacing) * 6);
|
||||||
}
|
}
|
||||||
@@ -6561,9 +6567,27 @@
|
|||||||
width: calc(var(--size-selector, 0.25rem) * 4);
|
width: calc(var(--size-selector, 0.25rem) * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.w-24 {
|
||||||
|
width: calc(var(--spacing) * 24);
|
||||||
|
}
|
||||||
|
.w-64 {
|
||||||
|
width: calc(var(--spacing) * 64);
|
||||||
|
}
|
||||||
|
.w-\[80px\] {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
.w-fit {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
.w-full {
|
.w-full {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.flex-1 {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.flex-none {
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
.flex-shrink {
|
.flex-shrink {
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
@@ -6928,6 +6952,9 @@
|
|||||||
.rounded-md {
|
.rounded-md {
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
}
|
}
|
||||||
|
.rounded-none {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
.rounded-selector {
|
.rounded-selector {
|
||||||
border-radius: var(--radius-selector);
|
border-radius: var(--radius-selector);
|
||||||
}
|
}
|
||||||
@@ -7392,6 +7419,12 @@
|
|||||||
.bg-base-300 {
|
.bg-base-300 {
|
||||||
background-color: var(--color-base-300);
|
background-color: var(--color-base-300);
|
||||||
}
|
}
|
||||||
|
.bg-neutral {
|
||||||
|
background-color: var(--color-neutral);
|
||||||
|
}
|
||||||
|
.bg-primary {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
}
|
||||||
.bg-red-500 {
|
.bg-red-500 {
|
||||||
background-color: var(--color-red-500);
|
background-color: var(--color-red-500);
|
||||||
}
|
}
|
||||||
@@ -7809,6 +7842,9 @@
|
|||||||
.px-4 {
|
.px-4 {
|
||||||
padding-inline: calc(var(--spacing) * 4);
|
padding-inline: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
|
.py-1 {
|
||||||
|
padding-block: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
.py-1\.5 {
|
.py-1\.5 {
|
||||||
padding-block: calc(var(--spacing) * 1.5);
|
padding-block: calc(var(--spacing) * 1.5);
|
||||||
}
|
}
|
||||||
@@ -7835,6 +7871,9 @@
|
|||||||
.pe-2 {
|
.pe-2 {
|
||||||
padding-inline-end: calc(var(--spacing) * 2);
|
padding-inline-end: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
|
.pe-4 {
|
||||||
|
padding-inline-end: calc(var(--spacing) * 4);
|
||||||
|
}
|
||||||
.pt-6 {
|
.pt-6 {
|
||||||
padding-top: calc(var(--spacing) * 6);
|
padding-top: calc(var(--spacing) * 6);
|
||||||
}
|
}
|
||||||
@@ -8462,6 +8501,9 @@
|
|||||||
color: var(--color-warning);
|
color: var(--color-warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.text-base-content {
|
||||||
|
color: var(--color-base-content);
|
||||||
|
}
|
||||||
.text-error {
|
.text-error {
|
||||||
color: var(--color-error);
|
color: var(--color-error);
|
||||||
}
|
}
|
||||||
@@ -9748,6 +9790,15 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.is-drawer-open\:space-x-2 {
|
||||||
|
&:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) {
|
||||||
|
:where(& > :not(:last-child)) {
|
||||||
|
--tw-space-x-reverse: 0;
|
||||||
|
margin-inline-start: calc(calc(var(--spacing) * 2) * var(--tw-space-x-reverse));
|
||||||
|
margin-inline-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-x-reverse)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.is-drawer-open\:space-x-4 {
|
.is-drawer-open\:space-x-4 {
|
||||||
&:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) {
|
&:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) {
|
||||||
:where(& > :not(:last-child)) {
|
:where(& > :not(:last-child)) {
|
||||||
|
|||||||
49
Sources/ViewController/Views/Navbar.swift
Normal file
49
Sources/ViewController/Views/Navbar.swift
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import Elementary
|
||||||
|
import ManualDCore
|
||||||
|
import Styleguide
|
||||||
|
|
||||||
|
struct Navbar: HTML, Sendable {
|
||||||
|
let sidebarToggle: Bool
|
||||||
|
|
||||||
|
var body: some HTML<HTMLTag.nav> {
|
||||||
|
nav(.class("navbar w-full bg-base-300 text-base-content shadow-sm mb-4")) {
|
||||||
|
div(.class("flex-1 space-x-4 items-center")) {
|
||||||
|
if sidebarToggle {
|
||||||
|
Tooltip("Open sidebar", position: .right) {
|
||||||
|
label(
|
||||||
|
.for("my-drawer-1"),
|
||||||
|
.class("size-7"),
|
||||||
|
.init(name: "aria-label", value: "open sidebar")
|
||||||
|
) {
|
||||||
|
SVG(.sidebarToggle)
|
||||||
|
}
|
||||||
|
.navButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tooltip("Home", position: .right) {
|
||||||
|
a(
|
||||||
|
.class("w-fit text-xl py-2 px-4"),
|
||||||
|
.href(route: .project(.index))
|
||||||
|
) {
|
||||||
|
"Manual-D"
|
||||||
|
}
|
||||||
|
.navButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div(.class("flex-none")) {
|
||||||
|
button(.class("w-fit px-4 py-2")) {
|
||||||
|
"User Menu"
|
||||||
|
}
|
||||||
|
.navButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension HTML where Tag: HTMLTrait.Attributes.Global {
|
||||||
|
func navButton() -> _AttributedElement<Self> {
|
||||||
|
attributes(
|
||||||
|
.class("btn btn-square btn-ghost hover:bg-neutral hover:text-white")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,69 +35,64 @@ struct ProjectView: HTML, Sendable {
|
|||||||
div(.class("drawer lg:drawer-open")) {
|
div(.class("drawer lg:drawer-open")) {
|
||||||
input(.id("my-drawer-1"), .type(.checkbox), .class("drawer-toggle"))
|
input(.id("my-drawer-1"), .type(.checkbox), .class("drawer-toggle"))
|
||||||
|
|
||||||
div(.class("drawer-content p-4")) {
|
div(.class("drawer-content")) {
|
||||||
Tooltip("Open sidebar", position: .right) {
|
Navbar(sidebarToggle: true)
|
||||||
label(
|
div(.class("p-4")) {
|
||||||
.for("my-drawer-1"),
|
switch self.activeTab {
|
||||||
.class("btn btn-square btn-ghost drawer-button size-7 pb-6")
|
case .project:
|
||||||
) {
|
await resultView(projectID) {
|
||||||
SVG(.sidebarToggle)
|
guard let project = try await database.projects.get(projectID) else {
|
||||||
}
|
throw NotFoundError()
|
||||||
}
|
}
|
||||||
switch self.activeTab {
|
return project
|
||||||
case .project:
|
} onSuccess: { project in
|
||||||
await resultView(projectID) {
|
ProjectDetail(project: project)
|
||||||
guard let project = try await database.projects.get(projectID) else {
|
}
|
||||||
throw NotFoundError()
|
case .rooms:
|
||||||
|
await resultView(projectID) {
|
||||||
|
try await (
|
||||||
|
database.rooms.fetch(projectID),
|
||||||
|
database.projects.getSensibleHeatRatio(projectID)
|
||||||
|
)
|
||||||
|
} onSuccess: { (rooms, shr) in
|
||||||
|
RoomsView(rooms: rooms, sensibleHeatRatio: shr)
|
||||||
}
|
}
|
||||||
return project
|
|
||||||
} onSuccess: { project in
|
|
||||||
ProjectDetail(project: project)
|
|
||||||
}
|
|
||||||
case .rooms:
|
|
||||||
await resultView(projectID) {
|
|
||||||
try await (
|
|
||||||
database.rooms.fetch(projectID),
|
|
||||||
database.projects.getSensibleHeatRatio(projectID)
|
|
||||||
)
|
|
||||||
} onSuccess: { (rooms, shr) in
|
|
||||||
RoomsView(rooms: rooms, sensibleHeatRatio: shr)
|
|
||||||
}
|
|
||||||
|
|
||||||
case .equivalentLength:
|
case .equivalentLength:
|
||||||
await resultView(projectID) {
|
await resultView(projectID) {
|
||||||
try await database.effectiveLength.fetch(projectID)
|
try await database.effectiveLength.fetch(projectID)
|
||||||
} onSuccess: {
|
} onSuccess: {
|
||||||
EffectiveLengthsView(effectiveLengths: $0)
|
EffectiveLengthsView(effectiveLengths: $0)
|
||||||
}
|
}
|
||||||
case .frictionRate:
|
case .frictionRate:
|
||||||
|
|
||||||
await resultView(projectID) {
|
await resultView(projectID) {
|
||||||
|
|
||||||
let equipmentInfo = try await database.equipment.fetch(projectID)
|
let equipmentInfo = try await database.equipment.fetch(projectID)
|
||||||
let componentLosses = try await database.componentLoss.fetch(projectID)
|
let componentLosses = try await database.componentLoss.fetch(projectID)
|
||||||
let equivalentLengths = try await database.effectiveLength.fetchMax(projectID)
|
let equivalentLengths = try await database.effectiveLength.fetchMax(projectID)
|
||||||
let frictionRateResponse = try await manualD.frictionRate(
|
let frictionRateResponse = try await manualD.frictionRate(
|
||||||
equipmentInfo: equipmentInfo,
|
equipmentInfo: equipmentInfo,
|
||||||
componentLosses: componentLosses,
|
componentLosses: componentLosses,
|
||||||
effectiveLength: equivalentLengths
|
effectiveLength: equivalentLengths
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
equipmentInfo, componentLosses, equivalentLengths, frictionRateResponse
|
equipmentInfo, componentLosses, equivalentLengths, frictionRateResponse
|
||||||
)
|
)
|
||||||
} onSuccess: {
|
} onSuccess: {
|
||||||
FrictionRateView(
|
FrictionRateView(
|
||||||
equipmentInfo: $0.0,
|
equipmentInfo: $0.0,
|
||||||
componentLosses: $0.1,
|
componentLosses: $0.1,
|
||||||
equivalentLengths: $0.2,
|
equivalentLengths: $0.2,
|
||||||
frictionRateResponse: $0.3
|
frictionRateResponse: $0.3
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case .ductSizing:
|
case .ductSizing:
|
||||||
await resultView(projectID) {
|
await resultView(projectID) {
|
||||||
try await database.calculateDuctSizes(projectID: projectID)
|
try await database.calculateDuctSizes(projectID: projectID)
|
||||||
} onSuccess: {
|
} onSuccess: {
|
||||||
DuctSizingView(rooms: $0)
|
DuctSizingView(rooms: $0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,7 +143,7 @@ extension ProjectView {
|
|||||||
div(
|
div(
|
||||||
.class(
|
.class(
|
||||||
"""
|
"""
|
||||||
flex min-h-full flex-col items-start bg-base-200
|
flex min-h-full flex-col items-start bg-base-300 text-base-content
|
||||||
is-drawer-close:min-w-[80px] is-drawer-open:max-w-[300px]
|
is-drawer-close:min-w-[80px] is-drawer-open:max-w-[300px]
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
@@ -156,32 +151,6 @@ extension ProjectView {
|
|||||||
|
|
||||||
ul(.class("w-full")) {
|
ul(.class("w-full")) {
|
||||||
|
|
||||||
li(.class("w-full")) {
|
|
||||||
div(
|
|
||||||
.class("w-full is-drawer-close:tooltip is-drawer-close:tooltip-right"),
|
|
||||||
.data("tip", value: "All Projects")
|
|
||||||
) {
|
|
||||||
a(
|
|
||||||
.class(
|
|
||||||
"""
|
|
||||||
flex btn btn-secondary btn-square btn-block
|
|
||||||
items-center
|
|
||||||
"""
|
|
||||||
),
|
|
||||||
.hx.get(route: .project(.index)),
|
|
||||||
.hx.target("body"),
|
|
||||||
.hx.pushURL(true),
|
|
||||||
.hx.swap(.outerHTML),
|
|
||||||
) {
|
|
||||||
div(.class("flex is-drawer-open:space-x-4")) {
|
|
||||||
// span { "<" }
|
|
||||||
SVG(.chevronsLeft)
|
|
||||||
span(.class("is-drawer-close:hidden")) { "All Projects" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIX: Move to user profile / settings page.
|
// FIX: Move to user profile / settings page.
|
||||||
li(.class("w-full is-drawer-close:hidden")) {
|
li(.class("w-full is-drawer-close:hidden")) {
|
||||||
div(.class("flex justify-between p-4")) {
|
div(.class("flex justify-between p-4")) {
|
||||||
@@ -198,7 +167,6 @@ extension ProjectView {
|
|||||||
isComplete: true
|
isComplete: true
|
||||||
)
|
)
|
||||||
.attributes(.data("active", value: "true"), when: active == .project)
|
.attributes(.data("active", value: "true"), when: active == .project)
|
||||||
.attributes(.class("btn-active"), when: active == .project)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
li(.class("w-full")) {
|
li(.class("w-full")) {
|
||||||
@@ -208,7 +176,6 @@ extension ProjectView {
|
|||||||
route: .project(.detail(projectID, .rooms(.index))),
|
route: .project(.detail(projectID, .rooms(.index))),
|
||||||
isComplete: completedSteps.rooms
|
isComplete: completedSteps.rooms
|
||||||
)
|
)
|
||||||
.attributes(.class("btn-active"), when: active == .rooms)
|
|
||||||
.attributes(.data("active", value: "true"), when: active == .rooms)
|
.attributes(.data("active", value: "true"), when: active == .rooms)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +188,6 @@ extension ProjectView {
|
|||||||
isComplete: completedSteps.equivalentLength
|
isComplete: completedSteps.equivalentLength
|
||||||
)
|
)
|
||||||
.attributes(.data("active", value: "true"), when: active == .equivalentLength)
|
.attributes(.data("active", value: "true"), when: active == .equivalentLength)
|
||||||
.attributes(.class("btn-active"), when: active == .equivalentLength)
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -233,7 +199,6 @@ extension ProjectView {
|
|||||||
isComplete: completedSteps.frictionRate
|
isComplete: completedSteps.frictionRate
|
||||||
)
|
)
|
||||||
.attributes(.data("active", value: "true"), when: active == .frictionRate)
|
.attributes(.data("active", value: "true"), when: active == .frictionRate)
|
||||||
.attributes(.class("btn-active"), when: active == .frictionRate)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
li(.class("w-full")) {
|
li(.class("w-full")) {
|
||||||
@@ -245,7 +210,6 @@ extension ProjectView {
|
|||||||
hideIsComplete: true
|
hideIsComplete: true
|
||||||
)
|
)
|
||||||
.attributes(.data("active", value: "true"), when: active == .ductSizing)
|
.attributes(.data("active", value: "true"), when: active == .ductSizing)
|
||||||
.attributes(.class("btn-active"), when: active == .ductSizing)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,47 +280,6 @@ extension ProjectView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// a(
|
|
||||||
//
|
|
||||||
// // flex w-full btn btn-soft btn-square btn-block btn-lg
|
|
||||||
// .class(
|
|
||||||
// """
|
|
||||||
// flex w-full hover:bg-gray-900 data-active:bg-gray-900
|
|
||||||
// is-drawer-open:justify-between is-drawer-close:items-center
|
|
||||||
// is-drawer-close:tooltip is-drawer-close:tooltip-right
|
|
||||||
// is-drawer-close:justify-center
|
|
||||||
// """
|
|
||||||
// ),
|
|
||||||
// .href(href),
|
|
||||||
// .data("tip", value: title)
|
|
||||||
// ) {
|
|
||||||
// div(
|
|
||||||
// .class(
|
|
||||||
// """
|
|
||||||
// justify-center items-center mx-auto space-4 py-2
|
|
||||||
// is-drawer-open:flex is-drawer-open:space-x-4
|
|
||||||
// """
|
|
||||||
// )
|
|
||||||
// ) {
|
|
||||||
// SVG(icon)
|
|
||||||
// span(.class("text-gray-200 is-drawer-open:text-xl is-drawer-close:text-sm")) {
|
|
||||||
// title
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if !hideIsComplete {
|
|
||||||
// div(.class("is-drawer-close:hidden")) {
|
|
||||||
// if isComplete {
|
|
||||||
// SVG(.badgeCheck)
|
|
||||||
// } else {
|
|
||||||
// SVG(.ban)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// .attributes(.class("text-green-400"), when: isComplete)
|
|
||||||
// .attributes(.class("text-error"), when: !isComplete)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// .attributes(.class("is-drawer-close:text-green-400"), when: isComplete)
|
|
||||||
// .attributes(.class("is-drawer-close:text-error"), when: !isComplete && !hideIsComplete)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func row(
|
private func row(
|
||||||
|
|||||||
@@ -16,36 +16,39 @@ struct ProjectsTable: HTML, Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some HTML {
|
var body: some HTML {
|
||||||
div(.class("m-6")) {
|
div {
|
||||||
Row {
|
Navbar(sidebarToggle: false)
|
||||||
h1(.class("text-2xl font-bold")) { "Projects" }
|
div(.class("m-6")) {
|
||||||
Tooltip("Add project") {
|
Row {
|
||||||
PlusButton()
|
h1(.class("text-2xl font-bold")) { "Projects" }
|
||||||
.attributes(
|
Tooltip("Add project") {
|
||||||
.class("btn-ghost"),
|
PlusButton()
|
||||||
.showModal(id: ProjectForm.id)
|
.attributes(
|
||||||
)
|
.class("btn-ghost"),
|
||||||
|
.showModal(id: ProjectForm.id)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
.attributes(.class("pb-6"))
|
||||||
.attributes(.class("pb-6"))
|
|
||||||
|
|
||||||
div(.class("overflow-x-auto rounded-box border")) {
|
div(.class("overflow-x-auto rounded-box border")) {
|
||||||
table(.class("table table-zebra")) {
|
table(.class("table table-zebra")) {
|
||||||
thead {
|
thead {
|
||||||
tr {
|
tr {
|
||||||
th { Label("Date") }
|
th { Label("Date") }
|
||||||
th { Label("Name") }
|
th { Label("Name") }
|
||||||
th { Label("Address") }
|
th { Label("Address") }
|
||||||
th {}
|
th {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tbody {
|
||||||
|
Rows(projects: projects)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tbody {
|
|
||||||
Rows(projects: projects)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ProjectForm(dismiss: true)
|
ProjectForm(dismiss: true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user