Misc stuff
This commit is contained in:
parent
1e772a97e2
commit
9a13efbd35
@ -26,6 +26,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
<meta property="og:url" content="https://{{ _domain }}{{ _permalink }}">
|
<meta property="og:url" content="https://{{ _domain }}{{ _permalink }}">
|
||||||
<meta property="og:site_name" content="Shadowfacts">
|
<meta property="og:site_name" content="Shadowfacts">
|
||||||
|
<meta name="fediverse:creator" content="@shadowfacts@social.shadowfacts.net">
|
||||||
|
|
||||||
{% block head %}{% endblock %}
|
{% block head %}{% endblock %}
|
||||||
|
|
||||||
|
@ -6,16 +6,19 @@
|
|||||||
|
|
||||||
{% block content -%}
|
{% block content -%}
|
||||||
|
|
||||||
<h1>{{ tag_name }} posts</h1>
|
<h1>Posts tagged ‘{{ tag_name }}’</h1>
|
||||||
|
|
||||||
<ul>
|
{% for year in years %}
|
||||||
{% for entry in posts %}
|
<h2>{{ year }}</h2>
|
||||||
<li>
|
<ul>
|
||||||
<a href="{{ entry.permalink }}">
|
{% for entry in posts_by_year[year] %}
|
||||||
{{ entry.title }}
|
<li>
|
||||||
</a>
|
<a href="{{ entry.permalink }}">
|
||||||
</li>
|
{{ entry.title }}
|
||||||
{% endfor %}
|
</a>
|
||||||
</ul>
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{%- endblock %}
|
{%- endblock %}
|
||||||
|
@ -69,7 +69,7 @@ impl Rule for Entries {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(InputVisitable)]
|
#[derive(InputVisitable)]
|
||||||
struct PostsByYear(Input<Vec<Entry>>);
|
pub struct PostsByYear(pub Input<Vec<Entry>>);
|
||||||
impl Rule for PostsByYear {
|
impl Rule for PostsByYear {
|
||||||
type Output = PostsYearMap;
|
type Output = PostsYearMap;
|
||||||
fn evaluate(&mut self) -> Self::Output {
|
fn evaluate(&mut self) -> Self::Output {
|
||||||
@ -81,11 +81,11 @@ impl Rule for PostsByYear {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq, Clone)]
|
||||||
struct PostsYearMap(HashMap<i32, Vec<Entry>>);
|
pub struct PostsYearMap(pub HashMap<i32, Vec<Entry>>);
|
||||||
|
|
||||||
impl PostsYearMap {
|
impl PostsYearMap {
|
||||||
fn years(&self) -> Vec<i32> {
|
pub fn years(&self) -> Vec<i32> {
|
||||||
let mut years = self.0.keys().cloned().collect::<Vec<_>>();
|
let mut years = self.0.keys().cloned().collect::<Vec<_>>();
|
||||||
years.sort();
|
years.sort();
|
||||||
years.reverse();
|
years.reverse();
|
||||||
@ -94,8 +94,8 @@ impl PostsYearMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Serialize)]
|
#[derive(PartialEq, Clone, Serialize)]
|
||||||
struct Entry {
|
pub struct Entry {
|
||||||
permalink: String,
|
pub permalink: String,
|
||||||
title: String,
|
pub title: String,
|
||||||
year: i32,
|
pub year: i32,
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,7 @@ impl<'a> Fs for TrackingFs<'a> {
|
|||||||
struct ReadFile(#[skip_visit] PathBuf);
|
struct ReadFile(#[skip_visit] PathBuf);
|
||||||
impl Rule for ReadFile {
|
impl Rule for ReadFile {
|
||||||
type Output = String;
|
type Output = String;
|
||||||
|
|
||||||
fn evaluate(&mut self) -> Self::Output {
|
fn evaluate(&mut self) -> Self::Output {
|
||||||
match std::fs::read(&self.0) {
|
match std::fs::read(&self.0) {
|
||||||
Ok(data) => BASE64_STANDARD.encode(data),
|
Ok(data) => BASE64_STANDARD.encode(data),
|
||||||
@ -170,4 +171,8 @@ impl Rule for ReadFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn node_label(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0.display())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ use compute_graph::{
|
|||||||
NodeId,
|
NodeId,
|
||||||
builder::GraphBuilder,
|
builder::GraphBuilder,
|
||||||
input::{DynamicInput, Input, InputVisitable},
|
input::{DynamicInput, Input, InputVisitable},
|
||||||
node::NodeValue,
|
|
||||||
rule::{DynamicNodeFactory, DynamicRule, DynamicRuleContext, Rule},
|
rule::{DynamicNodeFactory, DynamicRule, DynamicRuleContext, Rule},
|
||||||
synchronicity::Asynchronous,
|
synchronicity::Asynchronous,
|
||||||
};
|
};
|
||||||
@ -23,25 +22,22 @@ pub fn make_graph(
|
|||||||
) -> Input<()> {
|
) -> Input<()> {
|
||||||
let recents = builder.add_dynamic_rule(RecentPosts::new(posts));
|
let recents = builder.add_dynamic_rule(RecentPosts::new(posts));
|
||||||
let with_rss_html = builder.add_dynamic_rule(ConvertRecentsToRSSContent::new(recents));
|
let with_rss_html = builder.add_dynamic_rule(ConvertRecentsToRSSContent::new(recents));
|
||||||
|
|
||||||
builder.add_rule(RenderRSSFeed(with_rss_html))
|
builder.add_rule(RenderRSSFeed(with_rss_html))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(InputVisitable)]
|
#[derive(InputVisitable)]
|
||||||
struct RecentPosts {
|
struct RecentPosts {
|
||||||
posts: DynamicInput<ReadPostOutput>,
|
posts: DynamicInput<ReadPostOutput>,
|
||||||
factory: DynamicNodeFactory<NodeId, ReadPostOutput>,
|
|
||||||
}
|
}
|
||||||
impl RecentPosts {
|
impl RecentPosts {
|
||||||
fn new(posts: DynamicInput<ReadPostOutput>) -> Self {
|
fn new(posts: DynamicInput<ReadPostOutput>) -> Self {
|
||||||
Self {
|
Self { posts }
|
||||||
posts,
|
|
||||||
factory: DynamicNodeFactory::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl DynamicRule for RecentPosts {
|
impl DynamicRule for RecentPosts {
|
||||||
type ChildOutput = ReadPostOutput;
|
type ChildOutput = ReadPostOutput;
|
||||||
fn evaluate(&mut self, ctx: &mut impl DynamicRuleContext) -> Vec<Input<Self::ChildOutput>> {
|
fn evaluate(&mut self, _ctx: &mut impl DynamicRuleContext) -> Vec<Input<Self::ChildOutput>> {
|
||||||
let mut posts = vec![];
|
let mut posts = vec![];
|
||||||
for post_input in self.posts().inputs.iter() {
|
for post_input in self.posts().inputs.iter() {
|
||||||
if let Some(post) = post_input.value().as_ref() {
|
if let Some(post) = post_input.value().as_ref() {
|
||||||
@ -50,21 +46,11 @@ impl DynamicRule for RecentPosts {
|
|||||||
}
|
}
|
||||||
posts.sort_by_key(|post_and_date| post_and_date.1);
|
posts.sort_by_key(|post_and_date| post_and_date.1);
|
||||||
posts.reverse();
|
posts.reverse();
|
||||||
for (post_input, _) in posts.into_iter().take(10) {
|
posts
|
||||||
self.factory.add_node(ctx, post_input.node_id(), |ctx| {
|
.into_iter()
|
||||||
ctx.add_rule(Identity(post_input))
|
.map(|(post_input, _)| post_input)
|
||||||
});
|
.take(10)
|
||||||
}
|
.collect()
|
||||||
self.factory.all_nodes(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(InputVisitable)]
|
|
||||||
struct Identity<T>(Input<T>);
|
|
||||||
impl<T: Clone + NodeValue + 'static> Rule for Identity<T> {
|
|
||||||
type Output = T;
|
|
||||||
fn evaluate(&mut self) -> Self::Output {
|
|
||||||
self.input_0().clone()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use chrono::Datelike;
|
||||||
use compute_graph::{
|
use compute_graph::{
|
||||||
builder::GraphBuilder,
|
builder::GraphBuilder,
|
||||||
input::{DynamicInput, Input, InputVisitable},
|
input::{DynamicInput, Input, InputVisitable},
|
||||||
rule::{DynamicNodeFactory, DynamicRule, Rule},
|
rule::{DynamicNodeFactory, DynamicRule, Rule},
|
||||||
synchronicity::Asynchronous,
|
synchronicity::Asynchronous,
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
|
||||||
use tera::Context;
|
use tera::Context;
|
||||||
|
|
||||||
|
use crate::generator::archive::PostsByYear;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
FileWatcher,
|
FileWatcher,
|
||||||
|
archive::{Entry, PostsYearMap},
|
||||||
posts::{ReadPostOutput, metadata::Tag},
|
posts::{ReadPostOutput, metadata::Tag},
|
||||||
templates::{AddTemplate, BuildTemplateContext, RenderTemplate, Templates},
|
templates::{AddTemplate, BuildTemplateContext, RenderTemplate, Templates},
|
||||||
util::{MapDynamicToVoid, content_path},
|
util::{MapDynamicToVoid, content_path},
|
||||||
@ -39,13 +42,17 @@ pub fn make_graph(
|
|||||||
#[derive(InputVisitable)]
|
#[derive(InputVisitable)]
|
||||||
struct MakePostsByTags {
|
struct MakePostsByTags {
|
||||||
posts: DynamicInput<ReadPostOutput>,
|
posts: DynamicInput<ReadPostOutput>,
|
||||||
node_factory: DynamicNodeFactory<String, TagAndPosts>,
|
posts_by_tag_factory: DynamicNodeFactory<String, Vec<Entry>>,
|
||||||
|
posts_by_year_factory: DynamicNodeFactory<String, PostsYearMap>,
|
||||||
|
tag_and_posts_factory: DynamicNodeFactory<String, TagAndPosts>,
|
||||||
}
|
}
|
||||||
impl MakePostsByTags {
|
impl MakePostsByTags {
|
||||||
fn new(posts: DynamicInput<ReadPostOutput>) -> Self {
|
fn new(posts: DynamicInput<ReadPostOutput>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
posts,
|
posts,
|
||||||
node_factory: DynamicNodeFactory::new(),
|
posts_by_tag_factory: DynamicNodeFactory::new(),
|
||||||
|
posts_by_year_factory: DynamicNodeFactory::new(),
|
||||||
|
tag_and_posts_factory: DynamicNodeFactory::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,14 +71,35 @@ impl DynamicRule for MakePostsByTags {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (slug, name) in all_tags {
|
for (slug, name) in all_tags {
|
||||||
self.node_factory.add_node(ctx, slug.clone(), |ctx| {
|
let tag = Tag {
|
||||||
ctx.add_rule(PostsByTag {
|
slug: slug.clone(),
|
||||||
posts: self.posts.clone(),
|
name,
|
||||||
tag: Tag { slug, name },
|
};
|
||||||
})
|
|
||||||
});
|
let posts_for_tag = self
|
||||||
|
.posts_by_tag_factory
|
||||||
|
.add_node(ctx, slug.clone(), |ctx| {
|
||||||
|
ctx.add_rule(PostsByTag {
|
||||||
|
posts: self.posts.clone(),
|
||||||
|
tag: tag.clone(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let posts_by_year = self
|
||||||
|
.posts_by_year_factory
|
||||||
|
.add_node(ctx, slug.clone(), |ctx| {
|
||||||
|
ctx.add_rule(PostsByYear(posts_for_tag))
|
||||||
|
});
|
||||||
|
self.tag_and_posts_factory
|
||||||
|
.add_node(ctx, slug.clone(), |ctx| {
|
||||||
|
ctx.add_rule(CreateTagAndPosts {
|
||||||
|
posts: posts_by_year,
|
||||||
|
tag,
|
||||||
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
self.node_factory.all_nodes(ctx)
|
self.posts_by_tag_factory.finalize_nodes(ctx);
|
||||||
|
self.posts_by_year_factory.finalize_nodes(ctx);
|
||||||
|
self.tag_and_posts_factory.all_nodes(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,11 +110,10 @@ struct PostsByTag {
|
|||||||
tag: Tag,
|
tag: Tag,
|
||||||
}
|
}
|
||||||
impl Rule for PostsByTag {
|
impl Rule for PostsByTag {
|
||||||
type Output = TagAndPosts;
|
type Output = Vec<Entry>;
|
||||||
|
|
||||||
fn evaluate(&mut self) -> Self::Output {
|
fn evaluate(&mut self) -> Self::Output {
|
||||||
let entries = self
|
self.posts()
|
||||||
.posts()
|
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|post_input| {
|
.flat_map(|post_input| {
|
||||||
@ -101,16 +128,13 @@ impl Rule for PostsByTag {
|
|||||||
Some(Entry {
|
Some(Entry {
|
||||||
permalink: post.permalink(),
|
permalink: post.permalink(),
|
||||||
title: post.metadata.title.clone(),
|
title: post.metadata.title.clone(),
|
||||||
|
year: post.metadata.date.year(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
TagAndPosts {
|
|
||||||
tag: self.tag.clone(),
|
|
||||||
entries,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_label(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn node_label(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
@ -118,16 +142,26 @@ impl Rule for PostsByTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(InputVisitable)]
|
||||||
|
struct CreateTagAndPosts {
|
||||||
|
posts: Input<PostsYearMap>,
|
||||||
|
#[skip_visit]
|
||||||
|
tag: Tag,
|
||||||
|
}
|
||||||
|
impl Rule for CreateTagAndPosts {
|
||||||
|
type Output = TagAndPosts;
|
||||||
|
fn evaluate(&mut self) -> Self::Output {
|
||||||
|
TagAndPosts {
|
||||||
|
tag: self.tag.clone(),
|
||||||
|
posts: self.posts().clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
struct TagAndPosts {
|
struct TagAndPosts {
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
entries: Vec<Entry>,
|
posts: PostsYearMap,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Serialize)]
|
|
||||||
struct Entry {
|
|
||||||
permalink: String,
|
|
||||||
title: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(InputVisitable)]
|
#[derive(InputVisitable)]
|
||||||
@ -165,7 +199,8 @@ impl DynamicRule for MakeWriteTagPages {
|
|||||||
tag_input.clone(),
|
tag_input.clone(),
|
||||||
|tag_and_posts, ctx| {
|
|tag_and_posts, ctx| {
|
||||||
ctx.insert("tag_name", &tag_and_posts.tag.name);
|
ctx.insert("tag_name", &tag_and_posts.tag.name);
|
||||||
ctx.insert("posts", &tag_and_posts.entries);
|
ctx.insert("years", &tag_and_posts.posts.years());
|
||||||
|
ctx.insert("posts_by_year", &tag_and_posts.posts.0);
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
@ -112,6 +112,7 @@ impl<T, F: Fn(&T, &mut Context) -> ()> BuildTemplateContext<T, F> {
|
|||||||
}
|
}
|
||||||
impl<T: 'static, F: Fn(&T, &mut Context) -> () + 'static> Rule for BuildTemplateContext<T, F> {
|
impl<T: 'static, F: Fn(&T, &mut Context) -> () + 'static> Rule for BuildTemplateContext<T, F> {
|
||||||
type Output = Context;
|
type Output = Context;
|
||||||
|
|
||||||
fn evaluate(&mut self) -> Self::Output {
|
fn evaluate(&mut self) -> Self::Output {
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
(self.func)(&*self.input.value(), &mut context);
|
(self.func)(&*self.input.value(), &mut context);
|
||||||
@ -126,6 +127,14 @@ impl<T: 'static, F: Fn(&T, &mut Context) -> () + 'static> Rule for BuildTemplate
|
|||||||
context.insert("_generated_at", &Local::now());
|
context.insert("_generated_at", &Local::now());
|
||||||
context
|
context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn node_label(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
match self.permalink {
|
||||||
|
TemplatePermalink::Constant(s) => write!(f, "{s}"),
|
||||||
|
TemplatePermalink::ConstantOwned(ref s) => write!(f, "{s}"),
|
||||||
|
TemplatePermalink::Dynamic(ref inp) => write!(f, "{}", *inp.value()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(InputVisitable)]
|
#[derive(InputVisitable)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user