Merge pull request #352 from codesections/delete_order
Remove `order` and add `heavier`/`later`
This commit is contained in:
commit
be439d7bfb
|
@ -11,7 +11,7 @@ use std::collections::HashMap;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use tera::Tera;
|
use tera::Tera;
|
||||||
use front_matter::{SortBy, InsertAnchor};
|
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<Page> {
|
fn create_pages(number: usize, sort_by: SortBy) -> Vec<Page> {
|
||||||
|
@ -128,17 +128,17 @@ fn bench_sorting_order(b: &mut test::Bencher) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[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 pages = create_pages(250, SortBy::Order);
|
||||||
let (sorted_pages, _) = sort_pages(pages, 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]
|
#[bench]
|
||||||
fn bench_page_render_html(b: &mut test::Bencher) {
|
fn bench_page_render_html(b: &mut test::Bencher) {
|
||||||
let pages = create_pages(10, SortBy::Order);
|
let pages = create_pages(10, SortBy::Order);
|
||||||
let (mut sorted_pages, _) = sort_pages(pages, 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 config = Config::default();
|
||||||
let mut tera = Tera::default();
|
let mut tera = Tera::default();
|
||||||
|
|
|
@ -26,4 +26,4 @@ mod sorting;
|
||||||
pub use file_info::FileInfo;
|
pub use file_info::FileInfo;
|
||||||
pub use page::Page;
|
pub use page::Page;
|
||||||
pub use section::Section;
|
pub use section::Section;
|
||||||
pub use sorting::{sort_pages, populate_previous_and_next_pages};
|
pub use sorting::{sort_pages, populate_siblings};
|
||||||
|
|
|
@ -44,10 +44,14 @@ pub struct Page {
|
||||||
/// When <!-- more --> is found in the text, will take the content up to that part
|
/// When <!-- more --> is found in the text, will take the content up to that part
|
||||||
/// as summary
|
/// as summary
|
||||||
pub summary: Option<String>,
|
pub summary: Option<String>,
|
||||||
/// The previous page, by whatever sorting is used for the index/section
|
/// The earlier page, for pages sorted by date
|
||||||
pub previous: Option<Box<Page>>,
|
pub earlier: Option<Box<Page>>,
|
||||||
/// The next page, by whatever sorting is used for the index/section
|
/// The later page, for pages sorted by date
|
||||||
pub next: Option<Box<Page>>,
|
pub later: Option<Box<Page>>,
|
||||||
|
/// The lighter page, for pages sorted by weight
|
||||||
|
pub lighter: Option<Box<Page>>,
|
||||||
|
/// The heavier page, for pages sorted by weight
|
||||||
|
pub heavier: Option<Box<Page>>,
|
||||||
/// Toc made from the headers of the markdown file
|
/// Toc made from the headers of the markdown file
|
||||||
pub toc: Vec<Header>,
|
pub toc: Vec<Header>,
|
||||||
}
|
}
|
||||||
|
@ -68,8 +72,10 @@ impl Page {
|
||||||
components: vec![],
|
components: vec![],
|
||||||
permalink: "".to_string(),
|
permalink: "".to_string(),
|
||||||
summary: None,
|
summary: None,
|
||||||
previous: None,
|
earlier: None,
|
||||||
next: None,
|
later: None,
|
||||||
|
lighter: None,
|
||||||
|
heavier: None,
|
||||||
toc: vec![],
|
toc: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,8 +235,10 @@ impl Default for Page {
|
||||||
components: vec![],
|
components: vec![],
|
||||||
permalink: "".to_string(),
|
permalink: "".to_string(),
|
||||||
summary: None,
|
summary: None,
|
||||||
previous: None,
|
earlier: None,
|
||||||
next: None,
|
later: None,
|
||||||
|
lighter: None,
|
||||||
|
heavier: None,
|
||||||
toc: vec![],
|
toc: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,8 +271,10 @@ impl ser::Serialize for Page {
|
||||||
let (word_count, reading_time) = get_reading_analytics(&self.raw_content);
|
let (word_count, reading_time) = get_reading_analytics(&self.raw_content);
|
||||||
state.serialize_field("word_count", &word_count)?;
|
state.serialize_field("word_count", &word_count)?;
|
||||||
state.serialize_field("reading_time", &reading_time)?;
|
state.serialize_field("reading_time", &reading_time)?;
|
||||||
state.serialize_field("previous", &self.previous)?;
|
state.serialize_field("earlier", &self.earlier)?;
|
||||||
state.serialize_field("next", &self.next)?;
|
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("toc", &self.toc)?;
|
||||||
state.serialize_field("draft", &self.is_draft())?;
|
state.serialize_field("draft", &self.is_draft())?;
|
||||||
let assets = self.serialize_assets();
|
let assets = self.serialize_assets();
|
||||||
|
|
|
@ -7,7 +7,7 @@ use front_matter::SortBy;
|
||||||
|
|
||||||
/// Sort pages by the given criteria
|
/// 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.
|
/// will be ignored.
|
||||||
pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
|
pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
|
||||||
if sort_by == SortBy::None {
|
if sort_by == SortBy::None {
|
||||||
|
@ -19,7 +19,6 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
|
||||||
.partition(|page| {
|
.partition(|page| {
|
||||||
match sort_by {
|
match sort_by {
|
||||||
SortBy::Date => page.meta.date.is_some(),
|
SortBy::Date => page.meta.date.is_some(),
|
||||||
SortBy::Order => page.meta.order.is_some(),
|
|
||||||
SortBy::Weight => page.meta.weight.is_some(),
|
SortBy::Weight => page.meta.weight.is_some(),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -36,16 +35,6 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
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 => {
|
SortBy::Weight => {
|
||||||
can_be_sorted.par_sort_unstable_by(|a, b| {
|
can_be_sorted.par_sort_unstable_by(|a, b| {
|
||||||
let ord = a.meta.weight().cmp(&b.meta.weight());
|
let ord = a.meta.weight().cmp(&b.meta.weight());
|
||||||
|
@ -64,7 +53,7 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
|
||||||
|
|
||||||
/// Horribly inefficient way to set previous and next on each pages that skips drafts
|
/// 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_siblings(input: &[Page], sort_by: SortBy) -> Vec<Page> {
|
||||||
let mut res = Vec::with_capacity(input.len());
|
let mut res = Vec::with_capacity(input.len());
|
||||||
|
|
||||||
// The input is already sorted
|
// The input is already sorted
|
||||||
|
@ -91,9 +80,20 @@ pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec<Page> {
|
||||||
|
|
||||||
// Remove prev/next otherwise we serialise the whole thing...
|
// Remove prev/next otherwise we serialise the whole thing...
|
||||||
let mut next_page = input[j].clone();
|
let mut next_page = input[j].clone();
|
||||||
next_page.previous = None;
|
|
||||||
next_page.next = None;
|
match sort_by {
|
||||||
new_page.next = Some(Box::new(next_page));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,9 +113,20 @@ pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec<Page> {
|
||||||
|
|
||||||
// Remove prev/next otherwise we serialise the whole thing...
|
// Remove prev/next otherwise we serialise the whole thing...
|
||||||
let mut previous_page = input[j].clone();
|
let mut previous_page = input[j].clone();
|
||||||
previous_page.previous = None;
|
match sort_by {
|
||||||
previous_page.next = None;
|
SortBy::Weight => {
|
||||||
new_page.previous = Some(Box::new(previous_page));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +140,7 @@ pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec<Page> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use front_matter::{PageFrontMatter, SortBy};
|
use front_matter::{PageFrontMatter, SortBy};
|
||||||
use page::Page;
|
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 {
|
fn create_page_with_date(date: &str) -> Page {
|
||||||
let mut front_matter = PageFrontMatter::default();
|
let mut front_matter = PageFrontMatter::default();
|
||||||
|
@ -137,22 +148,6 @@ mod tests {
|
||||||
Page::new("content/hello.md", front_matter)
|
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 {
|
fn create_page_with_weight(weight: usize) -> Page {
|
||||||
let mut front_matter = PageFrontMatter::default();
|
let mut front_matter = PageFrontMatter::default();
|
||||||
front_matter.weight = Some(weight);
|
front_matter.weight = Some(weight);
|
||||||
|
@ -173,37 +168,6 @@ mod tests {
|
||||||
assert_eq!(pages[2].clone().meta.date.unwrap().to_string(), "2017-01-01");
|
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]
|
#[test]
|
||||||
fn can_sort_by_weight() {
|
fn can_sort_by_weight() {
|
||||||
let input = vec![
|
let input = vec![
|
||||||
|
@ -221,80 +185,48 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn can_sort_by_none() {
|
fn can_sort_by_none() {
|
||||||
let input = vec![
|
let input = vec![
|
||||||
create_page_with_order(2, "a.md"),
|
create_page_with_weight(2),
|
||||||
create_page_with_order(3, "a.md"),
|
create_page_with_weight(3),
|
||||||
create_page_with_order(1, "a.md"),
|
create_page_with_weight(1),
|
||||||
];
|
];
|
||||||
let (pages, _) = sort_pages(input, SortBy::None);
|
let (pages, _) = sort_pages(input, SortBy::None);
|
||||||
// Should be sorted by date
|
assert_eq!(pages[0].clone().meta.weight.unwrap(), 2);
|
||||||
assert_eq!(pages[0].clone().meta.order.unwrap(), 2);
|
assert_eq!(pages[1].clone().meta.weight.unwrap(), 3);
|
||||||
assert_eq!(pages[1].clone().meta.order.unwrap(), 3);
|
assert_eq!(pages[2].clone().meta.weight.unwrap(), 1);
|
||||||
assert_eq!(pages[2].clone().meta.order.unwrap(), 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ignore_page_with_missing_field() {
|
fn ignore_page_with_missing_field() {
|
||||||
let input = vec![
|
let input = vec![
|
||||||
create_page_with_order(2, "a.md"),
|
create_page_with_weight(2),
|
||||||
create_page_with_order(3, "a.md"),
|
create_page_with_weight(3),
|
||||||
create_page_with_date("2019-01-01"),
|
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!(pages.len(), 2);
|
||||||
assert_eq!(unsorted.len(), 1);
|
assert_eq!(unsorted.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_populate_previous_and_next_pages() {
|
fn can_populate_siblings() {
|
||||||
let input = vec![
|
let input = vec![
|
||||||
create_page_with_order(1, "a.md"),
|
create_page_with_weight(1),
|
||||||
create_page_with_order(2, "b.md"),
|
create_page_with_weight(2),
|
||||||
create_page_with_order(3, "a.md"),
|
create_page_with_weight(3),
|
||||||
];
|
];
|
||||||
let pages = populate_previous_and_next_pages(&input);
|
let pages = populate_siblings(&input, SortBy::Weight);
|
||||||
|
|
||||||
assert!(pages[0].clone().next.is_none());
|
assert!(pages[0].clone().lighter.is_none());
|
||||||
assert!(pages[0].clone().previous.is_some());
|
assert!(pages[0].clone().heavier.is_some());
|
||||||
assert_eq!(pages[0].clone().previous.unwrap().meta.order.unwrap(), 2);
|
assert_eq!(pages[0].clone().heavier.unwrap().meta.weight.unwrap(), 2);
|
||||||
|
|
||||||
assert!(pages[1].clone().next.is_some());
|
assert!(pages[1].clone().heavier.is_some());
|
||||||
assert!(pages[1].clone().previous.is_some());
|
assert!(pages[1].clone().lighter.is_some());
|
||||||
assert_eq!(pages[1].clone().previous.unwrap().meta.order.unwrap(), 3);
|
assert_eq!(pages[1].clone().lighter.unwrap().meta.weight.unwrap(), 1);
|
||||||
assert_eq!(pages[1].clone().next.unwrap().meta.order.unwrap(), 1);
|
assert_eq!(pages[1].clone().heavier.unwrap().meta.weight.unwrap(), 3);
|
||||||
|
|
||||||
assert!(pages[2].clone().next.is_some());
|
assert!(pages[2].clone().lighter.is_some());
|
||||||
assert!(pages[2].clone().previous.is_none());
|
assert!(pages[2].clone().heavier.is_none());
|
||||||
assert_eq!(pages[2].clone().next.unwrap().meta.order.unwrap(), 2);
|
assert_eq!(pages[2].clone().lighter.unwrap().meta.weight.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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,6 @@ lazy_static! {
|
||||||
pub enum SortBy {
|
pub enum SortBy {
|
||||||
/// Most recent to oldest
|
/// Most recent to oldest
|
||||||
Date,
|
Date,
|
||||||
/// Lower order comes last
|
|
||||||
Order,
|
|
||||||
/// Lower weight comes first
|
/// Lower weight comes first
|
||||||
Weight,
|
Weight,
|
||||||
/// No sorting
|
/// No sorting
|
||||||
|
|
|
@ -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#"
|
let file_path = edit_file!(site_path, "content/rebuild/first.md", br#"
|
||||||
+++
|
+++
|
||||||
title = "first"
|
title = "first"
|
||||||
order = 1
|
weight = 1
|
||||||
date = 2017-01-01
|
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#"
|
let file_path = edit_file!(site_path, "content/rebuild/first.md", br#"
|
||||||
+++
|
+++
|
||||||
title = "Premier"
|
title = "Premier"
|
||||||
order = 10
|
weight = 10
|
||||||
date = 2017-01-01
|
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#"
|
let file_path = edit_file!(site_path, "content/rebuild/_index.md", br#"
|
||||||
+++
|
+++
|
||||||
paginate_by = 1
|
paginate_by = 1
|
||||||
sort_by = "order"
|
sort_by = "weight"
|
||||||
template = "rebuild.html"
|
template = "rebuild.html"
|
||||||
+++
|
+++
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
let res = after_content_change(&mut site, &file_path);
|
let res = after_content_change(&mut site, &file_path);
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
assert!(file_contains!(site_path, "public/rebuild/index.html", "<h1>second</h1><h1>first</h1>"));
|
assert!(file_contains!(site_path, "public/rebuild/index.html", "<h1>first</h1><h1>second</h1>"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ use config::{Config, get_config};
|
||||||
use utils::fs::{create_file, copy_directory, create_directory, ensure_directory_exists};
|
use utils::fs::{create_file, copy_directory, create_directory, ensure_directory_exists};
|
||||||
use utils::templates::{render_template, rewrite_theme_paths};
|
use utils::templates::{render_template, rewrite_theme_paths};
|
||||||
use utils::net::get_available_port;
|
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 templates::{GUTENBERG_TERA, global_fns, render_redirect_template};
|
||||||
use front_matter::{SortBy, InsertAnchor};
|
use front_matter::{SortBy, InsertAnchor};
|
||||||
use taxonomies::{Taxonomy, find_taxonomies};
|
use taxonomies::{Taxonomy, find_taxonomies};
|
||||||
|
@ -401,7 +401,7 @@ impl Site {
|
||||||
}
|
}
|
||||||
let pages = mem::replace(&mut section.pages, vec![]);
|
let pages = mem::replace(&mut section.pages, vec![]);
|
||||||
let (sorted_pages, cannot_be_sorted_pages) = sort_pages(pages, section.meta.sort_by);
|
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_siblings(&sorted_pages, section.meta.sort_by);
|
||||||
section.ignored_pages = cannot_be_sorted_pages;
|
section.ignored_pages = cannot_be_sorted_pages;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,22 @@ weight = 30
|
||||||
A page is any file ending with `.md` in the `content` directory, except files
|
A page is any file ending with `.md` in the `content` directory, except files
|
||||||
named `_index.md`.
|
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
|
## Front-matter
|
||||||
|
|
||||||
The front-matter is a set of metadata embedded in a file. In Gutenberg,
|
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.
|
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
|
```md
|
||||||
+++
|
+++
|
||||||
|
@ -22,8 +39,15 @@ description = ""
|
||||||
|
|
||||||
# The date of the post.
|
# The date of the post.
|
||||||
# 2 formats are allowed: YYYY-MM-DD (2012-10-02) and RFC3339 (2002-10-02T15:00:00Z)
|
# 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
|
# Do not wrap dates in quotes, the line below only indicates that there is no default date.
|
||||||
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
|
# A draft page will not be present in prev/next pagination
|
||||||
draft = false
|
draft = false
|
||||||
|
@ -38,28 +62,18 @@ slug = ""
|
||||||
# It should not start with a `/` and the slash will be removed if it does
|
# It should not start with a `/` and the slash will be removed if it does
|
||||||
path = ""
|
path = ""
|
||||||
|
|
||||||
# A dict of taxonomies: the key is the name of the taxonomy which must match
|
# An array of strings allowing you to group pages with them
|
||||||
# one of the taxonomy defined in `config.toml` and the value is a list of
|
tags = []
|
||||||
# strings
|
|
||||||
[taxonomies]
|
|
||||||
|
|
||||||
# The order as defined in the Section page
|
# An overarching category name for that page, allowing you to group pages with it
|
||||||
order = 0
|
category = ""
|
||||||
|
|
||||||
# The weight as defined in the Section page
|
# Use aliases if you are moving content but want to redirect previous URLs to the
|
||||||
weight = 0
|
# current one. This takes an array of path, not URLs.
|
||||||
|
|
||||||
# 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"
|
|
||||||
aliases = []
|
aliases = []
|
||||||
|
|
||||||
# Whether the page should be in the search index. This is only used if
|
# 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
|
# hasn't set `in_search_index` to false in its front-matter
|
||||||
in_search_index = true
|
in_search_index = true
|
||||||
|
|
||||||
|
@ -75,7 +89,7 @@ Some content
|
||||||
|
|
||||||
## Summary
|
## 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.
|
paragraph of each page in a list for example.
|
||||||
|
|
||||||
To do so, add <code><!-- more --></code> in your content at the point
|
To do so, add <code><!-- more --></code> 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
|
available separately in the
|
||||||
[template](./documentation/templates/pages-sections.md#page-variables).
|
[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:
|
directly to it if needed for example:
|
||||||
`<a href="{{ page.permalink }}#continue-reading">Continue Reading</a>`
|
`<a href="{{ page.permalink }}#continue-reading">Continue Reading</a>`
|
||||||
|
|
|
@ -3,22 +3,32 @@ title = "Section"
|
||||||
weight = 20
|
weight = 20
|
||||||
+++
|
+++
|
||||||
|
|
||||||
A section is automatically created when a folder is found in the `content` section, unless it only
|
A section is created whenever a folder (or subfolder) in the `content` section contains an
|
||||||
contains a `index.md` file and is actually a page with assets.
|
`_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 (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.
|
||||||
The index page is actually a section created automatically like any other: you can add metadata
|
If you do not create an `_index.md` file in your content directory, this main content section will
|
||||||
and content by adding `_index.md` at the root of the `content` folder.
|
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
|
## 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,
|
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.
|
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.
|
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
|
```md
|
||||||
|
@ -27,7 +37,7 @@ title = ""
|
||||||
|
|
||||||
description = ""
|
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"
|
sort_by = "none"
|
||||||
|
|
||||||
# Used by the parent section to order its subsections.
|
# 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`.
|
by setting the `paginate_path` variable, which defaults to `page`.
|
||||||
|
|
||||||
## Sorting
|
## Sorting
|
||||||
Sections' pages can be sorted three different ways, not counting the unsorted default and
|
It is very common for Gutenberg templates to iterate over pages or sections
|
||||||
is enabled by setting the `sort_by` front-matter variable.
|
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
|
```j2
|
||||||
won't be rendered. The terminal will warn you if this is happening.
|
{% for post in section.pages %}
|
||||||
|
<h1><a href="{{ post.permalink }}">{{ post.title }}</a></h1>
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
If several pages have the same date/weight/order, their permalink will be used to break the tie following
|
This would iterate over the posts, and would do so in a specific order
|
||||||
an alphabetical 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`
|
### `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`
|
### `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`
|
When iterating through pages, you may wish to use the Tera `reverse` filter,
|
||||||
This will be sort all pages by their `order` field. Order is the opposite of weight, think of it as enumerating
|
which reverses the order of the pages. Thus, after using the `reverse` filter,
|
||||||
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.
|
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.
|
||||||
|
|
|
@ -32,9 +32,12 @@ extra: HashMap<String, Any>;
|
||||||
word_count: Number;
|
word_count: Number;
|
||||||
// Based on https://help.medium.com/hc/en-us/articles/214991667-Read-time
|
// Based on https://help.medium.com/hc/en-us/articles/214991667-Read-time
|
||||||
reading_time: Number;
|
reading_time: Number;
|
||||||
// `previous` and `next` are only filled if the content can be sorted
|
// `earlier` and `later` are only populated if the section variable `sort_by` is set to `date`
|
||||||
previous: Page?;
|
earlier: Page?;
|
||||||
next: 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
|
// See the Table of contents section below for more details
|
||||||
toc: Array<Header>;
|
toc: Array<Header>;
|
||||||
// Year/month/day is only set if the page has a date and month/day are 1-indexed
|
// Year/month/day is only set if the page has a date and month/day are 1-indexed
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "DevOps"
|
title = "DevOps"
|
||||||
sort_by = "order"
|
sort_by = "weight"
|
||||||
redirect_to = "posts/tutorials/devops/docker"
|
redirect_to = "posts/tutorials/devops/docker"
|
||||||
weight = 10
|
weight = 10
|
||||||
+++
|
+++
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "Docker"
|
title = "Docker"
|
||||||
order = 1
|
weight = 1
|
||||||
date = 2017-01-01
|
date = 2017-01-01
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "Nix"
|
title = "Nix"
|
||||||
order = 2
|
weight = 2
|
||||||
date = 2017-01-01
|
date = 2017-01-01
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
+++
|
+++
|
||||||
title = "Programming"
|
title = "Programming"
|
||||||
sort_by = "order"
|
sort_by = "weight"
|
||||||
weight = 1
|
weight = 1
|
||||||
+++
|
+++
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "Python tutorial"
|
title = "Python tutorial"
|
||||||
order = 1
|
weight = 1
|
||||||
date = 2017-01-01
|
date = 2017-01-01
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "Rust"
|
title = "Rust"
|
||||||
order = 2
|
weight = 2
|
||||||
date = 2017-01-01
|
date = 2017-01-01
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
+++
|
+++
|
||||||
paginate_by = 1
|
paginate_by = 1
|
||||||
sort_by = "order"
|
sort_by = "weight"
|
||||||
template = "rebuild.html"
|
template = "rebuild.html"
|
||||||
+++
|
+++
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "first"
|
title = "first"
|
||||||
order = 10
|
weight = 10
|
||||||
date = 2017-01-01
|
date = 2017-01-01
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "second"
|
title = "second"
|
||||||
order = 100
|
weight = 100
|
||||||
date = 2016-01-01
|
date = 2016-01-01
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue