From 302daacc822b554c1daacacaf0934701eb06df0e Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 17 Jan 2025 16:28:56 +0100 Subject: [PATCH] add screen wrapper --- examples/ui.rs | 6 +++ src/ui/mod.rs | 4 +- src/ui/wrapper/hover.rs | 66 ----------------------- src/ui/wrapper/mod.rs | 116 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 123 insertions(+), 69 deletions(-) delete mode 100644 src/ui/wrapper/hover.rs diff --git a/examples/ui.rs b/examples/ui.rs index e52b8db..b2256f7 100644 --- a/examples/ui.rs +++ b/examples/ui.rs @@ -14,6 +14,12 @@ pub async fn index_page(ctx: RequestContext) -> StringResponse { let content = html!( h1 { "Hello World!" }; + ( + Screen::medium(Hover(Background(Red::_700, Nothing()))).on( + Background(Blue::_700, Text("HELLO!")) + ) + ) + (Hover( Cursor::NorthEastResize.on( Padding(Text("").color(&Gray::_400)).x(ScreenValue::_10) diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 280dfa5..4812097 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -48,7 +48,9 @@ pub mod prelude { pub use super::primitives::visibility::Visibility; pub use super::primitives::width::{MaxWidth, MinWidth, Width}; pub use super::primitives::zindex::ZIndex; - pub use super::wrapper::Hover; + pub use super::wrapper::{ + _2XLScreen, Hover, LargeScreen, MediumScreen, Screen, SmallScreen, XLScreen, + }; } use crate::request::{RequestContext, StringResponse}; diff --git a/src/ui/wrapper/hover.rs b/src/ui/wrapper/hover.rs deleted file mode 100644 index b6d069f..0000000 --- a/src/ui/wrapper/hover.rs +++ /dev/null @@ -1,66 +0,0 @@ -use maud::{Markup, Render, html}; - -use crate::ui::UIWidget; - -#[allow(non_snake_case)] -pub fn Hover(inherit: I) -> HoverWrapper { - HoverWrapper(None, Box::new(inherit)) -} - -pub struct HoverWrapper(Option>, Box); - -impl HoverWrapper { - fn hovered_class(&self) -> Vec { - self.1 - .extended_class() - .into_iter() - .filter(|x| !x.is_empty()) - .map(|x| format!("hover:{x}")) - .collect::>() - } - - pub fn on(mut self, inner: T) -> Self { - self.0 = Some(Box::new(inner)); - self - } -} - -impl Render for HoverWrapper { - fn render(&self) -> Markup { - self.render_with_class("") - } -} - -impl UIWidget for HoverWrapper { - fn can_inherit(&self) -> bool { - true - } - - fn base_class(&self) -> Vec { - self.hovered_class() - } - - fn extended_class(&self) -> Vec { - let mut ret = self.base_class(); - if let Some(inner) = &self.0 { - ret.extend_from_slice(&inner.extended_class()); - } - - ret - } - - fn render_with_class(&self, class: &str) -> Markup { - if self.0.as_ref().unwrap().can_inherit() { - self.0 - .as_ref() - .unwrap() - .render_with_class(&format!("{} {class}", self.hovered_class().join(" "))) - } else { - html! { - div class=(format!("{} {class}", self.hovered_class().join(" "))) { - (self.0.as_ref().unwrap()) - } - } - } - } -} diff --git a/src/ui/wrapper/mod.rs b/src/ui/wrapper/mod.rs index b1312e7..4fac146 100644 --- a/src/ui/wrapper/mod.rs +++ b/src/ui/wrapper/mod.rs @@ -1,4 +1,116 @@ -pub mod hover; -pub use hover::Hover; +use crate::ui::UIWidget; +use maud::{Markup, Render, html}; + +macro_rules! wrapper { + ($constr:ident, $widgetname:ident, $class:literal) => { + #[allow(non_snake_case)] + pub fn $constr(inherit: I) -> $widgetname { + $widgetname(None, Box::new(inherit)) + } + + pub struct $widgetname(Option>, Box); + + impl $widgetname { + fn wrapped_class(&self) -> Vec { + self.1 + .extended_class() + .into_iter() + .filter(|x| !x.is_empty()) + .map(|x| { + let mut s = $class.to_string(); + s.push_str(":"); + s.push_str(&x); + s + }) + .collect::>() + } + + pub fn on(mut self, inner: T) -> Self { + self.0 = Some(Box::new(inner)); + self + } + } + + impl Render for $widgetname { + fn render(&self) -> Markup { + self.render_with_class("") + } + } + + impl UIWidget for $widgetname { + fn can_inherit(&self) -> bool { + true + } + + fn base_class(&self) -> Vec { + self.wrapped_class() + } + + fn extended_class(&self) -> Vec { + let mut ret = self.base_class(); + if let Some(inner) = &self.0 { + ret.extend_from_slice(&inner.extended_class()); + } + + ret + } + + fn render_with_class(&self, class: &str) -> Markup { + if self.0.as_ref().unwrap().can_inherit() { + self.0 + .as_ref() + .unwrap() + .render_with_class(&format!("{} {class}", self.wrapped_class().join(" "))) + } else { + html! { + div class=(format!("{} {class}", self.wrapped_class().join(" "))) { + (self.0.as_ref().unwrap()) + } + } + } + } + } + }; +} + +wrapper!(Hover, HoverWrapper, "hover"); + +wrapper!(SmallScreen, SmallScreenWrapper, "sm"); +wrapper!(MediumScreen, MediumScreenWrapper, "md"); +wrapper!(LargeScreen, LargeScreenWrapper, "lg"); +wrapper!(XLScreen, XLScreenWrapper, "xl"); +wrapper!(_2XLScreen, _2XLScreenWrapper, "2xl"); // TODO : responsive media + +// TODO : arbitrary values "min-[320px]:text-center max-[600px]:bg-sky-300" + +#[allow(non_snake_case)] +pub mod Screen { + use crate::ui::UIWidget; + + use super::{ + _2XLScreen, _2XLScreenWrapper, LargeScreen, LargeScreenWrapper, MediumScreen, + MediumScreenWrapper, SmallScreen, SmallScreenWrapper, XLScreen, XLScreenWrapper, + }; + + pub fn small(inherit: I) -> SmallScreenWrapper { + SmallScreen(inherit) + } + + pub fn medium(inherit: I) -> MediumScreenWrapper { + MediumScreen(inherit) + } + + pub fn large(inherit: I) -> LargeScreenWrapper { + LargeScreen(inherit) + } + + pub fn xl(inherit: I) -> XLScreenWrapper { + XLScreen(inherit) + } + + pub fn _2xl(inherit: I) -> _2XLScreenWrapper { + _2XLScreen(inherit) + } +}