mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-04-27 14:57:40 +00:00
Render Markdown pages using Plot instead of Stencil
This commit is contained in:
parent
e22c17e810
commit
8b676c443a
17 changed files with 235 additions and 86 deletions
|
|
@ -119,7 +119,7 @@ Execution, trying TDD for the first time:
|
||||||
|
|
||||||
- [x] Move template rendering from SiteGenerator to samhuri.net
|
- [x] Move template rendering from SiteGenerator to samhuri.net
|
||||||
|
|
||||||
- [ ] Replace page template with Swift code
|
- [x] Replace page template with Swift code
|
||||||
|
|
||||||
- [ ] Replace projects.json with Swift code
|
- [ ] Replace projects.json with Swift code
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,35 +6,8 @@
|
||||||
"repositoryURL": "https://github.com/johnsundell/ink.git",
|
"repositoryURL": "https://github.com/johnsundell/ink.git",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "af743ad6882bfe1adb0acf7453d36d2075ebb1d5",
|
"revision": "c88bbce588a1ebfde2cf4d61eb9865a3edaa27d4",
|
||||||
"version": "0.1.3"
|
"version": "0.2.0"
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "PathKit",
|
|
||||||
"repositoryURL": "https://github.com/kylef/PathKit.git",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "e2f5be30e4c8f531c9c1e8765aa7b71c0a45d7a0",
|
|
||||||
"version": "0.9.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "Spectre",
|
|
||||||
"repositoryURL": "https://github.com/kylef/Spectre.git",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "f14ff47f45642aa5703900980b014c2e9394b6e5",
|
|
||||||
"version": "0.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "Stencil",
|
|
||||||
"repositoryURL": "https://github.com/stencilproject/Stencil.git",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "0e9a78d6584e3812cd9c09494d5c7b483e8f533c",
|
|
||||||
"version": "0.13.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ let package = Package(
|
||||||
targets: ["SiteGenerator"]),
|
targets: ["SiteGenerator"]),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://github.com/johnsundell/ink.git", from: "0.1.0"),
|
.package(url: "https://github.com/johnsundell/ink.git", from: "0.2.0"),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||||
|
|
|
||||||
|
|
@ -52,14 +52,7 @@ final class RSSFeedWriter {
|
||||||
)
|
)
|
||||||
let renderedPosts: [FeedPost] = try posts.map { post in
|
let renderedPosts: [FeedPost] = try posts.map { post in
|
||||||
let title = post.isLink ? "→ \(post.title)" : post.title
|
let title = post.isLink ? "→ \(post.title)" : post.title
|
||||||
let author: String = {
|
let author = "\(site.email) (\(post.author))"
|
||||||
if let email = site.email {
|
|
||||||
return "\(email) (\(post.author))"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return post.author
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
let url = site.url.appendingPathComponent(post.path)
|
let url = site.url.appendingPathComponent(post.path)
|
||||||
return FeedPost(
|
return FeedPost(
|
||||||
title: title.escapedForXML(),
|
title: title.escapedForXML(),
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import Foundation
|
||||||
|
|
||||||
public struct Site {
|
public struct Site {
|
||||||
public let author: String
|
public let author: String
|
||||||
public let email: String?
|
public let email: String
|
||||||
public let title: String
|
public let title: String
|
||||||
public let description: String?
|
public let description: String?
|
||||||
public let url: URL
|
public let url: URL
|
||||||
|
|
@ -20,7 +20,7 @@ public struct Site {
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
author: String,
|
author: String,
|
||||||
email: String?,
|
email: String,
|
||||||
title: String,
|
title: String,
|
||||||
description: String?,
|
description: String?,
|
||||||
url: URL,
|
url: URL,
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,12 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public final class SiteBuilder {
|
public final class SiteBuilder {
|
||||||
private let author: String
|
|
||||||
private let title: String
|
private let title: String
|
||||||
|
private let description: String?
|
||||||
|
private let author: String
|
||||||
|
private let email: String
|
||||||
private let url: URL
|
private let url: URL
|
||||||
|
|
||||||
private var email: String?
|
|
||||||
private var description: String?
|
|
||||||
|
|
||||||
private var styles: [String] = []
|
private var styles: [String] = []
|
||||||
private var scripts: [String] = []
|
private var scripts: [String] = []
|
||||||
|
|
||||||
|
|
@ -22,29 +21,17 @@ public final class SiteBuilder {
|
||||||
private var renderers: [Renderer] = []
|
private var renderers: [Renderer] = []
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
author: String,
|
|
||||||
email: String? = nil,
|
|
||||||
title: String,
|
title: String,
|
||||||
description: String? = nil,
|
description: String? = nil,
|
||||||
|
author: String,
|
||||||
|
email: String,
|
||||||
url: URL
|
url: URL
|
||||||
) {
|
) {
|
||||||
self.author = author
|
|
||||||
self.email = email
|
|
||||||
self.title = title
|
self.title = title
|
||||||
self.description = description
|
self.description = description
|
||||||
self.url = url
|
self.author = author
|
||||||
}
|
|
||||||
|
|
||||||
public func email(_ email: String) -> SiteBuilder {
|
|
||||||
precondition(self.email == nil, "email is already defined")
|
|
||||||
self.email = email
|
self.email = email
|
||||||
return self
|
self.url = url
|
||||||
}
|
|
||||||
|
|
||||||
public func description(_ description: String) -> SiteBuilder {
|
|
||||||
precondition(self.description == nil, "description is already defined")
|
|
||||||
self.description = description
|
|
||||||
return self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func styles(_ styles: String...) -> SiteBuilder {
|
public func styles(_ styles: String...) -> SiteBuilder {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,15 @@
|
||||||
"version": "0.9.2"
|
"version": "0.9.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"package": "Plot",
|
||||||
|
"repositoryURL": "https://github.com/johnsundell/plot.git",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "dd7fce79ce4802afdc7d45ce34bddc5cea566202",
|
||||||
|
"version": "0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"package": "Spectre",
|
"package": "Spectre",
|
||||||
"repositoryURL": "https://github.com/kylef/Spectre.git",
|
"repositoryURL": "https://github.com/kylef/Spectre.git",
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,15 @@
|
||||||
"version": "0.9.2"
|
"version": "0.9.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"package": "Plot",
|
||||||
|
"repositoryURL": "https://github.com/johnsundell/plot.git",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "dd7fce79ce4802afdc7d45ce34bddc5cea566202",
|
||||||
|
"version": "0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"package": "Spectre",
|
"package": "Spectre",
|
||||||
"repositoryURL": "https://github.com/kylef/Spectre.git",
|
"repositoryURL": "https://github.com/kylef/Spectre.git",
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ let package = Package(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(path: "../SiteGenerator"),
|
.package(path: "../SiteGenerator"),
|
||||||
.package(url: "https://github.com/stencilproject/Stencil.git", from: "0.13.0"),
|
.package(url: "https://github.com/stencilproject/Stencil.git", from: "0.13.0"),
|
||||||
|
.package(url: "https://github.com/johnsundell/plot.git", from: "0.2.0"),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||||
|
|
@ -25,6 +26,7 @@ let package = Package(
|
||||||
.target(
|
.target(
|
||||||
name: "samhuri.net",
|
name: "samhuri.net",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
"Plot",
|
||||||
"SiteGenerator",
|
"SiteGenerator",
|
||||||
"Stencil",
|
"Stencil",
|
||||||
]),
|
]),
|
||||||
|
|
|
||||||
42
samhuri.net/Sources/samhuri.net/HTMLElements.swift
Normal file
42
samhuri.net/Sources/samhuri.net/HTMLElements.swift
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
//
|
||||||
|
// HTMLElements.swift
|
||||||
|
// samhuri.net
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Plot
|
||||||
|
|
||||||
|
extension Node where Context == HTML.HeadContext {
|
||||||
|
static func jsonFeedLink(_ url: URLRepresentable, title: String) -> Node<HTML.HeadContext> {
|
||||||
|
.link(.rel(.alternate), .href(url), .type("application/json"), .attribute(named: "title", value: title))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Node where Context == HTML.HeadContext {
|
||||||
|
static func appleTouchIcon(_ url: URLRepresentable) -> Node<HTML.HeadContext> {
|
||||||
|
.link(.attribute(named: "rel", value: "apple-touch-icon"), .href(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
static func safariPinnedTabIcon(_ url: URLRepresentable, color: String) -> Node<HTML.HeadContext> {
|
||||||
|
.link(.attribute(named: "rel", value: "mask-icon"), .attribute(named: "color", value: color), .href(url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Node where Context == HTML.BodyContext {
|
||||||
|
static func asyncStylesheetLinks(_ urls: [URLRepresentable]) -> Node<HTML.BodyContext> {
|
||||||
|
.script("""
|
||||||
|
(function() {
|
||||||
|
var urls = [\(urls.map { "'\($0)'" }.joined(separator: ", "))];
|
||||||
|
urls.forEach(function(url) {
|
||||||
|
var css = document.createElement('link');
|
||||||
|
css.href = url;
|
||||||
|
css.rel = 'stylesheet';
|
||||||
|
css.type = 'text/css';
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(css);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,14 +8,31 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SiteGenerator
|
import SiteGenerator
|
||||||
|
|
||||||
struct PageContext {
|
struct PageContext: TemplateContext {
|
||||||
let site: Site
|
let site: Site
|
||||||
let body: String
|
@available(*, deprecated) let body: String
|
||||||
let page: Page
|
let page: Page
|
||||||
let metadata: [String: String]
|
@available(*, deprecated) let metadata: [String: String]
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
"\(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PageContext {
|
extension PageContext {
|
||||||
|
@available(*, deprecated)
|
||||||
var dictionary: [String: Any] {
|
var dictionary: [String: Any] {
|
||||||
[
|
[
|
||||||
"site": site,
|
"site": site,
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import PathKit
|
import Plot
|
||||||
import SiteGenerator
|
import SiteGenerator
|
||||||
|
|
||||||
|
#warning("Deprecated imports")
|
||||||
|
import PathKit
|
||||||
import Stencil
|
import Stencil
|
||||||
|
|
||||||
final class PageRenderer {
|
final class PageRenderer {
|
||||||
|
|
@ -19,14 +22,79 @@ final class PageRenderer {
|
||||||
let loader = FileSystemLoader(paths: [templatesPath])
|
let loader = FileSystemLoader(paths: [templatesPath])
|
||||||
self.stencil = Environment(loader: loader)
|
self.stencil = Environment(loader: loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func siteTemplate(body: Node<HTML.BodyContext>, context: TemplateContext) -> HTML {
|
||||||
|
HTML(.lang("en"),
|
||||||
|
.head(
|
||||||
|
.encoding(.utf8),
|
||||||
|
.viewport(.accordingToDevice),
|
||||||
|
.title(context.title),
|
||||||
|
.siteName(context.site.title),
|
||||||
|
.url(context.site.url),
|
||||||
|
.rssFeedLink(context.url(for: "feed.xml"), title: context.site.title),
|
||||||
|
.jsonFeedLink(context.url(for: "feed.json"), title: context.site.title),
|
||||||
|
.link(.rel(.author), .type("text/plain"), .href(context.url(for: "humans.txt"))),
|
||||||
|
.link(.rel(.icon), .type("image/png"), .href(context.imageURL("favicon-32x32.png"))),
|
||||||
|
.link(.rel(.shortcutIcon), .href(context.imageURL("favicon.icon"))),
|
||||||
|
.appleTouchIcon(context.imageURL("apple-touch-icon.png")),
|
||||||
|
.safariPinnedTabIcon(context.imageURL("safari-pinned-tab.svg"), color: "#aa0000"),
|
||||||
|
.link(.attribute(named: "rel", value: "manifest"), .href(context.imageURL("manifest.json"))),
|
||||||
|
.meta(.name("msapplication-config"), .content(context.imageURL("browserconfig.xml").absoluteString)),
|
||||||
|
.meta(.name("theme-color"), .content("#ffffff")),
|
||||||
|
.link(.rel(.dnsPrefetch), .href("https://use.typekit.net")),
|
||||||
|
.link(.rel(.dnsPrefetch), .href("https://netdna.bootstrapcdn.com")),
|
||||||
|
.link(.rel(.dnsPrefetch), .href("https://gist.github.com"))
|
||||||
|
),
|
||||||
|
.body(
|
||||||
|
.header(.class("primary"),
|
||||||
|
.div(.class("title"),
|
||||||
|
.h1(.a(.href(context.site.url), .text(context.site.title))),
|
||||||
|
.br(),
|
||||||
|
.h4(.text("By "), .a(.href(context.url(for: "about")), .text(context.site.author)))
|
||||||
|
),
|
||||||
|
.nav(
|
||||||
|
.ul(
|
||||||
|
.li(.a(.href(context.url(for: "about")), "About")),
|
||||||
|
.li(.a(.href(context.url(for: "posts")), "Archive")),
|
||||||
|
.li(.a(.href(context.url(for: "projects")), "Projects")),
|
||||||
|
.li(.class("twitter"), .a(.href("https://twitter.com/_sjs"), .i(.class("fa fa-twitter")))),
|
||||||
|
.li(.class("github"), .a(.href("https://github.com/samsonjs"), .i(.class("fa fa-github")))),
|
||||||
|
.li(.class("email"), .a(.href("mailto:\(context.site.email)"), .i(.class("fa fa-envelope")))),
|
||||||
|
.li(.class("rss"), .a(.href(context.url(for: "feed.xml")), .i(.class("fa fa-rss"))))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
.div(.class("clearfix"))
|
||||||
|
),
|
||||||
|
body,
|
||||||
|
.footer(.class("container"),
|
||||||
|
"© 2006 - \(context.currentYear)",
|
||||||
|
.a(.href(context.url(for: "about")), .text(context.site.author))
|
||||||
|
),
|
||||||
|
.asyncStylesheetLinks(context.styles),
|
||||||
|
.group(context.scripts.map { script in
|
||||||
|
.script(.attribute(named: "defer"), .src(script))
|
||||||
|
}),
|
||||||
|
.script(.src("https://use.typekit.net/tcm1whv.js"), .attribute(named: "crossorigin", value: "anonymous")),
|
||||||
|
.script("try{Typekit.load({ async: true });}catch(e){}")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PageRenderer: MarkdownPageRenderer {
|
extension PageRenderer: MarkdownPageRenderer {
|
||||||
func renderPage(site: Site, bodyHTML: String, metadata: [String: String]) throws -> String {
|
func renderPage(site: Site, bodyHTML: String, metadata: [String: String]) throws -> String {
|
||||||
let page = Page(metadata: metadata)
|
let page = Page(metadata: metadata)
|
||||||
let context = PageContext(site: site, body: bodyHTML, page: page, metadata: metadata)
|
let context = PageContext(site: site, body: bodyHTML, page: page, metadata: metadata)
|
||||||
let pageHTML = try stencil.renderTemplate(name: "page.html", context: context.dictionary)
|
let body: Node<HTML.BodyContext> = .group([
|
||||||
return pageHTML
|
.article(.class("container"),
|
||||||
|
.h1(.text(page.title)),
|
||||||
|
.raw(bodyHTML)
|
||||||
|
),
|
||||||
|
.div(.class("row clearfix"),
|
||||||
|
.p(.class("fin"), .i(.class("fa fa-code")))
|
||||||
|
)
|
||||||
|
])
|
||||||
|
return siteTemplate(body: body, context: context).render(indentedBy: .spaces(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,33 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SiteGenerator
|
import SiteGenerator
|
||||||
|
|
||||||
struct SiteContext {
|
struct SiteContext: TemplateContext {
|
||||||
let site: Site
|
let site: Site
|
||||||
|
let subtitle: String?
|
||||||
|
|
||||||
init(site: Site) {
|
init(site: Site, subtitle: String? = nil) {
|
||||||
self.site = site
|
self.site = site
|
||||||
|
self.subtitle = subtitle
|
||||||
|
}
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
guard let subtitle = subtitle else {
|
||||||
|
return site.title
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
41
samhuri.net/Sources/samhuri.net/TemplateContext.swift
Normal file
41
samhuri.net/Sources/samhuri.net/TemplateContext.swift
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// TemplateContext.swift
|
||||||
|
// samhuri.net
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SiteGenerator
|
||||||
|
|
||||||
|
protocol TemplateContext {
|
||||||
|
// Concrete requirements, must be implemented
|
||||||
|
|
||||||
|
var site: Site { get }
|
||||||
|
var title: String { get }
|
||||||
|
var styles: [URL] { get }
|
||||||
|
var scripts: [URL] { get }
|
||||||
|
|
||||||
|
// These all have default implementations
|
||||||
|
|
||||||
|
var currentYear: Int { get }
|
||||||
|
|
||||||
|
func url(for path: String) -> URL
|
||||||
|
func imageURL(_ filename: String) -> URL
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TemplateContext {
|
||||||
|
var currentYear: Int {
|
||||||
|
Date().year
|
||||||
|
}
|
||||||
|
|
||||||
|
func url(for path: String) -> URL {
|
||||||
|
site.url.appendingPathComponent(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageURL(_ filename: String) -> URL {
|
||||||
|
site.url
|
||||||
|
.appendingPathComponent("images")
|
||||||
|
.appendingPathComponent(filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,13 +23,14 @@ public extension samhuri {
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return SiteBuilder(
|
return SiteBuilder(
|
||||||
author: "Sami Samhuri",
|
|
||||||
email: "sami@samhuri.net",
|
|
||||||
title: "samhuri.net",
|
title: "samhuri.net",
|
||||||
description: "just some blog",
|
description: "just some blog",
|
||||||
|
author: "Sami Samhuri",
|
||||||
|
email: "sami@samhuri.net",
|
||||||
url: siteURLOverride ?? URL(string: "https://samhuri.net")!
|
url: siteURLOverride ?? URL(string: "https://samhuri.net")!
|
||||||
)
|
)
|
||||||
.styles("/css/normalize.css", "/css/style.css")
|
.styles("/css/normalize.css", "/css/style.css")
|
||||||
|
.styles("https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css")
|
||||||
.renderMarkdown(pageRenderer: renderer)
|
.renderMarkdown(pageRenderer: renderer)
|
||||||
.projects(templateRenderer: renderer)
|
.projects(templateRenderer: renderer)
|
||||||
.plugin(postsPlugin)
|
.plugin(postsPlugin)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
{% extends "samhuri.net.html" %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
<article class="container">
|
|
||||||
<h1>{{ page.title }}</h1>
|
|
||||||
{{ body }}
|
|
||||||
</article>
|
|
||||||
<div class="row clearfix">
|
|
||||||
<p class="fin"><i class="fa fa-code"></i></p>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -31,11 +31,7 @@
|
||||||
<link rel="dns-prefetch" href="https://gist.github.com">
|
<link rel="dns-prefetch" href="https://gist.github.com">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
{% if bodyClassNames %}
|
|
||||||
<body class="{{ bodyClassNames }}">
|
|
||||||
{% else %}
|
|
||||||
<body>
|
<body>
|
||||||
{% endif %}
|
|
||||||
<header class="primary">
|
<header class="primary">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<h1><a href="/">{{ site.title }}</a></h1>
|
<h1><a href="/">{{ site.title }}</a></h1>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue