import Foundation import HTML /// The base page layout used to render the different sections of the website. /// /// - Parameters: /// - conocicalURL: The url for the page. /// - section: The section of the page. /// - title: The page title. /// - rssLink: A prefix for generating an rss feed for the page (generally only used for articles). /// - extraHeader: Any extra items to be placed in the `head` of the html. func baseLayout( canocicalURL: String, section: Section, title pageTitle: String, rssLink: String = "", extraHeader: NodeConvertible = Node.fragment([]), @NodeBuilder children: () -> NodeConvertible ) -> Node { return [ .documentType("html"), html(lang: "en-US") { generateHead(pageTitle, extraHeader) body(class: "text-white text-lg font-avenir \(section.rawValue)") { siteHeader(section) // mx-10 div(class: "mb-auto") { children() } if section == .articles { footer(rssLink) } // NOTE: These need to stay at / near bottom of page, so that icons are // generated properly. script(src: "https://unpkg.com/lucide@latest") Node.raw(""" """) } } ] } private func siteHeader(_ section: Section) -> Node { header(class: "header") { div(class: "header__inner") { div(class: "header__logo") { a(href: "/") { div(class: "logo") { img(src: "/static/favicon-32x32.png") span(class: "pl-2") { "docs.housh.dev" } } } } } // TODO: Explore search being hidden / triggered by a button and hover above // the page content. div(class: "font-avenir w-full p-4 px-8", id: "search") {} div(class: "mt-2 mb-0 w-full border-b border-slate-200") } } private func footer(_ rssLink: String) -> Node { div(class: "text-slate-400 border-t border-light text-center pt-2 text-sm") { div { "Copyright © Michael Housh \(Date().description.prefix(4))." } p(class: "mb-2") { "Built in Swift using" a( class: "text-orange-400 [&:hover]:border-b border-green-400", href: "https://github.com/loopwerk/Saga", rel: "nofollow", target: "_blank" ) { "Saga" } "(" %a( class: "[&:hover]:border-b border-green-400", href: "https://git.housh.dev/homelab/docs", rel: "nofollow", target: "_blank" ) { "source" } %")." } } } private func generateHead(_ pageTitle: String, _ extraHeader: NodeConvertible) -> Node { head { meta(charset: "utf-8") meta(content: "#0e1112", name: "theme-color", customAttributes: ["media": "(prefers-color-scheme: dark)"]) meta(content: "#566B78", name: "theme-color", customAttributes: ["media": "(prefers-color-scheme: light)"]) meta(content: "Michael Housh", name: "author") meta(content: "HHE-Docs", name: "apple-mobile-web-app-title") meta(content: "initial-scale=1.0, width=device-width", name: "viewport") meta(content: "telephone=no", name: "format-detection") meta(content: "True", name: "HandheldFriendly") meta(content: "320", name: "MobileOptimized") meta(content: "HHE-Docs", name: "og:site_name") meta(content: "hvac, developer, swift, home-performance, design", name: "keywords") title { SiteMetadata.name + ": \(pageTitle)" } Node.raw(""" """) link(href: "/static/output.css", rel: "stylesheet") link(href: "/articles/feed.xml", rel: "alternate", title: SiteMetadata.name, type: "application/rss+xml") extraHeader Node.raw(""" """) link(href: "/static/style.css", rel: "stylesheet") } }