use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Breakpoint {
Sm,
Md,
Lg,
Xl,
Xxl,
}
impl Breakpoint {
pub fn min_width(self) -> f32 {
match self {
Breakpoint::Sm => 640.0,
Breakpoint::Md => 768.0,
Breakpoint::Lg => 1024.0,
Breakpoint::Xl => 1280.0,
Breakpoint::Xxl => 1536.0,
}
}
pub fn from_width(width: f32) -> Self {
if width >= 1536.0 {
Breakpoint::Xxl
} else if width >= 1280.0 {
Breakpoint::Xl
} else if width >= 1024.0 {
Breakpoint::Lg
} else if width >= 768.0 {
Breakpoint::Md
} else {
Breakpoint::Sm
}
}
pub fn is_at_least(self, other: Breakpoint) -> bool {
self.min_width() >= other.min_width()
}
}
impl fmt::Display for Breakpoint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Breakpoint::Sm => write!(f, "sm"),
Breakpoint::Md => write!(f, "md"),
Breakpoint::Lg => write!(f, "lg"),
Breakpoint::Xl => write!(f, "xl"),
Breakpoint::Xxl => write!(f, "2xl"),
}
}
}
pub mod z_index_layers {
pub const BASE: i32 = 0;
pub const STICKY: i32 = 100;
pub const FLOATING: i32 = 200;
pub const OVERLAY: i32 = 1000;
pub const MODAL: i32 = 2000;
pub const TOAST: i32 = 3000;
pub const TOOLTIP: i32 = 5000;
}
#[derive(Debug, Clone)]
pub struct Responsive<T: Clone> {
pub sm: T,
pub md: Option<T>,
pub lg: Option<T>,
pub xl: Option<T>,
pub xxl: Option<T>,
}
impl<T: Clone> Responsive<T> {
pub fn all(value: T) -> Self {
Self {
sm: value.clone(),
md: Some(value.clone()),
lg: Some(value.clone()),
xl: Some(value.clone()),
xxl: Some(value),
}
}
pub fn new(sm: T, md: T, lg: T, xl: T, xxl: T) -> Self {
Self {
sm,
md: Some(md),
lg: Some(lg),
xl: Some(xl),
xxl: Some(xxl),
}
}
pub fn value_at(&self, breakpoint: Breakpoint) -> T {
match breakpoint {
Breakpoint::Sm => self.sm.clone(),
Breakpoint::Md => self.md.clone().unwrap_or_else(|| self.sm.clone()),
Breakpoint::Lg => self
.lg
.clone()
.or_else(|| self.md.clone())
.unwrap_or_else(|| self.sm.clone()),
Breakpoint::Xl => self
.xl
.clone()
.or_else(|| self.lg.clone())
.or_else(|| self.md.clone())
.unwrap_or_else(|| self.sm.clone()),
Breakpoint::Xxl => self
.xxl
.clone()
.or_else(|| self.xl.clone())
.or_else(|| self.lg.clone())
.or_else(|| self.md.clone())
.unwrap_or_else(|| self.sm.clone()),
}
}
}
impl<T: Clone> Default for Responsive<T>
where
T: Default,
{
fn default() -> Self {
Self {
sm: T::default(),
md: None,
lg: None,
xl: None,
xxl: None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn breakpoint_min_widths() {
assert_eq!(Breakpoint::Sm.min_width(), 640.0);
assert_eq!(Breakpoint::Md.min_width(), 768.0);
assert_eq!(Breakpoint::Lg.min_width(), 1024.0);
assert_eq!(Breakpoint::Xl.min_width(), 1280.0);
assert_eq!(Breakpoint::Xxl.min_width(), 1536.0);
}
#[test]
fn breakpoint_from_width() {
assert_eq!(Breakpoint::from_width(320.0), Breakpoint::Sm);
assert_eq!(Breakpoint::from_width(640.0), Breakpoint::Sm);
assert_eq!(Breakpoint::from_width(768.0), Breakpoint::Md);
assert_eq!(Breakpoint::from_width(1024.0), Breakpoint::Lg);
assert_eq!(Breakpoint::from_width(1280.0), Breakpoint::Xl);
assert_eq!(Breakpoint::from_width(1536.0), Breakpoint::Xxl);
assert_eq!(Breakpoint::from_width(2000.0), Breakpoint::Xxl);
}
#[test]
fn breakpoint_is_at_least() {
assert!(Breakpoint::Md.is_at_least(Breakpoint::Sm));
assert!(Breakpoint::Lg.is_at_least(Breakpoint::Md));
assert!(!Breakpoint::Sm.is_at_least(Breakpoint::Md));
}
#[test]
fn responsive_all_same() {
let r = Responsive::all(10);
assert_eq!(r.value_at(Breakpoint::Sm), 10);
assert_eq!(r.value_at(Breakpoint::Xxl), 10);
}
#[test]
fn responsive_fallback() {
let r: Responsive<i32> = Responsive::new(10, 20, 30, 40, 50);
assert_eq!(r.value_at(Breakpoint::Sm), 10);
assert_eq!(r.value_at(Breakpoint::Md), 20);
assert_eq!(r.value_at(Breakpoint::Lg), 30);
assert_eq!(r.value_at(Breakpoint::Xl), 40);
assert_eq!(r.value_at(Breakpoint::Xxl), 50);
}
#[test]
fn responsive_partial_fallback() {
let r = Responsive {
sm: 100,
md: None,
lg: None,
xl: Some(200),
xxl: None,
};
assert_eq!(r.value_at(Breakpoint::Sm), 100);
assert_eq!(r.value_at(Breakpoint::Md), 100); assert_eq!(r.value_at(Breakpoint::Lg), 100); assert_eq!(r.value_at(Breakpoint::Xl), 200);
assert_eq!(r.value_at(Breakpoint::Xxl), 200); }
#[test]
fn breakpoint_display() {
assert_eq!(format!("{}", Breakpoint::Sm), "sm");
assert_eq!(format!("{}", Breakpoint::Md), "md");
assert_eq!(format!("{}", Breakpoint::Lg), "lg");
assert_eq!(format!("{}", Breakpoint::Xl), "xl");
assert_eq!(format!("{}", Breakpoint::Xxl), "2xl");
}
}