feat: Adds pocket id authentication to caddy, adds server management article.
All checks were successful
CI / release (push) Successful in 6m31s
All checks were successful
CI / release (push) Successful in 6m31s
This commit is contained in:
@@ -21,10 +21,10 @@ func baseLayout(
|
||||
.documentType("html"),
|
||||
html(lang: "en-US") {
|
||||
generateHead(pageTitle, extraHeader)
|
||||
body(class: "text-white text-lg pb-5 font-avenir \(section.rawValue)") {
|
||||
body(class: "text-white text-lg font-avenir \(section.rawValue)") {
|
||||
siteHeader(section)
|
||||
|
||||
div(class: "container mb-auto") {
|
||||
div(class: "mb-auto") {
|
||||
children()
|
||||
}
|
||||
if section == .articles {
|
||||
@@ -57,9 +57,7 @@ private func siteHeader(_ section: Section) -> Node {
|
||||
}
|
||||
}
|
||||
}
|
||||
// if section == .home {
|
||||
div(class: "font-avenir w-full pt-4", id: "search") {}
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,25 +97,38 @@ func renderArticle(context: ItemRenderingContext<ArticleMetadata>) -> Node {
|
||||
title: context.item.title,
|
||||
extraHeader: generateHeader(.article(context.item))
|
||||
) {
|
||||
article(class: "pt-8") {
|
||||
h1 { context.item.title }
|
||||
div {
|
||||
renderArticleInfo(context.item)
|
||||
}
|
||||
// Only index the body of the articles for search.
|
||||
div(customAttributes: ["data-pagefind-body": ""]) {
|
||||
Node.raw(context.item.body)
|
||||
article(class: "pt-8 mx-10") {
|
||||
div(class: "bg-slate-800 py-10") {
|
||||
div(class: "mx-10") {
|
||||
h1 { context.item.title }
|
||||
div {
|
||||
renderArticleInfo(context.item)
|
||||
}
|
||||
// Only index the body of the articles for search.
|
||||
div(customAttributes: ["data-pagefind-body": ""]) {
|
||||
Node.raw(context.item.body)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div(class: "border-t border-light pt-8 mt-16", id: "recents") {
|
||||
div(class: "border-t border-light p-10 mt-16", id: "recents") {
|
||||
div(class: "grid lg:grid-cols-2") {
|
||||
h4(class: "text-3xl text-amber-500 font-extrabold mb-8") { otherArticles.title }
|
||||
if let tag = otherArticles.tag {
|
||||
a(href: "/articles/tag/\(tag)") {
|
||||
div(class: " [&:hover]:border-b border-orange px-5 flex flex-row gap-5") {
|
||||
img(src: "/static/img/tag.svg", width: "40")
|
||||
span(class: "text-4xl font-extrabold text-orange") { tag }
|
||||
div(class: " [&:hover]:border-b border-green-500 px-5 flex flex-row gap-5") {
|
||||
img(class: "-mt-2", src: "/static/img/tag.svg", width: "40")
|
||||
div(class: "block") {
|
||||
div(class: "block") {
|
||||
span(class: "mt-2 text-4xl font-extrabold text-orange") { tag }
|
||||
}
|
||||
div(class: "block") {
|
||||
span(class: "text-sm text-orange-400") {
|
||||
"View related articles with this tag."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,16 +150,18 @@ func renderArticle(context: ItemRenderingContext<ArticleMetadata>) -> Node {
|
||||
}
|
||||
}
|
||||
|
||||
func renderArticleForGrid(article: Item<ArticleMetadata>) -> Node {
|
||||
section {
|
||||
h3(class: "post-title text-2xl font-bold mb-2") {
|
||||
a(class: "[&:hover]:border-b border-orange-400", href: article.url) { article.title }
|
||||
}
|
||||
renderArticleInfo(article)
|
||||
p {
|
||||
a(href: article.url) {
|
||||
div {
|
||||
article.summary
|
||||
func renderArticleForGrid(article: Item<ArticleMetadata>, border: Bool = true) -> Node {
|
||||
div(class: "bg-slate-800\(border ? " border border-slate-400 rounded-lg" : "")") {
|
||||
section(class: "m-4") {
|
||||
h3(class: "post-title text-2xl font-bold mb-2") {
|
||||
a(class: "[&:hover]:border-b border-green-500", href: article.url) { article.title }
|
||||
}
|
||||
renderArticleInfo(article)
|
||||
p {
|
||||
a(href: article.url) {
|
||||
div {
|
||||
article.summary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,16 @@ func renderArticles(context: ItemsRenderingContext<ArticleMetadata>) -> Node {
|
||||
return baseLayout(canocicalURL: "/articles/", section: .articles, title: "Articles", rssLink: "", extraHeader: "") {
|
||||
// TODO: Add list of tags here that can be navigated to.
|
||||
sortedByYearDescending.map { year, articles in
|
||||
div {
|
||||
div(class: "border-b border-light flex flex-row gap-4 mb-12") {
|
||||
img(src: "/static/img/calendar.svg", width: "40")
|
||||
h1(class: "text-4xl font-extrabold pt-3") { year }
|
||||
}
|
||||
div(class: "mt-8 bg-slate-800") {
|
||||
div(class: "pt-8 mx-10") {
|
||||
div(class: "border-b border-light flex flex-row gap-4 mb-12") {
|
||||
img(src: "/static/img/calendar.svg", width: "40")
|
||||
h1(class: "text-4xl font-extrabold pt-3") { year }
|
||||
}
|
||||
|
||||
div(class: "grid gap-10 mb-16") {
|
||||
articles.map { renderArticleForGrid(article: $0) }
|
||||
div(class: "grid gap-10 mb-16") {
|
||||
articles.map { renderArticleForGrid(article: $0, border: false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,60 +65,6 @@ func renderYear<T>(context: PartitionedRenderingContext<T, ArticleMetadata>) ->
|
||||
baseRenderArticles(context.items, canocicalURL: "/articles/\(context.key)/", title: "Articles in \(context.key)")
|
||||
}
|
||||
|
||||
private struct SearchData: Encodable {
|
||||
let url: String
|
||||
let title: String
|
||||
let body: String
|
||||
|
||||
init(article: Item<ArticleMetadata>) throws {
|
||||
self.url = article.url
|
||||
self.title = article.title
|
||||
let rawContent: String = try article.absoluteSource.read()
|
||||
self.body = Self.parse(rawContent)
|
||||
}
|
||||
|
||||
/// Grabs the metadata (wrapped within `---`), the first title, and the body of the document.
|
||||
static func parts(from content: String) -> (String?, String?, String) {
|
||||
let scanner = Scanner(string: content)
|
||||
|
||||
var header: String? = nil
|
||||
var title: String? = nil
|
||||
|
||||
if scanner.scanString("---") == "---" {
|
||||
header = scanner.scanUpToString("---")
|
||||
_ = scanner.scanString("---")
|
||||
}
|
||||
|
||||
if scanner.scanString("# ") == "# " {
|
||||
title = scanner.scanUpToString("\n")
|
||||
}
|
||||
|
||||
let body = String(scanner.string[scanner.currentIndex...])
|
||||
|
||||
return (header, title, body)
|
||||
}
|
||||
|
||||
static func parse(_ content: String) -> String {
|
||||
let (_, _, body) = parts(from: content)
|
||||
return body
|
||||
.replacingOccurrences(of: "\n", with: " ")
|
||||
.replacingOccurrences(of: "#", with: "")
|
||||
}
|
||||
}
|
||||
|
||||
func renderJson(_ articles: ItemsRenderingContext<ArticleMetadata>) throws -> String {
|
||||
print(articles.items.count)
|
||||
print(articles.items)
|
||||
let data = try jsonEncoder.encode(articles.items.map(SearchData.init(article:)))
|
||||
return String(data: data, encoding: .utf8)!
|
||||
}
|
||||
|
||||
private let jsonEncoder: JSONEncoder = {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
|
||||
return encoder
|
||||
}()
|
||||
|
||||
private func baseRenderArticles(
|
||||
_ articles: [Item<ArticleMetadata>],
|
||||
canocicalURL: String,
|
||||
|
||||
@@ -31,63 +31,65 @@ func renderHome(body: String) -> Node {
|
||||
Node.raw(body)
|
||||
}
|
||||
div {
|
||||
h2 { "Quick Links" }
|
||||
div(class: "grid lg:grid-cols-2 gap-6") {
|
||||
HomeLink.internal(
|
||||
"Articles",
|
||||
icon: "newspaper",
|
||||
href: "/articles/",
|
||||
description: "Click here to view all articles."
|
||||
)
|
||||
div(class: "bg-slate-800 p-10 rounded-lg border border-slate-400") {
|
||||
h2 { "Quick Links" }
|
||||
div(class: "grid lg:grid-cols-2 gap-6") {
|
||||
HomeLink.internal(
|
||||
"Articles",
|
||||
icon: "newspaper",
|
||||
href: "/articles/",
|
||||
description: "Click here to view all articles."
|
||||
)
|
||||
|
||||
HomeLink.external(
|
||||
"Purchase Orders",
|
||||
icon: "calculator",
|
||||
href: "https://po.housh.dev",
|
||||
description: "Purchase orders application."
|
||||
)
|
||||
HomeLink.external(
|
||||
"Purchase Orders",
|
||||
icon: "calculator",
|
||||
href: "https://po.housh.dev",
|
||||
description: "Purchase orders application."
|
||||
)
|
||||
|
||||
HomeLink.external(
|
||||
"Service Monitor",
|
||||
icon: "heart-pulse",
|
||||
href: "https://uptime.housh.dev/status/housh-dev",
|
||||
description: "Server and services uptime status page."
|
||||
)
|
||||
HomeLink.external(
|
||||
"Service Monitor",
|
||||
icon: "heart-pulse",
|
||||
href: "https://uptime.housh.dev/status/housh-dev",
|
||||
description: "Server and services uptime status page."
|
||||
)
|
||||
|
||||
HomeLink.external(
|
||||
"Unifi Console",
|
||||
icon: "earth",
|
||||
href: "https://unifi.ui.com",
|
||||
description: "Network management."
|
||||
)
|
||||
HomeLink.external(
|
||||
"Unifi Console",
|
||||
icon: "earth",
|
||||
href: "https://unifi.ui.com",
|
||||
description: "Network management."
|
||||
)
|
||||
|
||||
HomeLink.external(
|
||||
"Excalidraw",
|
||||
icon: "pen-tool",
|
||||
href: "https://draw.housh.dev",
|
||||
description: "A drawing utility that runs locally in your browser."
|
||||
)
|
||||
HomeLink.external(
|
||||
"Excalidraw",
|
||||
icon: "pen-tool",
|
||||
href: "https://draw.housh.dev",
|
||||
description: "A drawing utility that runs locally in your browser."
|
||||
)
|
||||
|
||||
HomeLink.external(
|
||||
"Gitea",
|
||||
icon: "git-branch",
|
||||
href: "https://git.housh.dev/explore/repos",
|
||||
description: "Explore source code."
|
||||
)
|
||||
HomeLink.external(
|
||||
"Gitea",
|
||||
icon: "git-branch",
|
||||
href: "https://git.housh.dev/explore/repos",
|
||||
description: "Explore source code."
|
||||
)
|
||||
|
||||
HomeLink.external(
|
||||
"Legacy Purchase Orders",
|
||||
icon: "file-archive",
|
||||
href: "https://legach-po.housh.dev",
|
||||
description: "Legacy purchase order application (pre-2025)."
|
||||
)
|
||||
HomeLink.external(
|
||||
"Legacy Purchase Orders",
|
||||
icon: "file-archive",
|
||||
href: "https://legach-po.housh.dev",
|
||||
description: "Legacy purchase order application (pre-2025)."
|
||||
)
|
||||
|
||||
HomeLink.external(
|
||||
"HVAC Toolbox",
|
||||
icon: "hammer",
|
||||
href: "https://hvac-toolbox.com",
|
||||
description: "A collection of HVAC calculators."
|
||||
)
|
||||
HomeLink.external(
|
||||
"HVAC Toolbox",
|
||||
icon: "hammer",
|
||||
href: "https://hvac-toolbox.com",
|
||||
description: "A collection of HVAC calculators."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
script(src: "https://unpkg.com/lucide@latest")
|
||||
|
||||
Reference in New Issue
Block a user