diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d81e34..72e347f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Gutenberg has changed name to REPLACE_ME! - The `pagers` variable of Paginator objects has been removed +- `section.subsections` is now an array of paths to be used with the `get_section` +Tera function ### Others - Update dependencies, fixing a few bugs with templates @@ -25,6 +27,8 @@ - RSS feed now takes all available articles by default instead of limiting to 10000 - `templates` directory is now optional - Add Reason and F# syntax highlighting +- Add `ancestors` to pages and sections pointing to the relative path of all ancestor +sections up to the index to be used with the `get_section` Tera function ## 0.4.2 (2018-09-03) diff --git a/components/library/src/content/page.rs b/components/library/src/content/page.rs index 085c2fd..ca83c7b 100644 --- a/components/library/src/content/page.rs +++ b/components/library/src/content/page.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use tera::{Tera, Context as TeraContext, Value, Map}; use slug::slugify; -use slotmap::{Key, DenseSlotMap}; +use slotmap::{Key}; use errors::{Result, ResultExt}; use config::Config; @@ -23,6 +23,7 @@ pub struct SerializingPage<'a> { content: &'a str, permalink: &'a str, slug: &'a str, + ancestors: Vec, title: &'a Option, description: &'a Option, date: &'a Option, @@ -47,7 +48,7 @@ pub struct SerializingPage<'a> { impl<'a> SerializingPage<'a> { /// Grabs all the data from a page, including sibling pages - pub fn from_page(page: &'a Page, pages: &'a DenseSlotMap) -> Self { + pub fn from_page(page: &'a Page, library: &'a Library) -> Self { let mut year = None; let mut month = None; let mut day = None; @@ -56,12 +57,15 @@ impl<'a> SerializingPage<'a> { month = Some(d.1); day = Some(d.2); } - let lighter = page.lighter.map(|k| Box::new(SerializingPage::from_page_basic(pages.get(k).unwrap()))); - let heavier = page.heavier.map(|k| Box::new(SerializingPage::from_page_basic(pages.get(k).unwrap()))); - let earlier = page.earlier.map(|k| Box::new(SerializingPage::from_page_basic(pages.get(k).unwrap()))); - let later = page.later.map(|k| Box::new(SerializingPage::from_page_basic(pages.get(k).unwrap()))); + let pages = library.pages(); + let lighter = page.lighter.map(|k| Box::new(Self::from_page_basic(pages.get(k).unwrap(), Some(library)))); + let heavier = page.heavier.map(|k| Box::new(Self::from_page_basic(pages.get(k).unwrap(), Some(library)))); + let earlier = page.earlier.map(|k| Box::new(Self::from_page_basic(pages.get(k).unwrap(), Some(library)))); + let later = page.later.map(|k| Box::new(Self::from_page_basic(pages.get(k).unwrap(), Some(library)))); + let ancestors = page.ancestors.iter().map(|k| library.get_section_by_key(*k).file.relative.clone()).collect(); SerializingPage { + ancestors, content: &page.content, permalink: &page.permalink, slug: &page.slug, @@ -89,7 +93,7 @@ impl<'a> SerializingPage<'a> { } /// Same as from_page but does not fill sibling pages - pub fn from_page_basic(page: &'a Page) -> Self { + pub fn from_page_basic(page: &'a Page, library: Option<&'a Library>) -> Self { let mut year = None; let mut month = None; let mut day = None; @@ -98,8 +102,14 @@ impl<'a> SerializingPage<'a> { month = Some(d.1); day = Some(d.2); } + let ancestors = if let Some(ref lib) = library { + page.ancestors.iter().map(|k| lib.get_section_by_key(*k).file.relative.clone()).collect() + } else { + vec![] + }; SerializingPage { + ancestors, content: &page.content, permalink: &page.permalink, slug: &page.slug, @@ -133,6 +143,8 @@ pub struct Page { pub file: FileInfo, /// The front matter meta-data pub meta: PageFrontMatter, + /// The list of parent sections + pub ancestors: Vec, /// The actual content of the page, in markdown pub raw_content: String, /// All the non-md files we found next to the .md file @@ -177,6 +189,7 @@ impl Page { Page { file: FileInfo::new_page(file_path), meta, + ancestors: vec![], raw_content: "".to_string(), assets: vec![], content: "".to_string(), @@ -297,7 +310,7 @@ impl Page { anchor_insert, ); - context.tera_context.insert("page", &SerializingPage::from_page_basic(self)); + context.tera_context.insert("page", &SerializingPage::from_page_basic(self, None)); let res = render_content(&self.raw_content, &context) .chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?; @@ -320,7 +333,7 @@ impl Page { context.insert("config", config); context.insert("current_url", &self.permalink); context.insert("current_path", &self.path); - context.insert("page", &self.to_serialized(library.pages())); + context.insert("page", &self.to_serialized(library)); render_template(&tpl_name, tera, &context, &config.theme) .chain_err(|| format!("Failed to render page '{}'", self.file.path.display())) @@ -335,12 +348,12 @@ impl Page { .collect() } - pub fn to_serialized<'a>(&'a self, pages: &'a DenseSlotMap) -> SerializingPage<'a> { - SerializingPage::from_page(self, pages) + pub fn to_serialized<'a>(&'a self, library: &'a Library) -> SerializingPage<'a> { + SerializingPage::from_page(self, library) } - pub fn to_serialized_basic(&self) -> SerializingPage { - SerializingPage::from_page_basic(self) + pub fn to_serialized_basic<'a>(&'a self, library: &'a Library) -> SerializingPage<'a> { + SerializingPage::from_page_basic(self, Some(library)) } } @@ -349,6 +362,7 @@ impl Default for Page { Page { file: FileInfo::default(), meta: PageFrontMatter::default(), + ancestors: vec![], raw_content: "".to_string(), assets: vec![], content: "".to_string(), diff --git a/components/library/src/content/section.rs b/components/library/src/content/section.rs index 7910422..5f0a58f 100644 --- a/components/library/src/content/section.rs +++ b/components/library/src/content/section.rs @@ -21,6 +21,7 @@ use library::Library; pub struct SerializingSection<'a> { content: &'a str, permalink: &'a str, + ancestors: Vec, title: &'a Option, description: &'a Option, extra: &'a HashMap, @@ -31,7 +32,7 @@ pub struct SerializingSection<'a> { toc: &'a [Header], assets: Vec, pages: Vec>, - subsections: Vec>, + subsections: Vec<&'a str>, } impl<'a> SerializingSection<'a> { @@ -40,14 +41,17 @@ impl<'a> SerializingSection<'a> { let mut subsections = Vec::with_capacity(section.subsections.len()); for k in §ion.pages { - pages.push(library.get_page_by_key(*k).to_serialized(library.pages())); + pages.push(library.get_page_by_key(*k).to_serialized(library)); } for k in §ion.subsections { - subsections.push(library.get_section_by_key(*k).to_serialized(library)); + subsections.push(library.get_section_path_by_key(*k)); } + let ancestors = section.ancestors.iter().map(|k| library.get_section_by_key(*k).file.relative.clone()).collect(); + SerializingSection { + ancestors, content: §ion.content, permalink: §ion.permalink, title: §ion.meta.title, @@ -65,8 +69,15 @@ impl<'a> SerializingSection<'a> { } /// Same as from_section but doesn't fetch pages and sections - pub fn from_section_basic(section: &'a Section) -> Self { + pub fn from_section_basic(section: &'a Section, library: Option<&'a Library>) -> Self { + let ancestors = if let Some(ref lib) = library { + section.ancestors.iter().map(|k| lib.get_section_by_key(*k).file.relative.clone()).collect() + } else { + vec![] + }; + SerializingSection { + ancestors, content: §ion.content, permalink: §ion.permalink, title: §ion.meta.title, @@ -106,6 +117,8 @@ pub struct Section { pub pages: Vec, /// All pages that cannot be sorted in this section pub ignored_pages: Vec, + /// The list of parent sections + pub ancestors: Vec, /// All direct subsections pub subsections: Vec, /// Toc made from the headers of the markdown file @@ -124,6 +137,7 @@ impl Section { Section { file: FileInfo::new_section(file_path), meta, + ancestors: vec![], path: "".to_string(), components: vec![], permalink: "".to_string(), @@ -214,7 +228,7 @@ impl Section { self.meta.insert_anchor_links, ); - context.tera_context.insert("section", &SerializingSection::from_section_basic(self)); + context.tera_context.insert("section", &SerializingSection::from_section_basic(self, None)); let res = render_content(&self.raw_content, &context) .chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?; @@ -254,6 +268,10 @@ impl Section { pub fn to_serialized<'a>(&'a self, library: &'a Library) -> SerializingSection<'a> { SerializingSection::from_section(self, library) } + + pub fn to_serialized_basic<'a>(&'a self, library: &'a Library) -> SerializingSection<'a> { + SerializingSection::from_section_basic(self, Some(library)) + } } /// Used to create a default index section if there is no _index.md in the root content directory @@ -262,6 +280,7 @@ impl Default for Section { Section { file: FileInfo::default(), meta: SectionFrontMatter::default(), + ancestors: vec![], path: "".to_string(), components: vec![], permalink: "".to_string(), diff --git a/components/library/src/library.rs b/components/library/src/library.rs index 8c45f1d..4e5c5bd 100644 --- a/components/library/src/library.rs +++ b/components/library/src/library.rs @@ -25,7 +25,7 @@ pub struct Library { /// A mapping path -> key for pages so we can easily get their key paths_to_pages: HashMap, /// A mapping path -> key for sections so we can easily get their key - paths_to_sections: HashMap, + pub paths_to_sections: HashMap, } impl Library { @@ -81,24 +81,58 @@ impl Library { /// Find out the direct subsections of each subsection if there are some /// as well as the pages for each section pub fn populate_sections(&mut self) { - let mut grandparent_paths: HashMap> = HashMap::new(); + let (root_path, index_path) = self.sections + .values() + .find(|s| s.is_index()) + .map(|s| (s.file.parent.clone(), s.file.path.clone())) + .unwrap(); + let root_key = self.paths_to_sections[&index_path]; + + // We are going to get both the ancestors and grandparents for each section in one go + let mut ancestors: HashMap> = HashMap::new(); + let mut subsections: HashMap> = HashMap::new(); for section in self.sections.values_mut() { + // Make sure the pages of a section are empty since we can call that many times on `serve` + section.pages = vec![]; + section.ignored_pages = vec![]; + if let Some(ref grand_parent) = section.file.grand_parent { - grandparent_paths - .entry(grand_parent.to_path_buf()) + subsections + .entry(grand_parent.join("_index.md")) .or_insert_with(|| vec![]) .push(section.file.path.clone()); } - // Make sure the pages of a section are empty since we can call that many times on `serve` - section.pages = vec![]; - section.ignored_pages = vec![]; + + // Index has no ancestors, no need to go through it + if section.is_index() { + ancestors.insert(section.file.path.clone(), vec![]); + continue; + } + + let mut path = root_path.clone(); + // Index section is the first ancestor of every single section + let mut parents = vec![root_key.clone()]; + for component in §ion.file.components { + path = path.join(component); + // Skip itself + if path == section.file.parent { + continue; + } + if let Some(section_key) = self.paths_to_sections.get(&path.join("_index.md")) { + parents.push(*section_key); + } + } + ancestors.insert(section.file.path.clone(), parents); } for (key, page) in &mut self.pages { let parent_section_path = page.file.parent.join("_index.md"); if let Some(section_key) = self.paths_to_sections.get(&parent_section_path) { self.sections.get_mut(*section_key).unwrap().pages.push(key); + page.ancestors = ancestors.get(&parent_section_path).cloned().unwrap_or_else(|| vec![]); + // Don't forget to push the actual parent + page.ancestors.push(*section_key); } } @@ -109,15 +143,14 @@ impl Library { for (key, section) in &self.sections { sections_weight.insert(key, section.meta.weight); } + for section in self.sections.values_mut() { - if let Some(paths) = grandparent_paths.get(§ion.file.parent) { - section.subsections = paths - .iter() - .map(|p| sections[p]) - .collect::>(); - section.subsections - .sort_by(|a, b| sections_weight[a].cmp(§ions_weight[b])); + if let Some(ref children) = subsections.get(§ion.file.path) { + let mut children: Vec<_> = children.iter().map(|p| sections[p]).collect(); + children.sort_by(|a, b| sections_weight[a].cmp(§ions_weight[b])); + section.subsections = children; } + section.ancestors = ancestors.get(§ion.file.path).cloned().unwrap_or_else(|| vec![]); } } @@ -219,6 +252,11 @@ impl Library { None } + /// Only used in tests + pub fn get_section_key(&self, path: &PathBuf) -> Option<&Key> { + self.paths_to_sections.get(path) + } + pub fn get_section(&self, path: &PathBuf) -> Option<&Section> { self.sections.get(self.paths_to_sections.get(path).cloned().unwrap_or_default()) } @@ -231,6 +269,14 @@ impl Library { self.sections.get(key).unwrap() } + pub fn get_section_mut_by_key(&mut self, key: Key) -> &mut Section { + self.sections.get_mut(key).unwrap() + } + + pub fn get_section_path_by_key(&self, key: Key) -> &str { + &self.get_section_by_key(key).file.relative + } + pub fn get_page(&self, path: &PathBuf) -> Option<&Page> { self.pages.get(self.paths_to_pages.get(path).cloned().unwrap_or_default()) } @@ -241,7 +287,6 @@ impl Library { pub fn remove_section(&mut self, path: &PathBuf) -> Option
{ if let Some(k) = self.paths_to_sections.remove(path) { - // TODO: delete section from parent subsection if there is one self.sections.remove(k) } else { None @@ -250,7 +295,6 @@ impl Library { pub fn remove_page(&mut self, path: &PathBuf) -> Option { if let Some(k) = self.paths_to_pages.remove(path) { - // TODO: delete page from all parent sections self.pages.remove(k) } else { None diff --git a/components/library/src/pagination/mod.rs b/components/library/src/pagination/mod.rs index e5bcf22..3262009 100644 --- a/components/library/src/pagination/mod.rs +++ b/components/library/src/pagination/mod.rs @@ -108,7 +108,7 @@ impl<'a> Paginator<'a> { for key in self.all_pages { let page = library.get_page_by_key(*key); - current_page.push(page.to_serialized_basic()); + current_page.push(page.to_serialized_basic(library)); if current_page.len() == self.paginate_by { pages.push(current_page); @@ -188,12 +188,12 @@ impl<'a> Paginator<'a> { paginator } - pub fn render_pager(&self, pager: &Pager, config: &Config, tera: &Tera) -> Result { + pub fn render_pager(&self, pager: &Pager, config: &Config, tera: &Tera, library: &Library) -> Result { let mut context = Context::new(); context.insert("config", &config); let template_name = match self.root { PaginationRoot::Section(s) => { - context.insert("section", &SerializingSection::from_section_basic(s)); + context.insert("section", &SerializingSection::from_section_basic(s, Some(library))); s.get_template_name() } PaginationRoot::Taxonomy(t) => { diff --git a/components/library/src/taxonomies/mod.rs b/components/library/src/taxonomies/mod.rs index 205b396..0be0711 100644 --- a/components/library/src/taxonomies/mod.rs +++ b/components/library/src/taxonomies/mod.rs @@ -26,7 +26,7 @@ impl<'a> SerializedTaxonomyItem<'a> { for key in &item.pages { let page = library.get_page_by_key(*key); - pages.push(page.to_serialized_basic()); + pages.push(page.to_serialized_basic(library)); } SerializedTaxonomyItem { diff --git a/components/rebuild/src/lib.rs b/components/rebuild/src/lib.rs index 0ba50cb..dc751c7 100644 --- a/components/rebuild/src/lib.rs +++ b/components/rebuild/src/lib.rs @@ -125,6 +125,7 @@ fn handle_section_editing(site: &mut Site, path: &Path) -> Result<()> { s.ignored_pages = prev.ignored_pages; s.subsections = prev.subsections; } + site.populate_sections(); if site.library.get_section(&pathbuf).unwrap().meta == prev.meta { // Front matter didn't change, only content did diff --git a/components/site/benches/site.rs b/components/site/benches/site.rs index 51d8cea..2710a4c 100644 --- a/components/site/benches/site.rs +++ b/components/site/benches/site.rs @@ -63,7 +63,7 @@ fn bench_render_paginated(b: &mut test::Bencher) { let public = &tmp_dir.path().join("public"); site.set_output_path(&public); let section = site.library.sections_values()[0]; - let paginator = Paginator::from_section(§ion, site.library.pages()); + let paginator = Paginator::from_section(§ion, &site.library); b.iter(|| site.render_paginated(public, &paginator)); } diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index b2cc306..2d756d9 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -240,10 +240,8 @@ impl Site { } self.register_early_global_fns(); - self.render_markdown()?; self.populate_sections(); -// self.library.cache_all_pages(); -// self.library.cache_all_sections(); + self.render_markdown()?; self.populate_taxonomies()?; self.register_tera_global_fns(); @@ -737,7 +735,7 @@ impl Site { let p = pages .iter() .take(num_entries) - .map(|x| x.to_serialized_basic()) + .map(|x| x.to_serialized_basic(&self.library)) .collect::>(); context.insert("pages", &p); @@ -858,7 +856,7 @@ impl Site { .map(|pager| { let page_path = folder_path.join(&format!("{}", pager.index)); create_directory(&page_path)?; - let output = paginator.render_pager(pager, &self.config, &self.tera)?; + let output = paginator.render_pager(pager, &self.config, &self.tera, &self.library)?; if pager.index > 1 { create_file(&page_path.join("index.html"), &self.inject_livereload(output))?; } else { diff --git a/components/site/tests/site.rs b/components/site/tests/site.rs index e240d20..9e714d5 100644 --- a/components/site/tests/site.rs +++ b/components/site/tests/site.rs @@ -22,10 +22,6 @@ fn can_parse_site() { assert_eq!(site.library.pages().len(), 15); let posts_path = path.join("content").join("posts"); - // Make sure we remove all the pwd + content from the sections - let basic = site.library.get_page(&posts_path.join("simple.md")).unwrap(); - assert_eq!(basic.file.components, vec!["posts".to_string()]); - // Make sure the page with a url doesn't have any sections let url_post = site.library.get_page(&posts_path.join("fixed-url.md")).unwrap(); assert_eq!(url_post.path, "a-fixed-url/"); @@ -41,10 +37,23 @@ fn can_parse_site() { let index_section = site.library.get_section(&path.join("content").join("_index.md")).unwrap(); assert_eq!(index_section.subsections.len(), 3); assert_eq!(index_section.pages.len(), 1); + assert!(index_section.ancestors.is_empty()); let posts_section = site.library.get_section(&posts_path.join("_index.md")).unwrap(); assert_eq!(posts_section.subsections.len(), 1); assert_eq!(posts_section.pages.len(), 7); + assert_eq!(posts_section.ancestors, vec![*site.library.get_section_key(&index_section.file.path).unwrap()]); + + // Make sure we remove all the pwd + content from the sections + let basic = site.library.get_page(&posts_path.join("simple.md")).unwrap(); + assert_eq!(basic.file.components, vec!["posts".to_string()]); + assert_eq!( + basic.ancestors, + vec![ + *site.library.get_section_key(&index_section.file.path).unwrap(), + *site.library.get_section_key(&posts_section.file.path).unwrap(), + ] + ); let tutorials_section = site.library.get_section(&posts_path.join("tutorials").join("_index.md")).unwrap(); assert_eq!(tutorials_section.subsections.len(), 2); @@ -57,6 +66,14 @@ fn can_parse_site() { let devops_section = site.library.get_section(&posts_path.join("tutorials").join("devops").join("_index.md")).unwrap(); assert_eq!(devops_section.subsections.len(), 0); assert_eq!(devops_section.pages.len(), 2); + assert_eq!( + devops_section.ancestors, + vec![ + *site.library.get_section_key(&index_section.file.path).unwrap(), + *site.library.get_section_key(&posts_section.file.path).unwrap(), + *site.library.get_section_key(&tutorials_section.file.path).unwrap(), + ] + ); let prog_section = site.library.get_section(&posts_path.join("tutorials").join("programming").join("_index.md")).unwrap(); assert_eq!(prog_section.subsections.len(), 0); diff --git a/components/templates/src/global_fns.rs b/components/templates/src/global_fns.rs index 3fa58b5..872ed98 100644 --- a/components/templates/src/global_fns.rs +++ b/components/templates/src/global_fns.rs @@ -56,7 +56,7 @@ pub fn make_get_page(library: &Library) -> GlobalFn { for page in library.pages_values() { pages.insert( page.file.relative.clone(), - to_value(library.get_page(&page.file.path).unwrap().to_serialized(library.pages())).unwrap(), + to_value(library.get_page(&page.file.path).unwrap().to_serialized(library)).unwrap(), ); } @@ -75,11 +75,17 @@ pub fn make_get_page(library: &Library) -> GlobalFn { pub fn make_get_section(library: &Library) -> GlobalFn { let mut sections = HashMap::new(); + let mut sections_basic = HashMap::new(); for section in library.sections_values() { sections.insert( section.file.relative.clone(), to_value(library.get_section(§ion.file.path).unwrap().to_serialized(library)).unwrap(), ); + + sections_basic.insert( + section.file.relative.clone(), + to_value(library.get_section(§ion.file.path).unwrap().to_serialized_basic(library)).unwrap(), + ); } Box::new(move |args| -> Result { @@ -89,7 +95,19 @@ pub fn make_get_section(library: &Library) -> GlobalFn { "`get_section` requires a `path` argument with a string value" ); - match sections.get(&path) { + let metadata_only = args + .get("metadata_only") + .map_or(false, |c| { + from_value::(c.clone()).unwrap_or(false) + }); + + let container = if metadata_only { + §ions_basic + } else { + §ions + }; + + match container.get(&path) { Some(p) => Ok(p.clone()), None => Err(format!("Section `{}` not found.", path).into()) } diff --git a/docs/content/documentation/templates/overview.md b/docs/content/documentation/templates/overview.md index a9ab635..019d992 100644 --- a/docs/content/documentation/templates/overview.md +++ b/docs/content/documentation/templates/overview.md @@ -92,6 +92,12 @@ Takes a path to a `_index.md` file and returns the associated section {% set section = get_section(path="blog/_index.md") %} ``` +If you only need the metadata of the section, you can pass `metadata_only=true` to the function: + +```jinja2 +{% set section = get_section(path="blog/_index.md", metadata_only=true) %} +``` + ### ` get_url` Gets the permalink for the given path. If the path starts with `./`, it will be understood as an internal @@ -108,11 +114,11 @@ we want to link to the file that is located at `static/css/app.css`: {{/* get_url(path="css/app.css") */}} ``` -For assets it is reccommended that you pass `trailing_slash=false` to the `get_url` function. This prevents errors -when dealing with certain hosting providers. An example is: +By default, assets will not have a trailing slash. You can force one by passing `trailing_slash=true` to the `get_url` function. +An example is: ```jinja2 -{{/* get_url(path="css/app.css", trailing_slash=false) */}} +{{/* get_url(path="css/app.css", trailing_slash=true) */}} ``` In the case of non-internal links, you can also add a cachebust of the format `?t=1290192` at the end of a URL diff --git a/docs/content/documentation/templates/pages-sections.md b/docs/content/documentation/templates/pages-sections.md index 3c04e38..df90045 100644 --- a/docs/content/documentation/templates/pages-sections.md +++ b/docs/content/documentation/templates/pages-sections.md @@ -45,6 +45,10 @@ month: Number?; day: Number?; // Paths of colocated assets, relative to the content directory assets: Array; +// The relative paths of the parent sections until the index onef for use with the `get_section` Tera function +// The first item is the index section and the last one is the parent section +// This is filled after rendering a page content so it will be empty in shortcodes +ancestors: Array; ``` ## Section variables @@ -70,7 +74,9 @@ extra: HashMap; // Pages directly in this section, sorted if asked pages: Array; // Direct subsections to this section, sorted by subsections weight -subsections: Array
; +// This only contains the path to use in the `get_section` Tera function to get +// the actual section object if you need it +subsections: Array; // Unicode word count word_count: Number; // Based on https://help.medium.com/hc/en-us/articles/214991667-Read-time @@ -79,6 +85,10 @@ reading_time: Number; toc: Array
; // Paths of colocated assets, relative to the content directory assets: Array; +// The relative paths of the parent sections until the index onef for use with the `get_section` Tera function +// The first item is the index section and the last one is the parent section +// This is filled after rendering a page content so it will be empty in shortcodes +ancestors: Array; ``` ## Table of contents diff --git a/docs/templates/documentation.html b/docs/templates/documentation.html index 86c25c7..cfeb2b7 100644 --- a/docs/templates/documentation.html +++ b/docs/templates/documentation.html @@ -8,7 +8,8 @@