feat: migrate /images page to new typed methods

main
Jef Roosens 2025-01-26 15:46:53 +01:00
parent 4e92c02e63
commit b17c2e7df6
No known key found for this signature in database
GPG Key ID: 21FD3D77D56BAF49
7 changed files with 74 additions and 26 deletions

View File

@ -20,7 +20,7 @@ use std::{io::BufWriter, path::PathBuf};
use super::error::AppError;
use crate::{
db::{self, Image, NewImage, Pagination},
template::{Template, View},
template::{List, ListCard, Template, View},
IMG_DIR,
};
@ -72,17 +72,11 @@ async fn get_images(
.await
.unwrap()?;
let mut context = Context::new();
context.insert("images", &images);
let is_final_page = images.len() < page.per_page.try_into().unwrap();
context.insert("is_final_page", &is_final_page);
Ok(Html(
View::Images
.headers(&headers)
.render_ctx(&ctx.tera, &context)?,
))
let list = List::Card
.items("Images", ListCard::Image, images)
.page("/images", page)
.query(filter);
Ok(Html(View::other(list).headers(&headers).render(&ctx.tera)?))
}
async fn get_image_original(

View File

@ -67,7 +67,7 @@ async fn get_plants(
let list = List::Ul
.items("Plants", ListItem::Plant, plants)
.page("/plants", page, None);
.page("/plants", page);
Ok(Html(View::other(list).headers(&headers).render(&ctx.tera)?))
}

View File

@ -1,6 +1,6 @@
use serde::Serialize;
#[derive(Serialize)]
#[derive(Serialize, Clone)]
pub struct Query(pub Vec<(String, String)>);
impl Query {

View File

@ -11,16 +11,22 @@ use super::Template;
#[derive(Clone, Copy)]
pub enum List {
Ul,
Card,
}
pub enum ListItem {
Plant,
}
pub enum ListCard {
Image,
}
impl Template for List {
fn template(&self) -> &'static str {
match self {
List::Ul => "list/ul.html",
List::Card => "list/card.html",
}
}
}
@ -33,6 +39,14 @@ impl Template for ListItem {
}
}
impl Template for ListCard {
fn template(&self) -> &'static str {
match self {
Self::Image => "card/image.html",
}
}
}
impl List {
pub fn items<T: Template, I: Serialize>(
self,
@ -45,7 +59,8 @@ impl List {
heading,
item_tmpl,
items,
next_page_url: None,
next_page: None,
query: None,
}
}
}
@ -55,21 +70,26 @@ pub struct ListWrapper<T: Template, I: Serialize> {
heading: &'static str,
item_tmpl: T,
items: Vec<I>,
next_page_url: Option<String>,
next_page: Option<(&'static str, Pagination)>,
query: Option<Query>,
}
impl<T: Template, I: Serialize> ListWrapper<T, I> {
pub fn page(mut self, url: &'static str, mut page: Pagination, query: Option<Query>) -> Self {
pub fn page(mut self, url: &'static str, mut page: Pagination) -> Self {
if self.items.len() as u32 == page.per_page {
page.page += 1;
let query = if let Some(query) = query {
query.join(page)
} else {
page.to_query()
};
self.next_page = Some((url, page));
}
self.next_page_url = Some(format!("{url}?{}", query.encode()));
self
}
pub fn query(mut self, query: impl ToQuery) -> Self {
if let Some(old_query) = self.query {
self.query = Some(old_query.join(query));
} else {
self.query = Some(query.to_query());
}
self
@ -99,8 +119,15 @@ impl<T: Template, I: Serialize> Template for ListWrapper<T, I> {
ctx.insert("heading", &self.heading);
ctx.insert("items", &items);
if let Some(next_page_url) = &self.next_page_url {
ctx.insert("next_page_url", &next_page_url);
if let Some((url, page)) = &self.next_page {
let query = if let Some(query) = &self.query {
query.clone().join(page.clone())
} else {
page.to_query()
};
let full_url = format!("{url}?{}", query.encode());
ctx.insert("next_page_url", &full_url);
}
self.render_ctx(tera, &ctx)

View File

@ -2,7 +2,7 @@ mod list;
mod update;
mod view;
pub use list::{List, ListItem};
pub use list::{List, ListCard, ListItem};
pub use update::Update;
pub use view::View;

View File

@ -0,0 +1,9 @@
{% import "components/plant.html" as comp_plant %}
<article>
<p>Date taken: {{ item.0.date_taken }}</p>
<p>Note: {{ item.0.note }}</p>
<p>Plant: {{ comp_plant::name(plant=item.1) }}</p>
<a href="/images/{{ item.0.id }}/original" target="_blank">
<img src="/images/{{ item.0.id }}/thumb">
</a>
</article>

View File

@ -0,0 +1,18 @@
<h1>{{ heading }}</h1>
<div id="items">
{% for item in items %}
{{ item | safe }}
{% endfor %}
{% if next_page_url %}
<div
aria-busy="true"
hx-get="{{ next_page_url }}"
hx-select="#items > *"
hx-trigger="revealed"
hx-target="this"
hx-swap="outerHTML">
</div>
{% endif %}
</div>