import Foundation import HTML import Saga func tagPrefix(index: Int, totalTags: Int) -> Node { if index > 0 { if index == totalTags - 1 { return " and " } else { return ", " } } return "" } func renderArticleInfo(_ article: Item) -> Node { div(class: "text-gray gray-links text-sm") { span(class: "border-r border-gray pr-2 mr-2") { article.date.formatted("MMMM dd, yyyy") } %.text("\(article.body.withoutHtmlTags.numberOfWords) words, posted in ") article.metadata.tags.sorted().enumerated().map { index, tag in Node.fragment([ %tagPrefix(index: index, totalTags: article.metadata.tags.count), %a(href: "/articles/tag/\(tag.slugified)/") { tag } ]) } } } func ogURL(_ article: Item) -> String { SiteMetadata.url .appendingPathComponent("/articles/images/\(article.url)") .absoluteString } @NodeBuilder func getArticleHeader(_ article: Item) -> NodeConvertible { link(href: "/static/prism.css", rel: "stylesheet") meta(content: article.summary, name: "description") meta(content: "summary_large_image", name: "twitter:card") meta(content: article.imagePath, name: "twitter:image") meta(content: article.title, name: "twitter:image:alt") meta(content: ogURL(article), name: "og:url") meta(content: article.title, name: "og:title") meta(content: article.summary, name: "og:description") meta(content: article.imagePath, name: "og:image") meta(content: "1014", name: "og:image:width") meta(content: "530", name: "og:image:height") script(crossorigin: "anonymous", src: "https://kit.fontawesome.com/f209982030.js") } func renderArticle(context: ItemRenderingContext) -> Node { let extraHeader = getArticleHeader(context.item) let allArticles = context.allItems.compactMap { $0 as? Item } let otherArticles = allArticles.filter { $0.url != context.item.url }.prefix(2) return baseLayout( canocicalURL: context.item.url, section: .articles, title: context.item.title, extraHeader: extraHeader ) { article(class: "prose") { h1 { context.item.title } div(class: "-mt-6") { renderArticleInfo(context.item) } img(alt: "banner", src: context.item.imagePath) Node.raw(context.item.body) } div(class: "border-t border-light mt-8 pt-8") { h2(class: "text-4xl font-extrabold mb-8") { "Written by" } div(class: "flex flex-col lg:flex-row gap-8") { div(class: "flex-[0_0_120px]") { img(class: "w-[120px] h-[120px] rounded-full", src: "/static/images/avatar.png") } div(class: "prose") { h3(class: "!m-0") { SiteMetadata.author } p(class: "text-gray") { """ HVAC business owner with over 27 years of experience. Writes articles about HVAC, Programming, Home-Performance, and Building Science """ } } } } div(class: "mt-16") { h2(class: "text-4xl font-extrabold mb-8") { "More articles" } div(class: "grid lg:grid-cols-2 gap-10") { otherArticles.map { renderArticleForGrid(article: $0) } } p(class: "prose mt-8") { a(href: "/articles/") { "› See all articles" } } } // div(class: "border-t border-light mt-8 pt-8") { // Node.raw(""" // // """) // } } }