commit
f2a641abea
|
@ -10,7 +10,13 @@
|
||||||
- All Tera global fns are now rebuilt on changes
|
- All Tera global fns are now rebuilt on changes
|
||||||
- Use flags for port/interface in `gutenberg serve`
|
- Use flags for port/interface in `gutenberg serve`
|
||||||
- Fix various issues with headers markdown rendering
|
- Fix various issues with headers markdown rendering
|
||||||
|
- Rename `insert_anchor` in section front-matter to `insert_anchor_links`
|
||||||
|
- Remove `insert_anchor_links` from the config: it wasn't used
|
||||||
|
- Add `class` variable to `gist` shortcode
|
||||||
|
- Add reading analytics to sections content
|
||||||
|
- Add config to sitemap template
|
||||||
|
- Add `permalink` to all taxonomy items (tags & categories)
|
||||||
|
- Tags in the tags page are now sorting alphabetically instead of by number of pages in them
|
||||||
|
|
||||||
## 0.1.3 (2017-08-31)
|
## 0.1.3 (2017-08-31)
|
||||||
|
|
||||||
|
|
|
@ -47,10 +47,6 @@ pub struct Config {
|
||||||
pub generate_tags_pages: Option<bool>,
|
pub generate_tags_pages: Option<bool>,
|
||||||
/// Whether to generate categories and individual tag categories if some pages have them. Defaults to true
|
/// Whether to generate categories and individual tag categories if some pages have them. Defaults to true
|
||||||
pub generate_categories_pages: Option<bool>,
|
pub generate_categories_pages: Option<bool>,
|
||||||
/// Whether to insert a link for each header like in Github READMEs. Defaults to false
|
|
||||||
/// The default template can be overridden by creating a `anchor-link.html` template and CSS will need to be
|
|
||||||
/// written if you turn that on.
|
|
||||||
pub insert_anchor_links: Option<bool>,
|
|
||||||
/// Whether to compile the `sass` directory and output the css files into the static folder
|
/// Whether to compile the `sass` directory and output the css files into the static folder
|
||||||
pub compile_sass: Option<bool>,
|
pub compile_sass: Option<bool>,
|
||||||
|
|
||||||
|
@ -84,7 +80,6 @@ impl Config {
|
||||||
set_default!(config.rss_limit, 20);
|
set_default!(config.rss_limit, 20);
|
||||||
set_default!(config.generate_tags_pages, false);
|
set_default!(config.generate_tags_pages, false);
|
||||||
set_default!(config.generate_categories_pages, false);
|
set_default!(config.generate_categories_pages, false);
|
||||||
set_default!(config.insert_anchor_links, false);
|
|
||||||
set_default!(config.compile_sass, false);
|
set_default!(config.compile_sass, false);
|
||||||
set_default!(config.extra, HashMap::new());
|
set_default!(config.extra, HashMap::new());
|
||||||
|
|
||||||
|
@ -174,7 +169,6 @@ impl Default for Config {
|
||||||
rss_limit: Some(10_000),
|
rss_limit: Some(10_000),
|
||||||
generate_tags_pages: Some(true),
|
generate_tags_pages: Some(true),
|
||||||
generate_categories_pages: Some(true),
|
generate_categories_pages: Some(true),
|
||||||
insert_anchor_links: Some(false),
|
|
||||||
compile_sass: Some(false),
|
compile_sass: Some(false),
|
||||||
extra: None,
|
extra: None,
|
||||||
build_timestamp: Some(1),
|
build_timestamp: Some(1),
|
||||||
|
|
|
@ -10,6 +10,7 @@ use front_matter::{SectionFrontMatter, split_section_content};
|
||||||
use errors::{Result, ResultExt};
|
use errors::{Result, ResultExt};
|
||||||
use utils::fs::read_file;
|
use utils::fs::read_file;
|
||||||
use utils::templates::render_template;
|
use utils::templates::render_template;
|
||||||
|
use utils::site::get_reading_analytics;
|
||||||
use rendering::{Context, Header, markdown_to_html};
|
use rendering::{Context, Header, markdown_to_html};
|
||||||
|
|
||||||
use page::Page;
|
use page::Page;
|
||||||
|
@ -96,7 +97,7 @@ impl Section {
|
||||||
config.highlight_theme.clone().unwrap(),
|
config.highlight_theme.clone().unwrap(),
|
||||||
&self.permalink,
|
&self.permalink,
|
||||||
permalinks,
|
permalinks,
|
||||||
self.meta.insert_anchor.unwrap()
|
self.meta.insert_anchor_links.unwrap()
|
||||||
);
|
);
|
||||||
let res = markdown_to_html(&self.raw_content, &context)?;
|
let res = markdown_to_html(&self.raw_content, &context)?;
|
||||||
self.content = res.0;
|
self.content = res.0;
|
||||||
|
@ -139,7 +140,7 @@ impl Section {
|
||||||
|
|
||||||
impl ser::Serialize for Section {
|
impl ser::Serialize for Section {
|
||||||
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> where S: ser::Serializer {
|
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> where S: ser::Serializer {
|
||||||
let mut state = serializer.serialize_struct("section", 10)?;
|
let mut state = serializer.serialize_struct("section", 12)?;
|
||||||
state.serialize_field("content", &self.content)?;
|
state.serialize_field("content", &self.content)?;
|
||||||
state.serialize_field("permalink", &self.permalink)?;
|
state.serialize_field("permalink", &self.permalink)?;
|
||||||
state.serialize_field("title", &self.meta.title)?;
|
state.serialize_field("title", &self.meta.title)?;
|
||||||
|
@ -149,6 +150,9 @@ impl ser::Serialize for Section {
|
||||||
state.serialize_field("permalink", &self.permalink)?;
|
state.serialize_field("permalink", &self.permalink)?;
|
||||||
state.serialize_field("pages", &self.pages)?;
|
state.serialize_field("pages", &self.pages)?;
|
||||||
state.serialize_field("subsections", &self.subsections)?;
|
state.serialize_field("subsections", &self.subsections)?;
|
||||||
|
let (word_count, reading_time) = get_reading_analytics(&self.raw_content);
|
||||||
|
state.serialize_field("word_count", &word_count)?;
|
||||||
|
state.serialize_field("reading_time", &reading_time)?;
|
||||||
state.serialize_field("toc", &self.toc)?;
|
state.serialize_field("toc", &self.toc)?;
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
|
||||||
(can_be_sorted, cannot_be_sorted)
|
(can_be_sorted, cannot_be_sorted)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Horribly inefficient way to set previous and next on each pages
|
/// Horribly inefficient way to set previous and next on each pages that skips drafts
|
||||||
/// So many clones
|
/// So many clones
|
||||||
pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec<Page> {
|
pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec<Page> {
|
||||||
let mut res = Vec::with_capacity(input.len());
|
let mut res = Vec::with_capacity(input.len());
|
||||||
|
|
|
@ -28,9 +28,13 @@ lazy_static! {
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum SortBy {
|
pub enum SortBy {
|
||||||
|
/// Most recent to oldest
|
||||||
Date,
|
Date,
|
||||||
|
/// Lower order comes last
|
||||||
Order,
|
Order,
|
||||||
|
/// Lower weight comes first
|
||||||
Weight,
|
Weight,
|
||||||
|
/// No sorting
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ pub struct PageFrontMatter {
|
||||||
/// Integer to use to order content. Highest is at the bottom, lowest first
|
/// Integer to use to order content. Highest is at the bottom, lowest first
|
||||||
pub weight: Option<usize>,
|
pub weight: Option<usize>,
|
||||||
/// All aliases for that page. Gutenberg will create HTML templates that will
|
/// All aliases for that page. Gutenberg will create HTML templates that will
|
||||||
|
/// redirect to this
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
pub aliases: Option<Vec<String>>,
|
pub aliases: Option<Vec<String>>,
|
||||||
/// Specify a template different from `page.html` to use for that page
|
/// Specify a template different from `page.html` to use for that page
|
||||||
|
|
|
@ -20,8 +20,8 @@ pub struct SectionFrontMatter {
|
||||||
/// Whether to sort by "date", "order", "weight" or "none". Defaults to `none`.
|
/// Whether to sort by "date", "order", "weight" or "none". Defaults to `none`.
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
pub sort_by: Option<SortBy>,
|
pub sort_by: Option<SortBy>,
|
||||||
/// The weight for this section. This is used by the parent section to order its subsections.
|
/// Used by the parent section to order its subsections.
|
||||||
/// Higher values means it ends at the end.
|
/// Higher values means it will be at the end.
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
pub weight: Option<usize>,
|
pub weight: Option<usize>,
|
||||||
/// Optional template, if we want to specify which template to render for that page
|
/// Optional template, if we want to specify which template to render for that page
|
||||||
|
@ -33,10 +33,9 @@ pub struct SectionFrontMatter {
|
||||||
/// Path to be used by pagination: the page number will be appended after it. Defaults to `page`.
|
/// Path to be used by pagination: the page number will be appended after it. Defaults to `page`.
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
pub paginate_path: Option<String>,
|
pub paginate_path: Option<String>,
|
||||||
/// Whether to insert a link for each header like in Github READMEs. Defaults to false
|
/// Whether to insert a link for each header like the ones you can see in this site if you hover one
|
||||||
/// The default template can be overridden by creating a `anchor-link.html` template and CSS will need to be
|
/// The default template can be overridden by creating a `anchor-link.html` in the `templates` directory
|
||||||
/// written if you turn that on.
|
pub insert_anchor_links: Option<InsertAnchor>,
|
||||||
pub insert_anchor: Option<InsertAnchor>,
|
|
||||||
/// Whether to render that section or not. Defaults to `true`.
|
/// Whether to render that section or not. Defaults to `true`.
|
||||||
/// Useful when the section is only there to organize things but is not meant
|
/// Useful when the section is only there to organize things but is not meant
|
||||||
/// to be used directly, like a posts section in a personal site
|
/// to be used directly, like a posts section in a personal site
|
||||||
|
@ -70,8 +69,8 @@ impl SectionFrontMatter {
|
||||||
f.sort_by = Some(SortBy::None);
|
f.sort_by = Some(SortBy::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.insert_anchor.is_none() {
|
if f.insert_anchor_links.is_none() {
|
||||||
f.insert_anchor = Some(InsertAnchor::None);
|
f.insert_anchor_links = Some(InsertAnchor::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.weight.is_none() {
|
if f.weight.is_none() {
|
||||||
|
@ -111,7 +110,7 @@ impl Default for SectionFrontMatter {
|
||||||
paginate_path: Some(DEFAULT_PAGINATE_PATH.to_string()),
|
paginate_path: Some(DEFAULT_PAGINATE_PATH.to_string()),
|
||||||
render: Some(true),
|
render: Some(true),
|
||||||
redirect_to: None,
|
redirect_to: None,
|
||||||
insert_anchor: Some(InsertAnchor::None),
|
insert_anchor_links: Some(InsertAnchor::None),
|
||||||
extra: None,
|
extra: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,8 @@ impl Site {
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
let path = entry.as_path();
|
let path = entry.as_path();
|
||||||
Section::from_file(path, config)
|
Section::from_file(path, config)
|
||||||
}).collect::<Vec<_>>()
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
|
|
||||||
let pages = {
|
let pages = {
|
||||||
|
@ -189,7 +190,8 @@ impl Site {
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
let path = entry.as_path();
|
let path = entry.as_path();
|
||||||
Page::from_file(path, config)
|
Page::from_file(path, config)
|
||||||
}).collect::<Vec<_>>()
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Kinda duplicated code for add_section/add_page but necessary to do it that
|
// Kinda duplicated code for add_section/add_page but necessary to do it that
|
||||||
|
@ -224,8 +226,7 @@ impl Site {
|
||||||
let config = &self.config;
|
let config = &self.config;
|
||||||
|
|
||||||
self.pages.par_iter_mut()
|
self.pages.par_iter_mut()
|
||||||
.map(|(_, page)| page)
|
.map(|(_, page)| {
|
||||||
.map(|page| {
|
|
||||||
let insert_anchor = pages_insert_anchors[&page.file.path];
|
let insert_anchor = pages_insert_anchors[&page.file.path];
|
||||||
page.render_markdown(permalinks, tera, config, insert_anchor)
|
page.render_markdown(permalinks, tera, config, insert_anchor)
|
||||||
})
|
})
|
||||||
|
@ -233,8 +234,7 @@ impl Site {
|
||||||
.reduce(|| Ok(()), Result::and)?;
|
.reduce(|| Ok(()), Result::and)?;
|
||||||
|
|
||||||
self.sections.par_iter_mut()
|
self.sections.par_iter_mut()
|
||||||
.map(|(_, section)| section)
|
.map(|(_, section)| section.render_markdown(permalinks, tera, config))
|
||||||
.map(|section| section.render_markdown(permalinks, tera, config))
|
|
||||||
.fold(|| Ok(()), Result::and)
|
.fold(|| Ok(()), Result::and)
|
||||||
.reduce(|| Ok(()), Result::and)?;
|
.reduce(|| Ok(()), Result::and)?;
|
||||||
}
|
}
|
||||||
|
@ -295,7 +295,7 @@ impl Site {
|
||||||
/// Defaults to `AnchorInsert::None` if no parent section found
|
/// Defaults to `AnchorInsert::None` if no parent section found
|
||||||
pub fn find_parent_section_insert_anchor(&self, parent_path: &PathBuf) -> InsertAnchor {
|
pub fn find_parent_section_insert_anchor(&self, parent_path: &PathBuf) -> InsertAnchor {
|
||||||
match self.sections.get(&parent_path.join("_index.md")) {
|
match self.sections.get(&parent_path.join("_index.md")) {
|
||||||
Some(s) => s.meta.insert_anchor.unwrap(),
|
Some(s) => s.meta.insert_anchor_links.unwrap(),
|
||||||
None => InsertAnchor::None
|
None => InsertAnchor::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,6 +366,7 @@ impl Site {
|
||||||
|
|
||||||
// TODO: can we pass a reference?
|
// TODO: can we pass a reference?
|
||||||
let (tags, categories) = Taxonomy::find_tags_and_categories(
|
let (tags, categories) = Taxonomy::find_tags_and_categories(
|
||||||
|
&self.config,
|
||||||
self.pages
|
self.pages
|
||||||
.values()
|
.values()
|
||||||
.filter(|p| !p.is_draft())
|
.filter(|p| !p.is_draft())
|
||||||
|
@ -647,6 +648,7 @@ impl Site {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.add("tags", &tags);
|
context.add("tags", &tags);
|
||||||
|
context.add("config", &self.config);
|
||||||
|
|
||||||
let sitemap = &render_template("sitemap.xml", &self.tera, &context, self.config.theme.clone())?;
|
let sitemap = &render_template("sitemap.xml", &self.tera, &context, self.config.theme.clone())?;
|
||||||
|
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
title = "Posts"
|
title = "Posts"
|
||||||
paginate_by = 2
|
paginate_by = 2
|
||||||
template = "section_paginated.html"
|
template = "section_paginated.html"
|
||||||
insert_anchor = "left"
|
insert_anchor_links = "left"
|
||||||
+++
|
+++
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
extern crate site;
|
extern crate site;
|
||||||
|
extern crate front_matter;
|
||||||
extern crate tempdir;
|
extern crate tempdir;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -8,6 +9,7 @@ use std::io::prelude::*;
|
||||||
|
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
use site::Site;
|
use site::Site;
|
||||||
|
use front_matter::InsertAnchor;
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -296,6 +298,7 @@ fn can_build_site_and_insert_anchor_links() {
|
||||||
path.push("test_site");
|
path.push("test_site");
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
let mut site = Site::new(&path, "config.toml").unwrap();
|
||||||
site.load().unwrap();
|
site.load().unwrap();
|
||||||
|
|
||||||
let tmp_dir = TempDir::new("example").expect("create temp dir");
|
let tmp_dir = TempDir::new("example").expect("create temp dir");
|
||||||
let public = &tmp_dir.path().join("public");
|
let public = &tmp_dir.path().join("public");
|
||||||
site.set_output_path(&public);
|
site.set_output_path(&public);
|
||||||
|
|
|
@ -32,18 +32,30 @@ pub enum TaxonomyKind {
|
||||||
pub struct TaxonomyItem {
|
pub struct TaxonomyItem {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub slug: String,
|
pub slug: String,
|
||||||
|
pub permalink: String,
|
||||||
pub pages: Vec<Page>,
|
pub pages: Vec<Page>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaxonomyItem {
|
impl TaxonomyItem {
|
||||||
pub fn new(name: &str, pages: Vec<Page>) -> TaxonomyItem {
|
pub fn new(name: &str, kind: TaxonomyKind, config: &Config, pages: Vec<Page>) -> TaxonomyItem {
|
||||||
// We shouldn't have any pages without dates there
|
// Taxonomy are almost always used for blogs so we filter by dates
|
||||||
let (sorted_pages, _) = sort_pages(pages, SortBy::Date);
|
// and it's not like we can sort things across sections by anything other
|
||||||
|
// than dates
|
||||||
|
let (mut pages, ignored_pages) = sort_pages(pages, SortBy::Date);
|
||||||
|
let slug = slugify(name);
|
||||||
|
let permalink = {
|
||||||
|
let kind_path = if kind == TaxonomyKind::Tags { "tag" } else { "category" };
|
||||||
|
config.make_permalink(&format!("/{}/{}", kind_path, slug))
|
||||||
|
};
|
||||||
|
|
||||||
|
// We still append pages without dates at the end
|
||||||
|
pages.extend(ignored_pages);
|
||||||
|
|
||||||
TaxonomyItem {
|
TaxonomyItem {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
slug: slugify(name),
|
permalink,
|
||||||
pages: sorted_pages,
|
slug,
|
||||||
|
pages,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,21 +69,12 @@ pub struct Taxonomy {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Taxonomy {
|
impl Taxonomy {
|
||||||
// TODO: take a Vec<&'a Page> if it makes a difference in terms of perf for actual sites
|
pub fn find_tags_and_categories(config: &Config, all_pages: &[Page]) -> (Taxonomy, Taxonomy) {
|
||||||
pub fn find_tags_and_categories(all_pages: &[Page]) -> (Taxonomy, Taxonomy) {
|
|
||||||
let mut tags = HashMap::new();
|
let mut tags = HashMap::new();
|
||||||
let mut categories = HashMap::new();
|
let mut categories = HashMap::new();
|
||||||
|
|
||||||
// Find all the tags/categories first
|
// Find all the tags/categories first
|
||||||
for page in all_pages {
|
for page in all_pages {
|
||||||
// Don't consider pages without pages for tags/categories as that's the only thing
|
|
||||||
// we can sort pages with across sections
|
|
||||||
// If anyone sees that comment and wonder wtf, please open an issue as I can't think of
|
|
||||||
// usecases other than blog posts for built-in taxonomies
|
|
||||||
if page.meta.date.is_none() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ref category) = page.meta.category {
|
if let Some(ref category) = page.meta.category {
|
||||||
categories
|
categories
|
||||||
.entry(category.to_string())
|
.entry(category.to_string())
|
||||||
|
@ -90,20 +93,20 @@ impl Taxonomy {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then make TaxonomyItem out of them, after sorting it
|
// Then make TaxonomyItem out of them, after sorting it
|
||||||
let tags_taxonomy = Taxonomy::new(TaxonomyKind::Tags, tags);
|
let tags_taxonomy = Taxonomy::new(TaxonomyKind::Tags, config, tags);
|
||||||
let categories_taxonomy = Taxonomy::new(TaxonomyKind::Categories, categories);
|
let categories_taxonomy = Taxonomy::new(TaxonomyKind::Categories, config, categories);
|
||||||
|
|
||||||
(tags_taxonomy, categories_taxonomy)
|
(tags_taxonomy, categories_taxonomy)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(kind: TaxonomyKind, items: HashMap<String, Vec<Page>>) -> Taxonomy {
|
fn new(kind: TaxonomyKind, config: &Config, items: HashMap<String, Vec<Page>>) -> Taxonomy {
|
||||||
let mut sorted_items = vec![];
|
let mut sorted_items = vec![];
|
||||||
for (name, pages) in &items {
|
for (name, pages) in &items {
|
||||||
sorted_items.push(
|
sorted_items.push(
|
||||||
TaxonomyItem::new(name, pages.clone())
|
TaxonomyItem::new(name, kind, config, pages.clone())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
sorted_items.sort_by(|a, b| b.pages.len().cmp(&a.pages.len()));
|
sorted_items.sort_by(|a, b| a.name.cmp(&b.name));
|
||||||
|
|
||||||
Taxonomy {
|
Taxonomy {
|
||||||
kind,
|
kind,
|
||||||
|
@ -157,3 +160,55 @@ impl Taxonomy {
|
||||||
.chain_err(|| format!("Failed to render {} page.", name))
|
.chain_err(|| format!("Failed to render {} page.", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use config::Config;
|
||||||
|
use content::Page;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_make_taxonomies() {
|
||||||
|
let config = Config::default();
|
||||||
|
let mut page1 = Page::default();
|
||||||
|
page1.meta.tags = Some(vec!["rust".to_string(), "db".to_string()]);
|
||||||
|
page1.meta.category = Some("Programming tutorials".to_string());
|
||||||
|
let mut page2 = Page::default();
|
||||||
|
page2.meta.tags = Some(vec!["rust".to_string(), "js".to_string()]);
|
||||||
|
page2.meta.category = Some("Other".to_string());
|
||||||
|
let mut page3 = Page::default();
|
||||||
|
page3.meta.tags = Some(vec!["js".to_string()]);
|
||||||
|
let pages = vec![page1, page2, page3];
|
||||||
|
|
||||||
|
let (tags, categories) = Taxonomy::find_tags_and_categories(&config, &pages);
|
||||||
|
|
||||||
|
assert_eq!(tags.items.len(), 3);
|
||||||
|
assert_eq!(categories.items.len(), 2);
|
||||||
|
|
||||||
|
assert_eq!(tags.items[0].name, "db");
|
||||||
|
assert_eq!(tags.items[0].slug, "db");
|
||||||
|
assert_eq!(tags.items[0].permalink, "http://a-website.com/tag/db/");
|
||||||
|
assert_eq!(tags.items[0].pages.len(), 1);
|
||||||
|
|
||||||
|
assert_eq!(tags.items[1].name, "js");
|
||||||
|
assert_eq!(tags.items[1].slug, "js");
|
||||||
|
assert_eq!(tags.items[1].permalink, "http://a-website.com/tag/js/");
|
||||||
|
assert_eq!(tags.items[1].pages.len(), 2);
|
||||||
|
|
||||||
|
assert_eq!(tags.items[2].name, "rust");
|
||||||
|
assert_eq!(tags.items[2].slug, "rust");
|
||||||
|
assert_eq!(tags.items[2].permalink, "http://a-website.com/tag/rust/");
|
||||||
|
assert_eq!(tags.items[2].pages.len(), 2);
|
||||||
|
|
||||||
|
assert_eq!(categories.items[0].name, "Other");
|
||||||
|
assert_eq!(categories.items[0].slug, "other");
|
||||||
|
assert_eq!(categories.items[0].permalink, "http://a-website.com/category/other/");
|
||||||
|
assert_eq!(categories.items[0].pages.len(), 1);
|
||||||
|
|
||||||
|
assert_eq!(categories.items[1].name, "Programming tutorials");
|
||||||
|
assert_eq!(categories.items[1].slug, "programming-tutorials");
|
||||||
|
assert_eq!(categories.items[1].permalink, "http://a-website.com/category/programming-tutorials/");
|
||||||
|
assert_eq!(categories.items[1].pages.len(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
<div>
|
<div {% if class %}class="{{class}}"{% endif %}>
|
||||||
<script src="{{ url }}.js{% if file %}?file={{file}}{% endif %}"></script>
|
<script src="{{ url }}.js{% if file %}?file={{file}}{% endif %}"></script>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
base_url = "https://example.com"
|
base_url = "https://example.com"
|
||||||
title = "Gutenberg - your one-stop static site engine"
|
title = "Gutenberg"
|
||||||
description = "Everything you need to make a static site engine in one binary. And it's fast"
|
description = "Everything you need to make a static site engine in one binary. And it's fast"
|
||||||
|
|
||||||
compile_sass = true
|
compile_sass = true
|
||||||
highlight_code = true
|
highlight_code = true
|
||||||
|
insert_anchor_links = true
|
||||||
|
|
||||||
[extra]
|
[extra]
|
||||||
author = "Vincent Prouillet"
|
author = "Vincent Prouillet"
|
||||||
|
|
|
@ -10,24 +10,18 @@ Getting started
|
||||||
|
|
||||||
Content
|
Content
|
||||||
- Organisation
|
- Organisation
|
||||||
- Pages
|
|
||||||
- Sections
|
- Sections
|
||||||
|
- Pages
|
||||||
- Shortcodes
|
- Shortcodes
|
||||||
- Internal links
|
- Internal links & deep linking
|
||||||
- Table of contents
|
- Table of contents
|
||||||
- Deep linking (# links)
|
|
||||||
- Syntax highlighting
|
- Syntax highlighting
|
||||||
- Pagination
|
|
||||||
- Tag & categories
|
|
||||||
- RSS
|
|
||||||
- Sitemap
|
|
||||||
|
|
||||||
Templates
|
Templates
|
||||||
- Intro
|
- Intro
|
||||||
- Each kind of page and the variables available
|
- Each kind of page and the variables available
|
||||||
- Built-in global functions
|
- Built-in global functions
|
||||||
- Built-in filters
|
- Built-in filters
|
||||||
- Debugging
|
|
||||||
|
|
||||||
Theme
|
Theme
|
||||||
- Installing & customising a theme
|
- Installing & customising a theme
|
||||||
|
|
7
docs/content/documentation/content/_index.md
Normal file
7
docs/content/documentation/content/_index.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
+++
|
||||||
|
title = "Content"
|
||||||
|
weight = 2
|
||||||
|
sort_by = "weight"
|
||||||
|
redirect_to = "documentation/content/overview"
|
||||||
|
insert_anchor_links = "left"
|
||||||
|
+++
|
37
docs/content/documentation/content/linking.md
Normal file
37
docs/content/documentation/content/linking.md
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
+++
|
||||||
|
title = "Internal links & deep linking"
|
||||||
|
weight = 50
|
||||||
|
+++
|
||||||
|
|
||||||
|
## Header id and anchor insertion
|
||||||
|
While rendering the markdown content, a unique id will automatically be assigned to each header. This id is created
|
||||||
|
by converting the header text to a [slug](https://en.wikipedia.org/wiki/Semantic_URL#Slug), appending numbers at the end
|
||||||
|
if the slug already exists for that article. For example:
|
||||||
|
|
||||||
|
```md
|
||||||
|
# Something exciting! <- something-exciting
|
||||||
|
## Example code <- example-code
|
||||||
|
|
||||||
|
# Something else <- something-else
|
||||||
|
## Example code <- example-code-1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Anchor insertion
|
||||||
|
It is possible to have Gutenberg automatically insert anchor links next to the header, as you can see on the site you are currently
|
||||||
|
reading if you hover a title.
|
||||||
|
|
||||||
|
This option is set at the section level, look up the `insert_anchor_links` variable on the
|
||||||
|
[Section front-matter page](./documentation/content/section.md#front-matter).
|
||||||
|
|
||||||
|
The default template is very basic and will need CSS tweaks in your project to look decent.
|
||||||
|
If you want to change the anchor template, it can easily be overwritten by
|
||||||
|
creating a `anchor-link.html` file in the `templates` directory.
|
||||||
|
|
||||||
|
## Internal links
|
||||||
|
Linking to other pages and their headers is so common that Gutenberg adds a
|
||||||
|
special syntax to Markdown links to handle them: start the link with `./` and point to the `.md` file you want
|
||||||
|
to link to. The path to the file starts from the `content` directory.
|
||||||
|
|
||||||
|
For example, linking to a file located at `content/pages/about.md` would be `[my link](./pages/about.md)`.
|
||||||
|
You can still link to a header directly: `[my link](./pages/about.md#example)` would work as expected, granted
|
||||||
|
the `example` id exists on the header.
|
48
docs/content/documentation/content/overview.md
Normal file
48
docs/content/documentation/content/overview.md
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
+++
|
||||||
|
title = "Overview"
|
||||||
|
weight = 10
|
||||||
|
+++
|
||||||
|
|
||||||
|
|
||||||
|
Gutenberg uses the folder structure to determine the site structure.
|
||||||
|
Each folder in the `content` directory represents a [section](./documentation/content/section.md)
|
||||||
|
that contains [pages](./documentation/content/page.md) : your `.md` files.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
.
|
||||||
|
└── content
|
||||||
|
├── content
|
||||||
|
│ └── something.md // -> https://mywebsite.com/content/something/
|
||||||
|
├── blog
|
||||||
|
│ ├── cli-usage.md // -> https://mywebsite.com/blog/cli-usage/
|
||||||
|
│ ├── configuration.md // -> https://mywebsite.com/blog/configuration/
|
||||||
|
│ ├── directory-structure.md // -> https://mywebsite.com/blog/directory-structure/
|
||||||
|
│ ├── _index.md // -> https://mywebsite.com/blog/
|
||||||
|
│ └── installation.md // -> https://mywebsite.com/blog/installation/
|
||||||
|
└── landing
|
||||||
|
└── _index.md // -> https://mywebsite.com/landing/
|
||||||
|
```
|
||||||
|
|
||||||
|
Obviously, each page path (the part after the `base_url`, for example `blog/`) can be customised by setting the wanted value
|
||||||
|
in the [page front-matter](./documentation/content/page.md#front-matter).
|
||||||
|
|
||||||
|
You might have noticed a file named `_index.md` in the example above.
|
||||||
|
This file will be used for the metadata and content of the section itself and is not considered a page.
|
||||||
|
|
||||||
|
To make sure the terminology used in the rest of the documentation is understood, let's go over the example above.
|
||||||
|
|
||||||
|
The `content` directory in this case has three `sections`: `content`, `blog` and `landing`. The `content` section has only
|
||||||
|
one page, `something.md`, the `landing` section has no page and the `blog` section has 4 pages: `cli-usage.md`, `configuration.md`, `directory-structure.md`
|
||||||
|
and `installation.md`.
|
||||||
|
|
||||||
|
While not shown in the example, sections can be nested indefinitely.
|
||||||
|
|
||||||
|
The `content` directory is not limited to markup files though: it's natural to want to co-locate a page and some related
|
||||||
|
assets. Gutenberg supports that pattern out of the box: create a folder, add a `index.md` file and as many non-markdown as you want.
|
||||||
|
Those assets will be copied in the same folder when building so you can just use a relative path to access them.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
└── with-assets
|
||||||
|
├── index.md
|
||||||
|
└── yavascript.js
|
||||||
|
```
|
71
docs/content/documentation/content/page.md
Normal file
71
docs/content/documentation/content/page.md
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
+++
|
||||||
|
title = "Page"
|
||||||
|
weight = 30
|
||||||
|
+++
|
||||||
|
|
||||||
|
A page is any file ending with `.md` in the `content` directory, except files
|
||||||
|
named `_index/md`.
|
||||||
|
|
||||||
|
## Front-matter
|
||||||
|
|
||||||
|
The front-matter is a set of metadata embedded in a file. In Gutenberg,
|
||||||
|
it is at the beginning of the file, surrounded by `+++` and uses TOML.
|
||||||
|
|
||||||
|
None of the front-matter variables are mandatory. However the opening and closing `+++` are required even if there are
|
||||||
|
no variables in it.
|
||||||
|
|
||||||
|
Here is an example page with all the variables available:
|
||||||
|
|
||||||
|
```md
|
||||||
|
+++
|
||||||
|
title = ""
|
||||||
|
description = ""
|
||||||
|
|
||||||
|
# The date of the post.
|
||||||
|
# 2 formats are allowed: YYYY-MM-DD (2012-10-02) and RFC3339 (2002-10-02T15:00:00Z)
|
||||||
|
date = ""
|
||||||
|
|
||||||
|
# A draft page will not be present in prev/next pagination
|
||||||
|
draft = false
|
||||||
|
|
||||||
|
# If filled, it will use that slug instead of the filename to make up the URL
|
||||||
|
# It will still use the section path though
|
||||||
|
slug = ""
|
||||||
|
|
||||||
|
# The URL the content will appear at
|
||||||
|
# If set, it cannot be an empty string and will override both `slug` and the filename
|
||||||
|
# and the sections' path won't be used
|
||||||
|
url = ""
|
||||||
|
|
||||||
|
# An array of strings allowing you to group pages with them
|
||||||
|
tags = []
|
||||||
|
|
||||||
|
# An overarching category name for that page, allowing you to group pages with it
|
||||||
|
category = ""
|
||||||
|
|
||||||
|
# The order as defined in the Section page
|
||||||
|
order = 0
|
||||||
|
|
||||||
|
# The weight as defined in the Section page
|
||||||
|
weight = 0
|
||||||
|
|
||||||
|
# Use aliases if you are moving content but want to redirect previous URLs to the
|
||||||
|
# current one. This takes an array of path, not URLs.
|
||||||
|
aliases = []
|
||||||
|
|
||||||
|
# Template to use to render this page
|
||||||
|
template = "page.html"
|
||||||
|
|
||||||
|
# Your own data
|
||||||
|
[extra]
|
||||||
|
+++
|
||||||
|
|
||||||
|
Some content
|
||||||
|
```
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
You can ask Gutenberg to create a summary if you only want to show the first
|
||||||
|
paragraph of each page in a list for example.
|
||||||
|
To do so, add `<!-- more -->` in your content at the point where you want the
|
||||||
|
summary to end and the content up to that point will be also available separately
|
||||||
|
in the template.
|
88
docs/content/documentation/content/section.md
Normal file
88
docs/content/documentation/content/section.md
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
+++
|
||||||
|
title = "Section"
|
||||||
|
weight = 20
|
||||||
|
+++
|
||||||
|
|
||||||
|
A section is automatically created implicitly when a folder is found
|
||||||
|
in the `content` section.
|
||||||
|
|
||||||
|
You can add `_index.md` file to a folder to augment a section and give it
|
||||||
|
some metadata and/or content.
|
||||||
|
|
||||||
|
## Front-matter
|
||||||
|
|
||||||
|
The front-matter is a set of metadata embedded in a file. In Gutenberg,
|
||||||
|
it is at the beginning of the file, surrounded by `+++` and uses TOML.
|
||||||
|
|
||||||
|
As the file itself is optional, none of the front-matter variables are
|
||||||
|
mandatory. However the opening and closing `+++` are required even if there are
|
||||||
|
no variables in it.
|
||||||
|
|
||||||
|
Here is an example `_index.md` with all the variables available:
|
||||||
|
|
||||||
|
|
||||||
|
```md
|
||||||
|
+++
|
||||||
|
title = ""
|
||||||
|
|
||||||
|
description = ""
|
||||||
|
|
||||||
|
# Whether to sort by "date", "order", "weight" or "none". More on that below
|
||||||
|
sort_by = "none"
|
||||||
|
|
||||||
|
# Used by the parent section to order its subsections.
|
||||||
|
# Higher values means it will be at the end.
|
||||||
|
weight = 0
|
||||||
|
|
||||||
|
# Template to use to render this section page
|
||||||
|
template = "section.html"
|
||||||
|
|
||||||
|
# How many pages to be displayed per paginated page.
|
||||||
|
# No pagination will happen if this isn't set or if the value is 0
|
||||||
|
paginate_by = 0
|
||||||
|
|
||||||
|
# If set, will be the path used by paginated page and the page number will be appended after it.
|
||||||
|
# For example the default would be page/1
|
||||||
|
paginate_by = "page"
|
||||||
|
|
||||||
|
# Whether to insert a link for each header like the ones you can see in this site if you hover one
|
||||||
|
# The default template can be overridden by creating a `anchor-link.html` in the `templates` directory
|
||||||
|
# Options are "left", "right" and "none"
|
||||||
|
insert_anchor_links = "none"
|
||||||
|
|
||||||
|
# Whether to render that section or not.
|
||||||
|
# Useful when the section is only there to organize things but is not meant
|
||||||
|
# to be used directly
|
||||||
|
render = true
|
||||||
|
|
||||||
|
# Whether to redirect when landing on that section. Defaults to `None`.
|
||||||
|
# Useful for the same reason as `render` but when you don't want a 404 when
|
||||||
|
# landing on the root section page
|
||||||
|
redirect_to = ""
|
||||||
|
|
||||||
|
# Your own data
|
||||||
|
[extra]
|
||||||
|
+++
|
||||||
|
|
||||||
|
Some content
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep in mind that the variables only apply to the direct pages, not to the subsections' pages. This means
|
||||||
|
you can only paginate the pages directly in the section folder for example.
|
||||||
|
|
||||||
|
## Sorting
|
||||||
|
Sections' pages can be sorted three different ways, not counting the unsorted default.
|
||||||
|
Sorting is enabled by setting the `sort_by` front-matter variable.
|
||||||
|
|
||||||
|
Any page that cannot be sorted, for example if missing the date variable while sorting by `date`, will be ignored and
|
||||||
|
won't be rendered. The terminal will warn you if this is happening.
|
||||||
|
|
||||||
|
### `date`
|
||||||
|
This will sort all pages by their `date` field, from the most recent to the oldest.
|
||||||
|
|
||||||
|
### `weight`
|
||||||
|
This will be sort all pages by their `weight` field. Heavier weights fall at the bottom: 5 would be before 10.
|
||||||
|
|
||||||
|
### `order`
|
||||||
|
This will be sort all pages by their `order` field. Order is the opposite of weight, think of it as enumerating
|
||||||
|
the content: this is my first post, my second, etc. A page with `order: 5` will appear after a page with `order: 10` in the sorted list.
|
166
docs/content/documentation/content/shortcodes.md
Normal file
166
docs/content/documentation/content/shortcodes.md
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
+++
|
||||||
|
title = "Shortcodes"
|
||||||
|
weight = 40
|
||||||
|
+++
|
||||||
|
|
||||||
|
While Markdown is good at writing, it isn't great when you need write inline
|
||||||
|
HTML to add some styling for example.
|
||||||
|
|
||||||
|
To solve this, Gutenberg borrows the concept of [shortcodes](https://codex.wordpress.org/Shortcode_API)
|
||||||
|
from WordPress.
|
||||||
|
In our case, the shortcode corresponds to a template that is defined in the `templates/shortcodes` directory or a built-in one.
|
||||||
|
|
||||||
|
## Writing a shortcode
|
||||||
|
Let's write a shortcode to embed YouTube videos as an example.
|
||||||
|
In a file called `youtube.html` in the `templates/shortcodes` directory, paste the
|
||||||
|
following:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
<div {% if class %}class="{{class}}"{% endif %}>
|
||||||
|
<iframe
|
||||||
|
src="https://www.youtube.com/embed/{{id}}{% if autoplay %}?autoplay=1{% endif %}"
|
||||||
|
webkitallowfullscreen
|
||||||
|
mozallowfullscreen
|
||||||
|
allowfullscreen>
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
This template is very straightforward: an iframe pointing to the YouTube embed URL wrapped in a `<div>`.
|
||||||
|
In terms of input, it expects at least one variable: `id`. Since the other variables
|
||||||
|
are in a `if` statement, we can assume they are optional.
|
||||||
|
|
||||||
|
That's it, Gutenberg will now recognise this template as a shortcode named `youtube` (the filename minus the `.html` extension).
|
||||||
|
|
||||||
|
## Using shortcodes
|
||||||
|
|
||||||
|
There are two kinds of shortcodes: ones that do no take a body like the YouTube example above and ones that do, a quote for example.
|
||||||
|
In both cases, their arguments must be named and they will all be passed to the template.
|
||||||
|
|
||||||
|
Do note that shortcodes in code blocks will be ignored.
|
||||||
|
|
||||||
|
### Shortcodes without body
|
||||||
|
Those look like rendering a variable in Tera.
|
||||||
|
|
||||||
|
On a new line, call the shortcode as if it was a function in a variable block. All the examples below are valid
|
||||||
|
calls of the YouTube shortcode.
|
||||||
|
|
||||||
|
```md
|
||||||
|
{{ youtube(id="w7Ft2ymGmfc") }}
|
||||||
|
|
||||||
|
{{ youtube(id="w7Ft2ymGmfc", autoplay=true) }}
|
||||||
|
|
||||||
|
{{ youtube(id="w7Ft2ymGmfc", autoplay=true, class="youtube") }}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shortcodes with body
|
||||||
|
Those look like a block in Tera.
|
||||||
|
For example, let's imagine we have the following shortcode `quote.html` template:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
<blockquote>
|
||||||
|
{{ body }} <br>
|
||||||
|
-- {{ author}}
|
||||||
|
</blockquote>
|
||||||
|
```
|
||||||
|
|
||||||
|
We could use it in our markup file like so:
|
||||||
|
|
||||||
|
```md
|
||||||
|
{% quote(author="Vincent") %}
|
||||||
|
A quote
|
||||||
|
{% end %}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `body` variable used in the shortcode template will be implicitly passed down to the rendering
|
||||||
|
context automatically.
|
||||||
|
|
||||||
|
## Built-in shortcodes
|
||||||
|
|
||||||
|
Gutenberg comes with a few built-in shortcodes. If you want to override a default shortcode template,
|
||||||
|
simply place a `{shortcode_name}.html` file in the `templates/shortcodes` directory and Gutenberg will
|
||||||
|
use that instead.
|
||||||
|
|
||||||
|
### YouTube
|
||||||
|
Embed a responsive player for a YouTube video.
|
||||||
|
|
||||||
|
The arguments are:
|
||||||
|
|
||||||
|
- `id`: the video id (mandatory)
|
||||||
|
- `class`: a class to add the `div` surrounding the iframe
|
||||||
|
- `autoplay`: whether to autoplay the video on load
|
||||||
|
|
||||||
|
Usage example:
|
||||||
|
|
||||||
|
```md
|
||||||
|
{{ youtube(id="w7Ft2ymGmfc") }}
|
||||||
|
|
||||||
|
{{ youtube(id="w7Ft2ymGmfc", autoplay=true) }}
|
||||||
|
|
||||||
|
{{ youtube(id="w7Ft2ymGmfc", autoplay=true, class="youtube") }}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result example:
|
||||||
|
|
||||||
|
{{ youtube(id="w7Ft2ymGmfc") }}
|
||||||
|
|
||||||
|
### Vimeo
|
||||||
|
Embed a player for a Vimeo video.
|
||||||
|
|
||||||
|
The arguments are:
|
||||||
|
|
||||||
|
- `id`: the video id (mandatory)
|
||||||
|
- `class`: a class to add the `div` surrounding the iframe
|
||||||
|
|
||||||
|
Usage example:
|
||||||
|
|
||||||
|
```md
|
||||||
|
{{ vimeo(id="124313553") }}
|
||||||
|
|
||||||
|
{{ vimeo(id="124313553", class="vimeo") }}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result example:
|
||||||
|
|
||||||
|
{{ vimeo(id="124313553") }}
|
||||||
|
|
||||||
|
### Streamable
|
||||||
|
Embed a player for a Streamable video.
|
||||||
|
|
||||||
|
The arguments are:
|
||||||
|
|
||||||
|
- `id`: the video id (mandatory)
|
||||||
|
- `class`: a class to add the `div` surrounding the iframe
|
||||||
|
|
||||||
|
Usage example:
|
||||||
|
|
||||||
|
```md
|
||||||
|
{{ streamable(id="2zt0") }}
|
||||||
|
|
||||||
|
{{ streamable(id="2zt0", class="streamble") }}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result example:
|
||||||
|
|
||||||
|
{{ streamable(id="2zt0") }}
|
||||||
|
|
||||||
|
### Gist
|
||||||
|
Embed a [Github gist]().
|
||||||
|
|
||||||
|
The arguments are:
|
||||||
|
|
||||||
|
- `url`: the url to the gist (mandatory)
|
||||||
|
- `file`: by default, the shortcode will pull every file from the URL unless a specific filename is requested
|
||||||
|
- `class`: a class to add the `div` surrounding the iframe
|
||||||
|
|
||||||
|
Usage example:
|
||||||
|
|
||||||
|
```md
|
||||||
|
{{ gist(id="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57") }}
|
||||||
|
|
||||||
|
{{ gist(id="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57", class="gist") }}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result example:
|
||||||
|
|
||||||
|
{{ gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57") }}
|
111
docs/content/documentation/content/syntax-highlighting.md
Normal file
111
docs/content/documentation/content/syntax-highlighting.md
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
+++
|
||||||
|
title = "Syntax Highlighting"
|
||||||
|
weight = 80
|
||||||
|
+++
|
||||||
|
|
||||||
|
Gutenberg comes with built-in syntax highlighting but you first
|
||||||
|
need to enable it in the [configuration](./documentation/getting-started/configuration.md).
|
||||||
|
|
||||||
|
Once this is done, Gutenberg will automatically highlight all code blocks
|
||||||
|
in your content. A code block in Markdown looks like the following:
|
||||||
|
|
||||||
|
````md
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let highlight = true;
|
||||||
|
```
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
You can replace the `rust` by the language you want to highlight.
|
||||||
|
Here is a full list of the supported languages and the short name you can use:
|
||||||
|
|
||||||
|
```
|
||||||
|
- Plain Text -> ["txt"]
|
||||||
|
- Assembly x86 (NASM) -> ["asm", "inc", "nasm"]
|
||||||
|
- Elm -> ["elm"]
|
||||||
|
- Handlebars -> ["handlebars", "handlebars.html", "hbr", "hbrs", "hbs", "hdbs", "hjs", "mu", "mustache", "rac", "stache", "template", "tmpl"]
|
||||||
|
- Jinja2 -> ["j2", "jinja2"]
|
||||||
|
- Julia -> ["jl"]
|
||||||
|
- LESS -> ["less"]
|
||||||
|
- ASP -> ["asa"]
|
||||||
|
- HTML (ASP) -> ["asp"]
|
||||||
|
- ActionScript -> ["as"]
|
||||||
|
- AppleScript -> ["applescript", "script editor"]
|
||||||
|
- Batch File -> ["bat", "cmd"]
|
||||||
|
- NAnt Build File -> ["build"]
|
||||||
|
- C# -> ["cs", "csx"]
|
||||||
|
- C++ -> ["cpp", "cc", "cp", "cxx", "c++", "C", "h", "hh", "hpp", "hxx", "h++", "inl", "ipp"]
|
||||||
|
- C -> ["c", "h"]
|
||||||
|
- CSS -> ["css", "css.erb", "css.liquid"]
|
||||||
|
- Clojure -> ["clj"]
|
||||||
|
- D -> ["d", "di"]
|
||||||
|
- Diff -> ["diff", "patch"]
|
||||||
|
- Erlang -> ["erl", "hrl", "Emakefile", "emakefile"]
|
||||||
|
- HTML (Erlang) -> ["yaws"]
|
||||||
|
- Go -> ["go"]
|
||||||
|
- Graphviz (DOT) -> ["dot", "DOT"]
|
||||||
|
- Groovy -> ["groovy", "gvy", "gradle"]
|
||||||
|
- HTML -> ["html", "htm", "shtml", "xhtml", "inc", "tmpl", "tpl"]
|
||||||
|
- Haskell -> ["hs"]
|
||||||
|
- Literate Haskell -> ["lhs"]
|
||||||
|
- Java Server Page (JSP) -> ["jsp"]
|
||||||
|
- Java -> ["java", "bsh"]
|
||||||
|
- JavaDoc -> []
|
||||||
|
- Java Properties -> ["properties"]
|
||||||
|
- JSON -> ["json", "sublime-settings", "sublime-menu", "sublime-keymap", "sublime-mousemap", "sublime-theme", "sublime-build", "sublime-project", "sublime-completions", "sublime-commands", "sublime-macro"]
|
||||||
|
- JavaScript -> ["js", "htc"]
|
||||||
|
- Regular Expressions (Javascript) -> []
|
||||||
|
- BibTeX -> ["bib"]
|
||||||
|
- LaTeX Log -> []
|
||||||
|
- LaTeX -> ["tex", "ltx"]
|
||||||
|
- TeX -> ["sty", "cls"]
|
||||||
|
- Lisp -> ["lisp", "cl", "l", "mud", "el", "scm", "ss", "lsp", "fasl"]
|
||||||
|
- Lua -> ["lua"]
|
||||||
|
- Make Output -> []
|
||||||
|
- Makefile -> ["make", "GNUmakefile", "makefile", "Makefile", "OCamlMakefile", "mak", "mk"]
|
||||||
|
- Markdown -> ["md", "mdown", "markdown", "markdn"]
|
||||||
|
- MultiMarkdown -> []
|
||||||
|
- MATLAB -> ["matlab"]
|
||||||
|
- OCaml -> ["ml", "mli"]
|
||||||
|
- OCamllex -> ["mll"]
|
||||||
|
- OCamlyacc -> ["mly"]
|
||||||
|
- camlp4 -> []
|
||||||
|
- Objective-C++ -> ["mm", "M", "h"]
|
||||||
|
- Objective-C -> ["m", "h"]
|
||||||
|
- PHP Source -> []
|
||||||
|
- PHP -> ["php", "php3", "php4", "php5", "php7", "phps", "phpt", "phtml"]
|
||||||
|
- Pascal -> ["pas", "p", "dpr"]
|
||||||
|
- Perl -> ["pl", "pm", "pod", "t", "PL"]
|
||||||
|
- Python -> ["py", "py3", "pyw", "pyi", "rpy", "cpy", "SConstruct", "Sconstruct", "sconstruct", "SConscript", "gyp", "gypi", "Snakefile", "wscript"]
|
||||||
|
- Regular Expressions (Python) -> []
|
||||||
|
- R Console -> []
|
||||||
|
- R -> ["R", "r", "s", "S", "Rprofile"]
|
||||||
|
- Rd (R Documentation) -> ["rd"]
|
||||||
|
- HTML (Rails) -> ["rails", "rhtml", "erb", "html.erb"]
|
||||||
|
- JavaScript (Rails) -> ["js.erb"]
|
||||||
|
- Ruby Haml -> ["haml", "sass"]
|
||||||
|
- Ruby on Rails -> ["rxml", "builder"]
|
||||||
|
- SQL (Rails) -> ["erbsql", "sql.erb"]
|
||||||
|
- Regular Expression -> ["re"]
|
||||||
|
- reStructuredText -> ["rst", "rest"]
|
||||||
|
- Ruby -> ["rb", "Appfile", "Appraisals", "Berksfile", "Brewfile", "capfile", "cgi", "Cheffile", "config.ru", "Deliverfile", "Fastfile", "fcgi", "Gemfile", "gemspec", "Guardfile", "irbrc", "jbuilder", "podspec", "prawn", "rabl", "rake", "Rakefile", "Rantfile", "rbx", "rjs", "ruby.rail", "Scanfile", "simplecov", "Snapfile", "thor", "Thorfile", "Vagrantfile"]
|
||||||
|
- Cargo Build Results -> []
|
||||||
|
- Rust -> ["rs"]
|
||||||
|
- SQL -> ["sql", "ddl", "dml"]
|
||||||
|
- Scala -> ["scala", "sbt"]
|
||||||
|
- Shell Script (Bash) -> ["sh", "bash", "zsh", ".bash_aliases", ".bash_functions", ".bash_login", ".bash_logout", ".bash_profile", ".bash_variables", ".bashrc", ".profile", ".textmate_init"]
|
||||||
|
- HTML (Tcl) -> ["adp"]
|
||||||
|
- Tcl -> ["tcl"]
|
||||||
|
- Textile -> ["textile"]
|
||||||
|
- XML -> ["xml", "xsd", "xslt", "tld", "dtml", "rss", "opml", "svg"]
|
||||||
|
- YAML -> ["yaml", "yml", "sublime-syntax"]
|
||||||
|
- Generic Config -> ["cfg", "conf", "config", "ini", "pro"]
|
||||||
|
- Linker Script -> ["ld"]
|
||||||
|
- TOML -> ["toml", "tml"]
|
||||||
|
- TypeScript -> ["ts"]
|
||||||
|
- TypeScriptReact -> ["tsx"]
|
||||||
|
- VimL -> ["vim"]
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to highlight a language not on that list, please open an issue or a pull request on the [Gutenberg repo](https://github.com/Keats/gutenberg).
|
33
docs/content/documentation/content/table-of-contents.md
Normal file
33
docs/content/documentation/content/table-of-contents.md
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
+++
|
||||||
|
title = "Table of Contents"
|
||||||
|
weight = 60
|
||||||
|
+++
|
||||||
|
|
||||||
|
Each page/section will automatically generate a table of content for itself based on the headers present.
|
||||||
|
|
||||||
|
TODO: add link for template variables
|
||||||
|
It is available in the template through `section.toc` and `page.toc`. You can view the [template variables]()
|
||||||
|
documentation for information on its structure.
|
||||||
|
|
||||||
|
Here is an example of using that field to render a 2-level table of content:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
<ul>
|
||||||
|
{% for h1 in page.toc %}
|
||||||
|
<li>
|
||||||
|
<a href="{{h1.permalink | safe}}">{{ h1.title }}</a>
|
||||||
|
{% if h1.children %}
|
||||||
|
<ul>
|
||||||
|
{% for h2 in h1.children %}
|
||||||
|
<li>
|
||||||
|
<a href="{{h2.permalink | safe}}">{{ h2.title }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
```
|
||||||
|
|
||||||
|
While headers are neatly ordered in that example, it will work just as well with disjoint headers.
|
|
@ -1,4 +1,7 @@
|
||||||
+++
|
+++
|
||||||
title = "Getting Started"
|
title = "Getting Started"
|
||||||
sort_by = "order"
|
weight = 1
|
||||||
|
sort_by = "weight"
|
||||||
|
redirect_to = "documentation/getting-started/installation"
|
||||||
|
insert_anchor_links = "left"
|
||||||
+++
|
+++
|
||||||
|
|
|
@ -1,6 +1,43 @@
|
||||||
+++
|
+++
|
||||||
title = "CLI usage"
|
title = "CLI usage"
|
||||||
order = 2
|
weight = 2
|
||||||
+++
|
+++
|
||||||
|
|
||||||
Hey
|
Gutenberg only has 3 commands: init, build and serve.
|
||||||
|
|
||||||
|
You can view the help of the whole program by running `gutenberg --help` and
|
||||||
|
the command help by running `gutenberg <cmd> --help`.
|
||||||
|
|
||||||
|
## init
|
||||||
|
|
||||||
|
Creates the directory structure used by Gutenberg at the given directory.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ gutenberg init <my_site>
|
||||||
|
```
|
||||||
|
|
||||||
|
will create a new folder named `my_site` and the files/folders needed by
|
||||||
|
Gutenberg.
|
||||||
|
|
||||||
|
## build
|
||||||
|
|
||||||
|
This will build the whole site in the `public` directory.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ gutenberg build
|
||||||
|
```
|
||||||
|
|
||||||
|
## serve
|
||||||
|
|
||||||
|
This will build and serve the site using a local server. You can also specify
|
||||||
|
the interface/port combination to use if you want something different than the default (`127.0.0.1:1111`).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ gutenberg serve
|
||||||
|
$ gutenberg serve --port 2000
|
||||||
|
$ gutenberg serve --interface 0.0.0.0
|
||||||
|
$ gutenberg serve --interface 0.0.0.0 --port 2000
|
||||||
|
```
|
||||||
|
|
||||||
|
The serve command will watch all your content and will provide live reload, without
|
||||||
|
hard refresh if possible.
|
||||||
|
|
|
@ -1,6 +1,71 @@
|
||||||
+++
|
+++
|
||||||
title = "Configuration"
|
title = "Configuration"
|
||||||
order = 4
|
weight = 4
|
||||||
+++
|
+++
|
||||||
|
|
||||||
Hey
|
The default configuration will be enough to get Gutenberg running locally but not more than that.
|
||||||
|
It follows the philosophy of only paying for what you need: almost everything is turned off by default.
|
||||||
|
|
||||||
|
To change the config, edit the `config.toml` file.
|
||||||
|
If you are not familiar with TOML, have a look at [the TOML Spec](https://github.com/toml-lang/toml)
|
||||||
|
to learn about it.
|
||||||
|
|
||||||
|
Only one variable - `base_url` - is mandatory, everything else is optional. You can find all variables
|
||||||
|
used by Gutenberg config as well as their default values below:
|
||||||
|
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Base URL of the site, the only required config argument
|
||||||
|
base_url = "mywebsite.com"
|
||||||
|
|
||||||
|
# Used in RSS by default
|
||||||
|
title = ""
|
||||||
|
description = ""
|
||||||
|
language_code = "en"
|
||||||
|
|
||||||
|
# Theme name to use
|
||||||
|
theme = ""
|
||||||
|
|
||||||
|
# Highlight all code blocks found
|
||||||
|
highlight_code = false
|
||||||
|
|
||||||
|
# Which theme to use for the code highlighting. See below for list of accepted values
|
||||||
|
highlight_theme = "base16-ocean-dark"
|
||||||
|
|
||||||
|
# Whether to generate a RSS feed automatically
|
||||||
|
generate_rss = false
|
||||||
|
|
||||||
|
# The number of articles to include in the RSS feed
|
||||||
|
rss_limit = 20
|
||||||
|
|
||||||
|
# Whether to generate a tags page and individual tag pages for pages with tags
|
||||||
|
generate_tags_pages = false
|
||||||
|
|
||||||
|
# Whether to generate a categories page and individual category pages for pages with a category
|
||||||
|
generate_categories_pages = false
|
||||||
|
|
||||||
|
# Whether to compile the Sass files found in the `sass` directory
|
||||||
|
compile_sass = false
|
||||||
|
|
||||||
|
# You can put any kind of data in there and it will be accessible in all templates
|
||||||
|
[extra]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Syntax highlighting
|
||||||
|
|
||||||
|
Gutenberg currently has the following highlight themes available:
|
||||||
|
|
||||||
|
- base16-ocean-dark
|
||||||
|
- base16-ocean-light
|
||||||
|
- gruvbox-dark
|
||||||
|
- gruvbox-light
|
||||||
|
- inspired-github
|
||||||
|
- kronuz
|
||||||
|
- material-dark
|
||||||
|
- material-light
|
||||||
|
- monokai
|
||||||
|
- solarized-dark
|
||||||
|
- solarized-light
|
||||||
|
|
||||||
|
Gutenberg uses the Sublime Text themes, making it very easy to add more.
|
||||||
|
If you want a theme not on that list, please open an issue or a pull request on the [Gutenberg repo](https://github.com/Keats/gutenberg).
|
||||||
|
|
|
@ -1,6 +1,47 @@
|
||||||
+++
|
+++
|
||||||
title = "Directory structure"
|
title = "Directory structure"
|
||||||
order = 3
|
weight = 3
|
||||||
+++
|
+++
|
||||||
|
|
||||||
Hey
|
After running `gutenberg init`, you should see the following structure in your folder:
|
||||||
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
.
|
||||||
|
├── config.toml
|
||||||
|
├── content
|
||||||
|
├── sass
|
||||||
|
├── static
|
||||||
|
├── templates
|
||||||
|
└── themes
|
||||||
|
|
||||||
|
5 directories, 1 file
|
||||||
|
```
|
||||||
|
|
||||||
|
Here's a high level overview of each of these folders and `config.toml`.
|
||||||
|
|
||||||
|
## `config.toml`
|
||||||
|
A mandatory configuration file of Gutenberg in TOML format.
|
||||||
|
It is explained in details in the [Configuration page](./documentation/getting-started/configuration.md).
|
||||||
|
|
||||||
|
## `content`
|
||||||
|
Where all your markup content lies: this will most likely be mostly `.md` files.
|
||||||
|
Each folder in the `content` directory represents a [section](./documentation/content/section.md)
|
||||||
|
that contains [pages](./documentation/content/page.md) : your `.md` files.
|
||||||
|
|
||||||
|
To learn more, read [the content overview](./documentation/content/overview.md).
|
||||||
|
|
||||||
|
## `sass`
|
||||||
|
Contains the [Sass](http://sass-lang.com) files to be compiled. Non-Sass files will be ignored.
|
||||||
|
|
||||||
|
## `static`
|
||||||
|
Contains any kind of files. All the files/folders in the `static` folder will be copied as-is in the output directory.
|
||||||
|
|
||||||
|
## `templates`
|
||||||
|
Contains all the [Tera](tera.netlify.com) templates that will be used to render this site.
|
||||||
|
Have a look at the [Templates](./documentation/templates/_index.md) to learn more on the default templates
|
||||||
|
and the variables available.
|
||||||
|
|
||||||
|
## `themes`
|
||||||
|
Contains themes that can be used for that site. If you are not planning to use themes, you can safely ignore
|
||||||
|
this folder and let it be. If you want to learn about themes, head to the [themes documentation](./documentation/themes/_index.md).
|
||||||
|
|
|
@ -1,6 +1,31 @@
|
||||||
+++
|
+++
|
||||||
title = "Installation"
|
title = "Installation"
|
||||||
order = 1
|
weight = 1
|
||||||
+++
|
+++
|
||||||
|
|
||||||
Hey
|
Gutenberg provides pre-built binaries for Mac OS, Linux and Windows on the
|
||||||
|
[Github release page](https://github.com/Keats/gutenberg/releases).
|
||||||
|
|
||||||
|
## Using brew on Mac OS
|
||||||
|
|
||||||
|
TODO: it's not on brew right now
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
|
||||||
|
TODO: i have no clue whatsoever about packages in Windows
|
||||||
|
|
||||||
|
## Archlinux
|
||||||
|
|
||||||
|
TODO: add a `gutenberg-bin` in AUR and explain how to install it
|
||||||
|
|
||||||
|
## From source
|
||||||
|
To build it from source, you will need to have Git, [Rust and Cargo](https://www.rust-lang.org/en-US/)
|
||||||
|
installed.
|
||||||
|
|
||||||
|
From a terminal, you can now run the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
The binary will be available in the `target/release` folder.
|
||||||
|
|
6
docs/content/documentation/templates/_index.md
Normal file
6
docs/content/documentation/templates/_index.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
+++
|
||||||
|
title = "Templates"
|
||||||
|
weight = 3
|
||||||
|
sort_by = "weight"
|
||||||
|
insert_anchor_links = "left"
|
||||||
|
+++
|
73
docs/content/documentation/templates/overview.md
Normal file
73
docs/content/documentation/templates/overview.md
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
+++
|
||||||
|
title = "Overview"
|
||||||
|
weight = 10
|
||||||
|
+++
|
||||||
|
|
||||||
|
Gutenberg uses the [Tera](tera.netlify.com) template engine.
|
||||||
|
This documentation will only touch how templates work in Gutenberg, please read
|
||||||
|
the [Tera template documentation](https://tera.netlify.com/docs/templates/) if you want
|
||||||
|
to know how write them. If you are familiar with Jinja2, Liquid or Twig, this should be
|
||||||
|
a breeze.
|
||||||
|
|
||||||
|
All templates live in the `templates` directory and built-in or themes templates can
|
||||||
|
be overriden by creating a template with same name in the correct path. For example,
|
||||||
|
you can override the RSS template by creating a `templates/rss.xml` file.
|
||||||
|
|
||||||
|
If you are not sure what is available in a template, you can just stick `{{ __tera_context }}` in it
|
||||||
|
to print the whole context.
|
||||||
|
|
||||||
|
A few variables are available on all templates except for RSS/Sitemap:
|
||||||
|
|
||||||
|
- `config`: the [configuration](./documentation/getting-started/configuration.md) without any modifications
|
||||||
|
- `current_path`: the path (full URL without the `base_url`) of the current page
|
||||||
|
- `current_url`: the full URL for that page
|
||||||
|
|
||||||
|
## Built-in filters
|
||||||
|
Gutenberg adds a few filters, in addition of the ones already present in Tera.
|
||||||
|
|
||||||
|
### markdown
|
||||||
|
Converts the given variable to HTML using Markdown. This doesn't apply any of the
|
||||||
|
features that Gutenberg adds to Markdown: internal links, shortcodes etc won't work.
|
||||||
|
|
||||||
|
### base64_encode
|
||||||
|
Encode the variable to base64.
|
||||||
|
|
||||||
|
### base64_decode
|
||||||
|
Decode the variable from base64.
|
||||||
|
|
||||||
|
|
||||||
|
## Built-in global functions
|
||||||
|
Gutenberg adds a few global functions to Tera in order to make it easier to develop complex sites.
|
||||||
|
|
||||||
|
### `get_page`
|
||||||
|
Takes a path to a `.md` file and returns the associated page
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% set page = get_page(path="blog/page2.md") %}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `get_section`
|
||||||
|
Takes a path to a `_index.md` file and returns the associated section
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% set section = get_page(path="blog/_index.md") %}
|
||||||
|
```
|
||||||
|
|
||||||
|
###` get_url`
|
||||||
|
Gets the permalink for the given path.
|
||||||
|
If the path starts with `./`, it will be understood as an internal
|
||||||
|
link like the ones used in markdown.
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% set url = get_url(path="./blog/_index.md") %}
|
||||||
|
```
|
||||||
|
|
||||||
|
This can also be used to get the permalinks for static assets for example if
|
||||||
|
we want to link to the file that is located at `static/css/app.css`:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{{ get_url(path="css/app.css") }}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the case of non-internal links, you can also add a cachebust of the format `?t=1290192` at the end of a URL
|
||||||
|
by passing `cachebust=true` to the `get_url` function.
|
88
docs/content/documentation/templates/pages-sections.md
Normal file
88
docs/content/documentation/templates/pages-sections.md
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
+++
|
||||||
|
title = "Index, Sections and Pages"
|
||||||
|
weight = 20
|
||||||
|
+++
|
||||||
|
|
||||||
|
First off, it is important to know that in Gutenberg the index
|
||||||
|
page is actually a section like any other: you can add metadata
|
||||||
|
and content by adding `_index.md` at the root of the `content` folder.
|
||||||
|
|
||||||
|
Pages and sections are actually very similar.
|
||||||
|
|
||||||
|
## Page variables
|
||||||
|
By default, Gutenberg will try to load `templates/page.html`. If there isn't
|
||||||
|
one, it will render the built-in template: a blank page.
|
||||||
|
|
||||||
|
Whichever template you decide to render, you will get a `page` variable in your template
|
||||||
|
with the following fields:
|
||||||
|
|
||||||
|
|
||||||
|
```ts
|
||||||
|
content: String;
|
||||||
|
title: String?;
|
||||||
|
description: String?;
|
||||||
|
date: String?;
|
||||||
|
slug: String;
|
||||||
|
path: String;
|
||||||
|
permalink: String;
|
||||||
|
summary: String?;
|
||||||
|
tags: Array<String>;
|
||||||
|
category: String?;
|
||||||
|
extra: HashMap<String, Any>;
|
||||||
|
// Naive word count, will not work for languages without whitespace
|
||||||
|
word_count: Number;
|
||||||
|
// Based on https://help.medium.com/hc/en-us/articles/214991667-Read-time
|
||||||
|
reading_time: Number;
|
||||||
|
// `previous` and `next` are only filled if the content can be sorted
|
||||||
|
previous: Page?;
|
||||||
|
next: Page?;
|
||||||
|
// See the Table of contents section below for more details
|
||||||
|
toc: Array<Header>;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Section variables
|
||||||
|
By default, Gutenberg will try to load `templates/section.html`. If there isn't
|
||||||
|
one, it will render the built-in template: a blank page.
|
||||||
|
|
||||||
|
Whichever template you decide to render, you will get a `section` variable in your template
|
||||||
|
with the following fields:
|
||||||
|
|
||||||
|
|
||||||
|
```ts
|
||||||
|
content: String;
|
||||||
|
title: String?;
|
||||||
|
description: String?;
|
||||||
|
date: String?;
|
||||||
|
slug: String;
|
||||||
|
path: String;
|
||||||
|
permalink: String;
|
||||||
|
extra: HashMap<String, Any>;
|
||||||
|
// Pages directly in this section, sorted if asked
|
||||||
|
pages: Array<Pages>;
|
||||||
|
// Direct subsections to this section, sorted by subsections weight
|
||||||
|
subsections: Array<Section>;
|
||||||
|
// Naive word count, will not work for languages without whitespace
|
||||||
|
word_count: Number;
|
||||||
|
// Based on https://help.medium.com/hc/en-us/articles/214991667-Read-time
|
||||||
|
reading_time: Number;
|
||||||
|
// See the Table of contents section below for more details
|
||||||
|
toc: Array<Header>;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
Both page and section have a `toc` field which corresponds to an array of `Header`.
|
||||||
|
A `Header` has the following fields:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// The hX level
|
||||||
|
level: 1 | 2 | 3 | 4 | 5 | 6;
|
||||||
|
// The generated slug id
|
||||||
|
id: String;
|
||||||
|
// The text of the header
|
||||||
|
title: String;
|
||||||
|
// A link pointing directly to the header, using the inserted anchor
|
||||||
|
permalink: String;
|
||||||
|
// All lower level headers below this header
|
||||||
|
children: Array<Header>;
|
||||||
|
```
|
28
docs/content/documentation/templates/pagination.md
Normal file
28
docs/content/documentation/templates/pagination.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
+++
|
||||||
|
title = "Pagination"
|
||||||
|
weight = 30
|
||||||
|
+++
|
||||||
|
|
||||||
|
A paginated section gets the same `section` variable as a normal
|
||||||
|
[section page](./documentation/templates/pages-sections.md#section-variables) and will use
|
||||||
|
the template mentioned in the section front-matter or the default one.
|
||||||
|
In addition, a paginated section gets a `paginator` one, which has a `Pager` type:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// How many items per page
|
||||||
|
paginate_by: Number;
|
||||||
|
// Permalink to the first page
|
||||||
|
first: String;
|
||||||
|
// Permalink to the last page
|
||||||
|
last: String;
|
||||||
|
// Permalink to the previous page, if there is one
|
||||||
|
previous: String?;
|
||||||
|
// Permalink to the next page, if there is one
|
||||||
|
next: String?;
|
||||||
|
// All pages for the current page
|
||||||
|
pages: Array<Page>;
|
||||||
|
// All pagers for this section, but with their `pages` attribute set to an empty array
|
||||||
|
pagers: Array<Pagers>;
|
||||||
|
// Which page are we on
|
||||||
|
current_index: Number;
|
||||||
|
```
|
14
docs/content/documentation/templates/robots.md
Normal file
14
docs/content/documentation/templates/robots.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
+++
|
||||||
|
title = "Robots.txt"
|
||||||
|
weight = 70
|
||||||
|
+++
|
||||||
|
|
||||||
|
Gutenberg will look for a `robots.txt` file in the `templates` directory or
|
||||||
|
use the built-in one.
|
||||||
|
|
||||||
|
Robots.txt is the simplest of all templates: it doesn't take any variables
|
||||||
|
and the default is what most site want.
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
User-agent: *
|
||||||
|
```
|
16
docs/content/documentation/templates/rss.md
Normal file
16
docs/content/documentation/templates/rss.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
+++
|
||||||
|
title = "RSS"
|
||||||
|
weight = 50
|
||||||
|
+++
|
||||||
|
|
||||||
|
Gutenberg will look for a `rss.xml` file in the `templates` directory or
|
||||||
|
use the built-in one. Currently it is only possible to have one RSS feed for the whole
|
||||||
|
site, you cannot create a RSS feed per section or taxonomy.
|
||||||
|
|
||||||
|
**Only pages with a date and that are not draft will be available.**
|
||||||
|
|
||||||
|
The RSS template gets two variables in addition of the config:
|
||||||
|
|
||||||
|
- `last_build_date`: the date of the latest post
|
||||||
|
- `pages`: see [the page variables](./documentation/templates/pages-sections.md#page-variables) for
|
||||||
|
a detailed description of this variable.
|
23
docs/content/documentation/templates/sitemap.md
Normal file
23
docs/content/documentation/templates/sitemap.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
+++
|
||||||
|
title = "Sitemap"
|
||||||
|
weight = 60
|
||||||
|
+++
|
||||||
|
|
||||||
|
Gutenberg will look for a `sitemap.xml` file in the `templates` directory or
|
||||||
|
use the built-in one.
|
||||||
|
|
||||||
|
|
||||||
|
The sitemap template gets four variables in addition of the config:
|
||||||
|
|
||||||
|
- `pages`: all pages of the site
|
||||||
|
- `sections`: all sections of the site, including an index section
|
||||||
|
- `tags`: links the tags page and individual tag page, empty if no tags
|
||||||
|
- `categories`: links the categories page and individual category page, empty if no categories
|
||||||
|
|
||||||
|
As the sitemap only requires a link and an optional date for the `lastmod` field,
|
||||||
|
all the variables above are arrays of `SitemapEntry` with the following type:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
permalink: String;
|
||||||
|
date: String?;
|
||||||
|
```
|
30
docs/content/documentation/templates/tags-categories.md
Normal file
30
docs/content/documentation/templates/tags-categories.md
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
+++
|
||||||
|
title = "Tags & Categories"
|
||||||
|
weight = 40
|
||||||
|
+++
|
||||||
|
|
||||||
|
Tags and categories actually get the same data but with different variable names.
|
||||||
|
The default templates for those pages are the following:
|
||||||
|
|
||||||
|
- `tags.html`: list of tags, gets variable `tags`
|
||||||
|
- `tag.html`: individual tag, gets variable `tag`
|
||||||
|
- `categories.html`: list of categories, gets variable `categories`
|
||||||
|
- `category.html`: individual category, gets variable `category`
|
||||||
|
|
||||||
|
You can override any of those templates by putting one with the same name in the `templates` directory.
|
||||||
|
`tags` and `categories` both are an array of `TaxonomyItem` sorted alphabetically, while `tag` and `category`
|
||||||
|
are a `TaxonomyItem`.
|
||||||
|
|
||||||
|
A `TaxonomyItem` has the following fields:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
name: String;
|
||||||
|
slug: String;
|
||||||
|
// Permalink to the generated page
|
||||||
|
permalink: String;
|
||||||
|
pages: Array<Page>;
|
||||||
|
```
|
||||||
|
|
||||||
|
Currently, there is no way to define different taxonomy templates per section, change
|
||||||
|
the path used for them or paginate them.
|
||||||
|
|
5
docs/content/documentation/themes/_index.md
Normal file
5
docs/content/documentation/themes/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
title = "Themes"
|
||||||
|
weight = 4
|
||||||
|
sort_by = "weight"
|
||||||
|
+++
|
53
docs/content/documentation/themes/creating-a-theme.md
Normal file
53
docs/content/documentation/themes/creating-a-theme.md
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
+++
|
||||||
|
title = "Creating a theme"
|
||||||
|
weight = 30
|
||||||
|
+++
|
||||||
|
|
||||||
|
Creating is exactly like creating a normal site with Gutenberg, except you
|
||||||
|
will want to use many [Tera blocks](https://tera.netlify.com/docs/templates/#inheritance) to
|
||||||
|
allow users to easily modify it.
|
||||||
|
|
||||||
|
A theme also need to have a `theme.toml` configuration file with the
|
||||||
|
following fields, here's the one from a [real template](https://github.com/Keats/hyde):
|
||||||
|
|
||||||
|
```toml
|
||||||
|
name = "hyde"
|
||||||
|
description = "A classic blog theme"
|
||||||
|
license = "MIT"
|
||||||
|
homepage = "https://github.com/Keats/gutenberg-hyde"
|
||||||
|
# The minimum version of Gutenberg required
|
||||||
|
min_version = "0.1"
|
||||||
|
|
||||||
|
# Any variable there can be overriden in the end user `config.toml`
|
||||||
|
# You don't need to prefix variables by the theme name but as this will
|
||||||
|
# be merged with user data, some kind of prefix or nesting is preferable
|
||||||
|
# Use snake_casing to be consistent with the rest of Gutenberg
|
||||||
|
[extra]
|
||||||
|
hyde_sticky = true
|
||||||
|
hyde_reverse = false
|
||||||
|
hyde_theme = ""
|
||||||
|
hyde_links = [
|
||||||
|
{url = "https://google.com", name = "Google.com"},
|
||||||
|
{url = "https://google.fr", name = "Google.fr"},
|
||||||
|
]
|
||||||
|
|
||||||
|
# The theme author info: you!
|
||||||
|
[author]
|
||||||
|
name = "Vincent Prouillet"
|
||||||
|
homepage = "https://vincent.is"
|
||||||
|
|
||||||
|
# If this is porting a theme from another static site engine, provide
|
||||||
|
# the info of the original author here
|
||||||
|
[original]
|
||||||
|
author = "mdo"
|
||||||
|
homepage = "http://markdotto.com/"
|
||||||
|
repo = "https://www.github.com/mdo/hyde"
|
||||||
|
```
|
||||||
|
|
||||||
|
A theme will also need three directories to work:
|
||||||
|
|
||||||
|
- `static`: any static files used in this theme
|
||||||
|
- `templates`: all templates used in this theme
|
||||||
|
- `sass`: Sass stylesheets for this theme, can be empty
|
||||||
|
|
||||||
|
A simple theme you can use as example is [Hyde](https://github.com/Keats/hyde).
|
|
@ -0,0 +1,52 @@
|
||||||
|
+++
|
||||||
|
title = "Installing & using themes"
|
||||||
|
weight = 20
|
||||||
|
+++
|
||||||
|
|
||||||
|
|
||||||
|
## Installing a theme
|
||||||
|
|
||||||
|
The easiest way to install to theme is to clone its repository in the `themes`
|
||||||
|
directory.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cd themes
|
||||||
|
$ git clone THEME_REPO_URL
|
||||||
|
```
|
||||||
|
|
||||||
|
Cloning the repository using Git or another VCS will allow you to easily
|
||||||
|
update it but you can also simply download the files manually and paste
|
||||||
|
them in a folder.
|
||||||
|
|
||||||
|
## Using a theme
|
||||||
|
|
||||||
|
Now that you have the theme in your `themes` directory, you only need to tell
|
||||||
|
Gutenberg to use it to get started by setting the `theme` variable of the
|
||||||
|
[configuration file](./documentation/getting-started/configuration.md). The theme
|
||||||
|
name has to be name of the directory you cloned the theme in.
|
||||||
|
For example, if you cloned a theme in `templates/simple-blog`, the theme name to use
|
||||||
|
in the configuration file is `simple-blog`.
|
||||||
|
|
||||||
|
## Customizing a theme
|
||||||
|
|
||||||
|
Any file from the theme can be overriden by creating a file with the same path and name in your `templates` or `static`
|
||||||
|
directory. Here are a few examples of that, assuming the theme name is `simple-blog`:
|
||||||
|
|
||||||
|
```plain
|
||||||
|
templates/pages/post.html -> will override themes/simple-blog/pages/post.html
|
||||||
|
templates/macros.html -> will override themes/simple-blog/macros.html
|
||||||
|
static/js/site.js -> will override themes/simple-blog/static/js/site.jss
|
||||||
|
```
|
||||||
|
|
||||||
|
Most themes will also provide some variables that are meant to be overriden: this happens in the `extra` section
|
||||||
|
of the [configuration file](./documentation/getting-started/configuration.md).
|
||||||
|
Let's say a theme uses a `show_twitter` variable and sets it to `false` by default. If you want to set it to `true`,
|
||||||
|
you can update your `config.toml` like so:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[extra]
|
||||||
|
show_twitter = false
|
||||||
|
```
|
||||||
|
|
||||||
|
You can modify files directly in the `themes` directory but this will make updating the theme harder and live reload won't work with those
|
||||||
|
files.
|
10
docs/content/documentation/themes/overview.md
Normal file
10
docs/content/documentation/themes/overview.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
+++
|
||||||
|
title = "Overview"
|
||||||
|
weight = 10
|
||||||
|
+++
|
||||||
|
|
||||||
|
Gutenberg has built-in support for themes in a way that are easy to customise
|
||||||
|
but still easy to update if needed.
|
||||||
|
|
||||||
|
All themes can use the full power of Gutenberg, from shortcodes to Sass compilation.
|
||||||
|
|
8
docs/content/documentation/themes/themes-list.md
Normal file
8
docs/content/documentation/themes/themes-list.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
+++
|
||||||
|
title = "List of themes"
|
||||||
|
weight = 40
|
||||||
|
+++
|
||||||
|
|
||||||
|
The following themes are available for Gutenberg:
|
||||||
|
|
||||||
|
- [Hyde](https://github.com/Keats/gutenberg-hyde)
|
|
@ -1,3 +1,44 @@
|
||||||
.documentation {
|
.documentation {
|
||||||
padding: 3rem;
|
padding: 3rem;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&__sidebar {
|
||||||
|
margin-right: 2rem;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding-left: 1rem;
|
||||||
|
|
||||||
|
li.active a {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $background;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
border-bottom: 1px solid $background;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:visited {
|
||||||
|
color: $background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 400px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
11
docs/templates/documentation.html
vendored
11
docs/templates/documentation.html
vendored
|
@ -8,19 +8,24 @@
|
||||||
{% set section = get_section(path="documentation/_index.md") %}
|
{% set section = get_section(path="documentation/_index.md") %}
|
||||||
<div class="documentation container">
|
<div class="documentation container">
|
||||||
<aside class="documentation__sidebar">
|
<aside class="documentation__sidebar">
|
||||||
|
<ul>
|
||||||
{% for subsection in section.subsections %}
|
{% for subsection in section.subsections %}
|
||||||
<li>
|
<li>
|
||||||
{{ subsection.title }}
|
{{ subsection.title }}
|
||||||
<ul>
|
<ul>
|
||||||
{% for page in subsection.pages | reverse %}
|
{% for page in subsection.pages %}
|
||||||
<li>{{page.title}}</li>
|
<li class="{% if current_path == page.path %}active{% endif %}">
|
||||||
|
<a href="{{page.permalink}}">{{page.title}}</a>
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
</aside>
|
</aside>
|
||||||
<div class="documentation__content">
|
<div class="documentation__content">
|
||||||
hey
|
{% block doc_content %}
|
||||||
|
{% endblock doc_content %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
2
docs/templates/index.html
vendored
2
docs/templates/index.html
vendored
|
@ -37,7 +37,7 @@
|
||||||
<h2>Everything built-in</h2>
|
<h2>Everything built-in</h2>
|
||||||
<p>
|
<p>
|
||||||
Gutenberg comes with Sass compilation, syntax highlighting and
|
Gutenberg comes with Sass compilation, syntax highlighting and
|
||||||
a other features that usually require using additional tools
|
other features that usually require using additional tools
|
||||||
or use JavaScript libraries on your site.
|
or use JavaScript libraries on your site.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
7
docs/templates/page.html
vendored
Normal file
7
docs/templates/page.html
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends "documentation.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ super() }} - {{ page.title }} {% endblock title %}
|
||||||
|
{% block doc_content %}
|
||||||
|
<h1>{{page.title}}</h1>
|
||||||
|
{{page.content | safe}}
|
||||||
|
{% endblock doc_content %}
|
|
@ -60,7 +60,7 @@ fn find_section_front_matter_changes(current: &SectionFrontMatter, other: &Secti
|
||||||
|
|
||||||
if current.paginate_by != other.paginate_by
|
if current.paginate_by != other.paginate_by
|
||||||
|| current.paginate_path != other.paginate_path
|
|| current.paginate_path != other.paginate_path
|
||||||
|| current.insert_anchor != other.insert_anchor {
|
|| current.insert_anchor_links != other.insert_anchor_links {
|
||||||
changes_needed.push(SectionChangesNeeded::RenderWithPages);
|
changes_needed.push(SectionChangesNeeded::RenderWithPages);
|
||||||
// Nothing else we can do
|
// Nothing else we can do
|
||||||
return changes_needed;
|
return changes_needed;
|
||||||
|
@ -177,7 +177,6 @@ pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> {
|
||||||
let page = Page::from_file(path, &site.config)?;
|
let page = Page::from_file(path, &site.config)?;
|
||||||
match site.add_page(page, true)? {
|
match site.add_page(page, true)? {
|
||||||
Some(prev) => {
|
Some(prev) => {
|
||||||
site.register_tera_global_fns();
|
|
||||||
// Updating a page
|
// Updating a page
|
||||||
let current = site.pages[path].clone();
|
let current = site.pages[path].clone();
|
||||||
// Front matter didn't change, only content did
|
// Front matter didn't change, only content did
|
||||||
|
@ -212,6 +211,7 @@ pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
site.register_tera_global_fns();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue