feat: Ports all existing articles and images.
This commit is contained in:
@@ -27,4 +27,11 @@ extension String {
|
||||
|
||||
return prefix(length - end.count).split(separator: " ").dropLast().joined(separator: " ") + end
|
||||
}
|
||||
|
||||
var removeBreaks: String {
|
||||
replacingOccurrences(of: "<br>", with: "")
|
||||
.replacingOccurrences(of: "<br />", with: "")
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import HTML
|
||||
import PathKit
|
||||
@preconcurrency import Saga
|
||||
import SagaParsleyMarkdownReader
|
||||
@@ -45,6 +46,12 @@ func permalink(item: Item<ArticleMetadata>) {
|
||||
item.relativeDestination = Path(components: components)
|
||||
}
|
||||
|
||||
func removingBreaks<M>(item: Item<M>) {
|
||||
// remove explicit <br /> from items that show up likely due to how prettier formats
|
||||
// markdown files inside of neovim.
|
||||
item.body = item.body.removeBreaks
|
||||
}
|
||||
|
||||
@main
|
||||
struct Run {
|
||||
static func main() async throws {
|
||||
@@ -56,14 +63,13 @@ struct Run {
|
||||
folder: "articles",
|
||||
metadata: ArticleMetadata.self,
|
||||
readers: [.parsleyMarkdownReader],
|
||||
itemProcessor: sequence(publicationDateInFilename, permalink),
|
||||
itemProcessor: sequence(removingBreaks, publicationDateInFilename, permalink),
|
||||
filter: \.public,
|
||||
writers: [
|
||||
.itemWriter(swim(renderArticle)),
|
||||
.listWriter(swim(renderArticles)),
|
||||
.tagWriter(swim(renderTag), tags: \.metadata.tags),
|
||||
.yearWriter(swim(renderYear)),
|
||||
|
||||
// Atom feed for all articles, and a feed per tag
|
||||
.listWriter(
|
||||
atomFeed(
|
||||
@@ -84,27 +90,12 @@ struct Run {
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
// All markdown files within the "apps" subfolder will be parsed to html,
|
||||
// using AppMetadata as the Item's metadata type.
|
||||
// .register(
|
||||
// folder: "apps",
|
||||
// metadata: AppMetadata.self,
|
||||
// readers: [.parsleyMarkdownReader],
|
||||
// writers: [.listWriter(swim(renderApps))]
|
||||
// )
|
||||
//
|
||||
// .register(
|
||||
// folder: "photos",
|
||||
// readers: [.parsleyMarkdownReader],
|
||||
// writers: [.itemWriter(swim(renderPhotos))]
|
||||
// )
|
||||
|
||||
// All the remaining markdown files will be parsed to html,
|
||||
// using the default EmptyMetadata as the Item's metadata type.
|
||||
.register(
|
||||
metadata: PageMetadata.self,
|
||||
readers: [.parsleyMarkdownReader],
|
||||
itemWriteMode: .keepAsFile, // need to keep 404.md as 404.html, not 404/index.html
|
||||
writers: [.itemWriter(swim(renderPage))]
|
||||
)
|
||||
|
||||
|
||||
@@ -78,6 +78,9 @@ private func footer(_ rssLink: String) -> Node {
|
||||
" | "
|
||||
a(href: "mailto:michael@mhoush.com", rel: "nofollow") { "Email" }
|
||||
}
|
||||
script(src: "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js")
|
||||
script(src: "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/keep-markup/prism-keep-markup.min.js")
|
||||
script(src: "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ func renderArticleForGrid(article: Item<ArticleMetadata>) -> Node {
|
||||
p {
|
||||
a(href: article.url) {
|
||||
div {
|
||||
img(alt: "banner", src: article.imagePath)
|
||||
// img(alt: "banner", src: article.imagePath)
|
||||
article.summary
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,13 @@ func renderArticles(context: ItemsRenderingContext<ArticleMetadata>) -> Node {
|
||||
}
|
||||
}
|
||||
|
||||
func _renderArticles(_ articles: [Item<ArticleMetadata>], canocicalURL: String, title pageTitle: String, rssLink: String = "", extraHeader: NodeConvertible = Node.fragment([])) -> Node {
|
||||
func _renderArticles(
|
||||
_ articles: [Item<ArticleMetadata>],
|
||||
canocicalURL: String,
|
||||
title pageTitle: String,
|
||||
rssLink: String = "",
|
||||
extraHeader: NodeConvertible = Node.fragment([])
|
||||
) -> Node {
|
||||
return baseLayout(canocicalURL: canocicalURL, section: .articles, title: pageTitle, rssLink: rssLink, extraHeader: extraHeader) {
|
||||
articles.map { article in
|
||||
section(class: "mb-10") {
|
||||
@@ -73,9 +79,20 @@ func _renderArticles(_ articles: [Item<ArticleMetadata>], canocicalURL: String,
|
||||
}
|
||||
|
||||
func renderTag<T>(context: PartitionedRenderingContext<T, ArticleMetadata>) -> Node {
|
||||
let extraHeader = link(href: "/articles/tag/\(context.key.slugified)/feed.xml", rel: "alternate", title: "\(SiteMetadata.name): articles with tag \(context.key)", type: "application/rss+xml")
|
||||
let extraHeader = link(
|
||||
href: "/articles/tag/\(context.key.slugified)/feed.xml",
|
||||
rel: "alternate",
|
||||
title: "\(SiteMetadata.name): articles with tag \(context.key)",
|
||||
type: "application/rss+xml"
|
||||
)
|
||||
|
||||
return _renderArticles(context.items, canocicalURL: "/articles/tag/\(context.key.slugified)/", title: "Articles in \(context.key)", rssLink: "tag/\(context.key.slugified)/", extraHeader: extraHeader)
|
||||
return _renderArticles(
|
||||
context.items,
|
||||
canocicalURL: "/articles/tag/\(context.key.slugified)/",
|
||||
title: "Articles in \(context.key)",
|
||||
rssLink: "tag/\(context.key.slugified)/",
|
||||
extraHeader: extraHeader
|
||||
)
|
||||
}
|
||||
|
||||
func renderYear<T>(context: PartitionedRenderingContext<T, ArticleMetadata>) -> Node {
|
||||
|
||||
Reference in New Issue
Block a user