viewy 2.0.1

A web UI toolkit that combine the advantages of a design system and an ui library.
use crate::DefaultModifiers;
use crate::Renderable;
use crate::components::badge::{Badge, BadgeSupport};
use crate::components::icons::IconPack;
use crate::components::*;
use crate::node::Node;

#[derive(Debug, Clone)]
pub enum MenuStyle {
    HorizontalTab,
    HorizontalNav,
    Vertical,
}

//MENU SECTION

#[derive(Debug, Clone)]
pub struct MenuSection {
    node: Node,
    pub label: String,
}

impl MenuSection {
    pub fn new(label: &str) -> Self {
        Self {
            node: Default::default(),
            label: label.to_string(),
        }
    }
}

impl DefaultModifiers for MenuSection {}

impl std::ops::Deref for MenuSection {
    type Target = Node;

    fn deref(&self) -> &Self::Target {
        &self.node
    }
}

impl std::ops::DerefMut for MenuSection {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.node
    }
}

impl Renderable for MenuSection {
    fn render(mut self) -> Node {
        self.add_class("menu-section");
        self.node
            .children
            .push(Text::new(&self.label, TextStyle::Overline).render());
        self.node
    }
}

// MENU ITEM

#[derive(Debug, Clone)]
pub struct MenuItem {
    node: Node,
    pub icon: Option<Box<dyn IconPack>>,
    pub icon_color: Option<String>,
    pub label: String,
    badge: Option<Badge>,
    is_destructive: bool,
    is_selected: bool,
}

impl MenuItem {
    pub fn new(label: &str) -> Self {
        Self {
            node: Default::default(),
            icon: None,
            icon_color: None,
            label: label.to_string(),
            badge: None,
            is_destructive: false,
            is_selected: false,
        }
    }
    /// Set menu's icon
    pub fn icon<T>(&mut self, icon: T) -> &mut Self
    where
        T: 'static + IconPack,
    {
        self.icon = Some(Box::new(icon));
        self
    }

    pub fn icon_color(&mut self, color: &str) -> &mut Self {
        self.icon_color = Some(color.to_string());
        self
    }

    pub fn destructive(&mut self) -> &mut Self {
        self.is_destructive = true;
        self
    }

    pub fn selected(&mut self) -> &mut Self {
        self.is_selected = true;
        self
    }

    pub fn action(&mut self, url: &str) -> &mut Self {
        self.set_attr("href", url).tag("a")
    }
    pub fn attach_to_file_input(&mut self, input_id: &str) -> &mut Self {
        self.set_attr("data-input-file", &format!("file-input-{}", input_id))
    }

    /// Make the `MenuItem` submit specified form
    pub fn attach_to_form(&mut self, form_name: &str) -> &mut Self {
        self.set_attr("form", form_name)
            .set_attr("type", "submit")
            .tag("button")
    }
}

impl DefaultModifiers for MenuItem {}

impl BadgeSupport for MenuItem {
    fn add_badge(&mut self, badge: Badge) {
        self.badge = Some(badge);
    }
}

impl BadgeModifiers for MenuItem {}

impl std::ops::Deref for MenuItem {
    type Target = Node;

    fn deref(&self) -> &Self::Target {
        &self.node
    }
}

impl std::ops::DerefMut for MenuItem {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.node
    }
}

impl Renderable for MenuItem {
    fn render(mut self) -> Node {
        let destructive_class = match self.is_destructive {
            true => "menu-item--destructive",
            false => "menu-item--normal",
        };
        self.add_class("menu-item").add_class(destructive_class);
        if self.is_selected {
            self.add_class("menu-item--selected");
        }
        if let Some(icon) = self.icon {
            self.node.children.push({
                let mut icon = Icon::new(icon).size(16);
                if let Some(icon_color) = &self.icon_color {
                    icon.color(icon_color);
                }
                icon.render()
            });
        }

        self.node
            .children
            .push(Text::new(self.label.as_str(), TextStyle::Label).render());

        if let Some(badge) = self.badge {
            self.node.children.push(badge.render());
        }
        self.node
    }
}

#[derive(Debug, Clone)]
pub struct Menu {
    node: Node,
    pub style: MenuStyle,
}

impl Menu {
    pub fn new(style: MenuStyle) -> Self {
        Self {
            node: Default::default(),
            style,
        }
    }
}

impl std::ops::Deref for Menu {
    type Target = Node;

    fn deref(&self) -> &Self::Target {
        &self.node
    }
}

impl std::ops::DerefMut for Menu {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.node
    }
}
impl Appendable for Menu {}

impl DefaultModifiers for Menu {}

impl Renderable for Menu {
    fn render(mut self) -> Node {
        self.add_class("menu");

        let style = match &self.style {
            MenuStyle::Vertical => "menu--vertical",
            MenuStyle::HorizontalTab => "menu--horizontal-tab",
            MenuStyle::HorizontalNav => "menu--horizontal-nav",
        };
        self.add_class(style);

        self.node
    }
}