add screen wrapper

This commit is contained in:
JMARyA 2025-01-17 16:28:56 +01:00
parent 15e70da512
commit 302daacc82
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
4 changed files with 123 additions and 69 deletions

View file

@ -14,6 +14,12 @@ pub async fn index_page(ctx: RequestContext) -> StringResponse {
let content = html!( let content = html!(
h1 { "Hello World!" }; h1 { "Hello World!" };
(
Screen::medium(Hover(Background(Red::_700, Nothing()))).on(
Background(Blue::_700, Text("HELLO!"))
)
)
(Hover( (Hover(
Cursor::NorthEastResize.on( Cursor::NorthEastResize.on(
Padding(Text("").color(&Gray::_400)).x(ScreenValue::_10) Padding(Text("").color(&Gray::_400)).x(ScreenValue::_10)

View file

@ -48,7 +48,9 @@ pub mod prelude {
pub use super::primitives::visibility::Visibility; pub use super::primitives::visibility::Visibility;
pub use super::primitives::width::{MaxWidth, MinWidth, Width}; pub use super::primitives::width::{MaxWidth, MinWidth, Width};
pub use super::primitives::zindex::ZIndex; 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}; use crate::request::{RequestContext, StringResponse};

View file

@ -1,66 +0,0 @@
use maud::{Markup, Render, html};
use crate::ui::UIWidget;
#[allow(non_snake_case)]
pub fn Hover<I: UIWidget + 'static>(inherit: I) -> HoverWrapper {
HoverWrapper(None, Box::new(inherit))
}
pub struct HoverWrapper(Option<Box<dyn UIWidget>>, Box<dyn UIWidget>);
impl HoverWrapper {
fn hovered_class(&self) -> Vec<String> {
self.1
.extended_class()
.into_iter()
.filter(|x| !x.is_empty())
.map(|x| format!("hover:{x}"))
.collect::<Vec<_>>()
}
pub fn on<T: UIWidget + 'static>(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<String> {
self.hovered_class()
}
fn extended_class(&self) -> Vec<String> {
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())
}
}
}
}
}

View file

@ -1,4 +1,116 @@
pub mod hover; use crate::ui::UIWidget;
pub use hover::Hover; use maud::{Markup, Render, html};
macro_rules! wrapper {
($constr:ident, $widgetname:ident, $class:literal) => {
#[allow(non_snake_case)]
pub fn $constr<I: UIWidget + 'static>(inherit: I) -> $widgetname {
$widgetname(None, Box::new(inherit))
}
pub struct $widgetname(Option<Box<dyn UIWidget>>, Box<dyn UIWidget>);
impl $widgetname {
fn wrapped_class(&self) -> Vec<String> {
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::<Vec<_>>()
}
pub fn on<T: UIWidget + 'static>(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<String> {
self.wrapped_class()
}
fn extended_class(&self) -> Vec<String> {
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 : 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<I: UIWidget + 'static>(inherit: I) -> SmallScreenWrapper {
SmallScreen(inherit)
}
pub fn medium<I: UIWidget + 'static>(inherit: I) -> MediumScreenWrapper {
MediumScreen(inherit)
}
pub fn large<I: UIWidget + 'static>(inherit: I) -> LargeScreenWrapper {
LargeScreen(inherit)
}
pub fn xl<I: UIWidget + 'static>(inherit: I) -> XLScreenWrapper {
XLScreen(inherit)
}
pub fn _2xl<I: UIWidget + 'static>(inherit: I) -> _2XLScreenWrapper {
_2XLScreen(inherit)
}
}