use super::{margin::Margin, padding::PaddingWidget}; use crate::ui::UIWidget; use maud::{Markup, Render, html}; #[allow(non_snake_case)] pub fn Scroll(inner: T) -> ScrollWidget { ScrollWidget(Box::new(inner), true, None, None, None, None, false) } pub struct ScrollWidget( Box, bool, Option, Option, Option, Option, bool, ); impl ScrollWidget { pub fn smooth(mut self, value: bool) -> Self { self.1 = value; self } pub fn scroll_margin(mut self, margin: Margin) -> Self { self.2 = Some(margin); self } pub fn scroll_padding(mut self, padding: PaddingWidget) -> Self { self.3 = Some(padding); self } pub fn overscroll(mut self, behaviour: Overscroll) -> Self { self.4 = Some(behaviour); self } pub fn snap(mut self, kind: SnapType) -> Self { self.5 = Some(kind); self } pub fn skip_snap(mut self) -> Self { self.6 = true; self } } impl Render for ScrollWidget { fn render(&self) -> Markup { self.render_with_class("") } } impl UIWidget for ScrollWidget { fn can_inherit(&self) -> bool { true } fn base_class(&self) -> Vec { let mut ret = Vec::new(); if self.1 { ret.push("scroll-smooth".to_string()); } if let Some(margin) = &self.2 { let classes = margin .base_class() .into_iter() .map(|x| format!("scroll-{x}")) .collect::>(); ret.extend_from_slice(&classes); } if let Some(padding) = &self.3 { let classes = padding .base_class() .into_iter() .map(|x| format!("scroll-{x}")) .collect::>(); ret.extend_from_slice(&classes); } if let Some(overscroll) = &self.4 { ret.push(overscroll.to_value().to_string()); } if let Some(snap) = &self.5 { ret.push(snap.to_value().to_string()); } if self.6 { ret.push("snap-normal".to_string()); } else { ret.push("snap-always".to_string()); } ret } 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 Overscroll { Auto, Contain, None, YAuto, YContain, YNone, XAuto, XContain, XNone, } impl Overscroll { pub const fn to_value(&self) -> &str { match self { Overscroll::Auto => "overscroll-auto", Overscroll::Contain => "overscroll-contain", Overscroll::None => "overscroll-none", Overscroll::YAuto => "overscroll-y-auto", Overscroll::YContain => "overscroll-y-contain", Overscroll::YNone => "overscroll-y-none", Overscroll::XAuto => "overscroll-x-auto", Overscroll::XContain => "overscroll-x-contain", Overscroll::XNone => "overscroll-x-none", } } } pub enum SnapType { None, X, Y, Both, Mandatory, Proximity, } impl SnapType { pub const fn to_value(&self) -> &str { match self { SnapType::None => "snap-none", SnapType::X => "snap-x", SnapType::Y => "snap-y", SnapType::Both => "snap-both", SnapType::Mandatory => "snap-mandatory", SnapType::Proximity => "snap-proximity", } } } pub struct SnapAlign(Box, String); impl SnapAlign { #[allow(non_snake_case)] pub fn Start(inner: T) -> Self { Self(Box::new(inner), "snap-start".to_string()) } #[allow(non_snake_case)] pub fn End(inner: T) -> Self { Self(Box::new(inner), "snap-end".to_string()) } #[allow(non_snake_case)] pub fn Center(inner: T) -> Self { Self(Box::new(inner), "snap-center".to_string()) } #[allow(non_snake_case)] pub fn None(inner: T) -> Self { Self(Box::new(inner), "snap-align-none".to_string()) } } impl Render for SnapAlign { fn render(&self) -> Markup { self.render_with_class("") } } impl UIWidget for SnapAlign { 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()) } } } } }