feat: Initial commit

This commit is contained in:
2025-02-19 17:01:08 -05:00
commit e0fb6129ad
2362 changed files with 325107 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
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<ArticleMetadata>) -> 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<ArticleMetadata>) -> String {
SiteMetadata.url
.appendingPathComponent("/articles/images/\(article.url)")
.absoluteString
}
@NodeBuilder
func getArticleHeader(_ article: Item<ArticleMetadata>) -> 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<ArticleMetadata>) -> Node {
let extraHeader = getArticleHeader(context.item)
let allArticles = context.allItems.compactMap { $0 as? Item<ArticleMetadata> }
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("""
// <script src="https://giscus.app/client.js"
// data-repo="loopwerk/loopwerk.io"
// data-repo-id="MDEwOlJlcG9zaXRvcnk0Nzg0NTA3MA=="
// data-category="Article discussions"
// data-category-id="DIC_kwDOAtoOzs4Ciykw"
// data-mapping="pathname"
// data-strict="1"
// data-reactions-enabled="1"
// data-emit-metadata="0"
// data-input-position="bottom"
// data-theme="preferred_color_scheme"
// data-lang="en"
// data-loading="lazy"
// crossorigin="anonymous"
// async>
// </script>
// """)
// }
}
}