use maud::{Markup, Render, html}; use crate::ui::UIWidget; use super::Side; #[allow(non_snake_case)] pub fn Position(kind: PositionKind, inner: T) -> Positioned { Positioned { inner: Box::new(inner), kind, inset: None, inset_x: None, inset_y: None, start: None, end: None, top: None, right: None, bottom: None, left: None, } } pub struct Positioned { inner: Box, kind: PositionKind, inset: Option, inset_x: Option, inset_y: Option, start: Option, end: Option, top: Option, right: Option, bottom: Option, left: Option, } impl Positioned { pub fn inset(mut self, value: i64) -> Self { self.inset = Some(value); self } pub fn inset_x(mut self, value: i64) -> Self { self.inset_x = Some(value); self } pub fn inset_y(mut self, value: i64) -> Self { self.inset_y = Some(value); self } pub fn start(mut self, value: i64) -> Self { self.start = Some(value); self } pub fn end(mut self, value: i64) -> Self { self.end = Some(value); self } pub fn top(mut self, value: i64) -> Self { self.top = Some(value); self } pub fn right(mut self, value: i64) -> Self { self.right = Some(value); self } pub fn bottom(mut self, value: i64) -> Self { self.bottom = Some(value); self } pub fn left(mut self, value: i64) -> Self { self.left = Some(value); self } } impl Render for Positioned { fn render(&self) -> Markup { self.render_with_class("") } } impl UIWidget for Positioned { fn can_inherit(&self) -> bool { true } fn base_class(&self) -> Vec { let mut ret = vec![self.kind.to_value().to_string()]; if let Some(inset) = &self.inset { if inset.is_negative() { ret.push(format!("-inset-[{inset}px]")); } else { ret.push(format!("inset-[{inset}px]")); } } if let Some(inset) = &self.inset_x { if inset.is_negative() { ret.push(format!("-inset-x-[{inset}px]")); } else { ret.push(format!("inset-x-[{inset}px]")); } } if let Some(inset) = &self.inset_y { if inset.is_negative() { ret.push(format!("-inset-y-[{inset}px]")); } else { ret.push(format!("inset-y-[{inset}px]")); } } if let Some(start) = &self.start { if start.is_negative() { ret.push(format!("-start-[{start}px]")); } else { ret.push(format!("start-[{start}px]")); } } if let Some(end) = &self.end { if end.is_negative() { ret.push(format!("-end-[{end}px]")); } else { ret.push(format!("end-[{end}px]")); } } if let Some(value) = &self.top { if value.is_negative() { ret.push(format!("-top-[{value}px]")); } else { ret.push(format!("top-[{value}px]")); } } if let Some(value) = &self.right { if value.is_negative() { ret.push(format!("-right-[{value}px]")); } else { ret.push(format!("right-[{value}px]")); } } if let Some(value) = &self.bottom { if value.is_negative() { ret.push(format!("-bottom-[{value}px]")); } else { ret.push(format!("bottom-[{value}px]")); } } if let Some(value) = &self.left { if value.is_negative() { ret.push(format!("-left-[{value}px]")); } else { ret.push(format!("left-[{value}px]")); } } ret } fn extended_class(&self) -> Vec { let mut c = self.base_class(); c.extend_from_slice(&self.inner.extended_class()); c } fn render_with_class(&self, class: &str) -> Markup { if self.inner.as_ref().can_inherit() { self.inner .as_ref() .render_with_class(&format!("{} {class}", self.base_class().join(" "))) } else { html! { div class=(format!("{} {class}", self.base_class().join(" "))) { (self.inner.as_ref()) } } } } } pub enum PositionKind { Static, Fixed, Absolute, Relative, Sticky, } impl PositionKind { pub const fn to_value(&self) -> &str { match self { PositionKind::Static => "static", PositionKind::Fixed => "fixed", PositionKind::Absolute => "absolute", PositionKind::Relative => "relative", PositionKind::Sticky => "sticky", } } } #[allow(non_snake_case)] pub fn ObjectPosition(side: Side, inner: T) -> ObjectPositioned { ObjectPositioned { inner: Box::new(inner), side, } } pub struct ObjectPositioned { inner: Box, side: Side, } impl Render for ObjectPositioned { fn render(&self) -> Markup { self.render_with_class("") } } impl UIWidget for ObjectPositioned { fn can_inherit(&self) -> bool { true } fn base_class(&self) -> Vec { vec![ match self.side { Side::Start => "object-top", Side::End => "object-bottom", Side::Top => "object-top", Side::Right => "object-right", Side::Bottom => "object-bottom", Side::Left => "object-left", Side::StartStart => "object-left-top", Side::StartEnd => "object-right-top", Side::EndEnd => "object-right-bottom", Side::EndStart => "object-left-bottom", Side::TopLeft => "object-left-top", Side::TopRight => "object-right-top", Side::BottomRight => "object-right-bottom", Side::BottomLeft => "object-left-bottom", Side::Center => "object-center", } .to_string(), ] } fn extended_class(&self) -> Vec { let mut c = self.base_class(); c.extend_from_slice(&self.inner.extended_class()); c } fn render_with_class(&self, class: &str) -> Markup { if self.inner.as_ref().can_inherit() { self.inner .as_ref() .render_with_class(&format!("{} {class}", self.base_class().join(" "))) } else { html! { div class=(format!("{} {class}", self.base_class().join(" "))) { (self.inner.as_ref()) } } } } } pub enum Resize { None, Y, X, Both, } impl Resize { pub const fn to_value(&self) -> &str { match self { Resize::None => "resize-none", Resize::Y => "resize-y", Resize::X => "resize-x", Resize::Both => "resize", } } } #[allow(non_snake_case)] pub fn Resizeable(mode: Resize, inner: T) -> ResizeableWidget { ResizeableWidget(Box::new(inner), mode) } pub struct ResizeableWidget(Box, Resize); impl Render for ResizeableWidget { fn render(&self) -> Markup { self.render_with_class("") } } impl UIWidget for ResizeableWidget { fn can_inherit(&self) -> bool { false } 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()) } } } } }