Rust library to generate static websites

fix(assets): Use a newtype for Image so that we can implement traits on it (#58)

authored by

Erika and committed by
GitHub
d69679ae c149d758

+60 -11
+5
.sampo/changesets/cantankerous-queen-aurelien.md
··· 1 + --- 2 + maudit: patch 3 + --- 4 + 5 + Return a newtype around a String when using `Image.render()` so that images can be used directly in supported templating languages
+1 -1
crates/maudit/src/assets.rs
··· 10 10 mod script; 11 11 mod style; 12 12 mod tailwind; 13 - pub use image::{Image, ImageFormat, ImageOptions, ImagePlaceholder, RenderWithAlt}; 13 + pub use image::{Image, ImageFormat, ImageOptions, ImagePlaceholder, RenderWithAlt, RenderedImage}; 14 14 pub use script::Script; 15 15 pub use style::{Style, StyleOptions}; 16 16 pub use tailwind::TailwindPlugin;
+41 -5
crates/maudit/src/assets/image.rs
··· 1 + use std::fmt::Display; 1 2 use std::hash::Hash; 2 3 use std::{path::PathBuf, sync::OnceLock, time::Instant}; 3 4 ··· 128 129 get_placeholder(&self.path) 129 130 } 130 131 132 + // Get the dimensions of an image. Note that at this time, unsupported file formats such as SVGs will return (0, 0). 131 133 pub fn dimensions(&self) -> (u32, u32) { 132 134 image_dimensions(&self.path).unwrap_or((0, 0)) 133 135 } ··· 435 437 436 438 /// Trait to render an image with an alt text. 437 439 pub trait RenderWithAlt { 438 - fn render(&self, alt: &str) -> String; 440 + /// Render the image as an HTML `<img>` tag with the given alt text. 441 + fn render(&self, alt: &str) -> RenderedImage; 442 + } 443 + 444 + /// Newtype around a String representing a rendered image HTML tag. 445 + #[derive(Clone, Debug, PartialEq, Eq)] 446 + pub struct RenderedImage(String); 447 + 448 + impl From<String> for RenderedImage { 449 + fn from(value: String) -> Self { 450 + RenderedImage(value) 451 + } 452 + } 453 + 454 + impl Display for RenderedImage { 455 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 456 + write!(f, "{}", self.0) 457 + } 439 458 } 440 459 441 460 impl RenderWithAlt for Image { 442 - fn render(&self, alt: &str) -> String { 461 + fn render(&self, alt: &str) -> RenderedImage { 443 462 let (width, height) = self.dimensions(); 444 463 464 + // HACK: Only include width and height attributes if they are greater than 0 465 + // This is to workaround the fact that some unsupported image formats by `image` will return (0, 0) 466 + let width_attr = if width > 0 { 467 + format!(r#" width="{width}""#) 468 + } else { 469 + String::new() 470 + }; 471 + 472 + let height_attr = if height > 0 { 473 + format!(r#" height="{height}""#) 474 + } else { 475 + String::new() 476 + }; 477 + 445 478 format!( 446 - r#"<img src="{}" width="{}" height="{}" loading="lazy" decoding="async" alt="{}"/>"#, 447 - self.url, width, height, alt 448 - ) 479 + r#"<img src="{src}"{width_attr}{height_attr} loading="lazy" decoding="async" alt="{alt}"/>"#, 480 + src = self.url, 481 + width_attr = width_attr, 482 + height_attr = height_attr, 483 + alt = alt 484 + ).into() 449 485 } 450 486 }
+8 -2
crates/maudit/src/templating/maud_ext.rs
··· 1 - use maud::{Markup, Render, html}; 1 + use maud::{Markup, PreEscaped, Render, html}; 2 2 3 3 use crate::{ 4 4 GENERATOR, 5 - assets::{Asset, Script, Style}, 5 + assets::{Asset, RenderedImage, Script, Style}, 6 6 route::RenderResult, 7 7 }; 8 8 ··· 19 19 html! { 20 20 script src=(self.url()) type="module" {} 21 21 } 22 + } 23 + } 24 + 25 + impl Render for RenderedImage { 26 + fn render(&self) -> Markup { 27 + PreEscaped(self.to_string()) 22 28 } 23 29 } 24 30
+5 -3
website/content/docs/templating.md
··· 28 28 } 29 29 ``` 30 30 31 - Maudit implements the `Render` trait for scripts and styles, allowing one to use them directly in Maud templates. 31 + Maudit implements the `Render` trait for images, scripts and styles, allowing one to use them directly in Maud templates. 32 32 33 33 ```rs 34 34 use maud::{html, Markup}; ··· 40 40 impl Route for Index { 41 41 fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 42 42 let style = ctx.add_style("style.css"); 43 + let image = ctx.add_image("logo.png"); 43 44 44 45 html! { 45 46 (style) // Will render to a <link> tag for the CSS file 47 + (image.render("The logo of my product")) // Will render to an <img> tag for the image 46 48 } 47 49 } 48 50 } ··· 55 57 maud = "0.27" 56 58 ``` 57 59 58 - The `maud` feature is enabled by default. If you have disabled default features, you can enable it manually: 60 + The `maud` feature is enabled by default. If you have disabled default features, you can enable it manually by editing your `Cargo.toml`: 59 61 60 62 ```toml 61 - maudit = { version = "0.6", features = ["maud"] } 63 + maudit = { version = "...", features = ["maud"] } 62 64 ```