mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-04-27 14:57:40 +00:00
WIP: Render known pages and get template in place
This commit is contained in:
parent
6280bd6a20
commit
4785f241c8
22 changed files with 354 additions and 50 deletions
12
Readme.md
12
Readme.md
|
|
@ -21,13 +21,17 @@ Execution, trying TDD for the first time:
|
||||||
|
|
||||||
- [x] Write a site generator that renders www/index.html from site.json
|
- [x] Write a site generator that renders www/index.html from site.json
|
||||||
|
|
||||||
- [ ] Port _layout.ejs to Swift code
|
- [x] Add support for site styles
|
||||||
|
|
||||||
- [ ] Add support for CSS files
|
- [ ] Add support for page styles
|
||||||
|
|
||||||
- [ ] Transform LESS into CSS
|
- [x] Add support for site scripts
|
||||||
|
|
||||||
- [ ] Add support for JS files
|
- [ ] Add support for page scripts
|
||||||
|
|
||||||
|
- [x] Add support for CSS files
|
||||||
|
|
||||||
|
- [x] Transform LESS into CSS
|
||||||
|
|
||||||
- [ ] Migrate projects to the new site generator
|
- [ ] Migrate projects to the new site generator
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ import Stencil
|
||||||
public final class Generator {
|
public final class Generator {
|
||||||
private let fileManager: FileManager = .default
|
private let fileManager: FileManager = .default
|
||||||
|
|
||||||
public let site: Site
|
let site: Site
|
||||||
public let sourceURL: URL
|
let sourceURL: URL
|
||||||
|
|
||||||
private let lessParser: LessParser
|
private let lessParser: LessParser
|
||||||
private let mdParser: MarkdownParser
|
private let mdParser: MarkdownParser
|
||||||
|
|
@ -63,7 +63,7 @@ public final class Generator {
|
||||||
|
|
||||||
case "md":
|
case "md":
|
||||||
let htmlURL = targetURL.appendingPathComponent(filename.replacingOccurrences(of: ".md", with: ".html"))
|
let htmlURL = targetURL.appendingPathComponent(filename.replacingOccurrences(of: ".md", with: ".html"))
|
||||||
try renderMarkdown(from: fileURL, to: htmlURL, template: "site", context: [:])
|
try renderMarkdown(from: fileURL, to: htmlURL)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Who knows. Copy the file unchanged.
|
// Who knows. Copy the file unchanged.
|
||||||
|
|
@ -83,18 +83,52 @@ public final class Generator {
|
||||||
|
|
||||||
func renderMarkdown(
|
func renderMarkdown(
|
||||||
from sourceURL: URL,
|
from sourceURL: URL,
|
||||||
to targetURL: URL,
|
to targetURL: URL
|
||||||
template: String,
|
|
||||||
context: [String: Any]
|
|
||||||
) throws {
|
) throws {
|
||||||
let bodyMarkdown = try String(contentsOf: sourceURL, encoding: .utf8)
|
let bodyMarkdown = try String(contentsOf: sourceURL, encoding: .utf8)
|
||||||
let bodyResult = mdParser.parse(bodyMarkdown)
|
let bodyHTML = mdParser.html(from: bodyMarkdown).trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
let bodyHTML = bodyResult.html.trimmingCharacters(in: .whitespacesAndNewlines)
|
let metadata = try markdownMetadata(from: sourceURL)
|
||||||
var context = context
|
let context = templateContext(url: sourceURL, metadata: metadata, body: bodyHTML)
|
||||||
context["site"] = site
|
let siteHTML = try templateRenderer.renderTemplate(name: "\(context.template).html", context: context.dictionary)
|
||||||
context["body"] = bodyHTML
|
|
||||||
context.merge(bodyResult.metadata, uniquingKeysWith: { _, new in new })
|
|
||||||
let siteHTML = try templateRenderer.renderTemplate(name: "\(template).html", context: context)
|
|
||||||
try siteHTML.write(to: targetURL, atomically: true, encoding: .utf8)
|
try siteHTML.write(to: targetURL, atomically: true, encoding: .utf8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func markdownMetadata(from url: URL) throws -> [String: String] {
|
||||||
|
let md = try String(contentsOf: url, encoding: .utf8)
|
||||||
|
return mdParser.parse(md).metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
func templateContext(url: URL, metadata: [String: String], body: String) -> TemplateContext {
|
||||||
|
let template = metadata["Template"]
|
||||||
|
let styles = metadata["Styles"]?.split(separator: ",").map { $0.trimmingCharacters(in: .whitespaces) }
|
||||||
|
let scripts = metadata["Scripts"]?.split(separator: ",").map { $0.trimmingCharacters(in: .whitespaces) }
|
||||||
|
|
||||||
|
#warning("FIXME: this is all fucked ... we need to handle index, archive, etc. differently, just make them built in pages and use a templates in templates/archive.html or something like that")
|
||||||
|
|
||||||
|
switch url.lastPathComponent {
|
||||||
|
/*
|
||||||
|
case "index.md":
|
||||||
|
#warning("TODO: fetch recentPosts")
|
||||||
|
let index = Index(template: template, styles: styles, scripts: scripts, recentPosts: [])
|
||||||
|
return .index(index)
|
||||||
|
|
||||||
|
case "archive.md":
|
||||||
|
let archive = Archive(title: "Archive", template: template, styles: styles, scripts: scripts)
|
||||||
|
return .archive(archive)
|
||||||
|
case "projects.md":
|
||||||
|
*/
|
||||||
|
|
||||||
|
default:
|
||||||
|
let title = metadata["Title"]!
|
||||||
|
let page = DefaultPage(title: title, template: template, styles: styles ?? [], scripts: scripts ?? [])
|
||||||
|
return TemplateContext(site: site, pageType: .page(page))
|
||||||
|
}
|
||||||
|
// case projects(Projects)
|
||||||
|
// case project(Project)
|
||||||
|
// let title = (metadata["Title"] as? String) ?? ""
|
||||||
|
// case post(Post)
|
||||||
|
// let title = (metadata["Title"] as? String) ?? ""
|
||||||
|
// case page(DefaultPage)
|
||||||
|
let title = (metadata["Title"] as? String) ?? ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
SiteGenerator/Sources/SiteGenerator/Model/Archive.swift
Normal file
18
SiteGenerator/Sources/SiteGenerator/Model/Archive.swift
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
//
|
||||||
|
// Archive.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct Archive: Page {
|
||||||
|
// Page properties
|
||||||
|
let title: String
|
||||||
|
let template: String?
|
||||||
|
let styles: [String]
|
||||||
|
let scripts: [String]
|
||||||
|
|
||||||
|
// Other properties
|
||||||
|
}
|
||||||
15
SiteGenerator/Sources/SiteGenerator/Model/DefaultPage.swift
Normal file
15
SiteGenerator/Sources/SiteGenerator/Model/DefaultPage.swift
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// DefaultPage.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct DefaultPage: Page {
|
||||||
|
let title: String
|
||||||
|
let template: String?
|
||||||
|
let styles: [String]
|
||||||
|
let scripts: [String]
|
||||||
|
}
|
||||||
29
SiteGenerator/Sources/SiteGenerator/Model/HumanSite.swift
Normal file
29
SiteGenerator/Sources/SiteGenerator/Model/HumanSite.swift
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// HumanSite.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// This is used to make the JSON simpler to write with optionals.
|
||||||
|
struct HumanSite: Codable {
|
||||||
|
let author: String
|
||||||
|
let title: String
|
||||||
|
let url: String
|
||||||
|
let template: String?
|
||||||
|
let styles: [String]?
|
||||||
|
let scripts: [String]?
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Site {
|
||||||
|
init(humanSite: HumanSite) {
|
||||||
|
self.author = humanSite.author
|
||||||
|
self.title = humanSite.title
|
||||||
|
self.url = humanSite.url
|
||||||
|
self.template = humanSite.template ?? "site"
|
||||||
|
self.styles = humanSite.styles ?? []
|
||||||
|
self.scripts = humanSite.scripts ?? []
|
||||||
|
}
|
||||||
|
}
|
||||||
23
SiteGenerator/Sources/SiteGenerator/Model/Index.swift
Normal file
23
SiteGenerator/Sources/SiteGenerator/Model/Index.swift
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// Index.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct Index: Page {
|
||||||
|
// Page properties
|
||||||
|
let template: String?
|
||||||
|
let styles: [String]
|
||||||
|
let scripts: [String]
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
assertionFailure("Don't use this. Use Site.title instead.")
|
||||||
|
return "easter egg"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other properties
|
||||||
|
let recentPosts: [Post]
|
||||||
|
}
|
||||||
15
SiteGenerator/Sources/SiteGenerator/Model/Page.swift
Normal file
15
SiteGenerator/Sources/SiteGenerator/Model/Page.swift
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// Page.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
protocol Page {
|
||||||
|
var title: String { get }
|
||||||
|
var template: String? { get }
|
||||||
|
var styles: [String] { get }
|
||||||
|
var scripts: [String] { get }
|
||||||
|
}
|
||||||
20
SiteGenerator/Sources/SiteGenerator/Model/Post.swift
Normal file
20
SiteGenerator/Sources/SiteGenerator/Model/Post.swift
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
//
|
||||||
|
// Post.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct Post: Page {
|
||||||
|
// Page properties
|
||||||
|
let title: String
|
||||||
|
let template: String?
|
||||||
|
let styles: [String]
|
||||||
|
let scripts: [String]
|
||||||
|
|
||||||
|
// Other properties
|
||||||
|
let date: Date
|
||||||
|
let formattedDate: String
|
||||||
|
}
|
||||||
18
SiteGenerator/Sources/SiteGenerator/Model/Project.swift
Normal file
18
SiteGenerator/Sources/SiteGenerator/Model/Project.swift
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
//
|
||||||
|
// Project.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct Project: Page {
|
||||||
|
// Page properties
|
||||||
|
let title: String
|
||||||
|
let template: String?
|
||||||
|
let styles: [String]
|
||||||
|
let scripts: [String]
|
||||||
|
|
||||||
|
// Other properties
|
||||||
|
}
|
||||||
19
SiteGenerator/Sources/SiteGenerator/Model/Projects.swift
Normal file
19
SiteGenerator/Sources/SiteGenerator/Model/Projects.swift
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
//
|
||||||
|
// Projects.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct Projects: Page {
|
||||||
|
// Page properties
|
||||||
|
let title: String
|
||||||
|
let template: String?
|
||||||
|
let styles: [String]
|
||||||
|
let scripts: [String]
|
||||||
|
|
||||||
|
// Other properties
|
||||||
|
let projects: [Project]
|
||||||
|
}
|
||||||
13
SiteGenerator/Sources/SiteGenerator/Model/RenderedPage.swift
Normal file
13
SiteGenerator/Sources/SiteGenerator/Model/RenderedPage.swift
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// RenderedPage.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct RenderedPage<SomePage: Page> {
|
||||||
|
let page: SomePage
|
||||||
|
let body: String
|
||||||
|
}
|
||||||
25
SiteGenerator/Sources/SiteGenerator/Model/Site.swift
Normal file
25
SiteGenerator/Sources/SiteGenerator/Model/Site.swift
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
//
|
||||||
|
// Site.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct Site {
|
||||||
|
let author: String
|
||||||
|
let title: String
|
||||||
|
let url: String
|
||||||
|
let template: String
|
||||||
|
let styles: [String]
|
||||||
|
let scripts: [String]
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Site {
|
||||||
|
static func decode(from url: URL) throws -> Site {
|
||||||
|
let json = try Data(contentsOf: url)
|
||||||
|
let humanSite = try JSONDecoder().decode(HumanSite.self, from: json)
|
||||||
|
return Site(humanSite: humanSite)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
//
|
|
||||||
// Site.swift
|
|
||||||
// SiteGenerator
|
|
||||||
//
|
|
||||||
// Created by Sami Samhuri on 2019-12-01.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
public struct Site: Codable {
|
|
||||||
public let author: String
|
|
||||||
public let email: String
|
|
||||||
public let title: String
|
|
||||||
public let url: String
|
|
||||||
public let styles: [String]?
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension Site {
|
|
||||||
static func decode(from url: URL) throws -> Site {
|
|
||||||
let json = try Data(contentsOf: url)
|
|
||||||
return try JSONDecoder().decode(Site.self, from: json)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
87
SiteGenerator/Sources/SiteGenerator/TemplateContext.swift
Normal file
87
SiteGenerator/Sources/SiteGenerator/TemplateContext.swift
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
//
|
||||||
|
// TemplateContext.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum PageType {
|
||||||
|
case page(DefaultPage)
|
||||||
|
|
||||||
|
case index(Index)
|
||||||
|
case archive(Archive)
|
||||||
|
// case monthPosts(MonthPosts)
|
||||||
|
// case yearPosts(YearPosts)
|
||||||
|
case post(Post)
|
||||||
|
|
||||||
|
case projects(Projects)
|
||||||
|
case project(Project)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TemplateContext {
|
||||||
|
let site: Site
|
||||||
|
let pageType: PageType
|
||||||
|
|
||||||
|
var page: Page {
|
||||||
|
switch pageType {
|
||||||
|
case let .index(page as Page),
|
||||||
|
let .archive(page as Page),
|
||||||
|
let .projects(page as Page),
|
||||||
|
let .project(page as Page),
|
||||||
|
let .post(page as Page),
|
||||||
|
let .page(page as Page):
|
||||||
|
return page
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
if case .index = pageType {
|
||||||
|
return site.title
|
||||||
|
}
|
||||||
|
return "\(site.title): \(page.title)"
|
||||||
|
}
|
||||||
|
|
||||||
|
var template: String {
|
||||||
|
page.template ?? site.template
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Dictionary form
|
||||||
|
|
||||||
|
extension PageType {
|
||||||
|
var dictionary: [String: Any] {
|
||||||
|
switch self {
|
||||||
|
case let .index(index):
|
||||||
|
return ["index": index]
|
||||||
|
|
||||||
|
case let .archive(archive):
|
||||||
|
return ["archive": archive]
|
||||||
|
|
||||||
|
case let .projects(projects):
|
||||||
|
return ["projects": projects]
|
||||||
|
|
||||||
|
case let .project(project):
|
||||||
|
return ["project": project]
|
||||||
|
|
||||||
|
case let .post(post):
|
||||||
|
return ["post": post]
|
||||||
|
|
||||||
|
case .page:
|
||||||
|
return [:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TemplateContext {
|
||||||
|
var dictionary: [String: Any] {
|
||||||
|
[
|
||||||
|
"site": site,
|
||||||
|
"page": page,
|
||||||
|
"title": title,
|
||||||
|
"styles": site.styles + page.styles,
|
||||||
|
"scripts": site.scripts + page.scripts,
|
||||||
|
].merging(pageType.dictionary, uniquingKeysWith: { current, _ in current })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,6 @@ func main(sourcePath: String, targetPath: String) throws {
|
||||||
let sourcePath = CommandLine.arguments[1]
|
let sourcePath = CommandLine.arguments[1]
|
||||||
let targetPath = CommandLine.arguments[2]
|
let targetPath = CommandLine.arguments[2]
|
||||||
|
|
||||||
// TODO: validate args
|
#warning("TODO: validate args")
|
||||||
|
|
||||||
try! main(sourcePath: sourcePath, targetPath: targetPath)
|
try! main(sourcePath: sourcePath, targetPath: targetPath)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"author": "A man has no name",
|
"author": "A man has no name",
|
||||||
"email": "jaqen@hotmail.com",
|
|
||||||
"title": "Valar Morghulis",
|
"title": "Valar Morghulis",
|
||||||
"url": "http://example.net"
|
"url": "http://example.net"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"author": "A man has no name",
|
"author": "A man has no name",
|
||||||
"email": "jaqen@hotmail.com",
|
|
||||||
"title": "Valar Morghulis",
|
"title": "Valar Morghulis",
|
||||||
"url": "http://example.net"
|
"url": "http://example.net"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"author": "A man has no name",
|
"author": "A man has no name",
|
||||||
"email": "jaqen@hotmail.com",
|
|
||||||
"title": "Valar Morghulis",
|
"title": "Valar Morghulis",
|
||||||
"url": "http://example.net",
|
"url": "http://example.net",
|
||||||
"styles": [
|
"styles": [
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>{{ site.title }}</title>
|
<title>{{ site.title }}</title>
|
||||||
{% for style in site.styles %}
|
{% for style in allStyles %}
|
||||||
<link rel="stylesheet" href="{{ style }}">
|
<link rel="stylesheet" href="{{ style }}">
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,8 @@ ul.archive {
|
||||||
}
|
}
|
||||||
|
|
||||||
body.projects:not(.index) .container {
|
body.projects:not(.index) .container {
|
||||||
|
/* FIXME: find out where this is used and do it differently ... this selector sucks */
|
||||||
|
body { background-color: red; }
|
||||||
h2, h4 {
|
h2, h4 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
{
|
{
|
||||||
"title": "samhuri.net",
|
"title": "samhuri.net",
|
||||||
"author": "Sami Samhuri",
|
"author": "Sami Samhuri",
|
||||||
"email": "sami@samhuri.net",
|
"url": "https://samhuri.net",
|
||||||
"url": "https://samhuri.net"
|
"styles": [
|
||||||
|
"/css/normalize.css",
|
||||||
|
"/css/style.css"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||||
|
|
||||||
{% block title %}{{ site.title }}{% endblock %}
|
{% block title %}<title>{{ site.title }}</title>{% endblock %}
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="/images/favicon-32x32.png">
|
<link rel="icon" type="image/png" href="/images/favicon-32x32.png">
|
||||||
<link rel="shortcut icon" href="/images/favicon.ico">
|
<link rel="shortcut icon" href="/images/favicon.ico">
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
<meta name="msapplication-config" content="/images/browserconfig.xml">
|
<meta name="msapplication-config" content="/images/browserconfig.xml">
|
||||||
<meta name="theme-color" content="#ffffff">
|
<meta name="theme-color" content="#ffffff">
|
||||||
|
|
||||||
{% for style in styles %}
|
{% for style in allStyles %}
|
||||||
<link rel="stylesheet" href="{{ style }}">
|
<link rel="stylesheet" href="{{ style }}">
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
@ -45,7 +45,11 @@
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
{% if bodyClassNames %}
|
||||||
<body class="{{ bodyClassNames }}">
|
<body class="{{ bodyClassNames }}">
|
||||||
|
{% else %}
|
||||||
|
<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>
|
||||||
|
|
@ -84,7 +88,7 @@
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% for script in scripts %}
|
{% for script in allScripts %}
|
||||||
<script defer src="{{ script }}"></script>
|
<script defer src="{{ script }}"></script>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue