Add new sorting: UpdateDate that sorts by meta.updated
. (#1452)
* Add new sorting: UpdateDate that sorts by `meta.updated`. * Use `max(created, updated)` for sort-by-update-date This prevents created but never updated articles from appearing at the end/not appearing at all.
This commit is contained in:
parent
b244bcdfbb
commit
f8c6ea2b00
|
@ -48,6 +48,8 @@ impl RawFrontMatter<'_> {
|
||||||
pub enum SortBy {
|
pub enum SortBy {
|
||||||
/// Most recent to oldest
|
/// Most recent to oldest
|
||||||
Date,
|
Date,
|
||||||
|
/// Most recent to oldest
|
||||||
|
UpdateDate,
|
||||||
/// Sort by title
|
/// Sort by title
|
||||||
Title,
|
Title,
|
||||||
/// Lower weight comes first
|
/// Lower weight comes first
|
||||||
|
|
|
@ -20,6 +20,12 @@ pub struct PageFrontMatter {
|
||||||
/// Updated date
|
/// Updated date
|
||||||
#[serde(default, deserialize_with = "from_toml_datetime")]
|
#[serde(default, deserialize_with = "from_toml_datetime")]
|
||||||
pub updated: Option<String>,
|
pub updated: Option<String>,
|
||||||
|
/// Chrono converted update datatime
|
||||||
|
#[serde(default, skip_deserializing)]
|
||||||
|
pub updated_datetime: Option<NaiveDateTime>,
|
||||||
|
/// The converted update datetime into a (year, month, day) tuple
|
||||||
|
#[serde(default, skip_deserializing)]
|
||||||
|
pub updated_datetime_tuple: Option<(i32, u32, u32)>,
|
||||||
/// Date if we want to order pages (ie blog post)
|
/// Date if we want to order pages (ie blog post)
|
||||||
#[serde(default, deserialize_with = "from_toml_datetime")]
|
#[serde(default, deserialize_with = "from_toml_datetime")]
|
||||||
pub date: Option<String>,
|
pub date: Option<String>,
|
||||||
|
@ -107,6 +113,10 @@ impl PageFrontMatter {
|
||||||
pub fn date_to_datetime(&mut self) {
|
pub fn date_to_datetime(&mut self) {
|
||||||
self.datetime = self.date.as_ref().map(|s| s.as_ref()).and_then(parse_datetime);
|
self.datetime = self.date.as_ref().map(|s| s.as_ref()).and_then(parse_datetime);
|
||||||
self.datetime_tuple = self.datetime.map(|dt| (dt.year(), dt.month(), dt.day()));
|
self.datetime_tuple = self.datetime.map(|dt| (dt.year(), dt.month(), dt.day()));
|
||||||
|
|
||||||
|
self.updated_datetime = self.updated.as_ref().map(|s| s.as_ref()).and_then(parse_datetime);
|
||||||
|
self.updated_datetime_tuple =
|
||||||
|
self.updated_datetime.map(|dt| (dt.year(), dt.month(), dt.day()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn weight(&self) -> usize {
|
pub fn weight(&self) -> usize {
|
||||||
|
@ -120,6 +130,8 @@ impl Default for PageFrontMatter {
|
||||||
title: None,
|
title: None,
|
||||||
description: None,
|
description: None,
|
||||||
updated: None,
|
updated: None,
|
||||||
|
updated_datetime: None,
|
||||||
|
updated_datetime_tuple: None,
|
||||||
date: None,
|
date: None,
|
||||||
datetime: None,
|
datetime: None,
|
||||||
datetime_tuple: None,
|
datetime_tuple: None,
|
||||||
|
|
|
@ -60,6 +60,10 @@ 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 earlier updated page, for pages sorted by updated date
|
||||||
|
pub earlier_updated: Option<DefaultKey>,
|
||||||
|
/// The later updated page, for pages sorted by updated date
|
||||||
|
pub later_updated: Option<DefaultKey>,
|
||||||
/// The earlier page, for pages sorted by date
|
/// The earlier page, for pages sorted by date
|
||||||
pub earlier: Option<DefaultKey>,
|
pub earlier: Option<DefaultKey>,
|
||||||
/// The later page, for pages sorted by date
|
/// The later page, for pages sorted by date
|
||||||
|
|
|
@ -90,6 +90,8 @@ pub struct SerializingPage<'a> {
|
||||||
lang: &'a str,
|
lang: &'a str,
|
||||||
lighter: Option<Box<SerializingPage<'a>>>,
|
lighter: Option<Box<SerializingPage<'a>>>,
|
||||||
heavier: Option<Box<SerializingPage<'a>>>,
|
heavier: Option<Box<SerializingPage<'a>>>,
|
||||||
|
earlier_updated: Option<Box<SerializingPage<'a>>>,
|
||||||
|
later_updated: Option<Box<SerializingPage<'a>>>,
|
||||||
earlier: Option<Box<SerializingPage<'a>>>,
|
earlier: Option<Box<SerializingPage<'a>>>,
|
||||||
later: Option<Box<SerializingPage<'a>>>,
|
later: Option<Box<SerializingPage<'a>>>,
|
||||||
title_prev: Option<Box<SerializingPage<'a>>>,
|
title_prev: Option<Box<SerializingPage<'a>>>,
|
||||||
|
@ -115,6 +117,12 @@ impl<'a> SerializingPage<'a> {
|
||||||
let heavier = page
|
let heavier = page
|
||||||
.heavier
|
.heavier
|
||||||
.map(|k| Box::new(Self::from_page_basic(pages.get(k).unwrap(), Some(library))));
|
.map(|k| Box::new(Self::from_page_basic(pages.get(k).unwrap(), Some(library))));
|
||||||
|
let earlier_updated = page
|
||||||
|
.earlier_updated
|
||||||
|
.map(|k| Box::new(Self::from_page_basic(pages.get(k).unwrap(), Some(library))));
|
||||||
|
let later_updated = page
|
||||||
|
.later_updated
|
||||||
|
.map(|k| Box::new(Self::from_page_basic(pages.get(k).unwrap(), Some(library))));
|
||||||
let earlier = page
|
let earlier = page
|
||||||
.earlier
|
.earlier
|
||||||
.map(|k| Box::new(Self::from_page_basic(pages.get(k).unwrap(), Some(library))));
|
.map(|k| Box::new(Self::from_page_basic(pages.get(k).unwrap(), Some(library))));
|
||||||
|
@ -161,6 +169,8 @@ impl<'a> SerializingPage<'a> {
|
||||||
lang: &page.lang,
|
lang: &page.lang,
|
||||||
lighter,
|
lighter,
|
||||||
heavier,
|
heavier,
|
||||||
|
earlier_updated,
|
||||||
|
later_updated,
|
||||||
earlier,
|
earlier,
|
||||||
later,
|
later,
|
||||||
title_prev,
|
title_prev,
|
||||||
|
@ -225,6 +235,8 @@ impl<'a> SerializingPage<'a> {
|
||||||
lang: &page.lang,
|
lang: &page.lang,
|
||||||
lighter: None,
|
lighter: None,
|
||||||
heavier: None,
|
heavier: None,
|
||||||
|
earlier_updated: None,
|
||||||
|
later_updated: None,
|
||||||
earlier: None,
|
earlier: None,
|
||||||
later: None,
|
later: None,
|
||||||
title_prev: None,
|
title_prev: None,
|
||||||
|
|
|
@ -3,13 +3,12 @@ use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use slotmap::{DefaultKey, DenseSlotMap};
|
use slotmap::{DefaultKey, DenseSlotMap};
|
||||||
|
|
||||||
use front_matter::SortBy;
|
|
||||||
|
|
||||||
use crate::content::{Page, Section};
|
use crate::content::{Page, Section};
|
||||||
use crate::sorting::{
|
use crate::sorting::{
|
||||||
find_siblings, sort_pages_by_date, sort_pages_by_title, sort_pages_by_weight,
|
find_siblings, sort_pages_by_date, sort_pages_by_title, sort_pages_by_weight,
|
||||||
};
|
};
|
||||||
use config::Config;
|
use config::Config;
|
||||||
|
use front_matter::{PageFrontMatter, SortBy};
|
||||||
|
|
||||||
// Like vec! but for HashSet
|
// Like vec! but for HashSet
|
||||||
macro_rules! set {
|
macro_rules! set {
|
||||||
|
@ -265,52 +264,47 @@ impl Library {
|
||||||
/// Sort all sections pages according to sorting method given
|
/// Sort all sections pages according to sorting method given
|
||||||
/// Pages that cannot be sorted are set to the section.ignored_pages instead
|
/// Pages that cannot be sorted are set to the section.ignored_pages instead
|
||||||
pub fn sort_sections_pages(&mut self) {
|
pub fn sort_sections_pages(&mut self) {
|
||||||
|
fn get_data<'a, T>(
|
||||||
|
section: &'a Section,
|
||||||
|
pages: &'a DenseSlotMap<DefaultKey, Page>,
|
||||||
|
field: impl Fn(&'a PageFrontMatter) -> Option<T>,
|
||||||
|
) -> Vec<(&'a DefaultKey, Option<T>, &'a str)> {
|
||||||
|
section
|
||||||
|
.pages
|
||||||
|
.iter()
|
||||||
|
.map(|k| {
|
||||||
|
if let Some(page) = pages.get(*k) {
|
||||||
|
(k, field(&page.meta), page.permalink.as_ref())
|
||||||
|
} else {
|
||||||
|
unreachable!("Sorting got an unknown page")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
let mut updates = HashMap::new();
|
let mut updates = HashMap::new();
|
||||||
for (key, section) in &self.sections {
|
for (key, section) in &self.sections {
|
||||||
let (sorted_pages, cannot_be_sorted_pages) = match section.meta.sort_by {
|
let (sorted_pages, cannot_be_sorted_pages) = match section.meta.sort_by {
|
||||||
SortBy::None => continue,
|
SortBy::None => continue,
|
||||||
SortBy::Date => {
|
SortBy::Date => {
|
||||||
let data = section
|
let data = get_data(section, &self.pages, |meta| meta.datetime);
|
||||||
.pages
|
|
||||||
.iter()
|
sort_pages_by_date(data)
|
||||||
.map(|k| {
|
}
|
||||||
if let Some(page) = self.pages.get(*k) {
|
SortBy::UpdateDate => {
|
||||||
(k, page.meta.datetime, page.permalink.as_ref())
|
let data = get_data(section, &self.pages, |meta| {
|
||||||
} else {
|
std::cmp::max(meta.datetime, meta.updated_datetime)
|
||||||
unreachable!("Sorting got an unknown page")
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
sort_pages_by_date(data)
|
sort_pages_by_date(data)
|
||||||
}
|
}
|
||||||
SortBy::Title => {
|
SortBy::Title => {
|
||||||
let data = section
|
let data = get_data(section, &self.pages, |meta| meta.title.as_deref());
|
||||||
.pages
|
|
||||||
.iter()
|
|
||||||
.map(|k| {
|
|
||||||
if let Some(page) = self.pages.get(*k) {
|
|
||||||
(k, page.meta.title.as_deref(), page.permalink.as_ref())
|
|
||||||
} else {
|
|
||||||
unreachable!("Sorting got an unknown page")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
sort_pages_by_title(data)
|
sort_pages_by_title(data)
|
||||||
}
|
}
|
||||||
SortBy::Weight => {
|
SortBy::Weight => {
|
||||||
let data = section
|
let data = get_data(section, &self.pages, |meta| meta.weight);
|
||||||
.pages
|
|
||||||
.iter()
|
|
||||||
.map(|k| {
|
|
||||||
if let Some(page) = self.pages.get(*k) {
|
|
||||||
(k, page.meta.weight, page.permalink.as_ref())
|
|
||||||
} else {
|
|
||||||
unreachable!("Sorting got an unknown page")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
sort_pages_by_weight(data)
|
sort_pages_by_weight(data)
|
||||||
}
|
}
|
||||||
|
@ -329,6 +323,10 @@ impl Library {
|
||||||
page.earlier = val2;
|
page.earlier = val2;
|
||||||
page.later = val1;
|
page.later = val1;
|
||||||
}
|
}
|
||||||
|
SortBy::UpdateDate => {
|
||||||
|
page.earlier_updated = val2;
|
||||||
|
page.later_updated = val1;
|
||||||
|
}
|
||||||
SortBy::Title => {
|
SortBy::Title => {
|
||||||
page.title_prev = val1;
|
page.title_prev = val1;
|
||||||
page.title_next = val2;
|
page.title_next = val2;
|
||||||
|
|
Loading…
Reference in a new issue