// Rating Component - Star rating display and input
use super::traits::Renderable
pub enum RatingSize {
Small,
Medium,
Large,
}
pub struct Rating {
value: f32,
max: i32,
size: RatingSize,
readonly: bool,
color: string,
}
impl Rating {
pub fn new(value: f32) -> Rating {
Rating {
value: value,
max: 5,
size: RatingSize::Medium,
readonly: true,
color: "#fbbf24".to_string(),
}
}
pub fn max(self, max: i32) -> Rating {
self.max = max;
self
}
pub fn size(self, size: RatingSize) -> Rating {
self.size = size;
self
}
pub fn readonly(self, readonly: bool) -> Rating {
self.readonly = readonly;
self
}
pub fn color(self, color: string) -> Rating {
self.color = color;
self
}
}
impl Renderable for Rating {
pub fn render(self) -> string {
let star_size = match self.size {
RatingSize::Small => "16px",
RatingSize::Medium => "24px",
RatingSize::Large => "32px",
};
let mut html = String::new();
html.push_str("<div style='display: inline-flex; gap: 4px;'>");
let mut i = 1;
while i <= self.max {
let filled = i as f32 <= self.value;
let half_filled = i as f32 - 0.5 <= self.value && i as f32 > self.value;
let star_color = if filled || half_filled {
self.color.as_str()
} else {
"#e2e8f0"
};
let cursor = if self.readonly {
"default"
} else {
"pointer"
};
html.push_str("<span style='font-size: ");
html.push_str(star_size);
html.push_str("; color: ");
html.push_str(star_color);
html.push_str("; cursor: ");
html.push_str(cursor);
html.push_str(";'>");
if half_filled {
html.push('⯨'); // Half star
} else {
html.push('★');
}
html.push_str("</span>");
i += 1;
}
html.push_str("</div>");
html
}
}