diff --git a/Cargo.lock b/Cargo.lock
index ae995be..2ea43d5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -21,6 +21,46 @@ dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "askama"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "askama_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "askama_escape 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "askama_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "askama_derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "askama_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "askama_escape"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "askama_shared"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "askama_escape 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "atty"
version = "0.2.13"
@@ -270,29 +310,6 @@ name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "handlebars"
-version = "2.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
- "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "hermit-abi"
version = "0.1.3"
@@ -301,6 +318,11 @@ dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "humansize"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "humantime"
version = "1.3.0"
@@ -381,9 +403,9 @@ dependencies = [
name = "mkbook"
version = "0.1.0"
dependencies = [
+ "askama 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"comrak 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "handlebars 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"sass-rs 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"syntect 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -399,6 +421,14 @@ dependencies = [
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "num-traits"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "num_cpus"
version = "1.11.1"
@@ -641,6 +671,16 @@ name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "syn"
+version = "0.15.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "syn"
version = "1.0.8"
@@ -696,6 +736,14 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "toml"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "toml"
version = "0.5.5"
@@ -835,6 +883,10 @@ dependencies = [
"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+"checksum askama 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc2a4b6d7f812d2b13d251ae792caecebd635d6401761162d4b71d5ebe1a010"
+"checksum askama_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ee2fff0f22ad5d215cace1227cd036c28e81e26206763bb837b6d0e766c87d"
+"checksum askama_escape 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0de942230b5beedaa9e1d64df5b76fa1c97002e4c7982897be899cccf40621d"
+"checksum askama_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6dfa6b6d254fd066a8bbed9a8f913123e3f701db89216ad4f0aff04ad87718c"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
@@ -864,9 +916,8 @@ dependencies = [
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
-"checksum handlebars 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "91ef1ac30f2eaaa2b835fce73c57091cb6b9fc62b7eef285efbf980b0f20001b"
-"checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120"
+"checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e"
"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
@@ -880,6 +931,7 @@ dependencies = [
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625"
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
+"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
"checksum onig 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4e723fc996fff1aeab8f62205f3e8528bf498bdd5eadb2784d2d31f30077947"
"checksum onig_sys 69.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a8d4efbf5f59cece01f539305191485b651acb3785b9d5eef05749f0496514e"
@@ -910,11 +962,13 @@ dependencies = [
"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92"
"checksum syntect 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "955e9da2455eea5635f7032fc3a229908e6af18c39600313866095e07db0d8b8"
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
+"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf"
"checksum twoway 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc"
"checksum typed-arena 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d"
diff --git a/Cargo.toml b/Cargo.toml
index 315f65d..e82de1c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,7 +9,7 @@ build = "build.rs"
syntect = "3.3"
comrak = "0.6"
clap = "2.33"
-handlebars = "2.0"
+askama = "0.8"
serde = { version = "1.0", features = ["derive"] }
toml = "0.5"
diff --git a/assets/icons.svg b/assets/icons.svg
new file mode 100644
index 0000000..d50227b
--- /dev/null
+++ b/assets/icons.svg
@@ -0,0 +1,12 @@
+
diff --git a/demo/src/01-introduction.md b/demo/src/01-introduction.md
new file mode 100644
index 0000000..d956632
--- /dev/null
+++ b/demo/src/01-introduction.md
@@ -0,0 +1,4 @@
+---
+title = "Introduction"
+---
+
diff --git a/demo/src/02-markdown.md b/demo/src/02-markdown.md
new file mode 100644
index 0000000..f0ed0f3
--- /dev/null
+++ b/demo/src/02-markdown.md
@@ -0,0 +1,4 @@
+---
+title = "Markdown"
+---
+
diff --git a/demo/src/03-frontmatter.md b/demo/src/03-frontmatter.md
new file mode 100644
index 0000000..6b13927
--- /dev/null
+++ b/demo/src/03-frontmatter.md
@@ -0,0 +1,28 @@
+---
+title = "Front Matter"
+---
+
+# Front Matter
+
+Each `.md` file can optionally contain a header with metadata describing the document. If the header isn't present, default values will be used which may look ugly.
+
+To insert a header into a `.md` file, insert three dashes (`---`), followed by a new-line, followed by the front matter contents, followed by a newline, then another three dashes and a new-line. The metadata is in the [TOML](https://github.com/toml-lang/toml) format, so for example the front-matter (and first line) for this file looks like:
+
+```md
+---
+title = "Front Matter"
+---
+
+# Front Matter
+
+Each `.md` file can optionally contain a header with metadata describing the document. If the header isn't present, default values will be used which may look ugly.
+```
+
+## Supported Keys
+
+The list of supported keys is subject to change, but for now it is as follows:
+
+title
+
+: A human-readable title for the document
+
diff --git a/demo/src/04-structure.md b/demo/src/04-structure.md
new file mode 100644
index 0000000..25e4fbb
--- /dev/null
+++ b/demo/src/04-structure.md
@@ -0,0 +1,4 @@
+---
+title = "Structure"
+---
+
diff --git a/demo/src/index.md b/demo/src/index.md
deleted file mode 100644
index 3c0c18d..0000000
--- a/demo/src/index.md
+++ /dev/null
@@ -1,72 +0,0 @@
----
-title = "Sparte plura"
----
-
-# Sparte plura
-
-## Sine flumina
-
-Lorem markdownum procubuit animasse solos talia [flammis me
-quia](http://www.dedit.io/fessa-nec), attollite. Tu dulcedine tanta mitescere
-manebit movit qualia aequorei victa illo, ipsi collum, suum disque. Sperantemque
-triumphos praecipitatur potentia mea? Vox aere vestibus coepit utque deinde, heu
-infans non amor somnusque Peleus.
-
-1. Carminibus colle artibus ferunt fulgorem
-2. Sonantia eripui
-3. Divamque fixumque inter
-4. Ducar mihi vertigine in spoliis
-5. Fuit pendens talibus recentibus
-6. Utrumque praesens adit maduere detorquet siqua
-
-Tibi ego proelia mihi, hic precor, nil alba sitientes decusque linquendus.
-Coeptis dixi longa; *me avido*, et queat humi Achillem, ora bina.
-
-```c++
-webmaster(whitelist(processor, 3, deviceDos), columnMinisite * 5, 2);
-if (newlineWidgetTask) {
- toslink.tape = throughput;
- file_touchscreen_carrier.risc(point);
- checksumWais -= ringMegapixelSoftware;
-} else {
- solid_sdsl(standaloneEbookBasic, 2);
- syntax_drive_dynamic.gif_storage(losslessInsertion);
- drop_controller_net = dashboard;
-}
-postSocial = dac.led(streamingScrollQuicktime + logVlbLeaderboard(memory,
- terminal_grep), folderMemory);
-```
-
-## Functo mei ore terra liquidas praesepibus sopore
-
-Iovis retorserunt tamen cumque **intus** equorum lacrimas inritat pluviaque
-aliquas habebit videt: ignorat. Nec senex me **navigat mollit rogavi**
-meditataque erat furibunda iter ales. Ciconia sibi mitra. Tamen postquam possunt
-pariter contigerant **atris** expellitque odit; illam arva quae, partem medias?
-
-```haxe
-var icio = ugc(linkedin(310547, systrayPrimary, gatewayWindows + domain));
-excelErgonomics -= userUrlKey(prebindingRefreshLaser);
-if (fileCycleNumber(cmos(data / -2))) {
- safeUrlMarkup(source(hard_io), checksum_youtube_file,
- text_adc_myspace.eup(bankRup, -2, smb));
- dimmSafeKeystroke.ntfs += parity_thunderbolt;
-}
-```
-
-Ceris securum: cuius Amoris feliciter longe, *de esset plura*. Saevam vis seque,
-viderit tantosque feritate oriens quaesitisque aevi. Parvis quisquis qui: hausit
-est, pedum in fessa tutaque: leto sub fugias *non*, Halcyoneus. Globos te umeri
-struxerit Iuppiter vitae; est arator ecce, [sit
-et](http://www.tingui-ausus.io/), Aeneae per digestum rudis.
-
-- Cedere nudae profitemur nec aurato adspice non
-- Tibi artisque cornua nondum miratur ceperit
-- Metuunt uva utque nondum potes super vocatus
-- Velleris pecudes labens deseruitque regna
-- Erant lacteus dubitati iuvenco
-
-Lyraeque carpere luxque quas virgineos se deus reddidit colonos adflavit.
-Tepidos [superba](http://notavi-sibi.com/de-saucius.aspx), iubent omnia quereris
-tumidam est petentes, lumine.
-
diff --git a/src/main.rs b/src/main.rs
index 83134d0..ad8961b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,17 +1,12 @@
use std::path::PathBuf;
use std::{fs, io};
-use serde::Deserialize;
pub const STYLESHEET: &'static str = include_str!(concat!(env!("OUT_DIR"), "/style.css"));
-pub const TEMPLATE_PAGE: &'static str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/page.hbs"));
pub const ASSET_FAVICON: &'static [u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/favicon.ico"));
+pub const ASSET_ICONS: &'static [u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/icons.svg"));
mod cli;
-
-#[derive(Deserialize, Default)]
-struct Metadata {
- title: Option,
-}
+mod models;
fn format_code(lang: &str, src: &str) -> Result> {
use syntect::parsing::{SyntaxSet, SyntaxReference};
@@ -39,7 +34,7 @@ fn format_code(lang: &str, src: &str) -> Result Result<(Option, String), Box> {
+fn extract_frontmatter(src: &str) -> Result<(Option, String), Box> {
if src.starts_with("---\n") {
let slice = &src[4..];
let end = slice.find("---\n");
@@ -48,10 +43,10 @@ fn extract_metadata(src: &str) -> Result<(Option, String), Box Result<(Option, String), Box Result> {
hardbreaks: false,
smart: true,
github_pre_lang: true,
- default_info_string: Some("none".to_owned()),
+ default_info_string: None,
unsafe_: true,
ext_strikethrough: true,
ext_tagfilter: false,
@@ -131,26 +126,46 @@ fn format_markdown(src: &str) -> Result> {
Ok(output)
}
-fn format_page(metadata: Option, content: &str, output: W) -> Result<(), Box> {
- use handlebars::Handlebars;
-
- // create the handlebars registry
- let mut handlebars = Handlebars::new();
-
- // register the template. The template string will be verified and compiled.
- handlebars.register_template_string("page", TEMPLATE_PAGE).expect("page is valid template");
+fn format_page(frontmatter: models::frontmatter::FrontMatter, chapters: &Vec, url: &str, content: &str, mut output: W) -> Result<(), Box> {
+ use askama::Template;
+ #[derive(Template)]
+ #[template(path = "page.html")]
+ struct PageTemplate<'a, 'b, 'c, 'd, 'e, 'f> {
+ title: &'a str,
+ content: &'b str,
+ url: &'f str,
+ chapters: &'c Vec,
+ prev_chapter: Option<&'d models::chapter::Chapter>,
+ next_chapter: Option<&'e models::chapter::Chapter>,
+ }
- // generate our context
- use std::collections::BTreeMap;
- let mut data = BTreeMap::new();
- data.insert("content", content);
+ let this_index = chapters.iter().enumerate().find(|(_, chap)| chap.url == url).map(|(i, _)| i).expect("chapter exists");
+ let prev_chapter = if this_index > 0 {
+ Some(chapters.iter().nth(this_index - 1).expect("chapter n-1 exists"))
+ }
+ else {
+ None
+ };
+ let next_chapter = if this_index < chapters.len() - 1 {
+ Some(chapters.iter().nth(this_index + 1).expect("chapter n+1 exists"))
+ }
+ else {
+ None
+ };
- let metadata = metadata.unwrap_or_default();
- let title = metadata.title.unwrap_or_default();
- data.insert("title", &title);
+ // fill out our template
+ let template = PageTemplate {
+ title: &frontmatter.title,
+ content,
+ url,
+ chapters,
+ prev_chapter,
+ next_chapter,
+ };
- // and render
- handlebars.render_to_write("page", &data, output)?;
+ // and render!
+ let s = template.render()?;
+ output.write_all(s.as_bytes())?;
Ok(())
}
@@ -173,6 +188,27 @@ fn main() -> Result<(), Box> {
let dest = prefix.join("book");
std::fs::create_dir_all(&dest)?;
+ // load all our chapters
+ let mut chapters: Vec = Vec::default();
+ for entry in src.read_dir()? {
+ let entry = entry?;
+ let path = entry.path();
+ if let Some("md") = path.extension().map(std::ffi::OsStr::to_str).flatten() {
+ let name = path.file_stem().map(std::ffi::OsStr::to_str).flatten();
+ if name.is_none() { continue; }
+ let name = name.unwrap();
+
+ let contents = fs::read_to_string(&path)?;
+ let (front, _) = extract_frontmatter(&contents)?;
+ let front = front.unwrap_or_default().into_front(name);
+ chapters.push(models::chapter::Chapter {
+ url: format!("/{}.html", name),
+ title: front.title,
+ });
+ }
+ }
+ chapters.sort_by(|a, b| a.url.cmp(&b.url));
+
// compile markdown
for entry in src.read_dir()? {
let entry = entry?;
@@ -187,9 +223,10 @@ fn main() -> Result<(), Box> {
let outfile = io::BufWriter::new(outfile);
let contents = fs::read_to_string(&path)?;
- let (meta, contents) = extract_metadata(&contents)?;
+ let (front, contents) = extract_frontmatter(&contents)?;
+ let front = front.unwrap_or_default().into_front(name);
let contents = format_markdown(&contents)?;
- format_page(meta, &contents, outfile)?;
+ format_page(front, &chapters, &format!("/{}.html", name), &contents, outfile)?;
println!("Rendered `{}` into `{}`", path.display(), out.display());
}
@@ -200,6 +237,8 @@ fn main() -> Result<(), Box> {
println!("Wrote {}", dest.join("style.css").display());
fs::write(dest.join("favicon.ico"), ASSET_FAVICON)?;
println!("Wrote {}", dest.join("favicon.ico").display());
+ fs::write(dest.join("icons.svg"), ASSET_ICONS)?;
+ println!("Wrote {}", dest.join("icons.svg").display());
println!("Done!");
Ok(())
diff --git a/src/models.rs b/src/models.rs
new file mode 100644
index 0000000..0dd4194
--- /dev/null
+++ b/src/models.rs
@@ -0,0 +1,2 @@
+pub mod chapter;
+pub mod frontmatter;
diff --git a/src/models/chapter.rs b/src/models/chapter.rs
new file mode 100644
index 0000000..4991c62
--- /dev/null
+++ b/src/models/chapter.rs
@@ -0,0 +1,4 @@
+pub struct Chapter {
+ pub url: String,
+ pub title: String,
+}
diff --git a/src/models/frontmatter.rs b/src/models/frontmatter.rs
new file mode 100644
index 0000000..0655310
--- /dev/null
+++ b/src/models/frontmatter.rs
@@ -0,0 +1,21 @@
+use serde::Deserialize;
+
+#[derive(Deserialize, Default)]
+pub struct ParsedFrontMatter {
+ pub title: Option,
+}
+
+pub struct FrontMatter {
+ pub title: String,
+}
+
+impl ParsedFrontMatter {
+ pub fn into_front(&self, file_name: &str) -> FrontMatter {
+ FrontMatter {
+ title: match &self.title {
+ Some(title) => title.clone(),
+ None => file_name.to_owned(),
+ },
+ }
+ }
+}
diff --git a/style/base.scss b/style/base.scss
index c08d73a..213f98c 100644
--- a/style/base.scss
+++ b/style/base.scss
@@ -1,19 +1,19 @@
body {
- margin: 2em auto;
- max-width: 36em;
- line-height: 1.6;
+ margin: 0;
+ line-height: 1.5;
font-size: 14pt;
color: #222222;
background: #eeeeee;
- padding: 0 0.5em;
- font-family: "Georgia", Georgia, "Times New Roman", Times, serif;
+ padding: 0;
+ font-family: $font-serif;
}
h1,
h2,
h3 {
+ margin-top: 0;
line-height: 1.2;
- font-family: "Franklin Gothic Medium", "Arial Narrow", Arial, sans-serif;
+ font-family: $font-sansserif;
}
a {
@@ -45,14 +45,39 @@ figure {
code {
margin: 0 2px;
- padding: 0 5px;
+ padding: 0 2px;
border: 1px solid #4c566a;
border-radius: 3px;
word-break: break-all;
+ font-family: $font-mono;
+ font-size: 0.75em;
}
pre {
overflow-x: auto;
- font-family: "Courier New", Courier, monospace;
- padding: 0.25em 0.5em;
+ font-family: $font-mono;
+ padding: 0;
+}
+
+dl {
+ display: grid;
+ grid-template-columns: auto 1fr;
+
+ dt {
+ font-weight: 700;
+ margin: 0;
+ padding: 0.5em;
+ border-right: 1px solid #dddddd;
+ }
+
+ dd {
+ margin: 0;
+ padding: 0.5em;
+ }
+
+ dt, dd {
+ p {
+ margin: 0;
+ }
+ }
}
diff --git a/style/darktheme.scss b/style/darktheme.scss
index eefcfb9..b38461f 100644
--- a/style/darktheme.scss
+++ b/style/darktheme.scss
@@ -12,6 +12,10 @@
}
}
+ nav {
+ background: #18181d;
+ }
+
img {
filter: grayscale(30%);
}
diff --git a/style/icons.scss b/style/icons.scss
new file mode 100644
index 0000000..cb9cce0
--- /dev/null
+++ b/style/icons.scss
@@ -0,0 +1,22 @@
+span.icon {
+ display: flex;
+ align-items: center;
+}
+
+[class^="icon-"],
+[class*=" icon-"] {
+ display: inline-block;
+ width: 1em;
+ height: 1em;
+ stroke-width: 0;
+ stroke: currentColor;
+ fill: currentColor;
+}
+
+.icon-arrow-left {
+ width: 0.875em;
+}
+
+.icon-arrow-right {
+ width: 0.875em;
+}
\ No newline at end of file
diff --git a/style/layout.scss b/style/layout.scss
new file mode 100644
index 0000000..f874f49
--- /dev/null
+++ b/style/layout.scss
@@ -0,0 +1,105 @@
+html, body {
+ width: 100%;
+ min-height: 100vh;
+}
+
+body {
+ display: grid;
+ grid-template-columns: auto 1fr;
+ grid-template-rows: 1fr;
+ justify-items: stretch;
+ align-items: stretch;
+
+ nav.big {
+ background: #2c2c38;
+ padding: 1em;
+
+ display: flex;
+ flex-direction: column;
+
+ a {
+ width: 100%;
+ font-size: 1.5em;
+ text-decoration: none;
+ font-family: $font-sansserif;
+ margin: 0 0 0.25em 0;
+ color: #5babd1;
+
+ &:hover {
+ color: #cf5ccd;
+ }
+
+ &.current {
+ color: #cf5ccd;
+
+ &:hover {
+ color: #fefefe;
+ }
+ }
+ }
+ }
+
+ nav.small {
+ display: none;
+ width: 100%;
+ align-items: center;
+ justify-content: space-between;
+ background: #2c2c38;
+ padding: 0;
+
+ >* {
+ margin: 0.5em;
+ }
+
+ a {
+ text-decoration: none;
+ font-family: $font-sansserif;
+ color: #5babd1;
+
+ &:hover {
+ color: #cf5ccd;
+ }
+ }
+
+ span.title {
+ text-decoration: none;
+ font-family: $font-sansserif;
+ color: #fefefe;
+ }
+
+ span.placeholder {
+ width: 1em;
+ height: 1em;
+ }
+ }
+
+ article {
+ padding: 1em 2em 0 2em;
+ max-width: 38em;
+ min-width: 0;
+ min-height: 0;
+
+ >* {
+ max-width: 100%;
+ }
+ }
+}
+
+@media screen and (max-width: 768px) {
+ body {
+ grid-template-columns: 1fr;
+ grid-template-rows: auto 1fr;
+
+ nav.big {
+ display: none;
+ }
+
+ nav.small {
+ display: flex;
+ }
+
+ article {
+ padding: 1em 0.5em 0 0.5em;
+ }
+ }
+}
diff --git a/style/print.scss b/style/print.scss
index 2dac89e..2ae9f6f 100644
--- a/style/print.scss
+++ b/style/print.scss
@@ -26,4 +26,12 @@
* {
overflow: hidden;
}
+
+ nav {
+ display: none;
+ }
+
+ body {
+ display: block;
+ }
}
diff --git a/style/style.scss b/style/style.scss
index 039edb4..07e1deb 100644
--- a/style/style.scss
+++ b/style/style.scss
@@ -1,3 +1,6 @@
+@import 'variables';
@import 'base';
+@import 'layout';
+@import 'icons';
@import 'darktheme';
@import 'print';
\ No newline at end of file
diff --git a/style/variables.scss b/style/variables.scss
new file mode 100644
index 0000000..0a99ba5
--- /dev/null
+++ b/style/variables.scss
@@ -0,0 +1,5 @@
+@import url('https://fonts.googleapis.com/css?family=Crimson+Pro|Poppins:700|Source+Code+Pro&display=swap');
+
+$font-serif: 'Crimson Pro', "Georgia", Georgia, "Times New Roman", Times, serif !default;
+$font-sansserif: 'Poppins', "Franklin Gothic Medium", "Arial Narrow", Arial, sans-serif !default;
+$font-mono: 'Source Code Pro', "Courier New", Courier, monospace !default;
diff --git a/templates/page.hbs b/templates/page.hbs
deleted file mode 100644
index a2f759c..0000000
--- a/templates/page.hbs
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
- {{ title }}
-
-
-
-
- {{{content}}}
-
-
\ No newline at end of file
diff --git a/templates/page.html b/templates/page.html
new file mode 100644
index 0000000..19af53e
--- /dev/null
+++ b/templates/page.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+ {{ content|safe }}
+
+
\ No newline at end of file