+1
-9
lx/src/archive.rs
+1
-9
lx/src/archive.rs
···
1
1
use chrono::{Datelike, Month};
2
2
use indexmap::{IndexMap, IndexSet};
3
-
use minijinja::Environment;
4
3
use serde::Serialize;
5
4
use thiserror::Error;
6
5
7
-
use crate::{
8
-
page::{Item, PostLink},
9
-
templates::component::Component,
10
-
};
6
+
use crate::page::{Item, PostLink};
11
7
12
8
/// A data structure that maps each post to Y -> M -> D -> posts, preserving the order of
13
9
/// the posts.
···
42
38
43
39
Ok(Archive(year_map))
44
40
}
45
-
}
46
-
47
-
impl<'e> Component for Archive<'e> {
48
-
const VIEW_NAME: &'static str = "archive";
49
41
}
50
42
51
43
#[allow(dead_code)]
+2
-28
lx/src/data/config.rs
+2
-28
lx/src/data/config.rs
···
44
44
pub use serial::NavItem;
45
45
46
46
pub mod serial {
47
-
use std::{collections::HashMap, fmt::Display, sync::Arc};
47
+
use std::{collections::HashMap, fmt::Display};
48
48
49
49
use camino::{Utf8Path, Utf8PathBuf};
50
-
use minijinja::{Environment, State, Value, value::Object};
51
50
use normalize_path::NormalizePath as _;
52
51
use serde::{Deserialize, Serialize};
53
52
use thiserror::Error;
54
53
55
-
use crate::{data::email::Email, templates::component::Component};
54
+
use crate::data::email::Email;
56
55
57
56
#[derive(Serialize, Deserialize, Debug)]
58
57
pub struct Config {
···
117
116
pub enum NavItem {
118
117
Separator,
119
118
Page { title: String, path: String },
120
-
}
121
-
122
-
// NOTE(2025-10-09): this currently never gets hit when accessing via a template
123
-
// invocation that goes through `Config`, because `Config` and `NavItem` both
124
-
// implement `Serialize`, and so by the time the renderer is working with the
125
-
// `Config::nav` data, it is working with it as the *serialized* version of it,
126
-
// which means it never actually has a chance to see the `Component` version of it.
127
-
// In practice, this likely means that I need to get rid of the `Serialize` bound on
128
-
// `Component` and require custom rendering at each site (ugh) or find some other
129
-
// way to express these kinds of relations. _Le sigh_.
130
-
//
131
-
// TODO: also maybe move this elsewhere?
132
-
impl Component for NavItem {
133
-
const VIEW_NAME: &'static str = "nav-item";
134
-
}
135
-
136
-
impl Object for NavItem {
137
-
fn call(
138
-
self: &Arc<Self>,
139
-
state: &State<'_, '_>,
140
-
_args: &[Value],
141
-
) -> Result<Value, minijinja::Error> {
142
-
println!("got here?");
143
-
self.view(state.env()).map(Value::from)
144
-
}
145
119
}
146
120
147
121
#[derive(Error, Debug)]
-27
lx/src/data/item/mod.rs
-27
lx/src/data/item/mod.rs
···
6
6
use camino::{Utf8Path, Utf8PathBuf};
7
7
use chrono::{DateTime, FixedOffset};
8
8
use lx_md::Markdown;
9
-
use minijinja::Environment;
10
9
use serde::{Deserialize, Serialize};
11
10
use slug::slugify;
12
11
use thiserror::Error;
···
15
14
use crate::{
16
15
archive::Archive,
17
16
page::{self, Item},
18
-
templates::component::Component,
19
17
};
20
18
21
19
use self::cascade::Cascade;
···
233
231
}
234
232
}
235
233
236
-
impl Component for Qualifiers {
237
-
const VIEW_NAME: &'static str = "qualifiers";
238
-
239
-
fn view(&self, env: &Environment) -> Result<String, minijinja::Error> {
240
-
env.get_template(&Self::template())?.render(self)
241
-
}
242
-
}
243
-
244
234
#[derive(Debug, Serialize, Deserialize, PartialEq)]
245
235
pub struct Book {
246
236
title: Option<String>,
···
304
294
struct BookView<'a> {
305
295
book: &'a Book,
306
296
archive: Archive<'a>,
307
-
}
308
-
309
-
impl<'a> Component for BookView<'a> {
310
-
const VIEW_NAME: &'static str = "book";
311
-
312
-
fn view(&self, env: &Environment) -> Result<String, minijinja::Error> {
313
-
let rendered_archive = self.archive.view(env)?;
314
-
315
-
let rendered = env
316
-
.get_template(Self::VIEW_NAME)?
317
-
.render(minijinja::context! {
318
-
book => self.book,
319
-
archive => rendered_archive,
320
-
})?;
321
-
322
-
Ok(rendered)
323
-
}
324
297
}
325
298
326
299
#[derive(Debug, Serialize, Deserialize)]
+1
-8
lx/src/data/item/serial.rs
+1
-8
lx/src/data/item/serial.rs
···
11
11
use serde::{Deserialize, Serialize};
12
12
use thiserror::Error;
13
13
14
-
use crate::{
15
-
data::{image::serial::Image, item::nice_list},
16
-
templates::component::Component,
17
-
};
14
+
use crate::data::{image::serial::Image, item::nice_list};
18
15
19
16
#[derive(Deserialize, Debug, Default)]
20
17
pub struct Item {
···
92
89
pub discusses: Vec<String>,
93
90
pub disclosure: Option<String>,
94
91
pub retraction: Option<Retraction>,
95
-
}
96
-
97
-
impl Component for Qualifiers {
98
-
const VIEW_NAME: &'static str = "qualifiers";
99
92
}
100
93
101
94
#[derive(Serialize, Deserialize, Clone, Debug)]
+4
-22
lx/src/page.rs
+4
-22
lx/src/page.rs
···
1
-
use crate::{
2
-
data::{
3
-
config::Config,
4
-
item::{self, Metadata, Slug, cascade::Cascade, serial},
5
-
},
6
-
templates::component::Component,
1
+
use crate::data::{
2
+
config::Config,
3
+
item::{self, Metadata, Slug, cascade::Cascade, serial},
7
4
};
8
5
use camino::{Utf8Path, Utf8PathBuf};
9
6
use chrono::{DateTime, FixedOffset};
10
7
use json_feed::Author;
11
8
use lx_md::{self, Markdown, RenderError, ToRender};
12
-
use minijinja::{Environment, State, Value, context, value::Object};
13
9
use serde::{Deserialize, Serialize};
14
-
use std::{cmp::Ordering, sync::Arc};
10
+
use std::cmp::Ordering;
15
11
use std::{collections::HashMap, fmt, hash::Hash, os::unix::prelude::OsStrExt};
16
12
use thiserror::Error;
17
13
use uuid::Uuid;
···
242
238
slug: &value.page.data.slug,
243
239
}
244
240
}
245
-
}
246
-
247
-
impl Object for PostLink<'_> {
248
-
fn call(
249
-
self: &Arc<Self>,
250
-
state: &State<'_, '_>,
251
-
_args: &[Value],
252
-
) -> Result<Value, minijinja::Error> {
253
-
self.view(state.env()).map(Value::from)
254
-
}
255
-
}
256
-
257
-
impl<'e> Component for PostLink<'e> {
258
-
const VIEW_NAME: &'static str = "post-link";
259
241
}
260
242
261
243
#[derive(Error, Debug)]
-14
lx/src/templates/component.rs
-14
lx/src/templates/component.rs
···
1
-
use minijinja::Environment;
2
-
use serde::Serialize;
3
-
4
-
pub(crate) trait Component: Serialize + Sized {
5
-
const VIEW_NAME: &'static str;
6
-
7
-
fn view(&self, env: &Environment) -> Result<String, minijinja::Error> {
8
-
env.get_template(&Self::template())?.render(self)
9
-
}
10
-
11
-
fn template() -> String {
12
-
format!("components/{}.jinja", Self::VIEW_NAME)
13
-
}
14
-
}
+19
-30
lx/src/templates/functions.rs
+19
-30
lx/src/templates/functions.rs
···
1
1
use std::{fmt, sync::Arc};
2
2
3
3
use minijinja::{
4
-
State, Value, context,
4
+
State, Value,
5
5
value::{Object, Rest, ViaDeserialize},
6
6
};
7
-
use simplelog::debug;
8
7
9
8
use crate::{
10
9
data::{config::Config, image::Image, item::Metadata},
11
-
page::{self, RootedPath},
12
-
templates::component::{self, Component},
10
+
page::RootedPath,
13
11
};
14
12
15
13
pub(crate) fn add_all(env: &mut minijinja::Environment<'_>) {
···
102
100
}
103
101
104
102
/// Data for the `twitter:(label|data)(1|2)` meta tags.
105
-
#[derive(Debug, serde::Serialize)]
103
+
#[derive(Debug, serde::Serialize, serde::Deserialize)]
106
104
enum Label {
107
105
Post {
108
106
tags: Vec<String>,
···
139
137
// here given it’s pretty obviously just me on my own site?
140
138
pub fn label1(&self) -> &str {
141
139
match self {
142
-
Label::Post { .. } => "Author",
140
+
Label::Post { .. } => "Tags",
143
141
Label::Work { .. } => "Instrumentation",
144
142
Label::Custom { label1, .. } => label1.as_str(),
145
143
}
···
172
170
}
173
171
}
174
172
175
-
impl From<Label> for Value {
176
-
fn from(val: Label) -> Self {
177
-
Value::from_object(val)
178
-
}
179
-
}
180
-
181
-
impl Component for Label {
182
-
const VIEW_NAME: &'static str = "twitter-label";
183
-
184
-
fn view(&self, env: &minijinja::Environment) -> Result<String, minijinja::Error> {
185
-
env.get_template(&Self::template())?.render(context! {
186
-
label1 => self.label1(),
187
-
label2 => self.label2(),
188
-
data1 => self.data1(),
189
-
data2 => self.data2(),
190
-
})
191
-
}
192
-
}
193
-
194
173
impl Object for Label {
195
-
fn call(
196
-
self: &Arc<Self>,
197
-
state: &State<'_, '_>,
174
+
fn call_method(
175
+
self: &Arc<Label>,
176
+
_state: &State,
177
+
name: &str,
198
178
_args: &[Value],
199
179
) -> Result<Value, minijinja::Error> {
200
-
self.view(state.env()).map(Value::from)
180
+
match name {
181
+
"label1" => Ok(self.label1().into()),
182
+
"data1" => Ok(self.data1().into()),
183
+
"label2" => Ok(self.label2().into()),
184
+
"data2" => Ok(self.data2().into()),
185
+
_ => Err(minijinja::Error::new(
186
+
minijinja::ErrorKind::UnknownMethod,
187
+
name.to_owned(),
188
+
)),
189
+
}
201
190
}
202
191
}
203
192
204
-
#[derive(Debug, serde::Serialize)]
193
+
#[derive(Debug, serde::Serialize, serde::Deserialize)]
205
194
struct ApproximateLength {
206
195
rounded: u64,
207
196
}