mirror of
https://github.com/zyllian/webdog.git
synced 2025-01-18 03:32:21 -08:00
implement custom timestamp formats for resources, resolves #15
This commit is contained in:
parent
0233bf0dad
commit
5b09813f24
6 changed files with 62 additions and 38 deletions
|
@ -109,6 +109,10 @@ the name of this resource type if it is plural.
|
|||
|
||||
how many resources of this type to display per page when content is paginated.
|
||||
|
||||
### `timestamp_format`
|
||||
|
||||
format to display timestamps as, as defined by version 2 of [the rust time crate's format description](https://time-rs.github.io/book/api/format-description.html).
|
||||
|
||||
## defining a resource
|
||||
|
||||
resources are made up of markdown files with yaml front matter. for instance:
|
||||
|
@ -154,3 +158,11 @@ whether the resource is a draft and should be excluded from normal builds. defau
|
|||
### other properties
|
||||
|
||||
resources may add extra properties which will get passed to the various resource templates later. simply add the property like it was any other property.
|
||||
|
||||
## extra properties
|
||||
|
||||
in addition to the resource properties, resources may receive additional properties from webdog as follows:
|
||||
|
||||
### `readable_timestamp`
|
||||
|
||||
the resource's timestamp in the timestamp format provided in the resource type's config.
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
{% extends "base.tera" %}
|
||||
{% block content %}
|
||||
<div>
|
||||
<h1>{{ title }}</h1>
|
||||
<span>published {{ timestamp }}</span>
|
||||
{% if draft %}
|
||||
<h1>{{ data.title }}</h1>
|
||||
<span>published {{ data.readable_timestamp }}</span>
|
||||
{% if data.draft %}
|
||||
<h2>DRAFT</h2>
|
||||
{% endif %}
|
||||
<p>{{ desc }}</p>
|
||||
<p>{{ data.desc }}</p>
|
||||
<div>
|
||||
{{ content | safe }}
|
||||
{{ data.content | safe }}
|
||||
</div>
|
||||
<hr />
|
||||
<h3>tags</h3>
|
||||
<div>
|
||||
{% for tag in tags %}
|
||||
{% for tag in data.tags %}
|
||||
<a href="/!!RESOURCE_TYPE!!/tag/{{tag}}">{{ tag }}</a>{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use itertools::Itertools;
|
||||
use lol_html::{element, RewriteStrSettings};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -91,22 +92,31 @@ fn resource_list_outside(
|
|||
|
||||
let data: ResourceListData = serde_yml::from_value(data.inner.clone())?;
|
||||
|
||||
let res_builder = builder
|
||||
.resource_builders
|
||||
.get(&data.resource)
|
||||
.ok_or_else(|| eyre::eyre!("missing resource builder: {}", data.resource))?;
|
||||
|
||||
let resource_list = builder.tera.render(
|
||||
&data.template,
|
||||
&tera::Context::from_serialize(ResourceListTemplateData {
|
||||
resources: builder
|
||||
.resource_builders
|
||||
.get(&data.resource)
|
||||
.ok_or_else(|| eyre::eyre!("missing resource builder: {}", data.resource))?
|
||||
resources: res_builder
|
||||
.loaded_metadata
|
||||
.iter()
|
||||
.take(data.count)
|
||||
.map(|(id, v)| ResourceTemplateData {
|
||||
.map(|(id, v)| {
|
||||
crate::util::format_timestamp(
|
||||
v.data().timestamp,
|
||||
&res_builder.config.timestamp_format,
|
||||
)
|
||||
.map(|ts| (id, v, ts))
|
||||
})
|
||||
.map_ok(|(id, v, ts)| ResourceTemplateData {
|
||||
resource: v,
|
||||
id: id.clone(),
|
||||
timestamp: v.data().timestamp,
|
||||
readable_timestamp: ts,
|
||||
})
|
||||
.collect(),
|
||||
.collect::<eyre::Result<Vec<_>>>()?,
|
||||
})?,
|
||||
)?;
|
||||
|
||||
|
|
|
@ -222,6 +222,7 @@ fn main() -> eyre::Result<()> {
|
|||
tag_list_title: format!("{name} tags"),
|
||||
resource_name_plural: plural,
|
||||
resources_per_page: 3,
|
||||
timestamp_format: "[weekday], [month repr:long] [day], [year]".to_string(),
|
||||
};
|
||||
|
||||
config.resources.insert(id.clone(), resource_config);
|
||||
|
|
|
@ -7,11 +7,12 @@ use eyre::Context;
|
|||
use itertools::Itertools;
|
||||
use pulldown_cmark::{Options, Parser};
|
||||
use rss::{validation::Validate, ChannelBuilder, ItemBuilder};
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::{format_description::well_known::Rfc2822, OffsetDateTime};
|
||||
|
||||
use crate::{
|
||||
builder::SiteBuilder, frontmatter::FrontMatterRequired, link_list::Link, PageMetadata,
|
||||
builder::SiteBuilder, frontmatter::FrontMatterRequired, link_list::Link,
|
||||
util::format_timestamp, PageMetadata,
|
||||
};
|
||||
|
||||
/// Metadata for resources.
|
||||
|
@ -43,24 +44,8 @@ pub struct ResourceTemplateData<'r> {
|
|||
pub resource: &'r FrontMatterRequired<ResourceMetadata>,
|
||||
/// The resource's ID.
|
||||
pub id: String,
|
||||
/// The resource's timestamp. Duplicated to change serialization method.
|
||||
#[serde(serialize_with = "ResourceTemplateData::timestamp_formatter")]
|
||||
pub timestamp: OffsetDateTime,
|
||||
}
|
||||
|
||||
impl<'r> ResourceTemplateData<'r> {
|
||||
fn timestamp_formatter<S>(timestamp: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let out = timestamp
|
||||
.format(
|
||||
&time::format_description::parse("[weekday], [month repr:long] [day], [year]")
|
||||
.expect("Should never fail"),
|
||||
)
|
||||
.expect("Should never fail");
|
||||
serializer.serialize_str(&out)
|
||||
}
|
||||
/// The resource's timestamp in a readable format.
|
||||
pub readable_timestamp: String,
|
||||
}
|
||||
|
||||
/// struct for adding custom meta content embeds
|
||||
|
@ -121,7 +106,7 @@ struct ResourceListTemplateData<'r> {
|
|||
}
|
||||
|
||||
/// Config for the resource builder.
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ResourceBuilderConfig {
|
||||
/// Path to where the resources should be loaded from.
|
||||
pub source_path: String,
|
||||
|
@ -145,6 +130,8 @@ pub struct ResourceBuilderConfig {
|
|||
pub resource_name_plural: String,
|
||||
/// The number of resources to display on a single page.
|
||||
pub resources_per_page: usize,
|
||||
/// The format to use for the readable timestamp.
|
||||
pub timestamp_format: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
|
@ -158,7 +145,7 @@ pub struct ResourceRSSBuilderConfig {
|
|||
}
|
||||
|
||||
/// Helper to genericize resource building.
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug)]
|
||||
pub struct ResourceBuilder {
|
||||
/// The builder's config.
|
||||
pub config: ResourceBuilderConfig,
|
||||
|
@ -277,7 +264,10 @@ impl ResourceBuilder {
|
|||
ResourceTemplateData {
|
||||
resource,
|
||||
id,
|
||||
timestamp: resource.data.as_ref().expect("should never fail").timestamp,
|
||||
readable_timestamp: format_timestamp(
|
||||
resource.data().timestamp,
|
||||
&self.config.timestamp_format,
|
||||
)?,
|
||||
},
|
||||
)?;
|
||||
std::fs::write(out_path, out)?;
|
||||
|
@ -307,7 +297,10 @@ impl ResourceBuilder {
|
|||
data.push(ResourceTemplateData {
|
||||
resource,
|
||||
id: id.clone(),
|
||||
timestamp: resource.data().timestamp,
|
||||
readable_timestamp: format_timestamp(
|
||||
resource.data().timestamp,
|
||||
&self.config.timestamp_format,
|
||||
)?,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -435,7 +428,7 @@ impl ResourceBuilder {
|
|||
.to_string(),
|
||||
))
|
||||
.description(resource.resource.data().desc.clone())
|
||||
.pub_date(Some(resource.timestamp.format(&Rfc2822)?))
|
||||
.pub_date(Some(resource.resource.data().timestamp.format(&Rfc2822)?))
|
||||
.content(Some(builder.tera.render(
|
||||
&rss.template,
|
||||
&tera::Context::from_serialize(resource)?,
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
use std::path::Path;
|
||||
|
||||
use time::OffsetDateTime;
|
||||
|
||||
/// Simple helper to remove the contents of a directory without removing the directory itself.
|
||||
pub fn remove_dir_contents(path: &Path) -> eyre::Result<()> {
|
||||
for entry in path.read_dir()? {
|
||||
|
@ -16,3 +18,9 @@ pub fn remove_dir_contents(path: &Path) -> eyre::Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper to format a timestamp according to the given format.
|
||||
pub fn format_timestamp(ts: OffsetDateTime, format: &str) -> eyre::Result<String> {
|
||||
let fmt = time::format_description::parse_borrowed::<2>(format)?;
|
||||
Ok(ts.format(&fmt)?)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue