use crate::css_generator::types::CssProperty;
pub fn hex_to_rgba(hex: &str, opacity: f32) -> String {
let hex = hex.trim_start_matches('#');
let r = u8::from_str_radix(&hex[0..2], 16).unwrap_or(0);
let g = u8::from_str_radix(&hex[2..4], 16).unwrap_or(0);
let b = u8::from_str_radix(&hex[4..6], 16).unwrap_or(0);
format!("rgba({}, {}, {}, {})", r, g, b, opacity)
}
pub fn parse_opacity_from_class(class: &str) -> Option<f32> {
if let Some((_, opacity_str)) = class.split_once('/') {
if let Ok(opacity) = opacity_str.parse::<f32>() {
return Some(opacity / 100.0);
}
}
None
}
pub fn remove_opacity_suffix(class: &str) -> String {
if let Some((base, _)) = class.split_once('/') {
base.to_string()
} else {
class.to_string()
}
}
pub fn create_css_property(name: &str, value: &str, important: bool) -> CssProperty {
CssProperty {
name: name.to_string(),
value: value.to_string(),
important,
}
}
pub fn create_multiple_properties(properties: &[(&str, &str)], important: bool) -> Vec<CssProperty> {
properties
.iter()
.map(|(name, value)| create_css_property(name, value, important))
.collect()
}
pub fn matches_pattern(class: &str, pattern: &str) -> bool {
if pattern.ends_with('*') {
let prefix = pattern.trim_end_matches('*');
class.starts_with(prefix)
} else {
class == pattern
}
}
pub fn extract_numeric_value(class: &str, prefix: &str) -> Option<f32> {
if let Some(value_str) = class.strip_prefix(prefix) {
value_str.parse().ok()
} else {
None
}
}
pub fn numeric_to_css_unit(value: f32, unit: &str) -> String {
format!("{}{}", value, unit)
}
pub fn spacing_to_css(value: f32) -> String {
if value == 0.0 {
"0".to_string()
} else {
format!("{}rem", value * 0.25)
}
}
pub fn percentage_to_css(value: f32) -> String {
format!("{}%", value)
}
pub fn pixel_to_css(value: f32) -> String {
format!("{}px", value)
}
pub fn viewport_to_css(value: f32, _unit: &str) -> String {
format!("{}vw", value)
}
pub fn is_valid_color(value: &str) -> bool {
value.starts_with('#') ||
value.starts_with("rgb") ||
value.starts_with("hsl") ||
value.starts_with("var(") ||
matches!(value, "transparent" | "currentColor" | "inherit" | "initial" | "unset")
}
pub fn is_valid_length(value: &str) -> bool {
value.ends_with("px") ||
value.ends_with("rem") ||
value.ends_with("em") ||
value.ends_with("%") ||
value.ends_with("vw") ||
value.ends_with("vh") ||
value == "0" ||
value == "auto"
}
pub fn normalize_property_name(name: &str) -> String {
name.replace('_', "-").to_lowercase()
}
pub fn normalize_property_value(value: &str) -> String {
value.trim().to_string()
}
pub fn create_selector(class: &str) -> String {
format!(".{}", class)
}
pub fn create_responsive_selector(breakpoint: &str, class: &str) -> String {
format!("{}.{}", breakpoint, class)
}
pub fn create_media_query(condition: &str) -> String {
format!("@media {}", condition)
}
pub fn validate_css_property(property: &CssProperty) -> bool {
!property.name.is_empty() && !property.value.is_empty()
}
pub fn merge_properties(properties: &[CssProperty]) -> Vec<CssProperty> {
let mut merged = Vec::new();
let mut seen = std::collections::HashSet::new();
for property in properties {
let key = format!("{}:{}", property.name, property.value);
if seen.insert(key) {
merged.push(property.clone());
}
}
merged
}
pub fn sort_properties(properties: &mut [CssProperty]) {
properties.sort_by(|a, b| a.name.cmp(&b.name));
}
pub fn create_important_property(name: &str, value: &str) -> CssProperty {
create_css_property(name, value, true)
}
pub fn create_normal_property(name: &str, value: &str) -> CssProperty {
create_css_property(name, value, false)
}