feat: Updates styles
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
|
|
||||||
@config '../tailwind.config.js';
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The default border color has changed to `currentColor` in Tailwind CSS v4,
|
The default border color has changed to `currentColor` in Tailwind CSS v4,
|
||||||
so we've added these compatibility styles to make sure everything still
|
so we've added these compatibility styles to make sure everything still
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@ import Routes
|
|||||||
import Vapor
|
import Vapor
|
||||||
import VaporElementary
|
import VaporElementary
|
||||||
@preconcurrency import VaporRouting
|
@preconcurrency import VaporRouting
|
||||||
import ViewControllerLive
|
import ViewController
|
||||||
|
|
||||||
// configures your application
|
// configures your application
|
||||||
public func configure(_ app: Application) async throws {
|
public func configure(_ app: Application) async throws {
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ public struct SubmitButton: HTML, Sendable {
|
|||||||
button(
|
button(
|
||||||
.type(.submit),
|
.type(.submit),
|
||||||
.class("""
|
.class("""
|
||||||
w-full \(bg: .blue) \(text: .yellow) font-bold py-3 rounded-md
|
w-full font-bold py-3 rounded-md transition-colors
|
||||||
hover:\(bg: .darkBlue) transition-colors
|
bg-yellow-300 dark:bg-blue-500
|
||||||
|
hover:bg-yellow-400 hover:dark:bg-blue-600
|
||||||
|
text-blue-500 dark:text-yellow-300
|
||||||
""")
|
""")
|
||||||
) { label }
|
) { label }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,16 @@ public enum Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum BorderColor: Sendable {
|
public enum BorderColor: Sendable {
|
||||||
|
case blue
|
||||||
|
case darkGray
|
||||||
case darkYellow
|
case darkYellow
|
||||||
case gray
|
case gray
|
||||||
case yellow
|
case yellow
|
||||||
|
|
||||||
var color: String {
|
var color: String {
|
||||||
switch self {
|
switch self {
|
||||||
|
case .blue: return "border-blue-500"
|
||||||
|
case .darkGray: return "border-gray-400"
|
||||||
case .darkYellow: return "border-yellow-800"
|
case .darkYellow: return "border-yellow-800"
|
||||||
case .gray: return "border-gray-300"
|
case .gray: return "border-gray-300"
|
||||||
case .yellow: return "border-yellow-300"
|
case .yellow: return "border-yellow-300"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public struct FormHeader: HTML, Sendable {
|
|||||||
|
|
||||||
public var content: some HTML {
|
public var content: some HTML {
|
||||||
LabeledContent {
|
LabeledContent {
|
||||||
h2(.class("text-2xl font-extrabold dark:\(text: .white)")) { label }
|
h2(.class("text-2xl font-extrabold text-gray-600 dark:text-slate-200")) { label }
|
||||||
} label: {
|
} label: {
|
||||||
SVG(svg, color: .blue)
|
SVG(svg, color: .blue)
|
||||||
}
|
}
|
||||||
@@ -50,8 +50,8 @@ public struct Input: HTML, Sendable {
|
|||||||
input(
|
input(
|
||||||
.id(id), .placeholder(placeholder), .name(name ?? id),
|
.id(id), .placeholder(placeholder), .name(name ?? id),
|
||||||
.class("""
|
.class("""
|
||||||
w-full px-4 py-2 border \(border: .gray) rounded-md focus:ring-2
|
w-full px-4 py-2 border border-gray-300 dark:border-gray-400 rounded-md focus:ring-2
|
||||||
focus:ring-yellow-800 focus:border-yellow-800 \(text: .darkGray) dark:\(text: .white)
|
focus:ring-yellow-800 focus:border-yellow-800 text-blue-600 dark:text-gray-300
|
||||||
""")
|
""")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ public struct InputLabel<InputLabel: HTML>: HTML {
|
|||||||
public var content: some HTML<HTMLTag.label> {
|
public var content: some HTML<HTMLTag.label> {
|
||||||
label(
|
label(
|
||||||
.for(forInputId),
|
.for(forInputId),
|
||||||
.class("block text-sm font-medium \(text: .darkGray) dark:\(text: .gray) mb-2")
|
.class("block text-sm font-medium text-blue-500 dark:text-gray-300 mb-2")
|
||||||
) {
|
) {
|
||||||
self.inputLabel
|
self.inputLabel
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,12 @@ public struct ResultContainer<Body: HTML>: HTML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public var content: some HTML {
|
public var content: some HTML {
|
||||||
div(.class("mt-6 p-6 bg-blue-50 dark:bg-slate-400 rounded-lg")) {
|
div(.class("""
|
||||||
h3(.class("text-xl font-semibold \(text: .darkGray) mb-4")) { "Results" }
|
mt-6 p-6 rounded-lg border border-blue-500
|
||||||
|
bg-blue-50 dark:bg-slate-600
|
||||||
|
text-blue-500 dark:text-slate-200
|
||||||
|
""")) {
|
||||||
|
h3(.class("text-xl font-semibold mb-4")) { "Results" }
|
||||||
body
|
body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
Sources/ViewController/Extensions/String+double.swift
Normal file
14
Sources/ViewController/Extensions/String+double.swift
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
private let numberFormatter: NumberFormatter = {
|
||||||
|
let formatter = NumberFormatter()
|
||||||
|
formatter.numberStyle = .decimal
|
||||||
|
formatter.maximumFractionDigits = 2
|
||||||
|
return formatter
|
||||||
|
}()
|
||||||
|
|
||||||
|
extension String.StringInterpolation {
|
||||||
|
mutating func appendInterpolation(double: Double) {
|
||||||
|
appendInterpolation(numberFormatter.string(from: NSNumber(value: double))!)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ struct MainPage<Inner: HTML>: SendableHTMLDocument where Inner: Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some HTML {
|
var body: some HTML {
|
||||||
main(.class("bg-white dark:bg-gray-800")) {
|
main(.class("bg-slate-100 dark:bg-gray-800")) {
|
||||||
div(.class("min-h-screen")) {
|
div(.class("min-h-screen")) {
|
||||||
Header()
|
Header()
|
||||||
PageContent(body: inner)
|
PageContent(body: inner)
|
||||||
@@ -46,12 +46,13 @@ private struct Header: HTML {
|
|||||||
header(.class("\(bg: .blue) mb-8 flex flex-row gap-2 border \(border: .yellow)")) {
|
header(.class("\(bg: .blue) mb-8 flex flex-row gap-2 border \(border: .yellow)")) {
|
||||||
a(
|
a(
|
||||||
.href(route: .index),
|
.href(route: .index),
|
||||||
.class("flex flex-row gap-2 \(bg: .yellow) pe-2 rounded-e-lg \(text: .blue) hover:\(text: .darkBlue)")
|
.class("group flex flex-row gap-2 \(bg: .yellow) pe-2 rounded-e-lg \(text: .blue) hover:text-blue-600")
|
||||||
) {
|
) {
|
||||||
img(.src("/images/toolbox.svg"), .width(40), .height(40), .class("py-1"))
|
img(.src("/images/toolbox.svg"), .width(40), .height(40), .class("py-1"))
|
||||||
div(.class("flex flex-row mt-2")) {
|
div(.class("flex flex-row mt-2")) {
|
||||||
h2(.class("text-2xl font-extrabold pe-3")) { "HVAC-Toolbox" }
|
h2(.class("text-2xl font-extrabold pe-3")) { "HVAC-Toolbox" }
|
||||||
SVG(.wind, color: .blue)
|
SVG(.wind, color: .blue)
|
||||||
|
.attributes(.class("group-hover:text-blue-600"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nav(.class("flex flex-row gap-2 p-2 mt-2")) {
|
nav(.class("flex flex-row gap-2 p-2 mt-2")) {
|
||||||
@@ -78,7 +79,7 @@ private struct PageContent<Body: HTML>: HTML where Body: Sendable {
|
|||||||
|
|
||||||
var content: some HTML {
|
var content: some HTML {
|
||||||
div(.class("mx-5 lg:mx-20")) {
|
div(.class("mx-5 lg:mx-20")) {
|
||||||
div(.class("rounded-xl shadow-lg \(bg: .slate) dark:\(bg: .darkSlate) p-8")) {
|
div(.class("rounded-xl shadow-lg bg-white dark:bg-slate-700 p-8")) {
|
||||||
body()
|
body()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ struct MoldRiskForm: HTML {
|
|||||||
|
|
||||||
var content: some HTML {
|
var content: some HTML {
|
||||||
FormHeader(label: "Mold Risk Calculator", svg: .thermometer)
|
FormHeader(label: "Mold Risk Calculator", svg: .thermometer)
|
||||||
form {
|
form(.action("#")) {
|
||||||
div(.class("space-y-6")) {
|
div(.class("space-y-6")) {
|
||||||
LabeledContent(label: "Indoor Temperature (°F)") {
|
LabeledContent(label: "Indoor Temperature (°F)") {
|
||||||
Input(id: "temperature", placeholder: "Dry bulb temperature")
|
Input(id: "temperature", placeholder: "Dry bulb temperature")
|
||||||
@@ -43,7 +43,7 @@ struct MoldRiskResponse: HTML {
|
|||||||
"Risk Level: \(response.riskLevel.rawValue.capitalized)"
|
"Risk Level: \(response.riskLevel.rawValue.capitalized)"
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
SVG(.exclamation, color: "\(text: .green) dark:text-lime-600")
|
SVG(.exclamation, color: "text-green-600 dark:text-lime-600")
|
||||||
}
|
}
|
||||||
.attributes(.class("flex items-center gap-2"))
|
.attributes(.class("flex items-center gap-2"))
|
||||||
}
|
}
|
||||||
@@ -51,8 +51,8 @@ struct MoldRiskResponse: HTML {
|
|||||||
PsychrometricPropertiesGrid(properties: response.psychrometricProperties)
|
PsychrometricPropertiesGrid(properties: response.psychrometricProperties)
|
||||||
.attributes(.class("mx-6"))
|
.attributes(.class("mx-6"))
|
||||||
|
|
||||||
div(.class("mt-8 p-4 bg-gray-700 rounded-md shadow-md border border-blue-500")) {
|
div(.class("mt-8 p-4 bg-gray-100 dark:bg-gray-700 rounded-md shadow-md border border-blue-500")) {
|
||||||
p(.class("text-sm \(text: .blue)")) {
|
p(.class("text-sm text-blue-500")) {
|
||||||
span(.class("font-extrabold pe-2")) { "Note:" }
|
span(.class("font-extrabold pe-2")) { "Note:" }
|
||||||
"""
|
"""
|
||||||
These calculations are based on typical indoor conditions and common mold species. Actual mold growth can
|
These calculations are based on typical indoor conditions and common mold species. Actual mold growth can
|
||||||
@@ -70,22 +70,35 @@ struct PsychrometricPropertiesGrid: HTML {
|
|||||||
|
|
||||||
var content: some HTML<HTMLTag.div> {
|
var content: some HTML<HTMLTag.div> {
|
||||||
div(.class("grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mt-6 md:mx-20")) {
|
div(.class("grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mt-6 md:mx-20")) {
|
||||||
displayProperty("Dew Point", "\(properties.dewPoint.value) \(properties.dewPoint.units.symbol)")
|
displayProperty("Dew Point", \.dewPoint.rawValue)
|
||||||
displayProperty("Wet Bulb", "\(properties.wetBulb.value) \(properties.wetBulb.units.symbol)")
|
displayProperty("Wet Bulb", \.wetBulb.rawValue)
|
||||||
displayProperty("Enthalpy", "\(properties.enthalpy.value) \(properties.wetBulb.units.symbol)")
|
displayProperty("Enthalpy", \.enthalpy.rawValue)
|
||||||
displayProperty("Density", "\(properties.density.value) \(properties.density.units.rawValue)")
|
displayProperty("Density", \.density.rawValue)
|
||||||
displayProperty("Vapor Pressure", "\(properties.vaporPressure.value) \(properties.vaporPressure.units.symbol)")
|
displayProperty("Vapor Pressure", \.vaporPressure.rawValue)
|
||||||
displayProperty("Specific Volume", "\(properties.specificVolume.rawValue)")
|
displayProperty("Specific Volume", properties.specificVolume.rawValue)
|
||||||
displayProperty("Absolute Humidity", "\(properties.absoluteHumidity.value) \(properties.absoluteHumidity.units.symbol)")
|
displayProperty("Absolute Humidity", \.absoluteHumidity)
|
||||||
displayProperty("Humidity Ratio", "\(properties.humidityRatio.value)")
|
displayProperty("Humidity Ratio", properties.humidityRatio.value)
|
||||||
displayProperty("Degree of Saturation", "\(properties.degreeOfSaturation.value)")
|
displayProperty("Degree of Saturation", properties.degreeOfSaturation.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func displayProperty(_ label: String, _ value: String) -> some HTML {
|
private func displayProperty(_ label: String, _ value: Double, _ symbol: String? = nil) -> some HTML {
|
||||||
p(.class("\(text: .darkGray) dark:\(text: .white)")) {
|
let symbol = "\(symbol == nil ? "" : " \(symbol!)")"
|
||||||
|
|
||||||
|
return p(.class("text-blue-500 dark:text-slate-200")) {
|
||||||
span(.class("font-semibold")) { "\(label): " }
|
span(.class("font-semibold")) { "\(label): " }
|
||||||
span(.class("font-light")) { value }
|
span(.class("font-light")) {
|
||||||
|
"\(double: value)\(symbol)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func displayProperty<N: NumberWithUnitOfMeasure>(
|
||||||
|
_ label: String,
|
||||||
|
_ keyPath: KeyPath<PsychrometricProperties, N>
|
||||||
|
) -> some HTML where N.Number == Double, N.Units: RawRepresentable, N.Units.RawValue == String {
|
||||||
|
let property = properties[keyPath: keyPath]
|
||||||
|
return displayProperty(label, property.rawValue, property.units.rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
import defaultTheme from "tailwindcss/defaultTheme";
|
|
||||||
const colors = require('tailwindcss/colors');
|
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
module.exports = {
|
|
||||||
content: [
|
|
||||||
"./Sources/ViewControllerLive/Views/*.swift",
|
|
||||||
"./Sources/ViewControllerLive/*.swift",
|
|
||||||
"./Public/images/*.svg",
|
|
||||||
"./Sources/Styleguide/*.swift"
|
|
||||||
],
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user