Skip to main content

max / makenotwork

3.2 KB · 86 lines History Blame Raw
1 //! The Askama entry point for `quasi_basics::carousel`.
2 //!
3 //! The widget left for `quasi-basics` once three real pages had proved it, and
4 //! this is the part that stayed: glue between a template's own frame type and
5 //! the widget's. Called from `partials/carousel.html`, so all three call sites
6 //! keep the macro they already have.
7 //!
8 //! Why the island wraps the region rather than being it: a custom element is
9 //! what the browser re-upgrades after an htmx swap, which is the whole reason
10 //! islands are custom elements, and the description emits a plain `<div>`
11 //! because it has no idea this host prefixes its tags with `mnw-`. The template
12 //! puts one around the other and both halves stay honest.
13
14 use quasi_basics::Frame;
15 use quasi_router::Node;
16
17 /// The widget, for a screen that owns its whole document.
18 ///
19 /// [`html`] is the Askama half and this is the described half. Both come out of
20 /// `quasi_basics::carousel`, so the project page's gallery and the three
21 /// templates that still call the macro cannot be two different carousels.
22 #[must_use]
23 pub fn region(id: &str, items: &[crate::templates::CarouselFrame]) -> Node {
24 Node::Region(quasi_basics::carousel(
25 id,
26 items.iter().map(|frame| {
27 let mut built = Frame::new(&frame.image, &frame.alt);
28 if let Some((w, h)) = frame.intrinsic {
29 built = built.intrinsic(w, h);
30 }
31 match &frame.caption {
32 Some(caption) => built.caption(caption),
33 None => built,
34 }
35 }),
36 ))
37 }
38
39 /// The markup, for an Askama template to drop in.
40 #[must_use]
41 pub fn html(id: &str, items: &[crate::templates::CarouselFrame]) -> String {
42 use quasi_axum::Serves as _;
43
44 let node = region(id, items);
45
46 // No shell: this is a fragment landing inside a document Askama already
47 // built, which is exactly what `fragment` is for.
48 quasi_webview::Webview::new().fragment(&node)
49 }
50
51 #[cfg(test)]
52 mod tests {
53 use crate::templates::CarouselFrame;
54
55 /// What the widget guarantees is `quasi-basics`' to test, and it does.
56 /// What is MNW's is that this conversion loses nothing on the way through,
57 /// because it is the one place a template's frame becomes a widget's.
58 #[test]
59 fn a_template_frame_arrives_whole() {
60 let html = super::html(
61 "landing-shots",
62 &[
63 CarouselFrame {
64 image: "/a.png".into(),
65 alt: "The library, mid-import".into(),
66 caption: Some("Library".into()),
67 intrinsic: Some((5120, 3412)),
68 },
69 CarouselFrame {
70 image: "/b.png".into(),
71 alt: "A project page".into(),
72 caption: None,
73 intrinsic: None,
74 },
75 ],
76 );
77
78 assert!(html.contains(r#"data-widget="carousel""#), "{html}");
79 assert!(html.contains(r#"id="landing-shots""#), "{html}");
80 assert!(html.contains(r#"alt="The library, mid-import""#), "{html}");
81 assert!(html.contains("Library</figcaption>"), "{html}");
82 assert!(html.contains(r#"width="5120" height="3412""#), "{html}");
83 assert!(html.contains("/b.png"), "{html}");
84 }
85 }
86