summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAshelyn Rose <git@ashen.earth>2025-04-26 21:55:30 -0600
committerAshelyn Rose <git@ashen.earth>2025-04-26 21:55:30 -0600
commit864e058f009eb0416d86e9461726d3f97e956df9 (patch)
tree4bdd2e0c290df82601726a976f09ba87bb52db3a /src
parent57f68899cd2200568c53201c6fd1ced85b613a3b (diff)
allow doctype HEAD main
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs2
-rw-r--r--src/render.rs60
2 files changed, 51 insertions, 11 deletions
diff --git a/src/lib.rs b/src/lib.rs
index c760338..5b3a634 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,6 @@
 mod render;
 
-pub use render::{RenderNode, Component};
+pub use render::{RenderNode, Component, IntoRender, DoctypeElem};
 pub use morgana_proc::morx;
 
 pub async fn render_tree(parent_node: RenderNode) -> String {
diff --git a/src/render.rs b/src/render.rs
index 8addbdb..6ae948b 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -7,7 +7,13 @@ pub trait Component {
     fn render(self: Box<Self>) -> RenderNode;
 }
 
+pub enum DoctypeElem {
+    Word(&'static str),
+    String(&'static str),
+}
+
 pub enum RenderNode {
+    Doctype(Vec<DoctypeElem>),
     Suspense {
         fallback: Box<RenderNode>,
         children: Pin<Box<dyn Future<Output = Vec<RenderNode>>>>
@@ -30,19 +36,29 @@ pub enum RenderNode {
 impl RenderNode {
     pub(crate) fn render_to_string(self) -> Pin<Box<dyn Future<Output = String>>> {
         match self {
+            RenderNode::Doctype(elements) => {
+                let strings = elements.iter().map(|elem| match elem {
+                    DoctypeElem::Word(word) => word.to_string(),
+                    DoctypeElem::String(string) => format!("\"{}\"", string),
+                }).collect::<Vec<_>>().join(" ").clone();
+
+                Box::pin(async move {
+                    format!("<!doctype {}>", strings)
+                })
+            },
             RenderNode::Component(component) => {
                 let result_root = component.render();
-                Box::pin((async move || {
+                Box::pin(async move {
                         result_root.render_to_string().await
-                })())
+                })
             },
 
             RenderNode::Suspense {fallback: _, children} => {
-                Box::pin((async move || {
+                Box::pin(async move {
                     join_all(children.await.into_iter()
                         .map(|child| child.render_to_string())).await
                         .join("")
-                })())
+                })
             },
 
             RenderNode::Element { name, attributes, children } => {
@@ -50,25 +66,49 @@ impl RenderNode {
                     .map(|(key, value)| format!(" {key}=\"{value}\""))
                     .collect::<Vec<_>>().join("");
 
-                Box::pin((async move || {
+                Box::pin(async move {
                     let rendered_children = join_all(children.into_iter()
                         .map(|child| child.render_to_string())
                         .collect::<Vec<_>>()).await.join("");
 
                     format!("<{name}{text_attributes}>{rendered_children}</{name}>")
 
-                })())
+                })
             },
             RenderNode::Fragment { children } => {
-                Box::pin((async move || {
+                Box::pin(async move {
                     join_all(children.into_iter()
                         .map(|child| child.render_to_string())).await
                         .join("")
-                })())
+                })
             }
 
-            RenderNode::TextNode { content } => Box::pin((async move || content)()),
-            RenderNode::Null => Box::pin((async move || "".to_string())()),
+            RenderNode::TextNode { content } => Box::pin(async move { content }),
+            RenderNode::Null => Box::pin(async move { "".to_string() }),
+        }
+    }
+}
+
+pub trait IntoRender {
+    fn into_render(self) -> Vec<RenderNode>;
+}
+
+macro_rules! impl_str {
+    ($t:ty) => {
+        impl IntoRender for $t {
+            fn into_render(self) -> Vec<RenderNode> {
+                vec![RenderNode::TextNode { content: String::from(self) }]
+            }
         }
+    };
+}
+
+impl_str!(String);
+impl_str!(&str);
+impl_str!(std::borrow::Cow<'_,str>);
+
+impl IntoRender for Vec<RenderNode> {
+    fn into_render(self) -> Vec<RenderNode> {
+        self
     }
 }