Files
swift-hvac-toolbox/Sources/Styleguide/SVG.swift
Michael Housh a44cc6975d
Some checks failed
CI / ubuntu (push) Failing after 7m22s
CI / macOS (debug, 16.2) (push) Has been cancelled
CI / macOS (release, 16.2) (push) Has been cancelled
feat: Adds psi to feet of head conversion.
2025-03-07 16:27:03 -05:00

304 lines
14 KiB
Swift

import Elementary
public struct SVG: HTML, Sendable {
let color: String
let size: SVGSize
let svg: SVGType
public init(
_ svg: SVGType,
color: String,
size: SVGSize = .init()
) {
self.svg = svg
self.size = size
self.color = color
}
public init(
_ svg: SVGType,
color: Color.TextColor,
size: SVGSize = .init()
) {
self.svg = svg
self.size = size
self.color = color.color
}
public var content: some HTML<HTMLTag.div> {
div(.class("block \(color)")) {
svg.html(size)
}
}
}
public struct SVGSize: Sendable {
let width: Int
let height: Int
public init(width: Int = 24, height: Int? = nil) {
self.width = width
self.height = height ?? width
}
}
public enum SVGType: Sendable, CaseIterable {
case calculator
case checkCircle
case circleGauge
case droplets
case exclamation
case footprints
case funnel
case house
case leftRightArrow
case menu
case ruler
case scale
case thermometer
case thermometerSun
case wind
case zap
// swiftlint:disable cyclomatic_complexity
public func html(_ size: SVGSize) -> some HTML {
switch self {
case .calculator: return calculatorSvg(size: size)
case .checkCircle: return checkCircleSvg(size: size)
case .circleGauge: return circleGaugeSvg(size: size)
case .droplets: return dropletsSvg(size: size)
case .exclamation: return exclamationSvg(size: size)
case .footprints: return footprintsSvg(size: size)
case .funnel: return funnelSvg(size: size)
case .house: return houseSvg(size: size)
case .leftRightArrow: return leftRightArrowSvg(size: size)
case .menu: return menuSvg(size: size)
case .ruler: return rulerSvg(size: size)
case .scale: return scaleSvg(size: size)
case .thermometer: return thermometerSvg(size: size)
case .thermometerSun: return thermometerSunSvg(size: size)
case .wind: return windSvg(size: size)
case .zap: return zapSvg(size: size)
}
}
// swiftlint:enable cyclomatic_complexity
}
// MARK: - SVGs
// swiftlint:disable line_length
private func footprintsSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-footprints">
<path d="M4 16v-2.38C4 11.5 2.97 10.5 3 8c.03-2.72 1.49-6 4.5-6C9.37 2 10 3.8 10 5.5c0 3.11-2 5.66-2 8.68V16a2 2 0 1 1-4 0Z"/>
<path d="M20 20v-2.38c0-2.12 1.03-3.12 1-5.62-.03-2.72-1.49-6-4.5-6C14.63 6 14 7.8 14 9.5c0 3.11 2 5.66 2 8.68V20a2 2 0 1 0 4 0Z"/>
<path d="M16 17h4"/>
<path d="M4 13h4"/>
</svg>
""")
}
private func circleGaugeSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-gauge">
<path d="M15.6 2.7a10 10 0 1 0 5.7 5.7"/>
<circle cx="12" cy="12" r="2"/>
<path d="M13.4 10.6 19 5"/>
</svg>
""")
}
private func scaleSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-scale">
<path d="m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"/>
<path d="m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"/>
<path d="M7 21h10"/><path d="M12 3v18"/>
<path d="M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2"/>
</svg>
""")
}
private func checkCircleSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-check-big">
<path d="M21.801 10A10 10 0 1 1 17 3.335"/><path d="m9 11 3 3L22 4"/>
</svg>
""")
}
private func houseSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-house">
<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"/>
<path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
</svg>
""")
}
private func zapSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-zap">
<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>
</svg>
""")
}
private func rulerSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-ruler">
<path d="M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Z"/>
<path d="m14.5 12.5 2-2"/>
<path d="m11.5 9.5 2-2"/>
<path d="m8.5 6.5 2-2"/>
<path d="m17.5 15.5 2-2"/>
</svg>
""")
}
private func leftRightArrowSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-left-right">
<path d="M8 3 4 7l4 4"/>
<path d="M4 7h16"/>
<path d="m16 21 4-4-4-4"/>
<path d="M20 17H4"/>
</svg>
""")
}
// TODO: Requires attribution:
// Vectors and icons by <a href="https://dribbble.com/Laridae?ref=svgrepo.com" target="_blank">Laridae</a> in CC Attribution License via <a href="https://www.svgrepo.com/" target="_blank">SVG Repo</a>
// FIX: This doesn't work, but does as a file
private func toolboxSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="\(size.width)" height="\(size.height)" stroke="currentColor" viewBox="0 0 \(size.width) \(size.height)" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#000000">
<g id="SVGRepo_bgCarrier" stroke="currentColor" stroke-width="2"/>
<g id="SVGRepo_tracerCarrier" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier">
<path d="M619.52 194.56h35.84V128c0-5.632-4.608-10.24-10.24-10.24H378.88c-5.632 0-10.24 4.608-10.24 10.24v66.56h35.84v-30.72c0-5.632 4.608-10.24 10.24-10.24h194.56c5.632 0 10.24 4.608 10.24 10.24v30.72z" fill="#2C7FFF"/>
<path d="M184.32 209.92v20.48h655.36v-20.48H184.32z m-5.12-15.36h665.6c5.632 0 10.24 4.608 10.24 10.24v30.72c0 5.632-4.608 10.24-10.24 10.24H179.2c-5.632 0-10.24-4.608-10.24-10.24v-30.72c0-5.632 4.608-10.24 10.24-10.24zM240.64 890.88h51.2v-10.24H240.64v10.24z m-5.12-25.6h61.44c5.632 0 10.24 4.608 10.24 10.24v20.48c0 5.632-4.608 10.24-10.24 10.24H235.52c-5.632 0-10.24-4.608-10.24-10.24v-20.48c0-5.632 4.608-10.24 10.24-10.24zM737.28 890.88h51.2v-10.24h-51.2v10.24z m-5.12-25.6h61.44c5.632 0 10.24 4.608 10.24 10.24v20.48c0 5.632-4.608 10.24-10.24 10.24h-61.44c-5.632 0-10.24-4.608-10.24-10.24v-20.48c0-5.632 4.608-10.24 10.24-10.24z" fill=""/>
<path d="M199.68 343.04h122.88c5.632 0 10.24 4.608 10.24 10.24v81.92c0 5.632-4.608 10.24-10.24 10.24H199.68c-5.632 0-10.24-4.608-10.24-10.24V353.28c0-5.632 4.608-10.24 10.24-10.24zM701.44 343.04h122.88c5.632 0 10.24 4.608 10.24 10.24v81.92c0 5.632-4.608 10.24-10.24 10.24h-122.88c-5.632 0-10.24-4.608-10.24-10.24V353.28c0-5.632 4.608-10.24 10.24-10.24z" fill="#2C7FFF"/>
<path d="M873.472 276.48H148.48c-11.264 1.024-19.456 10.752-18.432 22.016l48.128 522.24c1.024 10.752 9.728 18.432 20.48 18.432h626.688c10.752 0 19.456-8.192 20.48-18.432l48.64-522.24v-2.048c-0.512-10.752-9.728-19.968-20.992-19.968zM150.528 291.84h722.944c3.072 0 5.12 2.048 5.12 5.632L870.4 384h-35.84v-30.72c0-5.632-4.608-10.24-10.24-10.24h-122.88c-5.632 0-10.24 4.608-10.24 10.24v30.72H332.8v-30.72c0-5.632-4.608-10.24-10.24-10.24H199.68c-5.632 0-10.24 4.608-10.24 10.24v30.72h-36.352l-8.192-86.528c0-3.072 2.048-5.12 5.632-5.632zM819.2 358.4v71.68h-112.64V358.4h112.64z m-501.76 0v71.68H204.8V358.4h112.64z m513.024 461.312c0 2.56-2.56 4.608-5.12 4.608H198.144c-2.56 0-4.608-2.048-5.12-4.608L154.624 399.36H189.44v35.84c0 5.632 4.608 10.24 10.24 10.24h122.88c5.632 0 10.24-4.608 10.24-10.24v-35.84h358.4v35.84c0 5.632 4.608 10.24 10.24 10.24h122.88c5.632 0 10.24-4.608 10.24-10.24v-35.84h34.816l-38.912 420.352z" fill=""/>
</g>
</svg>
""")
}
private func funnelSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<g clip-path="url(#clip0_429_11128)">
<path d="M20 3.99994H4L9.6 11.4666C9.85964 11.8128 10 12.2339 10 12.6666V19.9999L14 17.9999V12.6666C14 12.2339 14.1404 11.8128 14.4 11.4666L20 3.99994Z" stroke="currentColor" stroke-width="2.5" stroke-linejoin="round"></path>
</g>
<defs>
<clipPath id="clip0_429_11128"> <rect width="24" height="24" fill="white"></rect>
</clipPath>
</defs>
</g>
</svg>
""")
}
private func dropletsSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path d="M7 16.3c2.2 0 4-1.83 4-4.05 0-1.16-.57-2.26-1.71-3.19S7.29 6.75 7 5.3c-.29 1.45-1.14 2.84-2.29 3.76S3 11.1 3 12.25c0 2.22 1.8 4.05 4 4.05z"></path>
<path d="M12.56 6.6A10.97 10.97 0 0014 3.02c.5 2.5 2 4.9 4 6.5s3 3.5 3 5.5a6.98 6.98 0 01-11.91 4.97"></path>
</g>
</svg>
""")
}
private func thermometerSunSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path stroke="currentColor" d="M12 9C11.1077 8.98562 10.2363 9.27003 9.52424 9.808C8.81222 10.346 8.30055 11.1066 8.07061 11.9688C7.84068 12.8311 7.90568 13.7455 8.25529 14.5665C8.6049 15.3876 9.21904 16.0682 10 16.5M12 3V5M6.6 18.4L5.2 19.8M4 13H2M6.6 7.6L5.2 6.2M20 14.5351V4C20 2.89543 19.1046 2 18 2C16.8954 2 16 2.89543 16 4V14.5351C14.8044 15.2267 14 16.5194 14 18C14 20.2091 15.7909 22 18 22C20.2091 22 22 20.2091 22 18C22 16.5194 21.1956 15.2267 20 14.5351Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</g>
</svg>
""")
}
private func exclamationSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-6 h-6">
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path>
<path d="M12 9v4"></path>
<path d="M12 17h.01"></path>
</svg>
""")
}
private func windSvg(size: SVGSize) -> HTMLRaw {
return HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 \(size.width) \(size.height)" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="w-8 h-8">
<path d="M17.7 7.7a2.5 2.5 0 1 1 1.8 4.3H2"></path>
<path d="M9.6 4.6A2 2 0 1 1 11 8H2"></path>
<path d="M12.6 19.4A2 2 0 1 0 14 16H2"></path>
</svg>
""")
}
private func calculatorSvg(size: SVGSize) -> HTMLRaw {
return HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 \(size.width) \(size.height)" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="w-5 h-5">
<rect width="16" height="20" x="4" y="2" rx="2"></rect>
<line x1="8" x2="16" y1="6" y2="6"></line>
<line x1="16" x2="16" y1="14" y2="18"></line>
<path d="M16 10h.01"></path>
<path d="M12 10h.01"></path>
<path d="M8 10h.01"></path>
<path d="M12 14h.01"></path>
<path d="M8 14h.01"></path>
<path d="M12 18h.01"></path><path d="M8 18h.01"></path>
</svg>
""")
}
private func thermometerSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg xmlns="http://www.w3.org/2000/svg" width="\(size.width)" height="\(size.height)" viewBox="0 0 \(size.width) \(size.height)" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="w-8 h-8">
<path d="M14 4v10.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0Z"></path>
</svg>
""")
}
private func menuSvg(size: SVGSize) -> HTMLRaw {
HTMLRaw("""
<svg class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor"
viewBox="0 0 24 24" x="0" y="0" id="menu-icon">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
""")
}
// swiftlint:enable line_length