Skip to main content

max / makenotwork

3.9 KB · 91 lines History Blame Raw
1 //! The Askama entry point for a described "delete this blog post" button.
2 //!
3 //! Shape 8's first conversion that did not have to wait for a screen
4 //! (`b279b9eb`), and the second thing the glue-module ruling bought
5 //! (`27d5e5b8`, reasoning in [`super::widgets`]). The same button is written
6 //! twice — `templates/partials/tabs/project_content.html` and
7 //! `templates/partials/tabs/project_blog.html` — over the same route, with the
8 //! same prompt, in two tabs of the same dashboard. Described once, called from
9 //! both.
10 //!
11 //! # What the description says that the markup did not
12 //!
13 //! That the act is destructive, and what to ask before doing it.
14 //! [`Act::confirm`] is that, and `hx-confirm` was it: one of the 50 sites the
15 //! shape exists to move. The difference is where the sentence lives. A prompt
16 //! in an attribute is a fact about one template; a prompt on the act is a fact
17 //! about the call, so a terminal asks y/n and a touch host raises an action
18 //! sheet without either being told about this button.
19 //!
20 //! `Tone::Danger` for the same reason, and it is worth knowing it only started
21 //! working on 2026-08-21: until `35756077` landed the app's unlayered
22 //! `button { }` rule took the tone off every described act, so this would have
23 //! rendered as an ordinary button that claimed to be dangerous. The templates
24 //! said it with `class="danger-text"`, which is the same claim in a spelling no
25 //! other renderer can read.
26 //!
27 //! # Why the row id is a parameter
28 //!
29 //! The answer replaces the row it was pressed in, and `/api/blog/{id}` is a
30 //! plain API route the description layer does not serve — it answers an
31 //! `HX-Trigger` toast and an empty body — so it cannot name what it changed and
32 //! the control has to. See [`Action::replaces`]: this is exactly the case that
33 //! member exists for, rather than the misuse it warns about.
34 //!
35 //! Both templates already give the row a real id (`post-row-{id}`), which is
36 //! what makes these two describable when their neighbours are not. The Remove
37 //! buttons in `partials/link_row.html` and `partials/tag.html` carry
38 //! `hx-target="closest .link-row"` and `hx-target="closest .tag"`, and a
39 //! relative selector is not something [`Action::replaces`] can say; the tag one
40 //! additionally reads `×` and gets its name from `aria-label`, which is
41 //! quasicoherent `aad33ecc`. Both are left hand-written and filed rather than
42 //! approximated.
43
44 use makeover_layout::Tone;
45 use quasi_router::screen::Act;
46 use quasi_router::{Action, Node};
47
48 /// The delete button for one post's row.
49 ///
50 /// `id` is the blog post's, and it names both the route and the row: the two
51 /// are the same fact, so the caller states it once.
52 #[must_use]
53 pub fn html(id: &str) -> String {
54 use quasi_axum::Serves as _;
55
56 let act = Act::new(
57 "Delete",
58 Action::delete(format!("/api/blog/{id}")).replacing(format!("post-row-{id}")),
59 )
60 .tone(Tone::Danger)
61 .confirm("Delete this blog post?");
62
63 quasi_webview::Webview::new().fragment(&Node::Act(act))
64 }
65
66 #[cfg(test)]
67 mod tests {
68 /// The three things the two templates said between them, said once: where
69 /// it goes, what it replaces, and that it is destructive.
70 #[test]
71 fn a_delete_names_its_route_its_row_and_its_prompt() {
72 let html = super::html("42");
73
74 assert!(html.contains(r#"hx-delete="/api/blog/42""#), "{html}");
75 assert!(html.contains(r##"hx-target="#post-row-42""##), "{html}");
76 assert!(
77 html.contains(r#"hx-confirm="Delete this blog post?""#),
78 "{html}"
79 );
80 }
81
82 /// The tone, which is the half that could not survive before `35756077`.
83 /// `danger-text` in a class attribute said this to the stylesheet only.
84 #[test]
85 fn a_delete_says_it_is_dangerous_in_a_word_every_renderer_reads() {
86 let html = super::html("42");
87
88 assert!(html.contains(r#"data-tone="danger""#), "{html}");
89 }
90 }
91