use super::*;
#[doc=include_str!("readme.md")]
#[derive(Clone, Debug)]
pub struct TailwindBackgroundImage {
kind: BgImageKind,
value: Option<UnitValue>,
is_negative: bool,
}
#[derive(Clone, Debug, PartialEq)]
enum BgImageKind {
None,
Url,
Linear,
Radial,
Conic,
RepeatingLinear,
RepeatingRadial,
RepeatingConic,
}
impl Display for TailwindBackgroundImage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.is_negative {
write!(f, "-")?;
}
match (&self.kind, &self.value) {
(BgImageKind::None, _) => write!(f, "bg-none"),
(BgImageKind::Url, Some(val)) => write!(f, "bg-[url({})]", val),
(BgImageKind::Linear, Some(val)) => write!(f, "bg-linear-{}", val),
(BgImageKind::Radial, Some(val)) => write!(f, "bg-radial-{}", val),
(BgImageKind::Conic, Some(val)) => write!(f, "bg-conic-{}", val),
(BgImageKind::Linear, None) => write!(f, "bg-linear"),
(BgImageKind::Radial, None) => write!(f, "bg-radial"),
(BgImageKind::Conic, None) => write!(f, "bg-conic"),
(BgImageKind::RepeatingLinear, Some(val)) => write!(f, "bg-[repeating-linear-gradient({})]", val),
(BgImageKind::RepeatingRadial, Some(val)) => write!(f, "bg-[repeating-radial-gradient({})]", val),
(BgImageKind::RepeatingConic, Some(val)) => write!(f, "bg-[repeating-conic-gradient({})]", val),
_ => Ok(()), }
}
}
impl TailwindInstance for TailwindBackgroundImage {
fn attributes(&self, _: &TailwindBuilder) -> CssAttributes {
match &self.kind {
BgImageKind::None => css_attributes! { "background-image" => "none" },
BgImageKind::Url => {
let url_value = self.value.as_ref().unwrap().to_string();
css_attributes! { "background-image" => format!("url({})", url_value) }
}
BgImageKind::RepeatingLinear | BgImageKind::RepeatingRadial | BgImageKind::RepeatingConic => {
let arbitrary_gradient_val = self.value.as_ref().unwrap().to_string().replace('_', " ");
let gradient_type = match self.kind {
BgImageKind::RepeatingLinear => "repeating-linear-gradient",
BgImageKind::RepeatingRadial => "repeating-radial-gradient",
BgImageKind::RepeatingConic => "repeating-conic-gradient",
_ => unreachable!(),
};
css_attributes! { "background-image" => format!("{}({})", gradient_type, arbitrary_gradient_val) }
}
BgImageKind::Linear | BgImageKind::Radial | BgImageKind::Conic => {
let gradient_type = match self.kind {
BgImageKind::Linear => "linear-gradient",
BgImageKind::Radial => "radial-gradient",
BgImageKind::Conic => "conic-gradient",
_ => unreachable!(),
};
let direction_or_angle = match self.value.as_ref() {
None => "in oklab".to_string(),
Some(UnitValue::Keyword(k)) if k.starts_with("to-") => {
let direction = k.strip_prefix("to-").unwrap_or(k);
let mut full_direction = String::new();
if direction.contains('t') { full_direction.push_str("top "); }
if direction.contains('b') { full_direction.push_str("bottom "); }
if direction.contains('l') { full_direction.push_str("left "); }
if direction.contains('r') { full_direction.push_str("right "); }
format!("to {} in oklab", full_direction.trim())
}
Some(value) => {
let inner_value = match value {
UnitValue::Arbitrary(a) => a.get_properties(),
_ => value.to_string()
};
if self.is_negative {
format!("calc({} * -1)", inner_value)
} else {
format!("{} in oklab", inner_value)
}
}
};
let image = match self.value.as_ref() {
Some(UnitValue::Arbitrary(_)) | Some(UnitValue::Number {..}) | Some(UnitValue::Length(_)) => {
format!("{}(var(--tw-gradient-stops, {}))", gradient_type, direction_or_angle)
},
_ => format!("{}(var(--tw-gradient-stops))", gradient_type)
};
css_attributes! {
"--tw-gradient-position" => direction_or_angle,
"background-image" => image
}
}
}
}
}
impl TailwindBackgroundImage {
pub fn parse(pattern: &[&str], arbitrary: &TailwindArbitrary, neg: Negative) -> Result<Self> {
let (kind, rest) = match pattern {
["none"] => (BgImageKind::None, &pattern[1..]),
["gradient", rest @ ..] | ["linear", rest @ ..] => (BgImageKind::Linear, rest),
["radial", rest @ ..] => (BgImageKind::Radial, rest),
["conic", rest @ ..] => (BgImageKind::Conic, rest),
[] if arbitrary.as_str().starts_with("url(") => (BgImageKind::Url, pattern),
[] if arbitrary.as_str().starts_with("repeating-linear-gradient(") => (BgImageKind::RepeatingLinear, pattern),
[] if arbitrary.as_str().starts_with("repeating-radial-gradient(") => (BgImageKind::RepeatingRadial, pattern),
[] if arbitrary.as_str().starts_with("repeating-conic-gradient(") => (BgImageKind::RepeatingConic, pattern),
_ => return syntax_error!("Unknown background-image pattern: {}", pattern.join("-")),
};
let value = match kind {
BgImageKind::None => None,
BgImageKind::Url => {
let url = arbitrary.as_str().strip_prefix("url(").and_then(|s| s.strip_suffix(')')).unwrap_or("");
Some(UnitValue::Keyword(url.to_string()))
}
BgImageKind::RepeatingLinear | BgImageKind::RepeatingRadial | BgImageKind::RepeatingConic => {
let prefix = match kind {
BgImageKind::RepeatingLinear => "repeating-linear-gradient(",
BgImageKind::RepeatingRadial => "repeating-radial-gradient(",
BgImageKind::RepeatingConic => "repeating-conic-gradient(",
_ => unreachable!(),
};
let content = arbitrary.as_str().strip_prefix(prefix).and_then(|s| s.strip_suffix(')')).unwrap_or("");
Some(UnitValue::Keyword(content.to_string()))
}
BgImageKind::Linear
| BgImageKind::Radial
| BgImageKind::Conic => {
if rest.is_empty() && arbitrary.is_none() {
None
} else {
let joined = rest.join("-");
if joined.starts_with("to-") {
Some(UnitValue::Keyword(joined.replace("-b-r", "-br").replace("-b-l", "-bl").replace("-t-r", "-tr").replace("-t-l", "-tl")))
} else {
Some(UnitValue::negative_parser("bg-image", |_| false, false, false, false)(rest, arbitrary, neg)?)
}
}
}
};
Ok(Self { kind, value, is_negative: neg.0 })
}
}