Misc stuff

This commit is contained in:
Shadowfacts 2025-01-13 00:33:58 -05:00
parent 1e772a97e2
commit 9a13efbd35
7 changed files with 105 additions and 66 deletions

View File

@ -26,6 +26,7 @@
{% endblock %}
<meta property="og:url" content="https://{{ _domain }}{{ _permalink }}">
<meta property="og:site_name" content="Shadowfacts">
<meta name="fediverse:creator" content="@shadowfacts@social.shadowfacts.net">
{% block head %}{% endblock %}

View File

@ -6,10 +6,12 @@
{% block content -%}
<h1>{{ tag_name }} posts</h1>
<h1>Posts tagged &lsquo;{{ tag_name }}&rsquo;</h1>
{% for year in years %}
<h2>{{ year }}</h2>
<ul>
{% for entry in posts %}
{% for entry in posts_by_year[year] %}
<li>
<a href="{{ entry.permalink }}">
{{ entry.title }}
@ -17,5 +19,6 @@
</li>
{% endfor %}
</ul>
{% endfor %}
{%- endblock %}

View File

@ -69,7 +69,7 @@ impl Rule for Entries {
}
#[derive(InputVisitable)]
struct PostsByYear(Input<Vec<Entry>>);
pub struct PostsByYear(pub Input<Vec<Entry>>);
impl Rule for PostsByYear {
type Output = PostsYearMap;
fn evaluate(&mut self) -> Self::Output {
@ -81,11 +81,11 @@ impl Rule for PostsByYear {
}
}
#[derive(PartialEq)]
struct PostsYearMap(HashMap<i32, Vec<Entry>>);
#[derive(PartialEq, Clone)]
pub struct PostsYearMap(pub HashMap<i32, Vec<Entry>>);
impl PostsYearMap {
fn years(&self) -> Vec<i32> {
pub fn years(&self) -> Vec<i32> {
let mut years = self.0.keys().cloned().collect::<Vec<_>>();
years.sort();
years.reverse();
@ -94,8 +94,8 @@ impl PostsYearMap {
}
#[derive(PartialEq, Clone, Serialize)]
struct Entry {
permalink: String,
title: String,
year: i32,
pub struct Entry {
pub permalink: String,
pub title: String,
pub year: i32,
}

View File

@ -161,6 +161,7 @@ impl<'a> Fs for TrackingFs<'a> {
struct ReadFile(#[skip_visit] PathBuf);
impl Rule for ReadFile {
type Output = String;
fn evaluate(&mut self) -> Self::Output {
match std::fs::read(&self.0) {
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())
}
}

View File

@ -3,7 +3,6 @@ use compute_graph::{
NodeId,
builder::GraphBuilder,
input::{DynamicInput, Input, InputVisitable},
node::NodeValue,
rule::{DynamicNodeFactory, DynamicRule, DynamicRuleContext, Rule},
synchronicity::Asynchronous,
};
@ -23,25 +22,22 @@ pub fn make_graph(
) -> Input<()> {
let recents = builder.add_dynamic_rule(RecentPosts::new(posts));
let with_rss_html = builder.add_dynamic_rule(ConvertRecentsToRSSContent::new(recents));
builder.add_rule(RenderRSSFeed(with_rss_html))
}
#[derive(InputVisitable)]
struct RecentPosts {
posts: DynamicInput<ReadPostOutput>,
factory: DynamicNodeFactory<NodeId, ReadPostOutput>,
}
impl RecentPosts {
fn new(posts: DynamicInput<ReadPostOutput>) -> Self {
Self {
posts,
factory: DynamicNodeFactory::new(),
}
Self { posts }
}
}
impl DynamicRule for RecentPosts {
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![];
for post_input in self.posts().inputs.iter() {
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.reverse();
for (post_input, _) in posts.into_iter().take(10) {
self.factory.add_node(ctx, post_input.node_id(), |ctx| {
ctx.add_rule(Identity(post_input))
});
}
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()
posts
.into_iter()
.map(|(post_input, _)| post_input)
.take(10)
.collect()
}
}

View File

@ -1,16 +1,19 @@
use std::collections::HashMap;
use chrono::Datelike;
use compute_graph::{
builder::GraphBuilder,
input::{DynamicInput, Input, InputVisitable},
rule::{DynamicNodeFactory, DynamicRule, Rule},
synchronicity::Asynchronous,
};
use serde::Serialize;
use tera::Context;
use crate::generator::archive::PostsByYear;
use super::{
FileWatcher,
archive::{Entry, PostsYearMap},
posts::{ReadPostOutput, metadata::Tag},
templates::{AddTemplate, BuildTemplateContext, RenderTemplate, Templates},
util::{MapDynamicToVoid, content_path},
@ -39,13 +42,17 @@ pub fn make_graph(
#[derive(InputVisitable)]
struct MakePostsByTags {
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 {
fn new(posts: DynamicInput<ReadPostOutput>) -> Self {
Self {
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 {
self.node_factory.add_node(ctx, slug.clone(), |ctx| {
let tag = Tag {
slug: slug.clone(),
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 { slug, name },
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,
}
impl Rule for PostsByTag {
type Output = TagAndPosts;
type Output = Vec<Entry>;
fn evaluate(&mut self) -> Self::Output {
let entries = self
.posts()
self.posts()
.inputs
.iter()
.flat_map(|post_input| {
@ -101,16 +128,13 @@ impl Rule for PostsByTag {
Some(Entry {
permalink: post.permalink(),
title: post.metadata.title.clone(),
year: post.metadata.date.year(),
})
} else {
None
}
})
.collect();
TagAndPosts {
tag: self.tag.clone(),
entries,
}
.collect()
}
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)]
struct TagAndPosts {
tag: Tag,
entries: Vec<Entry>,
}
#[derive(PartialEq, Clone, Serialize)]
struct Entry {
permalink: String,
title: String,
posts: PostsYearMap,
}
#[derive(InputVisitable)]
@ -165,7 +199,8 @@ impl DynamicRule for MakeWriteTagPages {
tag_input.clone(),
|tag_and_posts, ctx| {
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);
},
))
});

View File

@ -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> {
type Output = Context;
fn evaluate(&mut self) -> Self::Output {
let mut context = Context::new();
(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
}
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)]