media queries
This commit is contained in:
parent
78a7799933
commit
0f09a5e22d
25
src/class.rs
25
src/class.rs
|
@ -1,4 +1,8 @@
|
||||||
use crate::{Zephyr, ZephyrError};
|
use crate::{
|
||||||
|
media_queries::{ReducedMotion, Responsive},
|
||||||
|
modifiers::Modifiers,
|
||||||
|
Zephyr, ZephyrError,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub(crate) struct Class<'a> {
|
pub(crate) struct Class<'a> {
|
||||||
|
@ -6,7 +10,7 @@ pub(crate) struct Class<'a> {
|
||||||
pub value: Option<&'a str>,
|
pub value: Option<&'a str>,
|
||||||
/// if true, no replacements will be done on `value`
|
/// if true, no replacements will be done on `value`
|
||||||
pub value_literal: bool,
|
pub value_literal: bool,
|
||||||
pub modifiers: Vec<&'a str>,
|
pub modifiers: Modifiers<'a>,
|
||||||
pub pseudo: Option<&'a str>,
|
pub pseudo: Option<&'a str>,
|
||||||
/// the original unparsed value
|
/// the original unparsed value
|
||||||
/// needed to generate the css selector
|
/// needed to generate the css selector
|
||||||
|
@ -23,7 +27,9 @@ impl<'a> Class<'a> {
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let mut rest = modifiers
|
let mut rest = modifiers
|
||||||
|
.all
|
||||||
.iter()
|
.iter()
|
||||||
|
.filter(|m| Responsive::from_str(*m).is_none() && ReducedMotion::from_str(*m).is_none())
|
||||||
.map(|m| -> &str { z.modifiers.get(*m).map(AsRef::as_ref).unwrap_or(m) })
|
.map(|m| -> &str { z.modifiers.get(*m).map(AsRef::as_ref).unwrap_or(m) })
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(":");
|
.join(":");
|
||||||
|
@ -56,6 +62,8 @@ impl<'a> Class<'a> {
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// generates the css rule for this class
|
||||||
|
/// does not generate the corresponding media query
|
||||||
pub(crate) fn generate(&self, z: &Zephyr) -> Result<String, ZephyrError> {
|
pub(crate) fn generate(&self, z: &Zephyr) -> Result<String, ZephyrError> {
|
||||||
let property = z
|
let property = z
|
||||||
.properties
|
.properties
|
||||||
|
@ -87,4 +95,17 @@ impl<'a> Class<'a> {
|
||||||
Err(ZephyrError::ValueMissing)
|
Err(ZephyrError::ValueMissing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_with_media_query(&self, z: &Zephyr) -> Result<String, ZephyrError> {
|
||||||
|
let mut css = self.generate(z)?;
|
||||||
|
|
||||||
|
if let Some(r) = &self.modifiers.responsive {
|
||||||
|
css = r.wrap(&css);
|
||||||
|
}
|
||||||
|
if let Some(r) = &self.modifiers.reduced_motion {
|
||||||
|
css = r.wrap(&css);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(css)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -6,6 +6,8 @@ use crate::{defaults::*, parse::*};
|
||||||
|
|
||||||
mod class;
|
mod class;
|
||||||
mod defaults;
|
mod defaults;
|
||||||
|
mod media_queries;
|
||||||
|
mod modifiers;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
|
||||||
#[cfg(feature = "inventory")]
|
#[cfg(feature = "inventory")]
|
||||||
|
@ -97,6 +99,8 @@ impl Zephyr {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// we ignore errors
|
// we ignore errors
|
||||||
|
// TODO change this to call parse_class directly
|
||||||
|
// TODO then group by media query
|
||||||
.flat_map(|c| match self.generate_class(c) {
|
.flat_map(|c| match self.generate_class(c) {
|
||||||
Ok(v) => Some(v),
|
Ok(v) => Some(v),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -116,7 +120,7 @@ impl Zephyr {
|
||||||
/// this one returns an error if parsing or generating fails
|
/// this one returns an error if parsing or generating fails
|
||||||
pub fn generate_class(&self, class: &str) -> Result<String, ZephyrError> {
|
pub fn generate_class(&self, class: &str) -> Result<String, ZephyrError> {
|
||||||
let c = parse_class(class)?;
|
let c = parse_class(class)?;
|
||||||
c.generate(self)
|
c.generate_with_media_query(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,4 +239,16 @@ mod tests {
|
||||||
r#".border\{1px_solid_black\}{border:1px_solid_black;}.w\{full\}{width:full;}"#
|
r#".border\{1px_solid_black\}{border:1px_solid_black;}.w\{full\}{width:full;}"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generate_with_media_query() {
|
||||||
|
let z = Zephyr::new();
|
||||||
|
|
||||||
|
// the curly brackets indicate that the value should not go through replacements
|
||||||
|
let classes = z.generate_classes(["m[1rem]sm"]);
|
||||||
|
assert_eq!(
|
||||||
|
classes,
|
||||||
|
r#"@media(min-width:640px){.m\[1rem\]sm{margin:1rem;}}"#
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub(crate) enum Responsive {
|
||||||
|
Sm,
|
||||||
|
Md,
|
||||||
|
Lg,
|
||||||
|
Xl,
|
||||||
|
Xxl,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Responsive {
|
||||||
|
pub fn wrap(&self, css: &str) -> String {
|
||||||
|
match self {
|
||||||
|
Responsive::Sm => wrap_in_query(css, "min-width:640px"),
|
||||||
|
Responsive::Md => wrap_in_query(css, "min-width:768px"),
|
||||||
|
Responsive::Lg => wrap_in_query(css, "min-width:1024px"),
|
||||||
|
Responsive::Xl => wrap_in_query(css, "min-width:1280px"),
|
||||||
|
Responsive::Xxl => wrap_in_query(css, "min-width:1536px"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_str(s: &str) -> Option<Self> {
|
||||||
|
match s {
|
||||||
|
"sm" => Some(Responsive::Sm),
|
||||||
|
"md" => Some(Responsive::Md),
|
||||||
|
"lg" => Some(Responsive::Lg),
|
||||||
|
"xl" => Some(Responsive::Xl),
|
||||||
|
"xxl" => Some(Responsive::Xxl),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub enum ReducedMotion {
|
||||||
|
MotionReduce,
|
||||||
|
MotionSafe,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReducedMotion {
|
||||||
|
pub fn wrap(&self, css: &str) -> String {
|
||||||
|
match self {
|
||||||
|
Self::MotionReduce => wrap_in_query(css, "prefers-reduced-motion:reduce"),
|
||||||
|
Self::MotionSafe => wrap_in_query(css, "prefers-reduced-motion:no-preference"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_str(s: &str) -> Option<Self> {
|
||||||
|
match s {
|
||||||
|
"motion-reduce" => Some(ReducedMotion::MotionReduce),
|
||||||
|
"motion-safe" => Some(ReducedMotion::MotionSafe),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_in_query(css: &str, query: &str) -> String {
|
||||||
|
format!("@media({query}){{{css}}}")
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
use crate::media_queries::{ReducedMotion, Responsive};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub(crate) struct Modifiers<'a> {
|
||||||
|
pub all: Vec<&'a str>,
|
||||||
|
pub responsive: Option<Responsive>,
|
||||||
|
pub reduced_motion: Option<ReducedMotion>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Modifiers<'a> {
|
||||||
|
pub(crate) fn new(all: Vec<&'a str>) -> Self {
|
||||||
|
let mut responsive = None;
|
||||||
|
let mut reduced_motion = None;
|
||||||
|
|
||||||
|
for m in &all {
|
||||||
|
responsive = Responsive::from_str(m);
|
||||||
|
reduced_motion = ReducedMotion::from_str(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
all,
|
||||||
|
responsive,
|
||||||
|
reduced_motion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Vec<&'a str>> for Modifiers<'a> {
|
||||||
|
fn from(v: Vec<&'a str>) -> Self {
|
||||||
|
Self::new(v)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue