mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-03-25 09:05:47 +00:00
Migrate projects plugin from Stencil and JSON to Swift
This commit is contained in:
parent
640c76d967
commit
0c17d5c543
21 changed files with 317 additions and 245 deletions
|
|
@ -121,9 +121,9 @@ Execution, trying TDD for the first time:
|
|||
|
||||
- [x] Replace page template with Swift code
|
||||
|
||||
- [ ] Replace projects.json with Swift code
|
||||
- [x] Replace projects.json with Swift code
|
||||
|
||||
- [ ] Replace project templates with Swift code
|
||||
- [x] Replace project templates with Swift code
|
||||
|
||||
- [ ] Replace post templates with Swift code
|
||||
|
||||
|
|
|
|||
8
SiteGenerator/Sources/SiteGenerator/File.swift
Normal file
8
SiteGenerator/Sources/SiteGenerator/File.swift
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by Sami Samhuri on 2019-12-20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
|
@ -7,8 +7,14 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
struct Project: Codable {
|
||||
let title: String
|
||||
let description: String
|
||||
var path: String!
|
||||
public struct Project {
|
||||
public let title: String
|
||||
public let description: String
|
||||
public let url: URL
|
||||
|
||||
public init(title: String, description: String, url: URL) {
|
||||
self.title = title
|
||||
self.description = description
|
||||
self.url = url
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,42 +7,47 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
private struct Projects: Codable {
|
||||
let projects: [Project]
|
||||
|
||||
static func decode(from url: URL) throws -> Projects {
|
||||
let json = try Data(contentsOf: url)
|
||||
let projects = try JSONDecoder().decode(Projects.self, from: json)
|
||||
return projects
|
||||
}
|
||||
struct PartialProject {
|
||||
let title: String
|
||||
let description: String
|
||||
}
|
||||
|
||||
final class ProjectsPlugin: Plugin {
|
||||
public final class ProjectsPlugin: Plugin {
|
||||
let fileManager: FileManager = .default
|
||||
let outputPath: String
|
||||
let partialProjects: [PartialProject]
|
||||
let templateRenderer: ProjectsTemplateRenderer
|
||||
let projectAssets: TemplateAssets
|
||||
|
||||
var projects: [Project] = []
|
||||
var sourceURL: URL!
|
||||
|
||||
init(templateRenderer: ProjectsTemplateRenderer, outputPath: String? = nil) {
|
||||
init(
|
||||
projects: [PartialProject],
|
||||
templateRenderer: ProjectsTemplateRenderer,
|
||||
projectAssets: TemplateAssets,
|
||||
outputPath: String? = nil
|
||||
) {
|
||||
self.partialProjects = projects
|
||||
self.templateRenderer = templateRenderer
|
||||
self.projectAssets = projectAssets
|
||||
self.outputPath = outputPath ?? "projects"
|
||||
}
|
||||
|
||||
// MARK: - Plugin methods
|
||||
|
||||
func setUp(site: Site, sourceURL: URL) throws {
|
||||
public func setUp(site: Site, sourceURL: URL) throws {
|
||||
self.sourceURL = sourceURL
|
||||
let projectsURL = sourceURL.appendingPathComponent("projects.json")
|
||||
if fileManager.fileExists(atPath: projectsURL.path) {
|
||||
self.projects = try Projects.decode(from: projectsURL).projects.map { project in
|
||||
Project(title: project.title, description: project.description, path: "/\(outputPath)/\(project.title)")
|
||||
}
|
||||
projects = partialProjects.map { partial in
|
||||
Project(
|
||||
title: partial.title,
|
||||
description: partial.description,
|
||||
url: site.url.appendingPathComponent("\(outputPath)/\(partial.title)")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func render(site: Site, targetURL: URL) throws {
|
||||
public func render(site: Site, targetURL: URL) throws {
|
||||
guard !projects.isEmpty else {
|
||||
return
|
||||
}
|
||||
|
|
@ -50,18 +55,12 @@ final class ProjectsPlugin: Plugin {
|
|||
let projectsDir = targetURL.appendingPathComponent(outputPath)
|
||||
try fileManager.createDirectory(at: projectsDir, withIntermediateDirectories: true, attributes: nil)
|
||||
let projectsURL = projectsDir.appendingPathComponent("index.html")
|
||||
let projectsHTML = try templateRenderer.renderTemplate(.projects, site: site, context: [
|
||||
"title": "Projects",
|
||||
"projects": projects,
|
||||
])
|
||||
let projectsHTML = try templateRenderer.renderProjects(projects, site: site, assets: .none())
|
||||
try projectsHTML.write(to: projectsURL, atomically: true, encoding: .utf8)
|
||||
|
||||
for project in projects {
|
||||
let projectURL = projectsDir.appendingPathComponent("\(project.title)/index.html")
|
||||
let projectHTML = try templateRenderer.renderTemplate(.project, site: site, context: [
|
||||
"title": "\(project.title)",
|
||||
"project": project,
|
||||
])
|
||||
let projectHTML = try templateRenderer.renderProject(project, site: site, assets: projectAssets)
|
||||
try fileManager.createDirectory(at: projectURL.deletingLastPathComponent(), withIntermediateDirectories: true, attributes: nil)
|
||||
try projectHTML.write(to: projectURL, atomically: true, encoding: .utf8)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// ProjectsPluginBuilder.swift
|
||||
// SiteGenerator
|
||||
//
|
||||
// Created by Sami Samhuri on 2019-12-19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public final class ProjectsPluginBuilder {
|
||||
let templateRenderer: ProjectsTemplateRenderer
|
||||
private var path: String?
|
||||
private var projects: [PartialProject] = []
|
||||
private var projectAssets: TemplateAssets?
|
||||
|
||||
public init(templateRenderer: ProjectsTemplateRenderer) {
|
||||
self.templateRenderer = templateRenderer
|
||||
}
|
||||
|
||||
public func path(_ path: String) -> ProjectsPluginBuilder {
|
||||
precondition(self.path == nil, "path is already defined")
|
||||
self.path = path
|
||||
return self
|
||||
}
|
||||
|
||||
public func projectAssets(_ projectAssets: TemplateAssets) -> ProjectsPluginBuilder {
|
||||
precondition(self.projectAssets == nil, "projectAssets are already defined")
|
||||
self.projectAssets = projectAssets
|
||||
return self
|
||||
}
|
||||
|
||||
public func add(_ title: String, description: String) -> ProjectsPluginBuilder {
|
||||
let project = PartialProject(title: title, description: description)
|
||||
projects.append(project)
|
||||
return self
|
||||
}
|
||||
|
||||
public func build() -> ProjectsPlugin {
|
||||
if projects.isEmpty {
|
||||
print("WARNING: No projects have been added")
|
||||
}
|
||||
return ProjectsPlugin(
|
||||
projects: projects,
|
||||
templateRenderer: templateRenderer,
|
||||
projectAssets: projectAssets ?? .none(),
|
||||
outputPath: path
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -7,11 +7,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
public enum ProjectTemplate {
|
||||
case project
|
||||
case projects
|
||||
}
|
||||
|
||||
public protocol ProjectsTemplateRenderer {
|
||||
func renderTemplate(_ template: ProjectTemplate, site: Site, context: [String: Any]) throws -> String
|
||||
func renderProjects(_ projects: [Project], site: Site, assets: TemplateAssets) throws -> String
|
||||
func renderProject(_ project: Project, site: Site, assets: TemplateAssets) throws -> String
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,17 +76,3 @@ public extension SiteBuilder {
|
|||
renderer(MarkdownRenderer(pageRenderer: pageRenderer))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Projects
|
||||
|
||||
public extension SiteBuilder {
|
||||
func projects(templateRenderer: ProjectsTemplateRenderer, path: String? = nil) -> SiteBuilder {
|
||||
plugin(ProjectsPlugin(templateRenderer: templateRenderer, outputPath: path))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Posts
|
||||
|
||||
public extension SiteBuilder {
|
||||
// anything nice we can do there?
|
||||
}
|
||||
|
|
|
|||
22
SiteGenerator/Sources/SiteGenerator/TemplateAssets.swift
Normal file
22
SiteGenerator/Sources/SiteGenerator/TemplateAssets.swift
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// TemplateAssets.swift
|
||||
// SiteGenerator
|
||||
//
|
||||
// Created by Sami Samhuri on 2019-12-20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct TemplateAssets {
|
||||
public let scripts: [String]
|
||||
public let styles: [String]
|
||||
|
||||
public init(scripts: [String], styles: [String]) {
|
||||
self.scripts = scripts
|
||||
self.styles = styles
|
||||
}
|
||||
|
||||
public static func none() -> TemplateAssets {
|
||||
TemplateAssets(scripts: [], styles: [])
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
{
|
||||
"projects": [
|
||||
{
|
||||
"title": "bin",
|
||||
"description": "my collection of scripts in ~/bin"
|
||||
},
|
||||
{
|
||||
"title": "config",
|
||||
"description": "important dot files (zsh, emacs, vim, screen)"
|
||||
},
|
||||
{
|
||||
"title": "compiler",
|
||||
"description": "a compiler targeting x86 in Ruby"
|
||||
},
|
||||
{
|
||||
"title": "lake",
|
||||
"description": "a simple implementation of Scheme in C"
|
||||
},
|
||||
{
|
||||
"title": "strftime",
|
||||
"description": "strftime for JavaScript"
|
||||
},
|
||||
{
|
||||
"title": "format",
|
||||
"description": "printf for JavaScript"
|
||||
},
|
||||
{
|
||||
"title": "gitter",
|
||||
"description": "a GitHub client for Node (v3 API)"
|
||||
},
|
||||
{
|
||||
"title": "mojo.el",
|
||||
"description": "turn emacs into a sweet mojo editor"
|
||||
},
|
||||
{
|
||||
"title": "ThePusher",
|
||||
"description": "Github post-receive hook router"
|
||||
},
|
||||
{
|
||||
"title": "NorthWatcher",
|
||||
"description": "cron for filesystem changes"
|
||||
},
|
||||
{
|
||||
"title": "repl-edit",
|
||||
"description": "edit Node repl commands with your text editor"
|
||||
},
|
||||
{
|
||||
"title": "cheat.el",
|
||||
"description": "cheat from emacs"
|
||||
},
|
||||
{
|
||||
"title": "batteries",
|
||||
"description": "a general purpose node library"
|
||||
},
|
||||
{
|
||||
"title": "samhuri.net",
|
||||
"description": "this site"
|
||||
}
|
||||
]
|
||||
}
|
||||
14
samhuri.net/Sources/samhuri.net/Date+Sugar.swift
Normal file
14
samhuri.net/Sources/samhuri.net/Date+Sugar.swift
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// Date+Sugar.swift
|
||||
// samhuri.net
|
||||
//
|
||||
// Created by Sami Samhuri on 2019-12-19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Date {
|
||||
var year: Int {
|
||||
Calendar.current.dateComponents([.year], from: self).year!
|
||||
}
|
||||
}
|
||||
|
|
@ -6,11 +6,11 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import SiteGenerator
|
||||
|
||||
struct Page {
|
||||
let title: String
|
||||
let styles: [String]
|
||||
let scripts: [String]
|
||||
let templateAssets: TemplateAssets
|
||||
}
|
||||
|
||||
extension Page {
|
||||
|
|
@ -22,6 +22,6 @@ extension Page {
|
|||
.split(separator: ",")
|
||||
.map { $0.trimmingCharacters(in: .whitespaces) }
|
||||
let title = metadata["Title", default: ""]
|
||||
self.init(title: title, styles: styles, scripts: scripts)
|
||||
self.init(title: title, templateAssets: TemplateAssets(scripts: scripts, styles: styles))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,15 +22,17 @@ final class PageRenderer {
|
|||
let loader = FileSystemLoader(paths: [templatesPath])
|
||||
self.stencil = Environment(loader: loader)
|
||||
}
|
||||
|
||||
func render(_ body: Node<HTML.BodyContext>, context: TemplateContext) -> String {
|
||||
Template.site(body: body, context: context).render(indentedBy: .spaces(2))
|
||||
}
|
||||
}
|
||||
|
||||
extension PageRenderer: MarkdownPageRenderer {
|
||||
func renderPage(site: Site, bodyHTML: String, metadata: [String: String]) throws -> String {
|
||||
let page = Page(metadata: metadata)
|
||||
let context = PageContext(site: site, body: bodyHTML, page: page, metadata: metadata)
|
||||
let body: Node<HTML.BodyContext> = .page(title: page.title, bodyHTML: bodyHTML)
|
||||
return Template.site(body: body, context: context)
|
||||
.render(indentedBy: .spaces(2))
|
||||
let pageTitle = metadata["Title", default: ""]
|
||||
let context = SiteContext(site: site, subtitle: pageTitle, templateAssets: .none())
|
||||
return render(.page(title: pageTitle, bodyHTML: bodyHTML), context: context)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,34 +60,21 @@ extension PostTemplate {
|
|||
|
||||
extension PageRenderer: PostsTemplateRenderer {
|
||||
func renderTemplate(_ template: PostTemplate, site: Site, context: [String : Any]) throws -> String {
|
||||
let siteContext = SiteContext(site: site)
|
||||
let siteContext = SiteContext(site: site, subtitle: nil, templateAssets: .none())
|
||||
let contextDict = siteContext.dictionary.merging(context, uniquingKeysWith: { _, new in new })
|
||||
return try stencil.renderTemplate(name: template.htmlFilename, context: contextDict)
|
||||
}
|
||||
}
|
||||
|
||||
extension ProjectTemplate {
|
||||
@available(*, deprecated)
|
||||
var htmlFilename: String {
|
||||
switch self {
|
||||
case .project:
|
||||
return "project.html"
|
||||
case .projects:
|
||||
return "projects.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PageRenderer: ProjectsTemplateRenderer {
|
||||
func renderTemplate(_ template: ProjectTemplate, site: Site, context: [String : Any]) throws -> String {
|
||||
let siteContext = SiteContext(site: site)
|
||||
let contextDict = siteContext.dictionary.merging(context, uniquingKeysWith: { _, new in new })
|
||||
return try stencil.renderTemplate(name: template.htmlFilename, context: contextDict)
|
||||
func renderProjects(_ projects: [Project], site: Site, assets: TemplateAssets) throws -> String {
|
||||
let context = SiteContext(site: site, subtitle: "Projects", templateAssets: assets)
|
||||
return render(.projects(projects), context: context)
|
||||
}
|
||||
}
|
||||
|
||||
extension Date {
|
||||
var year: Int {
|
||||
Calendar.current.dateComponents([.year], from: self).year!
|
||||
func renderProject(_ project: Project, site: Site, assets: TemplateAssets) throws -> String {
|
||||
let projectContext = ProjectContext(project: project, site: site, templateAssets: assets)
|
||||
let context = SiteContext(site: site, subtitle: project.title, templateAssets: assets)
|
||||
return render(.project(projectContext), context: context)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// ProjectContext.swift
|
||||
// samhuri.net
|
||||
//
|
||||
// Created by Sami Samhuri on 2019-12-19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SiteGenerator
|
||||
|
||||
struct ProjectContext: TemplateContext {
|
||||
let site: Site
|
||||
let title: String
|
||||
let description: String
|
||||
let githubURL: URL
|
||||
let templateAssets: TemplateAssets
|
||||
|
||||
init(project: Project, site: Site, templateAssets: TemplateAssets) {
|
||||
self.site = site
|
||||
self.title = project.title
|
||||
self.description = project.description
|
||||
self.githubURL = URL(string: "https://github.com/samsonjs/\(title)")!
|
||||
self.templateAssets = templateAssets
|
||||
}
|
||||
|
||||
var stargazersURL: URL {
|
||||
githubURL.appendingPathComponent("stargazers")
|
||||
}
|
||||
|
||||
var networkURL: URL {
|
||||
githubURL.appendingPathComponent("network/members")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// ProjectTemplates.swift
|
||||
// samhuri.net
|
||||
//
|
||||
// Created by Sami Samhuri on 2019-12-19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Plot
|
||||
import SiteGenerator
|
||||
|
||||
extension Node where Context == HTML.BodyContext {
|
||||
static func projects(_ projects: [Project]) -> Node<HTML.BodyContext> {
|
||||
.group([
|
||||
.article(.class("container"),
|
||||
.h1("Projects"),
|
||||
|
||||
.group(projects.map { project in
|
||||
.div(.class("project-listing"),
|
||||
.h4(.a(.href(project.url), .text(project.title))),
|
||||
.p(.class("description"), .text(project.description))
|
||||
)
|
||||
})
|
||||
),
|
||||
|
||||
.div(.class("row clearfix"),
|
||||
.p(.class("fin"), .i(.class("fa fa-code")))
|
||||
)
|
||||
])
|
||||
}
|
||||
|
||||
static func project(_ context: ProjectContext) -> Node<HTML.BodyContext> {
|
||||
.group([
|
||||
.article(.class("container project"),
|
||||
// projects.js picks up this data-title attribute and uses it to render all the Github stuff
|
||||
.h1(.id("project"), .data(named: "title", value: context.title), .text(context.title)),
|
||||
.h4(.text(context.description)),
|
||||
|
||||
.div(.class("project-stats"),
|
||||
.p(
|
||||
.a(.href(context.githubURL), "GitHub"),
|
||||
"•",
|
||||
.a(.id("nstar"), .href(context.stargazersURL)),
|
||||
"•",
|
||||
.a(.id("nfork"), .href(context.networkURL))
|
||||
),
|
||||
.p("Last updated on ", .span(.id("updated")))
|
||||
),
|
||||
|
||||
.div(.class("project-info row clearfix"),
|
||||
.div(.class("column half"),
|
||||
.h3("Contributors"),
|
||||
.div(.id("contributors"))
|
||||
),
|
||||
.div(.class("column half"),
|
||||
.h3("Languages"),
|
||||
.div(.id("langs"))
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
.div(.class("row clearfix"),
|
||||
.p(.class("fin"), .i(.class("fa fa-code")))
|
||||
),
|
||||
|
||||
.group(context.scripts.map { url in
|
||||
.script(.attribute(named: "defer"), .src(url))
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
|
|
@ -18,16 +18,8 @@ struct PageContext: TemplateContext {
|
|||
"\(site.title): \(page.title)"
|
||||
}
|
||||
|
||||
var styles: [URL] {
|
||||
(site.styles + page.styles).map { style in
|
||||
style.hasPrefix("http") ? URL(string: style)! : url(for: style)
|
||||
}
|
||||
}
|
||||
|
||||
var scripts: [URL] {
|
||||
(site.scripts + page.scripts).map { script in
|
||||
script.hasPrefix("http") ? URL(string: script)! : url(for: script)
|
||||
}
|
||||
var templateAssets: TemplateAssets {
|
||||
page.templateAssets
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -39,8 +31,8 @@ extension PageContext {
|
|||
"body": body,
|
||||
"page": page,
|
||||
"metadata": metadata,
|
||||
"styles": site.styles + page.styles,
|
||||
"scripts": site.scripts + page.scripts,
|
||||
"styles": site.styles + templateAssets.styles,
|
||||
"scripts": site.scripts + templateAssets.scripts,
|
||||
"currentYear": Date().year,
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,7 @@ import SiteGenerator
|
|||
struct SiteContext: TemplateContext {
|
||||
let site: Site
|
||||
let subtitle: String?
|
||||
|
||||
init(site: Site, subtitle: String? = nil) {
|
||||
self.site = site
|
||||
self.subtitle = subtitle
|
||||
}
|
||||
let templateAssets: TemplateAssets
|
||||
|
||||
var title: String {
|
||||
guard let subtitle = subtitle else {
|
||||
|
|
@ -24,18 +20,6 @@ struct SiteContext: TemplateContext {
|
|||
|
||||
return "\(site.title): \(subtitle)"
|
||||
}
|
||||
|
||||
var styles: [URL] {
|
||||
site.styles.map { style in
|
||||
style.hasPrefix("http") ? URL(string: style)! : url(for: style)
|
||||
}
|
||||
}
|
||||
|
||||
var scripts: [URL] {
|
||||
site.scripts.map { script in
|
||||
script.hasPrefix("http") ? URL(string: script)! : url(for: script)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SiteContext {
|
||||
|
|
|
|||
|
|
@ -13,18 +13,36 @@ protocol TemplateContext {
|
|||
|
||||
var site: Site { get }
|
||||
var title: String { get }
|
||||
var styles: [URL] { get }
|
||||
var scripts: [URL] { get }
|
||||
var templateAssets: TemplateAssets { get }
|
||||
|
||||
// These all have default implementations
|
||||
|
||||
var styles: [URL] { get }
|
||||
var scripts: [URL] { get }
|
||||
|
||||
var currentYear: Int { get }
|
||||
|
||||
func url(for path: String) -> URL
|
||||
func imageURL(_ filename: String) -> URL
|
||||
func scriptURL(_ filename: String) -> URL
|
||||
func styleURL(_ filename: String) -> URL
|
||||
}
|
||||
|
||||
extension TemplateContext {
|
||||
var styles: [URL] {
|
||||
let allStyles = site.styles + templateAssets.styles
|
||||
return allStyles.map { style in
|
||||
style.hasPrefix("http") ? URL(string: style)! : styleURL(style)
|
||||
}
|
||||
}
|
||||
|
||||
var scripts: [URL] {
|
||||
let allScripts = site.scripts + templateAssets.scripts
|
||||
return allScripts.map { script in
|
||||
script.hasPrefix("http") ? URL(string: script)! : scriptURL(script)
|
||||
}
|
||||
}
|
||||
|
||||
var currentYear: Int {
|
||||
Date().year
|
||||
}
|
||||
|
|
@ -38,4 +56,16 @@ extension TemplateContext {
|
|||
.appendingPathComponent("images")
|
||||
.appendingPathComponent(filename)
|
||||
}
|
||||
|
||||
func scriptURL(_ filename: String) -> URL {
|
||||
site.url
|
||||
.appendingPathComponent("js")
|
||||
.appendingPathComponent(filename)
|
||||
}
|
||||
|
||||
func styleURL(_ filename: String) -> URL {
|
||||
site.url
|
||||
.appendingPathComponent("css")
|
||||
.appendingPathComponent(filename)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,30 @@ public extension samhuri {
|
|||
}
|
||||
|
||||
func buildSite(renderer: PageRenderer) -> Site {
|
||||
let projectsPlugin = ProjectsPluginBuilder(templateRenderer: renderer)
|
||||
.path("projects")
|
||||
.projectAssets(TemplateAssets(scripts: [
|
||||
"https://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js",
|
||||
"gitter.js",
|
||||
"store.js",
|
||||
"projects.js",
|
||||
], styles: []))
|
||||
.add("bin", description: "my collection of scripts in ~/bin")
|
||||
.add("config", description: "important dot files (zsh, emacs, vim, screen)")
|
||||
.add("compiler", description: "a compiler targeting x86 in Ruby")
|
||||
.add("lake", description: "a simple implementation of Scheme in C")
|
||||
.add("strftime", description: "strftime for JavaScript")
|
||||
.add("format", description: "printf for JavaScript")
|
||||
.add("gitter", description: "a GitHub client for Node (v3 API)")
|
||||
.add("mojo.el", description: "turn emacs into a sweet mojo editor")
|
||||
.add("ThePusher", description: "Github post-receive hook router")
|
||||
.add("NorthWatcher", description: "cron for filesystem changes")
|
||||
.add("repl-edit", description: "edit Node repl commands with your text editor")
|
||||
.add("cheat.el", description: "cheat from emacs")
|
||||
.add("batteries", description: "a general purpose node library")
|
||||
.add("samhuri.net", description: "this site")
|
||||
.build()
|
||||
|
||||
let postsPlugin = PostsPluginBuilder(templateRenderer: renderer)
|
||||
.path("posts")
|
||||
.jsonFeed(
|
||||
|
|
@ -29,10 +53,10 @@ public extension samhuri {
|
|||
email: "sami@samhuri.net",
|
||||
url: siteURLOverride ?? URL(string: "https://samhuri.net")!
|
||||
)
|
||||
.styles("/css/normalize.css", "/css/style.css")
|
||||
.styles("normalize.css", "style.css")
|
||||
.styles("https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css")
|
||||
.renderMarkdown(pageRenderer: renderer)
|
||||
.projects(templateRenderer: renderer)
|
||||
.plugin(projectsPlugin)
|
||||
.plugin(postsPlugin)
|
||||
.build()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
{% extends "samhuri.net.html" %}
|
||||
{% block body %}
|
||||
<article class="container project">
|
||||
<!-- projects.js picks up this data-title attribute and uses it to render all the Github stuff -->
|
||||
<h1 id="project" data-title="{{ project.title }}">{{ project.title }}</h1>
|
||||
<h4>{{ project.description }}</h4>
|
||||
|
||||
<div class="project-stats">
|
||||
<p>
|
||||
<a href="https://github.com/samsonjs/{{ project.title }}">GitHub</a>
|
||||
•
|
||||
<a id="nstar" href="https://github.com/samsonjs/{{ project.title }}/stargazers"></a>
|
||||
•
|
||||
<a id="nfork" href="https://github.com/samsonjs/{{ project.title }}/network/members"></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Last updated on <span id="updated"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="project-info row clearfix">
|
||||
<div class="column half">
|
||||
<h3>Contributors</h3>
|
||||
<div id="contributors"></div>
|
||||
</div>
|
||||
|
||||
<div class="column half">
|
||||
<h3>Languages</h3>
|
||||
<div id="langs"></div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<div class="row clearfix">
|
||||
<p class="fin"><i class="fa fa-code"></i></p>
|
||||
</div>
|
||||
|
||||
<script defer src="https://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js"></script>
|
||||
<script defer src="/js/gitter.js"></script>
|
||||
<script defer src="/js/store.js"></script>
|
||||
<script defer src="/js/projects.js"></script>
|
||||
{% endblock %}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
{% extends "samhuri.net.html" %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<article class="container">
|
||||
<h1>Projects</h1>
|
||||
|
||||
{% for project in projects %}
|
||||
<div class="project-listing">
|
||||
<h4><a href="{{ project.path }}">{{ project.title }}</a></h4>
|
||||
<p class="description">{{ project.description }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</article>
|
||||
<div class="row clearfix">
|
||||
<p class="fin"><i class="fa fa-code"></i></p>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -64,7 +64,7 @@
|
|||
<script type="text/javascript">
|
||||
(function() {
|
||||
var css = document.createElement('link');
|
||||
css.href = '{{ style }}';
|
||||
css.href = '/css/{{ style }}';
|
||||
css.rel = 'stylesheet';
|
||||
css.type = 'text/css';
|
||||
document.getElementsByTagName('head')[0].appendChild(css);
|
||||
|
|
@ -72,16 +72,6 @@
|
|||
</script>
|
||||
{% endfor %}
|
||||
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var css = document.createElement('link');
|
||||
css.href = '//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css';
|
||||
css.rel = 'stylesheet';
|
||||
css.type = 'text/css';
|
||||
document.getElementsByTagName('head')[0].appendChild(css);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script src="https://use.typekit.net/tcm1whv.js" crossorigin="anonymous"></script>
|
||||
<script>try{Typekit.load({ async: true });}catch(e){}</script>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue