ahecha_html/
component.rs

1use axum_extra::routing::TypedPath;
2use http::StatusCode;
3
4use crate::{Children, Element, IntoNode, MaybeRedirect, Node, NodeId};
5
6pub struct LiveView {
7  pub id: String,
8  pub href: String,
9}
10
11impl LiveView {
12  pub fn new<I, T>(id: I, href: T) -> Self
13  where
14    I: ToString,
15    T: TypedPath,
16  {
17    Self {
18      id: id.to_string(),
19      href: href.to_string(),
20    }
21  }
22
23  pub fn view(self, inner: Node) -> Node {
24    Node::Element(
25      Element {
26        attributes: crate::Attributes::default()
27          .set(Some(("id", self.id.to_string())))
28          .set(Some(("href", self.href.to_string()))),
29        children: Children::default().set(inner),
30        name: "live-view",
31      },
32      NodeId::new(),
33    )
34  }
35}
36
37impl From<LiveView> for ComponentType {
38  fn from(item: LiveView) -> Self {
39    ComponentType::LiveView(item)
40  }
41}
42
43pub enum ComponentType {
44  LiveView(LiveView),
45  Component,
46}
47
48impl ComponentType {
49  pub fn view(self, inner: Node) -> Node {
50    match self {
51      ComponentType::LiveView(live_view) => live_view.view(inner),
52      ComponentType::Component => inner,
53    }
54  }
55}
56
57pub trait ComponentError {
58  fn message(&self) -> String {
59    "".to_string()
60  }
61}
62
63pub trait Component {
64  fn status_code(&self) -> StatusCode {
65    StatusCode::OK
66  }
67
68  fn ty(&self) -> ComponentType {
69    ComponentType::Component
70  }
71
72  fn view(self) -> Node;
73}
74
75impl<C> IntoNode for C
76where
77  C: Component,
78{
79  fn into_node(self) -> Node {
80    self.ty().view(self.view())
81  }
82}
83
84impl<C> From<C> for Node
85where
86  C: Component,
87{
88  fn from(item: C) -> Self {
89    item.ty().view(item.view())
90  }
91}
92
93impl<C> Component for Vec<C>
94where
95  C: Component + Clone,
96{
97  fn view(self) -> Node {
98    Node::Fragment(
99      Children {
100        children: self.iter().map(|c| c.clone().into_node()).collect(),
101      },
102      NodeId::new(),
103    )
104  }
105}
106
107impl<C> Component for Option<C>
108where
109  C: Component,
110{
111  fn view(self) -> Node {
112    match self {
113      Some(component) => component.into_node(),
114      None => Node::None,
115    }
116  }
117}
118
119impl<S, E> Component for Result<S, E>
120where
121  S: Component,
122  E: Component,
123{
124  fn view(self) -> Node {
125    match self {
126      Ok(s) => s.into_node(),
127      Err(e) => e.into_node(),
128    }
129  }
130}
131
132impl<C> Component for MaybeRedirect<C>
133where
134  C: Component,
135{
136  fn view(self) -> Node {
137    match self {
138      MaybeRedirect::Redirect(status_code, location) => {
139        Node::Redirect(status_code.clone(), location.clone())
140      }
141      MaybeRedirect::Else(component) => component.into_node(),
142    }
143  }
144}