viewy 2.0.6

A web UI toolkit that combine the advantages of a design system and an ui library.
use crate::engine::Renderable;
use std::collections::{HashMap, HashSet};

#[derive(Debug, Clone)]
pub enum NodeType {
    Normal(String),
    SelfClosing(String),
    Comment(String),
}

#[derive(Debug, Clone)]
pub struct Node {
    pub node_type: NodeType,
    pub text: Option<String>,
    pub children: Vec<Node>,
    pub class_list: HashSet<String>,
    pub node_style: Vec<(String, String)>,
    pub attributes: HashMap<String, String>,
    pub root_nodes: Vec<Node>,
}

impl Default for Node {
    fn default() -> Self {
        let mut class_list = HashSet::new();
        class_list.insert("view".to_string());
        Node {
            node_type: NodeType::Normal("div".to_string()),
            text: None,
            children: vec![],
            class_list,
            node_style: vec![],
            attributes: HashMap::new(),
            root_nodes: vec![],
        }
    }
}

impl Node {
    pub(crate) fn get_root_nodes(&mut self, all_root_nodes: &mut Vec<Node>) {
        all_root_nodes.append(&mut self.root_nodes);
        self.children
            .iter_mut()
            .for_each(|child| child.get_root_nodes(all_root_nodes));
    }

    pub(crate) fn get_html(&self) -> String {
        let classes: Vec<String> = self
            .class_list
            .iter()
            .map(|class_name| format!("{}", class_name))
            .collect();
        let attributes: Vec<String> = self
            .attributes
            .iter()
            .map(|(name, value)| format!("{}=\"{}\"", name, value))
            .collect();
        let style: Vec<String> = self
            .node_style
            .iter()
            .map(|(name, value)| format!("{}: {};", name, value))
            .collect();
        let content: Vec<String> = self.children.iter().map(|child| child.get_html()).collect();
        match self.node_type.clone() {
            NodeType::Normal(tag_name) => format!(
                "<{tag} class=\"{class_list}\" {attributes} style=\"{view_style}\">{children}</{tag}>",
                tag = tag_name,
                class_list = classes.join(" "),
                attributes = attributes.join(" "),
                view_style = style.join(""),
                children = match self.text.clone() {
                    None => content.join(""),
                    Some(text) => text,
                }
            ),
            NodeType::SelfClosing(tag_name) => format!(
                "<{tag} class=\"{class_list}\" {attributes} style=\"{view_style}\" />",
                tag = tag_name,
                class_list = classes.join(" "),
                attributes = attributes.join(" "),
                view_style = style.join("")
            ),
            NodeType::Comment(comment) => format!("<!--{comment}-->", comment = comment),
        }
    }

    pub(crate) fn to_html(mut self) -> String {
        let mut all_root_nodes = vec![];
        self.get_root_nodes(&mut all_root_nodes);
        let root_nodes_html: Vec<String> = all_root_nodes
            .into_iter()
            .map(|root_node| root_node.to_html())
            .collect();
        format!(
            "{view} {root_nodes}",
            view = self.get_html(),
            root_nodes = root_nodes_html.join(""),
        )
    }
}