diff --git a/Public/css/output.css b/Public/css/output.css index 6f47cc5..2c4275c 100644 --- a/Public/css/output.css +++ b/Public/css/output.css @@ -10,11 +10,14 @@ --color-red-500: oklch(63.7% 0.237 25.331); --color-red-600: oklch(57.7% 0.245 27.325); --color-green-400: oklch(79.2% 0.209 151.711); + --color-blue-400: oklch(70.7% 0.165 254.624); --color-indigo-600: oklch(51.1% 0.262 276.966); --color-slate-300: oklch(86.9% 0.022 252.894); --color-slate-900: oklch(20.8% 0.042 265.755); --color-gray-200: oklch(92.8% 0.006 264.531); + --color-gray-300: oklch(87.2% 0.01 258.338); --color-gray-400: oklch(70.7% 0.022 261.325); + --color-gray-900: oklch(21% 0.034 264.665); --color-black: #000; --color-white: #fff; --spacing: 0.25rem; @@ -6778,6 +6781,9 @@ .justify-end { justify-content: flex-end; } + .gap-1 { + gap: calc(var(--spacing) * 1); + } .gap-2 { gap: calc(var(--spacing) * 2); } @@ -7104,6 +7110,10 @@ border-bottom-style: var(--tw-border-style); border-bottom-width: 1px; } + .border-b-1 { + border-bottom-style: var(--tw-border-style); + border-bottom-width: 1px; + } .badge-dash { @layer daisyui.l1.l2 { color: var(--badge-color); @@ -7670,6 +7680,9 @@ } } } + .p-2 { + padding: calc(var(--spacing) * 2); + } .p-4 { padding: calc(var(--spacing) * 4); } @@ -8452,6 +8465,9 @@ .text-error { color: var(--color-error); } + .text-gray-200 { + color: var(--color-gray-200); + } .text-gray-400 { color: var(--color-gray-400); } @@ -9349,6 +9365,27 @@ border-color: var(--color-red-500); } } + .hover\:bg-gray-900 { + &:hover { + @media (hover: hover) { + background-color: var(--color-gray-900); + } + } + } + .hover\:bg-neutral { + &:hover { + @media (hover: hover) { + background-color: var(--color-neutral); + } + } + } + .hover\:bg-neutral-content { + &:hover { + @media (hover: hover) { + background-color: var(--color-neutral-content); + } + } + } .hover\:bg-red-600 { &:hover { @media (hover: hover) { @@ -9356,6 +9393,13 @@ } } } + .hover\:text-black { + &:hover { + @media (hover: hover) { + color: var(--color-black); + } + } + } .hover\:text-white { &:hover { @media (hover: hover) { @@ -9379,6 +9423,31 @@ outline-color: var(--color-indigo-600); } } + .data-active\:bg-gray-900 { + &[data-active] { + background-color: var(--color-gray-900); + } + } + .data-active\:bg-neutral { + &[data-active] { + background-color: var(--color-neutral); + } + } + .data-active\:bg-neutral-content { + &[data-active] { + background-color: var(--color-neutral-content); + } + } + .data-active\:text-black { + &[data-active] { + color: var(--color-black); + } + } + .data-active\:text-white { + &[data-active] { + color: var(--color-white); + } + } .md\:grid-cols-2 { @media (width >= 48rem) { grid-template-columns: repeat(2, minmax(0, 1fr)); @@ -9457,9 +9526,52 @@ display: table-cell; } } - .dark\:text-white { - @media (prefers-color-scheme: dark) { - color: var(--color-white); + .hover\:dark\:bg-gray-900 { + &:hover { + @media (hover: hover) { + @media (prefers-color-scheme: dark) { + background-color: var(--color-gray-900); + } + } + } + } + .hover\:dark\:bg-neutral { + &:hover { + @media (hover: hover) { + @media (prefers-color-scheme: dark) { + background-color: var(--color-neutral); + } + } + } + } + .hover\:dark\:text-white { + &:hover { + @media (hover: hover) { + @media (prefers-color-scheme: dark) { + color: var(--color-white); + } + } + } + } + .data-active\:dark\:bg-gray-900 { + &[data-active] { + @media (prefers-color-scheme: dark) { + background-color: var(--color-gray-900); + } + } + } + .data-active\:dark\:bg-neutral { + &[data-active] { + @media (prefers-color-scheme: dark) { + background-color: var(--color-neutral); + } + } + } + .data-active\:dark\:text-white { + &[data-active] { + @media (prefers-color-scheme: dark) { + color: var(--color-white); + } } } .is-drawer-close\:tooltip { @@ -9546,6 +9658,11 @@ } } } + .is-drawer-close\:mx-auto { + &:where(.drawer-toggle:not(:checked) ~ .drawer-side, .drawer-toggle:not(:checked) ~ .drawer-side *) { + margin-inline: auto; + } + } .is-drawer-close\:hidden { &:where(.drawer-toggle:not(:checked) ~ .drawer-side, .drawer-toggle:not(:checked) ~ .drawer-side *) { display: none; @@ -9561,16 +9678,41 @@ min-width: 80px; } } + .is-drawer-close\:grid-cols-1 { + &:where(.drawer-toggle:not(:checked) ~ .drawer-side, .drawer-toggle:not(:checked) ~ .drawer-side *) { + grid-template-columns: repeat(1, minmax(0, 1fr)); + } + } .is-drawer-close\:items-center { &:where(.drawer-toggle:not(:checked) ~ .drawer-side, .drawer-toggle:not(:checked) ~ .drawer-side *) { align-items: center; } } + .is-drawer-close\:justify-center { + &:where(.drawer-toggle:not(:checked) ~ .drawer-side, .drawer-toggle:not(:checked) ~ .drawer-side *) { + justify-content: center; + } + } + .is-drawer-close\:space-y-2 { + &:where(.drawer-toggle:not(:checked) ~ .drawer-side, .drawer-toggle:not(:checked) ~ .drawer-side *) { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse))); + } + } + } .is-drawer-close\:overflow-visible { &:where(.drawer-toggle:not(:checked) ~ .drawer-side, .drawer-toggle:not(:checked) ~ .drawer-side *) { overflow: visible; } } + .is-drawer-close\:text-sm { + &:where(.drawer-toggle:not(:checked) ~ .drawer-side, .drawer-toggle:not(:checked) ~ .drawer-side *) { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + } .is-drawer-close\:text-error { &:where(.drawer-toggle:not(:checked) ~ .drawer-side, .drawer-toggle:not(:checked) ~ .drawer-side *) { color: var(--color-error); @@ -9581,14 +9723,19 @@ color: var(--color-green-400); } } + .is-drawer-open\:flex { + &:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) { + display: flex; + } + } .is-drawer-open\:w-64 { &:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) { width: calc(var(--spacing) * 64); } } - .is-drawer-open\:min-w-\[340px\] { + .is-drawer-open\:max-w-\[300px\] { &:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) { - min-width: 340px; + max-width: 300px; } } .is-drawer-open\:justify-between { @@ -9596,6 +9743,11 @@ justify-content: space-between; } } + .is-drawer-open\:justify-start { + &:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) { + justify-content: flex-start; + } + } .is-drawer-open\:space-x-4 { &:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) { :where(& > :not(:last-child)) { @@ -9605,6 +9757,12 @@ } } } + .is-drawer-open\:text-xl { + &:where(.drawer-toggle:checked ~ .drawer-side, .drawer-toggle:checked ~ .drawer-side *) { + font-size: var(--text-xl); + line-height: var(--tw-leading, var(--text-xl--line-height)); + } + } } @layer base { :where(:root),:root:has(input.theme-controller[value=light]:checked),[data-theme=light] { diff --git a/Sources/Styleguide/SVG.swift b/Sources/Styleguide/SVG.swift index a6441a5..54afd7f 100644 --- a/Sources/Styleguide/SVG.swift +++ b/Sources/Styleguide/SVG.swift @@ -18,6 +18,7 @@ extension SVG { case badgeCheck case ban case chevronRight + case chevronsLeft case circlePlus case close case doorClosed @@ -46,6 +47,10 @@ extension SVG { return """ """ + case .chevronsLeft: + return """ + + """ case .circlePlus: return """ diff --git a/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift b/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift index 48f0d66..5c3a115 100644 --- a/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift +++ b/Sources/ViewController/Views/FrictionRate/FrictionRateView.swift @@ -44,19 +44,24 @@ struct FrictionRateView: HTML, Sendable { var body: some HTML { div(.class("p-4 space-y-6")) { - h1(.class("text-4xl font-bold pb-6")) { "Friction Rate" } - div(.class("flex space-x-4")) { - if let availableStaticPressure { - Label("Available Static Pressure") - Number(availableStaticPressure, digits: 2) - .attributes(.class("badge badge-lg badge-outline font-bold ms-4")) - } - } - div(.class("flex space-x-4")) { - if let frictionRateDesignValue { - Label("Friction Rate Design Value") - Number(frictionRateDesignValue, digits: 2) - .attributes(.class("badge badge-lg badge-outline \(badgeColor) font-bold")) + Row { + h1(.class("text-4xl font-bold pb-6")) { "Friction Rate" } + div(.class("space-y-4")) { + div(.class("flex space-x-4 justify-end")) { + if let availableStaticPressure { + Label("Available Static Pressure") + Number(availableStaticPressure, digits: 2) + .attributes(.class("badge badge-lg badge-outline font-bold ms-4")) + } + } + + div(.class("flex space-x-4 justify-end")) { + if let frictionRateDesignValue { + Label("Friction Rate Design Value") + Number(frictionRateDesignValue, digits: 2) + .attributes(.class("badge badge-lg badge-outline \(badgeColor) font-bold")) + } + } } } diff --git a/Sources/ViewController/Views/Project/ProjectView.swift b/Sources/ViewController/Views/Project/ProjectView.swift index ee00464..2edba36 100644 --- a/Sources/ViewController/Views/Project/ProjectView.swift +++ b/Sources/ViewController/Views/Project/ProjectView.swift @@ -36,11 +36,13 @@ struct ProjectView: HTML, Sendable { input(.id("my-drawer-1"), .type(.checkbox), .class("drawer-toggle")) div(.class("drawer-content p-4")) { - label( - .for("my-drawer-1"), - .class("btn btn-square btn-ghost drawer-button size-7 pb-6") - ) { - SVG(.sidebarToggle) + Tooltip("Open sidebar", position: .right) { + label( + .for("my-drawer-1"), + .class("btn btn-square btn-ghost drawer-button size-7 pb-6") + ) { + SVG(.sidebarToggle) + } } switch self.activeTab { case .project: @@ -127,58 +129,6 @@ struct ProjectView: HTML, Sendable { } } -// extension SiteRoute.View.ProjectRoute.DetailRoute.Tab { -// -// func view(projectID: Project.ID) async throws -> AnySendableHTML { -// @Dependency(\.database) var database -// @Dependency(\.manualD) var manualD -// -// switch self { -// case .project: -// if let project = try await database.projects.get(projectID) { -// return ProjectDetail(project: project) -// } else { -// return div { -// "FIX ME!" -// } -// } -// case .rooms: -// return try await RoomsView( -// projectID: projectID, -// rooms: database.rooms.fetch(projectID), -// sensibleHeatRatio: database.projects.getSensibleHeatRatio(projectID) -// ) -// -// case .equivalentLength: -// return try await EffectiveLengthsView( -// projectID: projectID, -// effectiveLengths: database.effectiveLength.fetch(projectID) -// ) -// case .frictionRate: -// let equipmentInfo = try await database.equipment.fetch(projectID) -// let componentLosses = try await database.componentLoss.fetch(projectID) -// let equivalentLengths = try await database.effectiveLength.fetchMax(projectID) -// -// return try await FrictionRateView( -// equipmentInfo: equipmentInfo, -// componentLosses: componentLosses, -// equivalentLengths: equivalentLengths, -// projectID: projectID, -// frictionRateResponse: manualD.frictionRate( -// equipmentInfo: equipmentInfo, -// componentLosses: componentLosses, -// effectiveLength: equivalentLengths -// ) -// ) -// case .ductSizing: -// return try await DuctSizingView( -// projectID: projectID, -// rooms: database.calculateDuctSizes(projectID: projectID) -// ) -// } -// } -// } - extension ProjectView { struct Sidebar: HTML { @@ -199,7 +149,7 @@ extension ProjectView { .class( """ flex min-h-full flex-col items-start bg-base-200 - is-drawer-close:min-w-[80px] is-drawer-open:min-w-[340px] + is-drawer-close:min-w-[80px] is-drawer-open:max-w-[300px] """ ) ) { @@ -215,7 +165,7 @@ extension ProjectView { .class( """ flex btn btn-secondary btn-square btn-block - is-drawer-close:items-center + items-center """ ), .hx.get(route: .project(.index)), @@ -224,7 +174,8 @@ extension ProjectView { .hx.swap(.outerHTML), ) { div(.class("flex is-drawer-open:space-x-4")) { - span { "<" } + // span { "<" } + SVG(.chevronsLeft) span(.class("is-drawer-close:hidden")) { "All Projects" } } } @@ -239,13 +190,14 @@ extension ProjectView { } } - li(.class("w-full")) { + li(.class("flex w-full")) { row( title: "Project", icon: .mapPin, route: .project(.detail(projectID, .index(tab: .project))), isComplete: true ) + .attributes(.data("active", value: "true"), when: active == .project) .attributes(.class("btn-active"), when: active == .project) } @@ -257,16 +209,20 @@ extension ProjectView { isComplete: completedSteps.rooms ) .attributes(.class("btn-active"), when: active == .rooms) + .attributes(.data("active", value: "true"), when: active == .rooms) } li(.class("w-full")) { + // Tooltip("Equivalent Lengths", position: .right) { row( - title: "Equivalent Lengths", + title: "T.E.L.", icon: .rulerDimensionLine, route: .project(.detail(projectID, .equivalentLength(.index))), isComplete: completedSteps.equivalentLength ) + .attributes(.data("active", value: "true"), when: active == .equivalentLength) .attributes(.class("btn-active"), when: active == .equivalentLength) + // } } li(.class("w-full")) { @@ -276,6 +232,7 @@ extension ProjectView { route: .project(.detail(projectID, .frictionRate(.index))), isComplete: completedSteps.frictionRate ) + .attributes(.data("active", value: "true"), when: active == .frictionRate) .attributes(.class("btn-active"), when: active == .frictionRate) } @@ -287,6 +244,7 @@ extension ProjectView { isComplete: false, hideIsComplete: true ) + .attributes(.data("active", value: "true"), when: active == .ductSizing) .attributes(.class("btn-active"), when: active == .ductSizing) } } @@ -301,38 +259,104 @@ extension ProjectView { href: String, isComplete: Bool, hideIsComplete: Bool = false - ) -> some HTML { - a( + ) -> some HTML { + button( .class( """ - flex w-full btn btn-soft btn-square btn-block - is-drawer-open:justify-between is-drawer-close:items-center - is-drawer-close:tooltip is-drawer-close:tooltip-right + w-full gap-1 py-2 border-b-1 border-gray-200 + hover:bg-neutral data-active:bg-neutral + hover:text-white data-active:text-white + is-drawer-open:flex is-drawer-open:space-x-4 + is-drawer-close:grid-cols-1 """ ), - .href(href), - .data("tip", value: title) + .hx.get(href), + .hx.target("body"), + .hx.swap(.outerHTML) ) { - div(.class("flex is-drawer-open:space-x-4")) { - SVG(icon) - span(.class("text-xl is-drawer-close:hidden")) { - title - } - } - if !hideIsComplete { - div(.class("is-drawer-close:hidden")) { - if isComplete { - SVG(.badgeCheck) - } else { - SVG(.ban) + div( + .class( + """ + w-full p-2 gap-1 + is-drawer-open:flex is-drawer-open:space-x-4 + is-drawer-close:grid-cols-1 + """ + ) + ) { + div( + .class( + """ + items-center + is-drawer-open:justify-start is-drawer-open:flex is-drawer-open:space-x-4 + is-drawer-close:justify-center is-drawer-close:mx-auto is-drawer-close:space-y-2 + """ + ) + ) { + div(.class("flex items-center justify-center")) { + SVG(icon) + } + .attributes(.class("is-drawer-close:text-green-400"), when: isComplete) + .attributes(.class("is-drawer-close:text-error"), when: !isComplete && !hideIsComplete) + + div(.class("flex items-center justify-center")) { + span { title } } } - .attributes(.class("text-green-400"), when: isComplete) - .attributes(.class("text-error"), when: !isComplete) + + if !hideIsComplete { + div(.class("flex grow justify-end items-end 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) + // 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( @@ -341,7 +365,7 @@ extension ProjectView { route: SiteRoute.View, isComplete: Bool, hideIsComplete: Bool = false - ) -> some HTML { + ) -> some HTML { row( title: title, icon: icon, href: SiteRoute.View.router.path(for: route), isComplete: isComplete, hideIsComplete: hideIsComplete diff --git a/input.css b/input.css index 8bc6dde..f577019 100644 --- a/input.css +++ b/input.css @@ -4,3 +4,5 @@ @source not "./daisyui{,*}.mjs"; @plugin "./daisyui.mjs"; +@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *)); +