mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-03-25 09:05:47 +00:00
Fix various broken parts of posts templates
This commit is contained in:
parent
0a876c0c01
commit
5fac69542c
9 changed files with 85 additions and 57 deletions
|
|
@ -73,14 +73,16 @@ Execution, trying TDD for the first time:
|
|||
|
||||
- [x] Search for other _data.json and .ejs files and eliminate any that are found
|
||||
|
||||
- [ ] Link years to year indexes in the posts archive
|
||||
- [x] Link years to year indexes in the posts archive
|
||||
|
||||
- [ ] Fix missing days on post dates in the archive and year indexes
|
||||
- [x] Fix missing days on post dates in the archive and year indexes
|
||||
|
||||
- [ ] Find a way to add the site name to HTML titles rendered by plugins
|
||||
- [x] Find a way to add the site name to HTML titles rendered by plugins
|
||||
|
||||
- [ ] Clean up the posts plugin
|
||||
|
||||
- [ ] Why don't plain data structures always work with Stencil? Maybe computed properties are a no-go but we can at least use structs instead of dictionaries for the actual rendering
|
||||
|
||||
- [ ] Consider using Swift for samhuri.net as well, and then making SiteGenerator a package that it uses ... then we can use Plot or pointfree.co's swift-html
|
||||
|
||||
- [ ] Replace remaining Ruby with Swift
|
||||
|
|
|
|||
|
|
@ -12,14 +12,6 @@ struct PageContext {
|
|||
let body: String
|
||||
let page: Page
|
||||
let metadata: [String: String]
|
||||
|
||||
var title: String {
|
||||
guard !page.title.isEmpty else {
|
||||
return site.title
|
||||
}
|
||||
|
||||
return "\(site.title): \(page.title)"
|
||||
}
|
||||
}
|
||||
|
||||
extension PageContext: TemplateContext {
|
||||
|
|
@ -30,7 +22,6 @@ extension PageContext: TemplateContext {
|
|||
var dictionary: [String: Any] {
|
||||
[
|
||||
"site": site,
|
||||
"title": title,
|
||||
"body": body,
|
||||
"page": page,
|
||||
"metadata": metadata,
|
||||
|
|
|
|||
|
|
@ -17,20 +17,28 @@ struct Post {
|
|||
let tags: [String]
|
||||
let bodyMarkdown: String
|
||||
|
||||
var isLink: Bool {
|
||||
link != nil
|
||||
var dictionary: [String: Any] {
|
||||
var result: [String: Any] = [
|
||||
"slug": slug,
|
||||
"title": title,
|
||||
"author": author,
|
||||
"day": date.day,
|
||||
"month": date.month,
|
||||
"year": date.year,
|
||||
"formattedDate": formattedDate,
|
||||
"tags": tags
|
||||
]
|
||||
if let link = link {
|
||||
result["isLink"] = true
|
||||
result["link"] = link
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
var path: String {
|
||||
let dateComponents = Calendar.current.dateComponents([.year, .month], from: date)
|
||||
let year = dateComponents.year!
|
||||
let month = dateComponents.month!
|
||||
return "/" + [
|
||||
"posts",
|
||||
String(format: "%02d", year),
|
||||
String(format: "%02d", month),
|
||||
"\(slug)",
|
||||
].joined(separator: "/")
|
||||
func dictionary(withPath path: String) -> [String: Any] {
|
||||
var dict = dictionary
|
||||
dict["path"] = path
|
||||
return dict
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ final class PostsPlugin: Plugin {
|
|||
print("renderPostsByDate(postsDir: \(postsDir), templateRenderer: \(templateRenderer)")
|
||||
for post in posts.flattened() {
|
||||
let monthDir = postsDir
|
||||
.appendingPathComponent(String(format: "%02d", post.date.year))
|
||||
.appendingPathComponent(String(format: "%02d", post.date.month))
|
||||
.appendingPathComponent("\(post.date.year)")
|
||||
.appendingPathComponent(Month(post.date.month).padded)
|
||||
try renderPost(post, monthDir: monthDir, templateRenderer: templateRenderer)
|
||||
}
|
||||
}
|
||||
|
|
@ -73,11 +73,10 @@ final class PostsPlugin: Plugin {
|
|||
let recentPosts = posts.flattened().prefix(10)
|
||||
let renderedRecentPosts: [[String: Any]] = recentPosts.map { post in
|
||||
let html = markdownParser.html(from: post.bodyMarkdown)
|
||||
return RenderedPost(post: post, body: html).dictionary
|
||||
let path = self.path(for: post)
|
||||
return RenderedPost(path: path, post: post, body: html).dictionary
|
||||
}
|
||||
#warning("FIXME: get the site name out of here somehow")
|
||||
let recentPostsHTML = try templateRenderer.renderTemplate(name: "recent-posts", context: [
|
||||
"title": "samhuri.net",
|
||||
"recentPosts": renderedRecentPosts,
|
||||
])
|
||||
let fileURL = targetURL.appendingPathComponent(recentPostsPath)
|
||||
|
|
@ -88,21 +87,23 @@ final class PostsPlugin: Plugin {
|
|||
print("renderArchive(postsDir: \(postsDir), templateRenderer: \(templateRenderer)")
|
||||
let allYears = posts.byYear.keys.sorted(by: >)
|
||||
let allMonths = (1 ... 12).map(Month.init(_:))
|
||||
let postsByMonthByYearForContext: [[String: Any]] = allYears.map { year in
|
||||
let yearsWithPostsByMonthForContext: [[String: Any]] = allYears.map { year in
|
||||
[
|
||||
"number": "\(year)",
|
||||
"months": posts[year].byMonth.keys.sorted(by: >).map { month in
|
||||
[
|
||||
"number": month.padded,
|
||||
"posts": posts[year][month].posts,
|
||||
"path": self.path(year: year),
|
||||
"title": "\(year)",
|
||||
"months": posts[year].byMonth.keys.sorted(by: >).map { (month: Month) -> [String: Any] in
|
||||
let sortedPosts = posts[year][month].posts.sorted(by: { $0.date > $1.date })
|
||||
return [
|
||||
"path": self.path(year: year, month: month),
|
||||
"title": month.padded,
|
||||
"posts": sortedPosts.map { $0.dictionary(withPath: self.path(for: $0)) },
|
||||
]
|
||||
} as Any,
|
||||
},
|
||||
]
|
||||
}
|
||||
let context: [String: Any] = [
|
||||
"title": "Archive",
|
||||
"path": postsPath,
|
||||
"years": postsByMonthByYearForContext,
|
||||
"years": yearsWithPostsByMonthForContext,
|
||||
"monthNames": allMonths.reduce(into: [String: String](), { dict, month in
|
||||
dict[month.padded] = month.name
|
||||
}),
|
||||
|
|
@ -130,11 +131,10 @@ final class PostsPlugin: Plugin {
|
|||
|
||||
try fileManager.createDirectory(at: yearDir, withIntermediateDirectories: true, attributes: nil)
|
||||
let months = Array(sortedPostsByMonth.keys.sorted().reversed())
|
||||
let postsByMonthForContext: [String: [Post]] = sortedPostsByMonth.reduce(into: [:]) { dict, pair in
|
||||
let postsByMonthForContext: [String: [[String: Any]]] = sortedPostsByMonth.reduce(into: [:]) { dict, pair in
|
||||
let (month, posts) = pair
|
||||
dict[month.padded] = posts
|
||||
dict[month.padded] = posts.map { $0.dictionary(withPath: self.path(for: $0)) }
|
||||
}
|
||||
#warning("FIXME: get the site name in the head title but not the body title")
|
||||
let context: [String: Any] = [
|
||||
"title": "\(year)",
|
||||
"path": postsPath,
|
||||
|
|
@ -166,12 +166,12 @@ final class PostsPlugin: Plugin {
|
|||
}
|
||||
|
||||
let renderedPosts = sortedPosts.map { post -> RenderedPost in
|
||||
let path = self.path(for: post)
|
||||
let bodyHTML = markdownParser.html(from: post.bodyMarkdown)
|
||||
return RenderedPost(post: post, body: bodyHTML)
|
||||
return RenderedPost(path: path, post: post, body: bodyHTML)
|
||||
}
|
||||
let monthDir = yearDir.appendingPathComponent(month.padded)
|
||||
try fileManager.createDirectory(at: monthDir, withIntermediateDirectories: true, attributes: nil)
|
||||
#warning("FIXME: get the site name in the head title but not the body title")
|
||||
let context: [String: Any] = [
|
||||
"title": "\(month.name) \(year)",
|
||||
"posts": renderedPosts.map { $0.dictionary },
|
||||
|
|
@ -187,10 +187,10 @@ final class PostsPlugin: Plugin {
|
|||
print("renderPost(\(post.debugDescription), monthDir: \(monthDir), templateRenderer: \(templateRenderer)")
|
||||
try fileManager.createDirectory(at: monthDir, withIntermediateDirectories: true, attributes: nil)
|
||||
let filename = "\(post.slug).html"
|
||||
let path = self.path(for: post)
|
||||
let postURL = monthDir.appendingPathComponent(filename)
|
||||
let bodyHTML = markdownParser.html(from: post.bodyMarkdown)
|
||||
let renderedPost = RenderedPost(post: post, body: bodyHTML)
|
||||
#warning("FIXME: get the site name in the head title but not the body title")
|
||||
let renderedPost = RenderedPost(path: path, post: post, body: bodyHTML)
|
||||
let postHTML = try templateRenderer.renderTemplate(name: "post", context: [
|
||||
"title": "\(renderedPost.post.title)",
|
||||
"post": renderedPost.dictionary,
|
||||
|
|
@ -211,4 +211,20 @@ final class PostsPlugin: Plugin {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func path(for post: Post) -> String {
|
||||
path(year: post.date.year, month: Month(post.date.month), filename: "\(post.slug).html")
|
||||
}
|
||||
|
||||
private func path(year: Int) -> String {
|
||||
"/\(postsPath)/\(year)"
|
||||
}
|
||||
|
||||
private func path(year: Int, month: Month) -> String {
|
||||
path(year: year).appending("/\(month.padded)")
|
||||
}
|
||||
|
||||
private func path(year: Int, month: Month, filename: String) -> String {
|
||||
path(year: year, month: month).appending("/\(filename)")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
import Foundation
|
||||
|
||||
struct RenderedPost {
|
||||
let path: String
|
||||
let post: Post
|
||||
let body: String
|
||||
|
||||
|
|
@ -18,9 +19,8 @@ struct RenderedPost {
|
|||
"date": post.date,
|
||||
"day": post.date.day,
|
||||
"formattedDate": post.formattedDate,
|
||||
"isLink": post.isLink,
|
||||
"link": post.link as Any,
|
||||
"path": post.path,
|
||||
"path": path,
|
||||
"body": body,
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ final class ProjectsPlugin: Plugin {
|
|||
let projectsDir = targetURL.appendingPathComponent(path)
|
||||
try fileManager.createDirectory(at: projectsDir, withIntermediateDirectories: true, attributes: nil)
|
||||
let projectsURL = projectsDir.appendingPathComponent("index.html")
|
||||
#warning("FIXME: get the site name in the head title but not the body title")
|
||||
let projectsHTML = try templateRenderer.renderTemplate(name: "projects", context: [
|
||||
"title": "Projects",
|
||||
"projects": projects,
|
||||
|
|
@ -56,7 +55,6 @@ final class ProjectsPlugin: Plugin {
|
|||
for project in projects {
|
||||
let filename = "\(project.title).html"
|
||||
let projectURL = projectsDir.appendingPathComponent(filename)
|
||||
#warning("FIXME: get the site name in the head title but not the body title")
|
||||
let projectHTML = try templateRenderer.renderTemplate(name: "project", context: [
|
||||
"title": "\(project.title)",
|
||||
"project": project,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,6 @@ do {
|
|||
exit(0)
|
||||
}
|
||||
catch {
|
||||
fputs("error: \(error.localizedDescription)", stderr)
|
||||
fputs("error: \(error)", stderr)
|
||||
exit(-1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,24 +2,31 @@
|
|||
|
||||
{% block body %}
|
||||
|
||||
<div class="container">
|
||||
<h1>{{ title }}</h1>
|
||||
</div>
|
||||
|
||||
{% for year in years %}
|
||||
<div class="container">
|
||||
<h1>{{ year.number }}</h1>
|
||||
<h2><a href="{{ year.path }}">{{ year.title }}</a></h2>
|
||||
|
||||
{% for month in year.months %}
|
||||
<h2>
|
||||
<a href="/{{ path }}/{{ year.number }}/{{ month.number }}">{{ monthNames[month.number] }}</a>
|
||||
</h2>
|
||||
<h3>
|
||||
<a href="{{ month.path }}">{{ monthNames[month.title] }}</a>
|
||||
</h3>
|
||||
|
||||
<ul class="archive">
|
||||
{% for post in month.posts %}
|
||||
<li>
|
||||
{% if post.isLink %}
|
||||
<a href="{{ post.path }}">→ {{ post.title }}</a>
|
||||
<a href="{{ post.link }}">→ {{ post.title }}</a>
|
||||
{% else %}
|
||||
<a href="{{ post.path }}">{{ post.title }}</a>
|
||||
{% endif %}
|
||||
<time>{{ post.day }} {{ monthAbbreviations[month.number] }}</time>
|
||||
<time>{{ post.day }} {{ monthAbbreviations[month.title] }}</time>
|
||||
{% if post.isLink %}
|
||||
<a class="permalink" href="{{ post.path }}">∞</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,13 @@
|
|||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
|
||||
<title>{{ title }}</title>
|
||||
{% if title %}
|
||||
<title>{{ site.title }}: {{ title }}</title>
|
||||
{% elif page.title %}
|
||||
<title>{{ site.title }}: {{ page.title }}</title>
|
||||
{% else %}
|
||||
<title>{{ site.title }}</title>
|
||||
{% endif %}
|
||||
|
||||
<link rel="icon" type="image/png" href="/images/favicon-32x32.png">
|
||||
<link rel="shortcut icon" href="/images/favicon.ico">
|
||||
|
|
|
|||
Loading…
Reference in a new issue