use crate::ui::{UIWidget, color::UIColor}; use maud::{Markup, Render, html}; use super::{ flex::{AlignContent, AlignItems, DivideStyle, DivideWidth, Justify, JustifyItems}, space::ScreenValue, }; #[allow(non_snake_case)] pub fn Grid(inner: T) -> GridWidget { GridWidget(Box::new(inner), vec![], false) } pub struct GridWidget(Box, Vec, bool); impl Render for GridWidget { fn render(&self) -> Markup { self.render_with_class("") } } pub enum GridAmount { _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, None, Subgrid, } impl GridAmount { pub const fn to_value(&self) -> &str { match self { GridAmount::_1 => "1", GridAmount::_2 => "2", GridAmount::_3 => "3", GridAmount::_4 => "4", GridAmount::_5 => "5", GridAmount::_6 => "6", GridAmount::_7 => "7", GridAmount::_8 => "8", GridAmount::_9 => "9", GridAmount::_10 => "10", GridAmount::_11 => "11", GridAmount::_12 => "12", GridAmount::None => "none", GridAmount::Subgrid => "subgrid", } } } impl GridWidget { #[must_use] pub fn columns(mut self, amount: GridAmount) -> Self { self.1.push(format!("grid-cols-{}", amount.to_value())); self } #[must_use] pub fn rows(mut self, amount: GridAmount) -> Self { self.1.push(format!("grid-rows-{}", amount.to_value())); self } #[must_use] pub fn auto_flow(mut self, flow: GridAutoFlow) -> Self { self.1.push(flow.to_value().to_string()); self } #[must_use] pub fn auto_columns(mut self, size: GridAutoSize) -> Self { self.1.push(format!("auto-cols-{}", size.to_value())); self } #[must_use] pub fn auto_rows(mut self, size: GridAutoSize) -> Self { self.1.push(format!("auto-rows-{}", size.to_value())); self } #[must_use] pub fn full_center(mut self) -> Self { self.1.push("items-center".to_owned()); self.1.push("justify-center".to_owned()); self } #[must_use] pub const fn group(mut self) -> Self { self.2 = true; self } #[must_use] pub fn divide_style(mut self, style: DivideStyle) -> Self { self.1.push(style.to_value().to_string()); self } #[must_use] pub fn divide_color(mut self, color: C) -> Self { self.1.push(format!("divide-{}", color.color_class())); self } #[must_use] pub fn divide_x(mut self, width: DivideWidth) -> Self { self.1.push(format!("divide-x-{}", width.to_value())); self } #[must_use] pub fn divide_y(mut self, width: DivideWidth) -> Self { self.1.push(format!("divide-y-{}", width.to_value())); self } #[must_use] pub fn justify_items(mut self, justify: JustifyItems) -> Self { self.1.push(justify.to_value().to_string()); self } #[must_use] pub fn align_content(mut self, align: AlignContent) -> Self { self.1.push(align.to_value().to_string()); self } #[must_use] pub fn align_items(mut self, align: AlignItems) -> Self { self.1.push(align.to_value().to_string()); self } #[must_use] pub fn justify(mut self, value: Justify) -> Self { let class = match value { Justify::Center => "justify-center".to_string(), Justify::Between => "justify-between".to_string(), Justify::Normal => "justify-normal".to_string(), Justify::Start => "justify-start".to_string(), Justify::End => "justify-end".to_string(), Justify::Around => "justify-around".to_string(), Justify::Evenly => "justify-evenly".to_string(), Justify::Stretch => "justify-stretch".to_string(), }; self.1.push(class); self } #[must_use] pub fn items_center(mut self) -> Self { self.1.push("items-center".to_owned()); self } #[must_use] pub fn gap(mut self, amount: ScreenValue) -> Self { self.1.push(format!("gap-{}", amount.to_value())); self } #[must_use] pub fn gap_x(mut self, amount: ScreenValue) -> Self { self.1.push(format!("gap-x-{}", amount.to_value())); self } #[must_use] pub fn gap_y(mut self, amount: ScreenValue) -> Self { self.1.push(format!("gap-y-{}", amount.to_value())); self } } impl UIWidget for GridWidget { fn can_inherit(&self) -> bool { true } fn base_class(&self) -> Vec { let mut res = vec!["grid".to_string()]; res.extend_from_slice(&self.1); res } fn extended_class(&self) -> Vec { let mut c = self.base_class(); c.extend_from_slice(&self.0.extended_class()); c } fn render_with_class(&self, class: &str) -> Markup { if self.0.as_ref().can_inherit() && !self.2 { self.0 .as_ref() .render_with_class(&format!("{} {class}", self.base_class().join(" "))) } else { html! { div class=(format!("{} {class}", self.base_class().join(" "))) { (self.0.as_ref()) } } } } } pub enum GridAutoFlow { Row, Column, Dense, RowDense, ColumnDense, } impl GridAutoFlow { pub const fn to_value(&self) -> &str { match self { GridAutoFlow::Row => "grid-flow-row", GridAutoFlow::Column => "grid-flow-col", GridAutoFlow::Dense => "grid-flow-dense", GridAutoFlow::RowDense => "grid-flow-row-dense", GridAutoFlow::ColumnDense => "grid-flow-col-dense", } } } pub enum GridAutoSize { Auto, Min, Max, Fr, } impl GridAutoSize { pub const fn to_value(&self) -> &str { match self { GridAutoSize::Auto => "auto", GridAutoSize::Min => "min", GridAutoSize::Max => "max", GridAutoSize::Fr => "fr", } } } #[allow(non_snake_case)] pub fn GridElementColumn(inner: T) -> GridElement { GridElement(Box::new(inner), Vec::new(), "col".to_string()) } #[allow(non_snake_case)] pub fn GridElementRow(inner: T) -> GridElement { GridElement(Box::new(inner), Vec::new(), "row".to_string()) } pub struct GridElement(Box, Vec, String); impl GridElement { pub fn auto(mut self) -> Self { self.1.push(format!("{}-auto", self.2)); self } pub fn span(mut self, value: GridElementValue) -> Self { self.1.push(format!("{}-span-{}", self.2, match value { GridElementValue::_1 => "1", GridElementValue::_2 => "2", GridElementValue::_3 => "3", GridElementValue::_4 => "4", GridElementValue::_5 => "5", GridElementValue::_6 => "6", GridElementValue::_7 => "7", GridElementValue::_8 => "8", GridElementValue::_9 => "9", GridElementValue::_10 => "10", GridElementValue::_11 => "11", GridElementValue::_12 => "12", GridElementValue::Auto => "full", })); self } pub fn start(mut self, value: GridElementValue) -> Self { self.1 .push(format!("{}-start-{}", self.2, value.to_value())); self } pub fn end(mut self, value: GridElementValue) -> Self { self.1.push(format!("{}-end-{}", self.2, value.to_value())); self } } impl Render for GridElement { fn render(&self) -> Markup { self.render_with_class("") } } impl UIWidget for GridElement { fn can_inherit(&self) -> bool { true } fn base_class(&self) -> Vec { let mut res = vec!["grid".to_string()]; res.extend_from_slice(&self.1); res } fn extended_class(&self) -> Vec { let mut c = self.base_class(); c.extend_from_slice(&self.0.extended_class()); c } fn render_with_class(&self, class: &str) -> Markup { if self.0.as_ref().can_inherit() { self.0 .as_ref() .render_with_class(&format!("{} {class}", self.base_class().join(" "))) } else { html! { div class=(format!("{} {class}", self.base_class().join(" "))) { (self.0.as_ref()) } } } } } pub enum GridElementValue { _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, Auto, } impl GridElementValue { pub const fn to_value(&self) -> &str { match self { GridElementValue::_1 => "1", GridElementValue::_2 => "2", GridElementValue::_3 => "3", GridElementValue::_4 => "4", GridElementValue::_5 => "5", GridElementValue::_6 => "6", GridElementValue::_7 => "7", GridElementValue::_8 => "8", GridElementValue::_9 => "9", GridElementValue::_10 => "10", GridElementValue::_11 => "11", GridElementValue::_12 => "12", GridElementValue::Auto => "auto", } } } macro_rules! string_class_widget { ($name:ident) => { pub struct $name(Box, String); impl Render for $name { fn render(&self) -> Markup { self.render_with_class("") } } impl UIWidget for $name { fn can_inherit(&self) -> bool { true } fn base_class(&self) -> Vec { vec![self.1.clone()] } fn extended_class(&self) -> Vec { let mut c = self.base_class(); c.extend_from_slice(&self.0.extended_class()); c } fn render_with_class(&self, class: &str) -> Markup { if self.0.as_ref().can_inherit() { self.0 .as_ref() .render_with_class(&format!("{} {class}", self.base_class().join(" "))) } else { html! { div class=(format!("{} {class}", self.base_class().join(" "))) { (self.0.as_ref()) } } } } } }; } macro_rules! constructor { ($name:ident, $class:literal) => { #[allow(non_snake_case)] pub fn $name(inner: T) -> Self { Self(Box::new(inner), $class.to_string()) } }; } string_class_widget!(Columns); impl Columns { constructor!(_1, "columns-1"); constructor!(_2, "columns-2"); constructor!(_3, "columns-3"); constructor!(_4, "columns-4"); constructor!(_5, "columns-5"); constructor!(_6, "columns-6"); constructor!(_7, "columns-7"); constructor!(_8, "columns-8"); constructor!(_9, "columns-9"); constructor!(_10, "columns-10"); constructor!(_11, "columns-11"); constructor!(_12, "columns-12"); constructor!(Auto, "columns-auto"); constructor!(_3XS, "columns-3xs"); constructor!(_2XS, "columns-2xs"); constructor!(XS, "columns-xs"); constructor!(Small, "columns-sm"); constructor!(Medium, "columns-md"); constructor!(Large, "columns-lg"); constructor!(XL, "columns-xl"); constructor!(_2XL, "columns-2xl"); constructor!(_3XL, "columns-3xl"); constructor!(_4XL, "columns-4xl"); constructor!(_5XL, "columns-5xl"); constructor!(_6XL, "columns-6xl"); constructor!(_7XL, "columns-7xl"); }