From c2437cc0eb7e431493022d3b1a5c254fa998119c Mon Sep 17 00:00:00 2001 From: Daniel Sockwell Date: Fri, 27 Jul 2018 22:20:20 -0400 Subject: [PATCH 1/5] Remove `order` and add `heavier`/`later` This commit removes the option to sort by order and also removes `page.next` and `page.previous` variables. Instead, pages can be sorted by two methods `date` and `weight`. The Tera `reverse` filter will reverse either of those sorts, so the old `order` behavior can be achieved by using the `reverse` filter with `weight`. In place of the `previous`/`next` variables, this commit adds the `page.earlier`/`page.later` variables (which are set when the page is sorted by date) and the `page.heavier`/`page.lighter` variables (which are set when the page is sorted by weight). These variables have the advantage of not having confusing semantics when the `reverse` filter is used. --- components/content/src/page.rs | 30 ++- components/content/src/sorting.rs | 174 ++++++------------ components/front_matter/src/lib.rs | 2 - components/rebuild/tests/rebuild.rs | 10 +- components/site/src/lib.rs | 2 +- .../content/posts/tutorials/devops/_index.md | 2 +- .../content/posts/tutorials/devops/docker.md | 2 +- .../content/posts/tutorials/devops/nix.md | 2 +- .../posts/tutorials/programming/_index.md | 2 +- .../posts/tutorials/programming/python.md | 2 +- .../posts/tutorials/programming/rust.md | 2 +- test_site/content/rebuild/_index.md | 2 +- test_site/content/rebuild/first.md | 2 +- test_site/content/rebuild/second.md | 2 +- 14 files changed, 89 insertions(+), 147 deletions(-) diff --git a/components/content/src/page.rs b/components/content/src/page.rs index 780faf23..567c95ca 100644 --- a/components/content/src/page.rs +++ b/components/content/src/page.rs @@ -44,10 +44,14 @@ pub struct Page { /// When is found in the text, will take the content up to that part /// as summary pub summary: Option, - /// The previous page, by whatever sorting is used for the index/section - pub previous: Option>, - /// The next page, by whatever sorting is used for the index/section - pub next: Option>, + /// The earlier page, for pages sorted by date + pub earlier: Option>, + /// The later page, for pages sorted by date + pub later: Option>, + /// The lighter page, for pages sorted by weight + pub lighter: Option>, + /// The heavier page, for pages sorted by weight + pub heavier: Option>, /// Toc made from the headers of the markdown file pub toc: Vec
, } @@ -68,8 +72,10 @@ impl Page { components: vec![], permalink: "".to_string(), summary: None, - previous: None, - next: None, + earlier: None, + later: None, + lighter: None, + heavier: None, toc: vec![], } } @@ -229,8 +235,10 @@ impl Default for Page { components: vec![], permalink: "".to_string(), summary: None, - previous: None, - next: None, + earlier: None, + later: None, + lighter: None, + heavier: None, toc: vec![], } } @@ -263,8 +271,10 @@ impl ser::Serialize for Page { 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("previous", &self.previous)?; - state.serialize_field("next", &self.next)?; + state.serialize_field("earlier", &self.earlier)?; + state.serialize_field("later", &self.later)?; + state.serialize_field("lighter", &self.lighter)?; + state.serialize_field("heavier", &self.heavier)?; state.serialize_field("toc", &self.toc)?; state.serialize_field("draft", &self.is_draft())?; let assets = self.serialize_assets(); diff --git a/components/content/src/sorting.rs b/components/content/src/sorting.rs index b96c6b1d..8d9bcda7 100644 --- a/components/content/src/sorting.rs +++ b/components/content/src/sorting.rs @@ -7,7 +7,7 @@ use front_matter::SortBy; /// Sort pages by the given criteria /// -/// Any pages that doesn't have a the required field when the sorting method is other than none +/// Any pages that doesn't have a required field when the sorting method is other than none /// will be ignored. pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { if sort_by == SortBy::None { @@ -19,7 +19,6 @@ pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { .partition(|page| { match sort_by { SortBy::Date => page.meta.date.is_some(), - SortBy::Order => page.meta.order.is_some(), SortBy::Weight => page.meta.weight.is_some(), _ => unreachable!() } @@ -36,16 +35,6 @@ pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { } }) }, - SortBy::Order => { - can_be_sorted.par_sort_unstable_by(|a, b| { - let ord = b.meta.order().cmp(&a.meta.order()); - if ord == Ordering::Equal { - a.permalink.cmp(&b.permalink) - } else { - ord - } - }) - }, SortBy::Weight => { can_be_sorted.par_sort_unstable_by(|a, b| { let ord = a.meta.weight().cmp(&b.meta.weight()); @@ -64,7 +53,7 @@ pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { /// Horribly inefficient way to set previous and next on each pages that skips drafts /// So many clones -pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec { +pub fn populate_previous_and_next_pages(input: &[Page], sort_by: SortBy) -> Vec { let mut res = Vec::with_capacity(input.len()); // The input is already sorted @@ -91,9 +80,21 @@ pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec { // Remove prev/next otherwise we serialise the whole thing... let mut next_page = input[j].clone(); - next_page.previous = None; - next_page.next = None; - new_page.next = Some(Box::new(next_page)); + + match sort_by { + SortBy::Weight => { + next_page.lighter = None; + next_page.heavier = None; + new_page.lighter = Some(Box::new(next_page)); + }, + SortBy::Date => { + next_page.earlier = None; + next_page.later = None; + new_page.later = Some(Box::new(next_page)); + }, + SortBy::None => { + } + } break; } } @@ -113,9 +114,20 @@ pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec { // Remove prev/next otherwise we serialise the whole thing... let mut previous_page = input[j].clone(); - previous_page.previous = None; - previous_page.next = None; - new_page.previous = Some(Box::new(previous_page)); + match sort_by { + SortBy::Weight => { + previous_page.lighter = None; + previous_page.heavier = None; + new_page.heavier = Some(Box::new(previous_page)); + }, + SortBy::Date => { + previous_page.earlier = None; + previous_page.later = None; + new_page.earlier = Some(Box::new(previous_page)); + }, + SortBy::None => { + } + } break; } } @@ -137,22 +149,6 @@ mod tests { Page::new("content/hello.md", front_matter) } - fn create_page_with_order(order: usize, filename: &str) -> Page { - let mut front_matter = PageFrontMatter::default(); - front_matter.order = Some(order); - let mut p = Page::new("content/".to_string() + filename, front_matter); - // Faking a permalink to test sorting with equal order - p.permalink = filename.to_string(); - p - } - - fn create_draft_page_with_order(order: usize) -> Page { - let mut front_matter = PageFrontMatter::default(); - front_matter.order = Some(order); - front_matter.draft = true; - Page::new("content/hello.md", front_matter) - } - fn create_page_with_weight(weight: usize) -> Page { let mut front_matter = PageFrontMatter::default(); front_matter.weight = Some(weight); @@ -173,37 +169,6 @@ mod tests { assert_eq!(pages[2].clone().meta.date.unwrap().to_string(), "2017-01-01"); } - #[test] - fn can_sort_by_order() { - let input = vec![ - create_page_with_order(2, "hello.md"), - create_page_with_order(3, "hello2.md"), - create_page_with_order(1, "hello3.md"), - ]; - let (pages, _) = sort_pages(input, SortBy::Order); - // Should be sorted by order - assert_eq!(pages[0].clone().meta.order.unwrap(), 3); - assert_eq!(pages[1].clone().meta.order.unwrap(), 2); - assert_eq!(pages[2].clone().meta.order.unwrap(), 1); - } - - #[test] - fn can_sort_by_order_uses_permalink_to_break_ties() { - let input = vec![ - create_page_with_order(3, "b.md"), - create_page_with_order(3, "a.md"), - create_page_with_order(3, "c.md"), - ]; - let (pages, _) = sort_pages(input, SortBy::Order); - // Should be sorted by order - assert_eq!(pages[0].clone().meta.order.unwrap(), 3); - assert_eq!(pages[0].clone().permalink, "a.md"); - assert_eq!(pages[1].clone().meta.order.unwrap(), 3); - assert_eq!(pages[1].clone().permalink, "b.md"); - assert_eq!(pages[2].clone().meta.order.unwrap(), 3); - assert_eq!(pages[2].clone().permalink, "c.md"); - } - #[test] fn can_sort_by_weight() { let input = vec![ @@ -221,25 +186,25 @@ mod tests { #[test] fn can_sort_by_none() { let input = vec![ - create_page_with_order(2, "a.md"), - create_page_with_order(3, "a.md"), - create_page_with_order(1, "a.md"), + create_page_with_weight(2), + create_page_with_weight(3), + create_page_with_weight(1), ]; let (pages, _) = sort_pages(input, SortBy::None); // Should be sorted by date - assert_eq!(pages[0].clone().meta.order.unwrap(), 2); - assert_eq!(pages[1].clone().meta.order.unwrap(), 3); - assert_eq!(pages[2].clone().meta.order.unwrap(), 1); + assert_eq!(pages[0].clone().meta.weight.unwrap(), 2); + assert_eq!(pages[1].clone().meta.weight.unwrap(), 3); + assert_eq!(pages[2].clone().meta.weight.unwrap(), 1); } #[test] fn ignore_page_with_missing_field() { let input = vec![ - create_page_with_order(2, "a.md"), - create_page_with_order(3, "a.md"), + create_page_with_weight(2), + create_page_with_weight(3), create_page_with_date("2019-01-01"), ]; - let (pages, unsorted) = sort_pages(input, SortBy::Order); + let (pages, unsorted) = sort_pages(input, SortBy::Weight); assert_eq!(pages.len(), 2); assert_eq!(unsorted.len(), 1); } @@ -247,54 +212,23 @@ mod tests { #[test] fn can_populate_previous_and_next_pages() { let input = vec![ - create_page_with_order(1, "a.md"), - create_page_with_order(2, "b.md"), - create_page_with_order(3, "a.md"), + create_page_with_weight(1), + create_page_with_weight(2), + create_page_with_weight(3), ]; - let pages = populate_previous_and_next_pages(&input); + let pages = populate_previous_and_next_pages(&input, SortBy::Weight); - assert!(pages[0].clone().next.is_none()); - assert!(pages[0].clone().previous.is_some()); - assert_eq!(pages[0].clone().previous.unwrap().meta.order.unwrap(), 2); + assert!(pages[0].clone().lighter.is_none()); + assert!(pages[0].clone().heavier.is_some()); + assert_eq!(pages[0].clone().heavier.unwrap().meta.weight.unwrap(), 2); - assert!(pages[1].clone().next.is_some()); - assert!(pages[1].clone().previous.is_some()); - assert_eq!(pages[1].clone().previous.unwrap().meta.order.unwrap(), 3); - assert_eq!(pages[1].clone().next.unwrap().meta.order.unwrap(), 1); + assert!(pages[1].clone().heavier.is_some()); + assert!(pages[1].clone().lighter.is_some()); + assert_eq!(pages[1].clone().lighter.unwrap().meta.weight.unwrap(), 1); + assert_eq!(pages[1].clone().heavier.unwrap().meta.weight.unwrap(), 3); - assert!(pages[2].clone().next.is_some()); - assert!(pages[2].clone().previous.is_none()); - assert_eq!(pages[2].clone().next.unwrap().meta.order.unwrap(), 2); - } - - #[test] - fn can_populate_previous_and_next_pages_skip_drafts() { - let input = vec![ - create_draft_page_with_order(0), - create_page_with_order(1, "a.md"), - create_page_with_order(2, "b.md"), - create_page_with_order(3, "c.md"), - create_draft_page_with_order(4), - ]; - let pages = populate_previous_and_next_pages(&input); - - assert!(pages[0].clone().next.is_none()); - assert!(pages[0].clone().previous.is_none()); - - assert!(pages[1].clone().next.is_none()); - assert!(pages[1].clone().previous.is_some()); - assert_eq!(pages[1].clone().previous.unwrap().meta.order.unwrap(), 2); - - assert!(pages[2].clone().next.is_some()); - assert!(pages[2].clone().previous.is_some()); - assert_eq!(pages[2].clone().previous.unwrap().meta.order.unwrap(), 3); - assert_eq!(pages[2].clone().next.unwrap().meta.order.unwrap(), 1); - - assert!(pages[3].clone().next.is_some()); - assert!(pages[3].clone().previous.is_none()); - assert_eq!(pages[3].clone().next.unwrap().meta.order.unwrap(), 2); - - assert!(pages[4].clone().next.is_none()); - assert!(pages[4].clone().previous.is_none()); + assert!(pages[2].clone().lighter.is_some()); + assert!(pages[2].clone().heavier.is_none()); + assert_eq!(pages[2].clone().lighter.unwrap().meta.weight.unwrap(), 2); } } diff --git a/components/front_matter/src/lib.rs b/components/front_matter/src/lib.rs index 6cf79f0c..82493762 100644 --- a/components/front_matter/src/lib.rs +++ b/components/front_matter/src/lib.rs @@ -30,8 +30,6 @@ lazy_static! { pub enum SortBy { /// Most recent to oldest Date, - /// Lower order comes last - Order, /// Lower weight comes first Weight, /// No sorting diff --git a/components/rebuild/tests/rebuild.rs b/components/rebuild/tests/rebuild.rs index 12cdb415..dbc3a357 100644 --- a/components/rebuild/tests/rebuild.rs +++ b/components/rebuild/tests/rebuild.rs @@ -2,7 +2,7 @@ extern crate rebuild; extern crate site; extern crate tempfile; extern crate fs_extra; - + use std::env; use std::fs::{remove_dir_all, File}; use std::io::prelude::*; @@ -79,7 +79,7 @@ fn can_rebuild_after_simple_change_to_page_content() { let file_path = edit_file!(site_path, "content/rebuild/first.md", br#" +++ title = "first" -order = 1 +weight = 1 date = 2017-01-01 +++ @@ -97,7 +97,7 @@ fn can_rebuild_after_title_change_page_global_func_usage() { let file_path = edit_file!(site_path, "content/rebuild/first.md", br#" +++ title = "Premier" -order = 10 +weight = 10 date = 2017-01-01 +++ @@ -115,12 +115,12 @@ fn can_rebuild_after_sort_change_in_section() { let file_path = edit_file!(site_path, "content/rebuild/_index.md", br#" +++ paginate_by = 1 -sort_by = "order" +sort_by = "weight" template = "rebuild.html" +++ "#); let res = after_content_change(&mut site, &file_path); assert!(res.is_ok()); - assert!(file_contains!(site_path, "public/rebuild/index.html", "

second

first

")); + assert!(file_contains!(site_path, "public/rebuild/index.html", "

first

second

")); } diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index ce333849..85d10953 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -401,7 +401,7 @@ impl Site { } let pages = mem::replace(&mut section.pages, vec![]); let (sorted_pages, cannot_be_sorted_pages) = sort_pages(pages, section.meta.sort_by); - section.pages = populate_previous_and_next_pages(&sorted_pages); + section.pages = populate_previous_and_next_pages(&sorted_pages, section.meta.sort_by); section.ignored_pages = cannot_be_sorted_pages; } } diff --git a/test_site/content/posts/tutorials/devops/_index.md b/test_site/content/posts/tutorials/devops/_index.md index 8e996741..29223641 100644 --- a/test_site/content/posts/tutorials/devops/_index.md +++ b/test_site/content/posts/tutorials/devops/_index.md @@ -1,6 +1,6 @@ +++ title = "DevOps" -sort_by = "order" +sort_by = "weight" redirect_to = "posts/tutorials/devops/docker" weight = 10 +++ diff --git a/test_site/content/posts/tutorials/devops/docker.md b/test_site/content/posts/tutorials/devops/docker.md index ad19af5c..46aea980 100644 --- a/test_site/content/posts/tutorials/devops/docker.md +++ b/test_site/content/posts/tutorials/devops/docker.md @@ -1,6 +1,6 @@ +++ title = "Docker" -order = 1 +weight = 1 date = 2017-01-01 +++ diff --git a/test_site/content/posts/tutorials/devops/nix.md b/test_site/content/posts/tutorials/devops/nix.md index 004ad58d..bc808530 100644 --- a/test_site/content/posts/tutorials/devops/nix.md +++ b/test_site/content/posts/tutorials/devops/nix.md @@ -1,6 +1,6 @@ +++ title = "Nix" -order = 2 +weight = 2 date = 2017-01-01 +++ diff --git a/test_site/content/posts/tutorials/programming/_index.md b/test_site/content/posts/tutorials/programming/_index.md index 4a2c76fb..6515620e 100644 --- a/test_site/content/posts/tutorials/programming/_index.md +++ b/test_site/content/posts/tutorials/programming/_index.md @@ -1,5 +1,5 @@ +++ title = "Programming" -sort_by = "order" +sort_by = "weight" weight = 1 +++ diff --git a/test_site/content/posts/tutorials/programming/python.md b/test_site/content/posts/tutorials/programming/python.md index d65d52fb..891ff299 100644 --- a/test_site/content/posts/tutorials/programming/python.md +++ b/test_site/content/posts/tutorials/programming/python.md @@ -1,6 +1,6 @@ +++ title = "Python tutorial" -order = 1 +weight = 1 date = 2017-01-01 +++ diff --git a/test_site/content/posts/tutorials/programming/rust.md b/test_site/content/posts/tutorials/programming/rust.md index 3582c4bc..a409b439 100644 --- a/test_site/content/posts/tutorials/programming/rust.md +++ b/test_site/content/posts/tutorials/programming/rust.md @@ -1,6 +1,6 @@ +++ title = "Rust" -order = 2 +weight = 2 date = 2017-01-01 +++ diff --git a/test_site/content/rebuild/_index.md b/test_site/content/rebuild/_index.md index c617948a..46570a3c 100644 --- a/test_site/content/rebuild/_index.md +++ b/test_site/content/rebuild/_index.md @@ -1,5 +1,5 @@ +++ paginate_by = 1 -sort_by = "order" +sort_by = "weight" template = "rebuild.html" +++ diff --git a/test_site/content/rebuild/first.md b/test_site/content/rebuild/first.md index a3bd65e6..213fa4bb 100644 --- a/test_site/content/rebuild/first.md +++ b/test_site/content/rebuild/first.md @@ -1,6 +1,6 @@ +++ title = "first" -order = 10 +weight = 10 date = 2017-01-01 +++ diff --git a/test_site/content/rebuild/second.md b/test_site/content/rebuild/second.md index 4a849192..2ee56019 100644 --- a/test_site/content/rebuild/second.md +++ b/test_site/content/rebuild/second.md @@ -1,6 +1,6 @@ +++ title = "second" -order = 100 +weight = 100 date = 2016-01-01 +++ From bedf469d16f313f020f952d5983414f08d186fe5 Mon Sep 17 00:00:00 2001 From: Daniel Sockwell Date: Sun, 29 Jul 2018 15:54:36 -0400 Subject: [PATCH 2/5] Update docs for removal of order --- docs/content/documentation/content/page.md | 58 +++++++----- docs/content/documentation/content/section.md | 92 +++++++++++++++---- 2 files changed, 109 insertions(+), 41 deletions(-) diff --git a/docs/content/documentation/content/page.md b/docs/content/documentation/content/page.md index 04cb6c23..08105242 100644 --- a/docs/content/documentation/content/page.md +++ b/docs/content/documentation/content/page.md @@ -6,6 +6,22 @@ weight = 30 A page is any file ending with `.md` in the `content` directory, except files named `_index.md`. +If a file ending with `.md` is named `index.md`, then it will generate a page +with the name of the containing folder (for example, `/content/about/index.md` would +create a page at `[base_url]/about`). (Note the lack of an underscore; if the file +were named `_index.md`, then it would create a **section** at `[base_url]/about`, as +discussed in the prior part of this documentation. But naming the file `index.md` will +create a **page** at `[base_url]/about`). + +If the file is given any name *other* than `index.md` or `_index.md`, then it will +create a page with that name (without the `.md`). So naming a file in the root of your +content directory `about.md` would also create a page at `[base_url]/about`. + +As you can see, creating an `about.md` file is exactly equivalent to creating an +`about/index.md` file. The only difference between the two methods is that creating +the `about` folder allows you to use asset colocation, as discussed in the +[Overview](./documentation/content/overview.md) section of this documentation. + ## Front-matter The front-matter is a set of metadata embedded in a file. In Gutenberg, @@ -13,7 +29,8 @@ it is at the beginning of the file, surrounded by `+++` and uses TOML. While none of the front-matter variables are mandatory, the opening and closing `+++` are required. -Here is an example page with all the variables available: +Here is an example page with all the variables available. The values provided below are the default +values. ```md +++ @@ -22,8 +39,15 @@ description = "" # The date of the post. # 2 formats are allowed: YYYY-MM-DD (2012-10-02) and RFC3339 (2002-10-02T15:00:00Z) -# Do not wrap dates in quotes, the line below only indicates that there is no default date -date = +# Do not wrap dates in quotes, the line below only indicates that there is no default date. +# If the section variable `sort_by` is set to `date`, then any page that lacks a `date` +# will not be rendered. +date = + +# The weight as defined in the Section page +# If the section variable `sort_by` is set to `weight`, then any page that lacks a `weight` +# will not be rendered. +weight = 0 # A draft page will not be present in prev/next pagination draft = false @@ -38,28 +62,18 @@ slug = "" # It should not start with a `/` and the slash will be removed if it does path = "" -# A dict of taxonomies: the key is the name of the taxonomy which must match -# one of the taxonomy defined in `config.toml` and the value is a list of -# strings -[taxonomies] +# An array of strings allowing you to group pages with them +tags = [] -# The order as defined in the Section page -order = 0 +# An overarching category name for that page, allowing you to group pages with it +category = "" -# 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. Each element in the array of aliases may take one of two forms: -# * "some/alias/path", which will generate "some/alias/path/index.html" -# * "some/alias/path.html", which will generate "some/alias/path.html" -# -# The former is useful if your previous site had the form "example.com/some/alias/path", -# the latter is useful if your previous site had the form "example.com/some/alias/path.html" +# 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 = [] # Whether the page should be in the search index. This is only used if -# `build_search_index` is set to true in the config and the parent section +# `build_search_index` is set to true in the config and the parent section # hasn't set `in_search_index` to false in its front-matter in_search_index = true @@ -75,7 +89,7 @@ Some content ## Summary -You can ask Gutenberg to create a summary if you only want to show the first +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 @@ -83,6 +97,6 @@ where you want the summary to end and the content up to that point will be also available separately in the [template](./documentation/templates/pages-sections.md#page-variables). -An anchor link to this position named `continue-reading` is created so you can link +An anchor link to this position named `continue-reading` is created so you can link directly to it if needed for example: `Continue Reading` diff --git a/docs/content/documentation/content/section.md b/docs/content/documentation/content/section.md index 2228544d..7baba791 100644 --- a/docs/content/documentation/content/section.md +++ b/docs/content/documentation/content/section.md @@ -3,22 +3,32 @@ title = "Section" weight = 20 +++ -A section is automatically created when a folder is found in the `content` section, unless it only -contains a `index.md` file and is actually a page with assets. +A section is created whenever a folder (or subfolder) in the `content` section contains an +`_index.md` file. If a folder does not contain an `_index.md` file, no section will be +created, but markdown files within that folder will still create pages (known as orphan pages). -You can add `_index.md` file to a folder to augment a section and give it some metadata and/or content. - -The index page is actually a section created automatically like any other: you can add metadata -and content by adding `_index.md` at the root of the `content` folder. +The index page (i.e., the page displayed when a user browses to your `base_url`) is a section, +which is created whether or not you add an `_index.md` file at the root of your `content` folder. +If you do not create an `_index.md` file in your content directory, this main content section will +not have any content or metadata. If you would like to add content or metadata, you can add an +`_index.md` file at the root of the `content` folder and edit it just as you would edit any other +`_index.md` file; your `index.html` template will then have access to that content and metadata. ## Front-matter +The `_index.md` file within a folder defines the content and metadata for that section. To set +the metadata, add front matter to the file. + 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. +After the closing `+++`, you can add content that will be parsed as markdown and will be available +to your templates through the `section.content` variable. + While none of the front-matter variables are mandatory, the opening and closing `+++` are required. -Here is an example `_index.md` with all the variables available: +Here is an example `_index.md` with all the variables available. The values provided below are the +default values. ```md @@ -27,7 +37,7 @@ title = "" description = "" -# Whether to sort by "date", "order", "weight" or "none". More on that below +# Whether to sort pages by "date", "weight", or "none". More on that below sort_by = "none" # Used by the parent section to order its subsections. @@ -83,22 +93,66 @@ You can also change the pagination path (the word displayed while paginated in t by setting the `paginate_path` variable, which defaults to `page`. ## Sorting -Sections' pages can be sorted three different ways, not counting the unsorted default and -is enabled by setting the `sort_by` front-matter variable. +It is very common for Gutenberg templates to iterate over pages or sections +to display all pages/sections a given directory. Consider a very simple +example: a `blog` directory with three files: `blog/Post_1.md`, +`blog/Post_2.md`, and `blog/Post_3.md`. To iterate over these posts and +create a list of links to the posts, a simple template might look like this: -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. +```j2 +{% for post in section.pages %} +

{{ post.title }}

+{% endfor %} +``` -If several pages have the same date/weight/order, their permalink will be used to break the tie following -an alphabetical order. +This would iterate over the posts, and would do so in a specific order +based on the `sort_by` variable set in the `_index.md` page for the +containing section. The `sort_by` variable can be given three values: `date`, +`weight`, and `none`. If no `sort_by` method is set, the pages will be +sorted in the `none` order, which is not intended to be used for sorted content. + +Any page that is missing the data it needs to be sorted will be ignored and +won't be rendered. For example, if a page is missing the date variable the +containing section sets `sort_by = "date"`, then that page will be ignored. +The terminal will warn you if this is happening. + +If several pages have the same date/weight/order, their permalink will be used +to break the tie following an alphabetical order. + +## Sorting Pages +The `sort_by` front-matter variable can have the following values: ### `date` -This will sort all pages by their `date` field, from the most recent to the oldest. +This will sort all pages by their `date` field, from the most recent (at the +top of the list) to the oldest (at the bottom of the list). Each page will +get `page.earlier` and `page.later` variables that contain the pages with +earlier and later dates, respectively. ### `weight` -This will be sort all pages by their `weight` field. Heavier weights fall at the bottom: 5 would be before 10. +This will be sort all pages by their `weight` field, from lightest weight +(at the top of the list) to heaviest (at the bottom of the list). Each +page gets `page.lighter` and `page.heavier` variables that contain the +pages with lighter and heavier weights, respectively. -### `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. +When iterating through pages, you may wish to use the Tera `reverse` filter, +which reverses the order of the pages. Thus, after using the `reverse` filter, +pages sorted by weight will be sorted from lightest (at the top) to heaviest +(at the bottom); pages sorted by date will be sorted from oldest (at the top) +to newest (at the bottom). +`reverse` has no effect on `page.later`/`page.earlier`/`page.heavier`/`page.lighter`. + +## Sorting Subsections +Sorting sections is a bit less flexible: sections are always sorted by `weight`, +and do not have any variables that point to the next heavier/lighter sections. + +Based on this, by default the lightest (lowest `weight`) subsections will be at +the top of the list and the heaviest (highest `weight`) will be at the top; +the `reverse` filter reverses this order. + +**Note**: Unlike pages, permalinks will **not** be used to break ties between +equally weighted sections. Thus, if the `weight` variable for your section is not set (or if it +is set in a way that produces ties), then your sections will be sorted in +**random** order. Moreover, that order is determined at build time and will +change with each site rebuild. Thus, if there is any chance that you will +iterate over your sections, you should always assign them weight. From 554d50720cb4be8c786849636e9587a27ec67939 Mon Sep 17 00:00:00 2001 From: Daniel Sockwell Date: Sun, 29 Jul 2018 16:53:42 -0400 Subject: [PATCH 3/5] Update templates/pages-sections.md --- docs/content/documentation/templates/pages-sections.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/content/documentation/templates/pages-sections.md b/docs/content/documentation/templates/pages-sections.md index 6dcf7ac7..297c95b3 100644 --- a/docs/content/documentation/templates/pages-sections.md +++ b/docs/content/documentation/templates/pages-sections.md @@ -32,9 +32,12 @@ extra: HashMap; 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?; +// `earlier` and `later` are only populated if the section variable `sort_by` is set to `date` +earlier: Page?; +later: Page?; +// `heavier` and `lighter` are only populated if the section variable `sort_by` is set to `weight` +heavier: Page?; +lighter: Page?; // See the Table of contents section below for more details toc: Array
; // Year/month/day is only set if the page has a date and month/day are 1-indexed From 97f5065259da7a9bab079801977bee5554d31e57 Mon Sep 17 00:00:00 2001 From: Daniel Sockwell Date: Sun, 29 Jul 2018 17:03:14 -0400 Subject: [PATCH 4/5] Fix formating/typos flaged in code review --- components/content/src/sorting.rs | 4 +--- components/rebuild/tests/rebuild.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/components/content/src/sorting.rs b/components/content/src/sorting.rs index 8d9bcda7..592d8446 100644 --- a/components/content/src/sorting.rs +++ b/components/content/src/sorting.rs @@ -92,8 +92,7 @@ pub fn populate_previous_and_next_pages(input: &[Page], sort_by: SortBy) -> Vec< next_page.later = None; new_page.later = Some(Box::new(next_page)); }, - SortBy::None => { - } + SortBy::None => {} } break; } @@ -191,7 +190,6 @@ mod tests { create_page_with_weight(1), ]; let (pages, _) = sort_pages(input, SortBy::None); - // Should be sorted by date assert_eq!(pages[0].clone().meta.weight.unwrap(), 2); assert_eq!(pages[1].clone().meta.weight.unwrap(), 3); assert_eq!(pages[2].clone().meta.weight.unwrap(), 1); diff --git a/components/rebuild/tests/rebuild.rs b/components/rebuild/tests/rebuild.rs index dbc3a357..42bbae2e 100644 --- a/components/rebuild/tests/rebuild.rs +++ b/components/rebuild/tests/rebuild.rs @@ -2,7 +2,7 @@ extern crate rebuild; extern crate site; extern crate tempfile; extern crate fs_extra; - + use std::env; use std::fs::{remove_dir_all, File}; use std::io::prelude::*; From 77ac196f46c1637667a22f50c4e63be50b91fa1f Mon Sep 17 00:00:00 2001 From: Daniel Sockwell Date: Mon, 30 Jul 2018 22:36:03 -0400 Subject: [PATCH 5/5] Change populate_next_and_previous_page Replace `populate_next_and_previous_page` with `populate_siblings` --- components/content/benches/all.rs | 8 ++++---- components/content/src/lib.rs | 2 +- components/content/src/sorting.rs | 8 ++++---- components/site/src/lib.rs | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/components/content/benches/all.rs b/components/content/benches/all.rs index cb80fdbb..5a90943e 100644 --- a/components/content/benches/all.rs +++ b/components/content/benches/all.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; use config::Config; use tera::Tera; use front_matter::{SortBy, InsertAnchor}; -use content::{Page, sort_pages, populate_previous_and_next_pages}; +use content::{Page, sort_pages, populate_siblings}; fn create_pages(number: usize, sort_by: SortBy) -> Vec { @@ -128,17 +128,17 @@ fn bench_sorting_order(b: &mut test::Bencher) { } #[bench] -fn bench_populate_previous_and_next_pages(b: &mut test::Bencher) { +fn bench_populate_siblings(b: &mut test::Bencher) { let pages = create_pages(250, SortBy::Order); let (sorted_pages, _) = sort_pages(pages, SortBy::Order); - b.iter(|| populate_previous_and_next_pages(&sorted_pages.clone())); + b.iter(|| populate_siblings(&sorted_pages.clone())); } #[bench] fn bench_page_render_html(b: &mut test::Bencher) { let pages = create_pages(10, SortBy::Order); let (mut sorted_pages, _) = sort_pages(pages, SortBy::Order); - sorted_pages = populate_previous_and_next_pages(&sorted_pages); + sorted_pages = populate_siblings(&sorted_pages); let config = Config::default(); let mut tera = Tera::default(); diff --git a/components/content/src/lib.rs b/components/content/src/lib.rs index 5d111c4e..11bfcc85 100644 --- a/components/content/src/lib.rs +++ b/components/content/src/lib.rs @@ -26,4 +26,4 @@ mod sorting; pub use file_info::FileInfo; pub use page::Page; pub use section::Section; -pub use sorting::{sort_pages, populate_previous_and_next_pages}; +pub use sorting::{sort_pages, populate_siblings}; diff --git a/components/content/src/sorting.rs b/components/content/src/sorting.rs index 592d8446..775c67b5 100644 --- a/components/content/src/sorting.rs +++ b/components/content/src/sorting.rs @@ -53,7 +53,7 @@ pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { /// Horribly inefficient way to set previous and next on each pages that skips drafts /// So many clones -pub fn populate_previous_and_next_pages(input: &[Page], sort_by: SortBy) -> Vec { +pub fn populate_siblings(input: &[Page], sort_by: SortBy) -> Vec { let mut res = Vec::with_capacity(input.len()); // The input is already sorted @@ -140,7 +140,7 @@ pub fn populate_previous_and_next_pages(input: &[Page], sort_by: SortBy) -> Vec< mod tests { use front_matter::{PageFrontMatter, SortBy}; use page::Page; - use super::{sort_pages, populate_previous_and_next_pages}; + use super::{sort_pages, populate_siblings}; fn create_page_with_date(date: &str) -> Page { let mut front_matter = PageFrontMatter::default(); @@ -208,13 +208,13 @@ mod tests { } #[test] - fn can_populate_previous_and_next_pages() { + fn can_populate_siblings() { let input = vec![ create_page_with_weight(1), create_page_with_weight(2), create_page_with_weight(3), ]; - let pages = populate_previous_and_next_pages(&input, SortBy::Weight); + let pages = populate_siblings(&input, SortBy::Weight); assert!(pages[0].clone().lighter.is_none()); assert!(pages[0].clone().heavier.is_some()); diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index 85d10953..2e9a4aa1 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -36,7 +36,7 @@ use config::{Config, get_config}; use utils::fs::{create_file, copy_directory, create_directory, ensure_directory_exists}; use utils::templates::{render_template, rewrite_theme_paths}; use utils::net::get_available_port; -use content::{Page, Section, populate_previous_and_next_pages, sort_pages}; +use content::{Page, Section, populate_siblings, sort_pages}; use templates::{GUTENBERG_TERA, global_fns, render_redirect_template}; use front_matter::{SortBy, InsertAnchor}; use taxonomies::{Taxonomy, find_taxonomies}; @@ -401,7 +401,7 @@ impl Site { } let pages = mem::replace(&mut section.pages, vec![]); let (sorted_pages, cannot_be_sorted_pages) = sort_pages(pages, section.meta.sort_by); - section.pages = populate_previous_and_next_pages(&sorted_pages, section.meta.sort_by); + section.pages = populate_siblings(&sorted_pages, section.meta.sort_by); section.ignored_pages = cannot_be_sorted_pages; } }