// Skeleton - Loading placeholder component
pub struct Skeleton {
variant: SkeletonVariant,
width: string,
height: string,
class: string,
}
pub enum SkeletonVariant {
Text,
Circle,
Rectangle,
}
impl Skeleton {
pub fn new() -> Skeleton {
Skeleton {
variant: SkeletonVariant::Text,
width: "100%".to_string(),
height: "20px".to_string(),
class: String::new(),
}
}
pub fn variant(variant: SkeletonVariant) -> Skeleton {
self.variant = variant
self
}
pub fn width(width: string) -> Skeleton {
self.width = width
self
}
pub fn height(height: string) -> Skeleton {
self.height = height
self
}
pub fn class(class: string) -> Skeleton {
self.class = class
self
}
pub fn render() -> string {
let border_radius = match self.variant {
SkeletonVariant::Text => "4px",
SkeletonVariant::Circle => "50%",
SkeletonVariant::Rectangle => "8px",
}
let mut html = String::new()
html.push_str("<div class=\"wj-skeleton ")
html.push_str(self.class.as_str())
html.push_str("\" style=\"width: ")
html.push_str(self.width.as_str())
html.push_str("; height: ")
html.push_str(self.height.as_str())
html.push_str("; border-radius: ")
html.push_str(border_radius)
html.push_str("; background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; animation: skeleton-loading 1.5s ease-in-out infinite;\"></div>")
// Add animation keyframes (only once per page)
html.push_str("<style>@keyframes skeleton-loading { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }</style>")
html
}
}