mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-04-27 14:57:40 +00:00
Render the post archive at /posts and redirect /archive
This commit is contained in:
parent
5ed68c45f8
commit
c8dc29a511
12 changed files with 169 additions and 148 deletions
18
Readme.md
18
Readme.md
|
|
@ -15,7 +15,7 @@ This version will go back to its roots and use headers at the top of markdown fi
|
||||||
|
|
||||||
Execution, trying TDD for the first time:
|
Execution, trying TDD for the first time:
|
||||||
|
|
||||||
- [ ] Replace harp with custom Swift code
|
- [x] Replace harp with custom Swift code
|
||||||
|
|
||||||
- [x] Write a test harness that renders a site and then checks the output with `diff -r`
|
- [x] Write a test harness that renders a site and then checks the output with `diff -r`
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ Execution, trying TDD for the first time:
|
||||||
|
|
||||||
- [x] Check and delete _data.json
|
- [x] Check and delete _data.json
|
||||||
|
|
||||||
- [ ] Migrate posts to markdown with headers somehow
|
- [x] Migrate posts to markdown with headers somehow
|
||||||
|
|
||||||
- [x] Define the new format
|
- [x] Define the new format
|
||||||
|
|
||||||
|
|
@ -63,15 +63,19 @@ Execution, trying TDD for the first time:
|
||||||
|
|
||||||
- [x] Migrate month indexes
|
- [x] Migrate month indexes
|
||||||
|
|
||||||
- [ ] Migrate index / recent posts
|
- [x] Migrate index / recent posts
|
||||||
|
|
||||||
- [ ] Migrate archive and put it at /posts/index.html, duh!
|
- [x] Migrate archive and put it at /posts/index.html, duh!
|
||||||
|
|
||||||
- [ ] 301 redirect /archive to /posts, and update the header link
|
- [x] 301 redirect /archive to /posts, and update the header link
|
||||||
|
|
||||||
- [ ] Check and delete _data.json filse
|
- [x] Check and delete _data.json filse
|
||||||
|
|
||||||
- [ ] Search for other _data.json files and eliminate any that are found
|
- [x] Search for other _data.json and .ejs files and eliminate any that are found
|
||||||
|
|
||||||
|
- [ ] Find a way to add the site name to HTML titles rendered by plugins
|
||||||
|
|
||||||
|
- [ ] Clean up the posts plugin
|
||||||
|
|
||||||
- [ ] 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
|
- [ ] 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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,19 +50,12 @@ final class PostsPlugin: Plugin {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let recentPostsURL = targetURL.appendingPathComponent(recentPostsPath)
|
|
||||||
try renderRecentPosts(targetFileURL: recentPostsURL, templateRenderer: templateRenderer)
|
|
||||||
|
|
||||||
let postsDir = targetURL.appendingPathComponent(postsPath)
|
let postsDir = targetURL.appendingPathComponent(postsPath)
|
||||||
try renderYearsAndMonths(postsDir: postsDir, templateRenderer: templateRenderer)
|
|
||||||
try renderPostsByDate(postsDir: postsDir, templateRenderer: templateRenderer)
|
try renderPostsByDate(postsDir: postsDir, templateRenderer: templateRenderer)
|
||||||
}
|
try renderYears(postsDir: postsDir, templateRenderer: templateRenderer)
|
||||||
|
try renderMonths(postsDir: postsDir, templateRenderer: templateRenderer)
|
||||||
func renderRecentPosts(targetFileURL: URL, templateRenderer: TemplateRenderer) throws {
|
try renderArchive(postsDir: postsDir, templateRenderer: templateRenderer)
|
||||||
print("renderRecentPosts(targetFileURL: \(targetFileURL), templateRenderer: \(templateRenderer)")
|
try renderRecentPosts(targetURL: targetURL, templateRenderer: templateRenderer)
|
||||||
let recentPosts = posts.flattened().prefix(10)
|
|
||||||
let recentPostsHTML = try templateRenderer.renderTemplate(name: "recent-posts", context: ["recentPosts": recentPosts])
|
|
||||||
try recentPostsHTML.write(to: targetFileURL, atomically: true, encoding: .utf8)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderPostsByDate(postsDir: URL, templateRenderer: TemplateRenderer) throws {
|
func renderPostsByDate(postsDir: URL, templateRenderer: TemplateRenderer) throws {
|
||||||
|
|
@ -75,49 +68,78 @@ final class PostsPlugin: Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderYearsAndMonths(postsDir: URL, templateRenderer: TemplateRenderer) throws {
|
func renderRecentPosts(targetURL: URL, templateRenderer: TemplateRenderer) throws {
|
||||||
print("renderYearsAndMonths(postsDir: \(postsDir), templateRenderer: \(templateRenderer)")
|
print("renderRecentPosts(targetURL: \(targetURL), templateRenderer: \(templateRenderer)")
|
||||||
|
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
|
||||||
|
}
|
||||||
|
#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)
|
||||||
|
try recentPostsHTML.write(to: fileURL, atomically: true, encoding: .utf8)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderArchive(postsDir: URL, templateRenderer: TemplateRenderer) throws {
|
||||||
|
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
|
||||||
|
[
|
||||||
|
"number": "\(year)",
|
||||||
|
"months": posts[year].byMonth.keys.sorted(by: >).map { month in
|
||||||
|
[
|
||||||
|
"number": month.padded,
|
||||||
|
"posts": posts[year][month].posts,
|
||||||
|
]
|
||||||
|
} as Any,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
let context: [String: Any] = [
|
||||||
|
"title": "Archive",
|
||||||
|
"path": postsPath,
|
||||||
|
"years": postsByMonthByYearForContext,
|
||||||
|
"monthNames": allMonths.reduce(into: [String: String](), { dict, month in
|
||||||
|
dict[month.padded] = month.name
|
||||||
|
}),
|
||||||
|
"monthAbbreviations": allMonths.reduce(into: [String: String](), { dict, month in
|
||||||
|
dict[month.padded] = month.abbreviatedName
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
let archiveHTML = try templateRenderer.renderTemplate(name: "posts-archive", context: context)
|
||||||
|
let archiveURL = postsDir.appendingPathComponent("index.html")
|
||||||
|
try archiveHTML.write(to: archiveURL, atomically: true, encoding: .utf8)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderYears(postsDir: URL, templateRenderer: TemplateRenderer) throws {
|
||||||
|
print("renderYears(postsDir: \(postsDir), templateRenderer: \(templateRenderer)")
|
||||||
let allMonths = (1 ... 12).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: [Month: [RenderedPost]] = [:]
|
var sortedPostsByMonth: [Month: [Post]] = [:]
|
||||||
for month in allMonths {
|
for month in allMonths {
|
||||||
let sortedPosts = monthPosts[month].posts.sorted(by: { $1.date < $0.date })
|
let sortedPosts = monthPosts[month].posts.sorted(by: { $1.date < $0.date })
|
||||||
guard !sortedPosts.isEmpty else {
|
if !sortedPosts.isEmpty {
|
||||||
continue
|
sortedPostsByMonth[month] = sortedPosts
|
||||||
}
|
}
|
||||||
|
|
||||||
let renderedPosts = sortedPosts.map { post -> RenderedPost in
|
|
||||||
let bodyHTML = markdownParser.html(from: post.bodyMarkdown)
|
|
||||||
return RenderedPost(post: post, body: bodyHTML)
|
|
||||||
}
|
|
||||||
sortedPostsByMonth[month] = renderedPosts
|
|
||||||
|
|
||||||
let monthDir = yearDir.appendingPathComponent(month.padded)
|
|
||||||
try fileManager.createDirectory(at: monthDir, withIntermediateDirectories: true, attributes: nil)
|
|
||||||
#warning("FIXME: get the site name out of here somehow")
|
|
||||||
let context: [String: Any] = [
|
|
||||||
"title": "samhuri.net: \(month.name) \(year)",
|
|
||||||
"posts": renderedPosts.map { $0.dictionary },
|
|
||||||
]
|
|
||||||
let monthHTML = try templateRenderer.renderTemplate(name: "posts-month", context: context)
|
|
||||||
let monthURL = monthDir.appendingPathComponent("index.html")
|
|
||||||
try monthHTML.write(to: monthURL, atomically: true, encoding: .utf8)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 months = Array(sortedPostsByMonth.keys.sorted().reversed())
|
||||||
let postsByMonthForContext: [String: [[String: Any]]] = sortedPostsByMonth.reduce(into: [:]) { dict, pair in
|
let postsByMonthForContext: [String: [Post]] = sortedPostsByMonth.reduce(into: [:]) { dict, pair in
|
||||||
let (month, renderedPosts) = pair
|
let (month, posts) = pair
|
||||||
dict[month.padded] = renderedPosts.map { $0.dictionary }
|
dict[month.padded] = posts
|
||||||
}
|
}
|
||||||
let monthsPadded = months.map { $0.padded }
|
#warning("FIXME: get the site name in the head title but not the body title")
|
||||||
#warning("FIXME: get the site name out of here somehow")
|
|
||||||
let context: [String: Any] = [
|
let context: [String: Any] = [
|
||||||
"title": "samhuri.net: \(year)",
|
"title": "\(year)",
|
||||||
"path": postsPath,
|
"path": postsPath,
|
||||||
"year": year,
|
"year": year,
|
||||||
"months": monthsPadded,
|
"months": months.map { $0.padded },
|
||||||
"monthNames": months.reduce(into: [String: String](), { dict, month in
|
"monthNames": months.reduce(into: [String: String](), { dict, month in
|
||||||
dict[month.padded] = month.name
|
dict[month.padded] = month.name
|
||||||
}),
|
}),
|
||||||
|
|
@ -132,6 +154,35 @@ final class PostsPlugin: Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func renderMonths(postsDir: URL, templateRenderer: TemplateRenderer) throws {
|
||||||
|
print("renderMonths(postsDir: \(postsDir), templateRenderer: \(templateRenderer)")
|
||||||
|
let allMonths = (1 ... 12).map(Month.init(_:))
|
||||||
|
for (year, monthPosts) in posts.byYear.sorted(by: { $1.key < $0.key }) {
|
||||||
|
let yearDir = postsDir.appendingPathComponent("\(year)")
|
||||||
|
for month in allMonths {
|
||||||
|
let sortedPosts = monthPosts[month].posts.sorted(by: { $1.date < $0.date })
|
||||||
|
guard !sortedPosts.isEmpty else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let renderedPosts = sortedPosts.map { post -> RenderedPost in
|
||||||
|
let bodyHTML = markdownParser.html(from: post.bodyMarkdown)
|
||||||
|
return RenderedPost(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 },
|
||||||
|
]
|
||||||
|
let monthHTML = try templateRenderer.renderTemplate(name: "posts-month", context: context)
|
||||||
|
let monthURL = monthDir.appendingPathComponent("index.html")
|
||||||
|
try monthHTML.write(to: monthURL, atomically: true, encoding: .utf8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func renderPost(_ post: Post, monthDir: URL, templateRenderer: TemplateRenderer) throws {
|
private func renderPost(_ post: Post, monthDir: URL, templateRenderer: TemplateRenderer) throws {
|
||||||
print("renderPost(\(post.debugDescription), monthDir: \(monthDir), templateRenderer: \(templateRenderer)")
|
print("renderPost(\(post.debugDescription), monthDir: \(monthDir), templateRenderer: \(templateRenderer)")
|
||||||
try fileManager.createDirectory(at: monthDir, withIntermediateDirectories: true, attributes: nil)
|
try fileManager.createDirectory(at: monthDir, withIntermediateDirectories: true, attributes: nil)
|
||||||
|
|
@ -139,9 +190,9 @@ final class PostsPlugin: Plugin {
|
||||||
let postURL = monthDir.appendingPathComponent(filename)
|
let postURL = monthDir.appendingPathComponent(filename)
|
||||||
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)
|
||||||
#warning("FIXME: get the site name out of here somehow")
|
#warning("FIXME: get the site name in the head title but not the body title")
|
||||||
let postHTML = try templateRenderer.renderTemplate(name: "post", context: [
|
let postHTML = try templateRenderer.renderTemplate(name: "post", context: [
|
||||||
"title": "samhuri.net: \(renderedPost.post.title)",
|
"title": "\(renderedPost.post.title)",
|
||||||
"post": renderedPost.dictionary,
|
"post": renderedPost.dictionary,
|
||||||
])
|
])
|
||||||
try postHTML.write(to: postURL, atomically: true, encoding: .utf8)
|
try postHTML.write(to: postURL, atomically: true, encoding: .utf8)
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,9 @@ final class ProjectsPlugin: Plugin {
|
||||||
let projectsDir = targetURL.appendingPathComponent(path)
|
let projectsDir = targetURL.appendingPathComponent(path)
|
||||||
try fileManager.createDirectory(at: projectsDir, withIntermediateDirectories: true, attributes: nil)
|
try fileManager.createDirectory(at: projectsDir, withIntermediateDirectories: true, attributes: nil)
|
||||||
let projectsURL = projectsDir.appendingPathComponent("index.html")
|
let projectsURL = projectsDir.appendingPathComponent("index.html")
|
||||||
#warning("FIXME: get the site name out of here somehow")
|
#warning("FIXME: get the site name in the head title but not the body title")
|
||||||
let projectsHTML = try templateRenderer.renderTemplate(name: "projects", context: [
|
let projectsHTML = try templateRenderer.renderTemplate(name: "projects", context: [
|
||||||
"title": "samhuri.net: Projects",
|
"title": "Projects",
|
||||||
"projects": projects,
|
"projects": projects,
|
||||||
])
|
])
|
||||||
try projectsHTML.write(to: projectsURL, atomically: true, encoding: .utf8)
|
try projectsHTML.write(to: projectsURL, atomically: true, encoding: .utf8)
|
||||||
|
|
@ -56,9 +56,9 @@ final class ProjectsPlugin: Plugin {
|
||||||
for project in projects {
|
for project in projects {
|
||||||
let filename = "\(project.title).html"
|
let filename = "\(project.title).html"
|
||||||
let projectURL = projectsDir.appendingPathComponent(filename)
|
let projectURL = projectsDir.appendingPathComponent(filename)
|
||||||
#warning("FIXME: get the site name out of here somehow")
|
#warning("FIXME: get the site name in the head title but not the body title")
|
||||||
let projectHTML = try templateRenderer.renderTemplate(name: "project", context: [
|
let projectHTML = try templateRenderer.renderTemplate(name: "project", context: [
|
||||||
"title": "samhuri.net: \(project.title)",
|
"title": "\(project.title)",
|
||||||
"project": project,
|
"project": project,
|
||||||
])
|
])
|
||||||
try projectHTML.write(to: projectURL, atomically: true, encoding: .utf8)
|
try projectHTML.write(to: projectURL, atomically: true, encoding: .utf8)
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
{
|
|
||||||
"mach-o-symbol-and-relocation-tables": {
|
|
||||||
"id": "mach-o-symbol-and-relocation-tables",
|
|
||||||
"author": "Sami Samhuri",
|
|
||||||
"title": "Mach-O Symbol and Relocation Tables",
|
|
||||||
"date": "28th June, 2015",
|
|
||||||
"timestamp": 1435527198,
|
|
||||||
"link": null,
|
|
||||||
"url": "/posts/drafts/mach-o-symbol-and-relocation-tables",
|
|
||||||
"tags": [
|
|
||||||
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"09c2b186-3ce7-445c-89bf-5d5b7f830cd7": {
|
|
||||||
"id": "09c2b186-3ce7-445c-89bf-5d5b7f830cd7",
|
|
||||||
"author": "Sami Samhuri",
|
|
||||||
"title": "The Case for Native",
|
|
||||||
"date": "27th June, 2015",
|
|
||||||
"timestamp": 1435424525,
|
|
||||||
"link": null,
|
|
||||||
"url": "/posts/drafts/09c2b186-3ce7-445c-89bf-5d5b7f830cd7",
|
|
||||||
"tags": [
|
|
||||||
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"security-through-obscurity-is-still-not-a-best-practice": {
|
|
||||||
"id": "security-through-obscurity-is-still-not-a-best-practice",
|
|
||||||
"author": "Sami Samhuri",
|
|
||||||
"title": "security-through-obscurity-is-still-not-a-best-practice",
|
|
||||||
"date": "20th August, 2017",
|
|
||||||
"timestamp": 1503246688,
|
|
||||||
"link": null,
|
|
||||||
"url": "/posts/2017/08/security-through-obscurity-is-still-not-a-best-practice",
|
|
||||||
"tags": [
|
|
||||||
"rails",
|
|
||||||
"security"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
---
|
||||||
|
Title: Mach-O Symbol and Relocation Tables
|
||||||
|
Author: Sami Samhuri
|
||||||
|
Date: 28th June, 2015
|
||||||
|
Timestamp: 1435527198
|
||||||
|
Tags:
|
||||||
|
---
|
||||||
|
|
||||||
The latest technology I've been learning is Palm's SDK for webOS,
|
The latest technology I've been learning is Palm's SDK for webOS,
|
||||||
Mojo. My first impression is that it's a great platform and
|
Mojo. My first impression is that it's a great platform and
|
||||||
Palm could do a great job of 2.0 if they cut down on some of the
|
Palm could do a great job of 2.0 if they cut down on some of the
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
---
|
||||||
|
Title: TBD
|
||||||
|
Author: Sami Samhuri
|
||||||
|
Date: 20th August, 2017
|
||||||
|
Timestamp: 1503246688
|
||||||
|
Tags: rails, security
|
||||||
|
---
|
||||||
|
|
||||||
A common way to configure a Rails server for different deployment environments is to use environment variables. This is a good practice as described by [The Twelve-Factor App][12factor] and can be applied to any server framework in any language running on a Unix OS. It keeps such secrets out of your code repository which is good, and it also makes it easy to customize your application for different environments. It's a pretty solid technique.
|
A common way to configure a Rails server for different deployment environments is to use environment variables. This is a good practice as described by [The Twelve-Factor App][12factor] and can be applied to any server framework in any language running on a Unix OS. It keeps such secrets out of your code repository which is good, and it also makes it easy to customize your application for different environments. It's a pretty solid technique.
|
||||||
|
|
||||||
[12factor]: https://12factor.net
|
[12factor]: https://12factor.net
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
---
|
||||||
|
Title: The Case for Native
|
||||||
|
Author: Sami Samhuri
|
||||||
|
Date: 27th June, 2015
|
||||||
|
Timestamp: 1435424525
|
||||||
|
Tags:
|
||||||
|
---
|
||||||
|
|
||||||
For the past month I've been using [Appcelerator Titanium](http://www.appcelerator.com/products/) on a two man team. We made a simple iPhone app with a tab bar with embedded nav controllers, just 10 screens or so total. We started porting it to the iPad and Android so have some experience there. It's been a pretty frustrating exercise most days. I had a lot of little complaints but didn't take the time to step back and look at the bigger picture. I love JavaScript and in theory Titanium is awesome and a huge win. I wanted it to be a win but in reality it just hasn't been.
|
For the past month I've been using [Appcelerator Titanium](http://www.appcelerator.com/products/) on a two man team. We made a simple iPhone app with a tab bar with embedded nav controllers, just 10 screens or so total. We started porting it to the iPad and Android so have some experience there. It's been a pretty frustrating exercise most days. I had a lot of little complaints but didn't take the time to step back and look at the bigger picture. I love JavaScript and in theory Titanium is awesome and a huge win. I wanted it to be a win but in reality it just hasn't been.
|
||||||
|
|
||||||
Here are 9 reasons why native is better in the short and long run.
|
Here are 9 reasons why native is better in the short and long run.
|
||||||
|
|
@ -79,8 +79,10 @@ Redirect 301 /json-diff http://tlrobinson.net/projects/javascript-fun/jsondiff
|
||||||
# The great vowel shortage of 1974 is over.
|
# The great vowel shortage of 1974 is over.
|
||||||
Redirect 301 /proj /projects
|
Redirect 301 /proj /projects
|
||||||
|
|
||||||
|
Redirect 301 /archive /posts
|
||||||
|
Redirect 301 /archive/index.html /posts
|
||||||
Redirect 301 /blog/sjs.rss /feed.xml
|
Redirect 301 /blog/sjs.rss /feed.xml
|
||||||
Redirect 301 /blog /posts
|
Redirect 301 /blog /
|
||||||
|
|
||||||
# Old naming scheme, incompatible with Harp.
|
# Old naming scheme, incompatible with Harp.
|
||||||
Redirect 301 /blog/2006.02.08-first-post /posts/2006/02/first-post
|
Redirect 301 /blog/2006.02.08-first-post /posts/2006/02/first-post
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
<% function pad(n) { -%>
|
|
||||||
<% return +n < 10 ? '0' + n : String(n) -%>
|
|
||||||
<% } -%>
|
|
||||||
|
|
||||||
<% var _months = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ') -%>
|
|
||||||
<% function formatDate(t) { -%>
|
|
||||||
<% var d = new Date(t) -%>
|
|
||||||
<% return d.getDate() + ' ' + _months[d.getMonth()] -%>
|
|
||||||
<% } -%>
|
|
||||||
|
|
||||||
<% function sortPosts(dir) { -%>
|
|
||||||
<% var slugs = Object.keys(dir._data) -%>
|
|
||||||
<% var posts = slugs.map(function(slug) { return dir._data[slug] }) -%>
|
|
||||||
<% posts.sort(function(a, b) { -%>
|
|
||||||
<% var t1 = a.timestamp -%>
|
|
||||||
<% var t2 = b.timestamp -%>
|
|
||||||
<% return t1 < t2 ? 1 : (t1 > t2 ? -1 : 0) -%>
|
|
||||||
<% }) -%>
|
|
||||||
<% return posts -%>
|
|
||||||
<% } -%>
|
|
||||||
|
|
||||||
<% function posts(dir, year) { -%>
|
|
||||||
<% if (!dir) return -%>
|
|
||||||
|
|
||||||
<h3>
|
|
||||||
<a href="/posts/<%= year %>"><%= year %></a>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<% for (var month = 12; month >= 1; month--) { -%>
|
|
||||||
<% var monthDir = dir[pad(month)] -%>
|
|
||||||
<% if (!monthDir) continue -%>
|
|
||||||
<ul class="archive">
|
|
||||||
<% var posts = sortPosts(monthDir) -%>
|
|
||||||
<% for (var i in posts) { -%>
|
|
||||||
<% var post = posts[i] -%>
|
|
||||||
<% if (post.hidden) continue -%>
|
|
||||||
<li>
|
|
||||||
<% if (post.link) { -%>
|
|
||||||
<a href="<%= post.url %>">→ <%= post.title %></a>
|
|
||||||
<% } else { -%>
|
|
||||||
<a href="<%= post.url %>"><%= post.title %></a>
|
|
||||||
<% } -%>
|
|
||||||
<time><%= formatDate(1000 * post.timestamp) %></time>
|
|
||||||
</li>
|
|
||||||
<% } -%>
|
|
||||||
</ul>
|
|
||||||
<% } -%>
|
|
||||||
<% } -%>
|
|
||||||
|
|
||||||
<% var year = new Date().getFullYear(); -%>
|
|
||||||
<% for (; year >= 2006; year--) { -%>
|
|
||||||
<% posts(public.posts[year], year) -%>
|
|
||||||
<% } -%>
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<header>
|
<header>
|
||||||
<h2><a href="{{ post.path }}">{{ post.title }}</a></h2>
|
<h2><a href="{{ post.path }}">{{ post.title }}</a></h2>
|
||||||
<time>{{ post.formattedDate }}</time>
|
<time>{{ post.formattedDate }}</time>
|
||||||
|
<a class="permalink" href="{{ post.path }}">∞</a>
|
||||||
</header>
|
</header>
|
||||||
{{ post.body }}
|
{{ post.body }}
|
||||||
</article>
|
</article>
|
||||||
|
|
|
||||||
31
templates/posts-archive.html
Normal file
31
templates/posts-archive.html
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
{% extends "samhuri.net.html" %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
{% for year in years %}
|
||||||
|
<div class="container">
|
||||||
|
<h1>{{ year.number }}</h1>
|
||||||
|
|
||||||
|
{% for month in year.months %}
|
||||||
|
<h2>
|
||||||
|
<a href="/{{ path }}/{{ year.number }}/{{ month.number }}">{{ monthNames[month.number] }}</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<ul class="archive">
|
||||||
|
{% for post in month.posts %}
|
||||||
|
<li>
|
||||||
|
{% if post.isLink %}
|
||||||
|
<a href="{{ post.path }}">→ {{ post.title }}</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ post.path }}">{{ post.title }}</a>
|
||||||
|
{% endif %}
|
||||||
|
<time>{{ post.day }} {{ monthAbbreviations[month.number] }}</time>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/about">About</a></li>
|
<li><a href="/about">About</a></li>
|
||||||
<li><a href="/archive">Archive</a></li>
|
<li><a href="/posts">Archive</a></li>
|
||||||
<li><a href="/projects">Projects</a></li>
|
<li><a href="/projects">Projects</a></li>
|
||||||
<li class="twitter"><a href="https://twitter.com/_sjs"><i class="fa fa-twitter"></i></a></li>
|
<li class="twitter"><a href="https://twitter.com/_sjs"><i class="fa fa-twitter"></i></a></li>
|
||||||
<li class="github"><a href="https://github.com/samsonjs"><i class="fa fa-github"></i></a></li>
|
<li class="github"><a href="https://github.com/samsonjs"><i class="fa fa-github"></i></a></li>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue