mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-04-27 14:57:40 +00:00
Make it work by using dictionaries in template context 👎
This is a work-around but it works.
This commit is contained in:
parent
57de420eee
commit
4a03060c8c
6 changed files with 87 additions and 43 deletions
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct Month {
|
struct Month: Equatable {
|
||||||
static let names = [
|
static let names = [
|
||||||
"January", "Februrary", "March", "April",
|
"January", "Februrary", "March", "April",
|
||||||
"May", "June", "July", "August",
|
"May", "June", "July", "August",
|
||||||
|
|
@ -16,15 +16,49 @@ struct Month {
|
||||||
|
|
||||||
let number: Int
|
let number: Int
|
||||||
|
|
||||||
|
init(_ number: Int) {
|
||||||
|
precondition((1 ... 12).contains(number), "Month number must be from 1 to 12, got \(number)")
|
||||||
|
self.number = number
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ name: String) {
|
||||||
|
precondition(Month.names.contains(name), "Month name is unknown: \(name)")
|
||||||
|
self.number = 1 + Month.names.firstIndex(of: name)!
|
||||||
|
}
|
||||||
|
|
||||||
var padded: String {
|
var padded: String {
|
||||||
String(format: "%02d", number)
|
String(format: "%02d", number)
|
||||||
}
|
}
|
||||||
|
|
||||||
var name: String {
|
var name: String {
|
||||||
Month.names[number]
|
Month.names[number - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
var abbreviatedName: String {
|
var abbreviatedName: String {
|
||||||
String(name.prefix(3))
|
String(name.prefix(3))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Month: Hashable {
|
||||||
|
func hash(into hasher: inout Hasher) {
|
||||||
|
hasher.combine(number)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Month: Comparable {
|
||||||
|
static func <(lhs: Month, rhs: Month) -> Bool {
|
||||||
|
lhs.number < rhs.number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Month: ExpressibleByIntegerLiteral {
|
||||||
|
init(integerLiteral value: Int) {
|
||||||
|
self.init(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Month: ExpressibleByStringLiteral {
|
||||||
|
init(stringLiteral value: String) {
|
||||||
|
self.init(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct MonthPosts {
|
struct MonthPosts {
|
||||||
let month: Int
|
let month: Month
|
||||||
var posts: [Post]
|
var posts: [Post]
|
||||||
|
|
||||||
var isEmpty: Bool {
|
var isEmpty: Bool {
|
||||||
|
|
@ -18,9 +18,9 @@ struct MonthPosts {
|
||||||
|
|
||||||
struct YearPosts {
|
struct YearPosts {
|
||||||
let year: Int
|
let year: Int
|
||||||
var byMonth: [Int: MonthPosts]
|
var byMonth: [Month: MonthPosts]
|
||||||
|
|
||||||
subscript(month: Int) -> MonthPosts {
|
subscript(month: Month) -> MonthPosts {
|
||||||
get {
|
get {
|
||||||
byMonth[month, default: MonthPosts(month: month, posts: [])]
|
byMonth[month, default: MonthPosts(month: month, posts: [])]
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ struct PostsByYear {
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func add(post: Post) {
|
mutating func add(post: Post) {
|
||||||
let (year, month) = (post.date.year, post.date.month)
|
let (year, month) = (post.date.year, Month(post.date.month))
|
||||||
self[year][month].posts.append(post)
|
self[year][month].posts.append(post)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,18 +29,16 @@ final class PostsPlugin: Plugin {
|
||||||
|
|
||||||
let posts = try enumerateMarkdownFiles(directory: postsURL)
|
let posts = try enumerateMarkdownFiles(directory: postsURL)
|
||||||
.compactMap { (url: URL) -> Post? in
|
.compactMap { (url: URL) -> Post? in
|
||||||
guard let result = (try? String(contentsOf: url)).map(markdownParser.parse) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
do {
|
do {
|
||||||
return try Post(bodyMarkdown: "(TEST)", metadata: result.metadata)
|
let markdown = try String(contentsOf: url)
|
||||||
|
let result = markdownParser.parse(markdown)
|
||||||
|
return try Post(bodyMarkdown: result.html, metadata: result.metadata)
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
print("Cannot create post from markdown file \(url): \(error)")
|
print("Cannot create post from markdown file \(url): \(error)")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print("posts: \(posts)")
|
|
||||||
self.posts = PostsByYear(posts: posts)
|
self.posts = PostsByYear(posts: posts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,12 +74,12 @@ final class PostsPlugin: Plugin {
|
||||||
|
|
||||||
func renderYearsAndMonths(postsDir: URL, templateRenderer: TemplateRenderer) throws {
|
func renderYearsAndMonths(postsDir: URL, templateRenderer: TemplateRenderer) throws {
|
||||||
print("renderYearsAndMonths(postsDir: \(postsDir), templateRenderer: \(templateRenderer)")
|
print("renderYearsAndMonths(postsDir: \(postsDir), templateRenderer: \(templateRenderer)")
|
||||||
let allMonths = (1 ... 12).reversed().map(Month.init)
|
let allMonths = (1 ... 12).map(Month.init(_:))
|
||||||
for (year, monthPosts) in posts.byYear.sorted(by: { $1.key < $0.key }) {
|
for (year, monthPosts) in posts.byYear.sorted(by: { $1.key < $0.key }) {
|
||||||
let yearDir = postsDir.appendingPathComponent("\(year)")
|
let yearDir = postsDir.appendingPathComponent("\(year)")
|
||||||
var sortedPostsByMonth: [Int: [RenderedPost]] = [:]
|
var sortedPostsByMonth: [Month: [RenderedPost]] = [:]
|
||||||
for month in allMonths {
|
for month in allMonths {
|
||||||
let sortedPosts = monthPosts[month.number].posts.sorted(by: { $1.date < $0.date })
|
let sortedPosts = monthPosts[month].posts.sorted(by: { $1.date < $0.date })
|
||||||
guard !sortedPosts.isEmpty else {
|
guard !sortedPosts.isEmpty else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -90,7 +88,7 @@ final class PostsPlugin: Plugin {
|
||||||
let bodyHTML = markdownParser.html(from: post.bodyMarkdown)
|
let bodyHTML = markdownParser.html(from: post.bodyMarkdown)
|
||||||
return RenderedPost(post: post, body: bodyHTML)
|
return RenderedPost(post: post, body: bodyHTML)
|
||||||
}
|
}
|
||||||
sortedPostsByMonth[month.number] = renderedPosts
|
sortedPostsByMonth[month] = renderedPosts
|
||||||
|
|
||||||
let monthDir = yearDir.appendingPathComponent(month.padded)
|
let monthDir = yearDir.appendingPathComponent(month.padded)
|
||||||
try fileManager.createDirectory(at: monthDir, withIntermediateDirectories: true, attributes: nil)
|
try fileManager.createDirectory(at: monthDir, withIntermediateDirectories: true, attributes: nil)
|
||||||
|
|
@ -101,11 +99,23 @@ final class PostsPlugin: Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
try fileManager.createDirectory(at: yearDir, withIntermediateDirectories: true, attributes: nil)
|
try fileManager.createDirectory(at: yearDir, withIntermediateDirectories: true, attributes: nil)
|
||||||
|
let months = Array(sortedPostsByMonth.keys.sorted().reversed())
|
||||||
|
let postsByMonthForContext: [String: [[String: Any]]] = sortedPostsByMonth.reduce(into: [:]) { dict, pair in
|
||||||
|
let (month, renderedPosts) = pair
|
||||||
|
dict[month.padded] = renderedPosts.map { $0.dictionary }
|
||||||
|
}
|
||||||
|
let monthsPadded = months.map { $0.padded }
|
||||||
let context: [String: Any] = [
|
let context: [String: Any] = [
|
||||||
"path": path,
|
"path": path,
|
||||||
"year": year,
|
"year": year,
|
||||||
"months": sortedPostsByMonth.keys.sorted().reversed().map(Month.init),
|
"months": monthsPadded,
|
||||||
"postsByMonth": sortedPostsByMonth,
|
"monthNames": months.reduce(into: [String: String](), { dict, month in
|
||||||
|
dict[month.padded] = month.name
|
||||||
|
}),
|
||||||
|
"monthAbbreviations": months.reduce(into: [String: String](), { dict, month in
|
||||||
|
dict[month.padded] = month.abbreviatedName
|
||||||
|
}),
|
||||||
|
"postsByMonth": postsByMonthForContext,
|
||||||
]
|
]
|
||||||
let yearHTML = try templateRenderer.renderTemplate(name: "posts-year", context: context)
|
let yearHTML = try templateRenderer.renderTemplate(name: "posts-year", context: context)
|
||||||
let yearURL = yearDir.appendingPathComponent("index.html")
|
let yearURL = yearDir.appendingPathComponent("index.html")
|
||||||
|
|
@ -121,7 +131,7 @@ final class PostsPlugin: Plugin {
|
||||||
let templateName = self.templateName(for: post)
|
let templateName = self.templateName(for: post)
|
||||||
let bodyHTML = markdownParser.html(from: post.bodyMarkdown)
|
let bodyHTML = markdownParser.html(from: post.bodyMarkdown)
|
||||||
let renderedPost = RenderedPost(post: post, body: bodyHTML)
|
let renderedPost = RenderedPost(post: post, body: bodyHTML)
|
||||||
let postHTML = try templateRenderer.renderTemplate(name: templateName, context: ["post": renderedPost])
|
let postHTML = try templateRenderer.renderTemplate(name: templateName, context: ["post": renderedPost.dictionary])
|
||||||
try postHTML.write(to: postURL, atomically: true, encoding: .utf8)
|
try postHTML.write(to: postURL, atomically: true, encoding: .utf8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,17 @@ struct RenderedPost {
|
||||||
let post: Post
|
let post: Post
|
||||||
let body: String
|
let body: String
|
||||||
|
|
||||||
var author: String { post.author }
|
var dictionary: [String: Any] {
|
||||||
|
[
|
||||||
var title: String { post.title }
|
"author": post.author,
|
||||||
|
"title": post.title,
|
||||||
var date: Date { post.date }
|
"date": post.date,
|
||||||
|
"day": post.date.day,
|
||||||
var formattedDate: String { post.formattedDate }
|
"formattedDate": post.formattedDate,
|
||||||
|
"isLink": post.isLink,
|
||||||
var isLink: Bool { post.isLink }
|
"link": post.link as Any,
|
||||||
|
"path": post.path,
|
||||||
var link: URL? { post.link }
|
"body": body,
|
||||||
|
]
|
||||||
var path: String { post.path }
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<article class="container">
|
<article class="container">
|
||||||
<header>
|
<header>
|
||||||
<h1><a href="{{ post.url }}">{{ post.title }}</a></h1>
|
<h1><a href="{{ post.path }}">{{ post.title }}</a></h1>
|
||||||
<time>{{ post.formattedDate }}</time>
|
<time>{{ post.formattedDate }}</time>
|
||||||
</header>
|
</header>
|
||||||
{{ post.body }}
|
{{ post.body }}
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,24 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>{{ year }}</h2>
|
<h2>{{ year }}</h2>
|
||||||
|
|
||||||
{% for month in months %}
|
{% for month in months %}
|
||||||
<h3>
|
<h3>
|
||||||
<a href="/{{ path }}/{{ year }}/{{ month.padded }}">{{ month.name }}</a>
|
<a href="/{{ path }}/{{ year }}/{{ month }}">{{ monthNames[month] }}</a>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<ul class="archive">
|
<ul class="archive">
|
||||||
{% for post in postsByMonth[month.number] %}
|
{% for post in postsByMonth[month] %}
|
||||||
<li>
|
<li>
|
||||||
{% if post.isLink %}
|
{% if post.isLink %}
|
||||||
<a href="{{ post.path }}">→ {{ post.title }}</a>
|
<a href="{{ post.path }}">→ {{ post.title }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ post.path }}">{{ post.title }}</a>
|
<a href="{{ post.path }}">{{ post.title }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<time>{{ post.date.day }} {{ month.abbreviatedName }}</time>
|
<time>{{ post.day }} {{ monthAbbreviations[month] }}</time>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue