use crate::ui::UIWidget; use maud::{Markup, Render, html}; 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()) } }; } pub enum BreakValue { Auto, Avoid, All, AvoidPage, Page, Left, Right, Column, } impl BreakValue { pub const fn to_value(&self) -> &str { match self { BreakValue::Auto => "auto", BreakValue::Avoid => "avoid", BreakValue::All => "all", BreakValue::AvoidPage => "break-page", BreakValue::Page => "page", BreakValue::Left => "left", BreakValue::Right => "right", BreakValue::Column => "column", } } } #[allow(non_snake_case)] pub fn BreakAfter(value: BreakValue, inner: T) -> BreakWidget { BreakWidget(Box::new(inner), false, value) } #[allow(non_snake_case)] pub fn BreakBefore(value: BreakValue, inner: T) -> BreakWidget { BreakWidget(Box::new(inner), true, value) } pub struct BreakWidget(Box, bool, BreakValue); impl Render for BreakWidget { fn render(&self) -> Markup { self.render_with_class("") } } impl UIWidget for BreakWidget { fn can_inherit(&self) -> bool { true } fn base_class(&self) -> Vec { if self.1 { vec![format!("break-before-{}", self.2.to_value())] } else { vec![format!("break-after-{}", self.2.to_value())] } } 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 BreakInsideValue { Auto, Avoid, AvoidPage, AvoidColumn, } impl BreakInsideValue { pub const fn to_value(&self) -> &str { match self { BreakInsideValue::Auto => "break-inside-auto", BreakInsideValue::Avoid => "break-inside-avoid", BreakInsideValue::AvoidPage => "break-inside-avoid-page", BreakInsideValue::AvoidColumn => "break-inside-avoid-column", } } } #[allow(non_snake_case)] pub fn BreakInside(value: BreakValue, inner: T) -> BreakWidget { BreakWidget(Box::new(inner), true, value) } pub struct BreakInsideWidget(Box, BreakValue); impl Render for BreakInsideWidget { fn render(&self) -> Markup { self.render_with_class("") } } impl UIWidget for BreakInsideWidget { fn can_inherit(&self) -> bool { true } fn base_class(&self) -> Vec { vec![self.1.to_value().to_string()] } 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()) } } } } } string_class_widget!(BoxDecorationBreak); impl BoxDecorationBreak { constructor!(Clone, "box-decoration-clone"); constructor!(Slice, "box-decoration-slice"); } string_class_widget!(BoxSizing); impl BoxSizing { constructor!(Border, "box-border"); constructor!(Content, "box-content"); } string_class_widget!(Display); impl Display { constructor!(Block, "block"); constructor!(InlineBlock, "inline-block"); constructor!(Inline, "inline"); constructor!(Flex, "flex"); constructor!(InlineFlex, "inline-flex"); constructor!(Table, "table"); constructor!(InlineTable, "inline-table"); constructor!(TableCaption, "table-caption"); constructor!(TableCell, "table-cell"); constructor!(TableColumn, "table-column"); constructor!(TableColumnGroup, "table-column-group"); constructor!(TableFooterGroup, "table-footer-group"); constructor!(TableHeaderGroup, "table-header-group"); constructor!(TableRowGroup, "table-row-group"); constructor!(TableRow, "table-row"); constructor!(FlowRoot, "flow-root"); constructor!(Grid, "grid"); constructor!(InlineGrid, "inline-grid"); constructor!(Contents, "contents"); constructor!(ListItem, "list-item"); constructor!(Hidden, "hidden"); } string_class_widget!(Float); impl Float { constructor!(Start, "float-start"); constructor!(End, "float-end"); constructor!(Left, "float-left"); constructor!(Right, "float-right"); constructor!(None, "float-none"); } string_class_widget!(Clear); impl Clear { constructor!(Start, "clear-start"); constructor!(End, "clear-end"); constructor!(Left, "clear-left"); constructor!(Right, "clear-right"); constructor!(Both, "clear-both"); constructor!(None, "clear-none"); } string_class_widget!(ObjectFit); impl ObjectFit { constructor!(Contain, "object-contain"); constructor!(Cover, "object-cover"); constructor!(Fill, "object-fill"); constructor!(None, "object-none"); constructor!(ScaleDown, "object-scale-down"); } string_class_widget!(Overflow); impl Overflow { constructor!(Auto, "overflow-auto"); constructor!(Hidden, "overflow-hidden"); constructor!(Clip, "overflow-clip"); constructor!(Visible, "overflow-visible"); constructor!(Scroll, "overflow-scroll"); constructor!(XAuto, "overflow-x-auto"); constructor!(YAuto, "overflow-y-auto"); constructor!(XHidden, "overflow-x-hidden"); constructor!(YHidden, "overflow-y-hidden"); constructor!(XClip, "overflow-x-clip"); constructor!(YClip, "overflow-y-clip"); constructor!(XVisible, "overflow-x-visible"); constructor!(YVisible, "overflow-y-visible"); constructor!(XScroll, "overflow-x-scroll"); constructor!(YScroll, "overflow-y-scroll"); }