use dioxus::prelude::*;
#[derive(Clone, PartialEq)]
pub enum ProgressType {
Line,
Circle,
Dashboard,
}
impl ProgressType {
pub fn as_str(&self) -> &'static str {
match self {
ProgressType::Line => "line",
ProgressType::Circle => "circle",
ProgressType::Dashboard => "dashboard",
}
}
}
#[derive(Clone, PartialEq)]
pub enum ProgressStatus {
Default,
Success,
Exception,
Warning,
}
impl ProgressStatus {
pub fn as_class(&self) -> &'static str {
match self {
ProgressStatus::Default => "",
ProgressStatus::Success => "is-success",
ProgressStatus::Exception => "is-exception",
ProgressStatus::Warning => "is-warning",
}
}
}
#[derive(Props, Clone, PartialEq)]
pub struct ProgressProps {
#[props(default = ProgressType::Line)]
pub progress_type: ProgressType,
#[props(default = 0)]
pub percentage: u32,
#[props(default = ProgressStatus::Default)]
pub status: ProgressStatus,
#[props(default = false)]
pub indeterminate: bool,
#[props(default = 6)]
pub stroke_width: u32,
#[props(default = false)]
pub text_inside: bool,
#[props(default = 126)]
pub width: u32,
#[props(default = true)]
pub show_text: bool,
#[props(default)]
pub color: Option<String>,
#[props(default = false)]
pub striped: bool,
#[props(default = false)]
pub striped_flow: bool,
#[props(default)]
pub class: Option<String>,
#[props(default)]
pub style: Option<String>,
}
#[component]
pub fn Progress(props: ProgressProps) -> Element {
let percentage = props.percentage.min(100);
let mut class_names = vec!["el-progress".to_string()];
class_names.push(format!("el-progress--{}", props.progress_type.as_str()));
let status_class = props.status.as_class();
if !status_class.is_empty() {
class_names.push(status_class.to_string());
}
if props.indeterminate {
class_names.push("el-progress--indeterminate".to_string());
}
if props.striped {
class_names.push("el-progress--striped".to_string());
}
if props.striped_flow {
class_names.push("el-progress--striped-flow".to_string());
}
if props.text_inside && props.progress_type == ProgressType::Line {
class_names.push("el-progress--text-inside".to_string());
}
if let Some(ref custom_class) = props.class {
class_names.push(custom_class.clone());
}
let class_string = class_names.join(" ");
let style_string = props.style.clone().unwrap_or_default();
let bar_color = props.color.clone().unwrap_or_else(|| {
match props.status {
ProgressStatus::Success => "#67C23A".to_string(),
ProgressStatus::Exception => "#F56C6C".to_string(),
ProgressStatus::Warning => "#E6A23C".to_string(),
ProgressStatus::Default => "#409EFF".to_string(),
}
});
let display_text = format!("{}%", percentage);
if props.progress_type == ProgressType::Line {
let bar_style = format!("width: {}%; background-color: {};", percentage, bar_color);
let height_style = format!("height: {}px;", props.stroke_width);
rsx! {
div {
class: "{class_string}",
style: "{style_string}",
div {
class: "el-progress__outer",
style: "{height_style}",
div {
class: "el-progress__inner",
div {
class: "el-progress__bar",
style: "{bar_style}",
if props.text_inside && props.show_text {
div {
class: "el-progress__text el-progress__text--inside",
"{display_text}"
}
}
}
}
}
if props.show_text && !props.text_inside {
div {
class: "el-progress__text",
if props.status == ProgressStatus::Success {
i { class: "el-icon-circle-check" }
} else if props.status == ProgressStatus::Exception {
i { class: "el-icon-circle-close" }
} else if props.status == ProgressStatus::Warning {
i { class: "el-icon-warning" }
} else {
"{display_text}"
}
}
}
}
}
} else {
let size = props.width;
let deg = (percentage as f64 / 100.0) * 360.0;
let bg_gradient = if props.progress_type == ProgressType::Dashboard {
format!("conic-gradient(from 135deg, {} 0deg, {} {}deg, transparent {}deg)",
bar_color, bar_color, deg * 0.75, deg * 0.75)
} else {
format!("conic-gradient({} {}deg, var(--el-fill-color-light) {}deg)",
bar_color, deg, deg)
};
let inner_size = size - props.stroke_width * 2;
rsx! {
div {
class: "{class_string}",
style: "{style_string}",
div {
class: "el-progress-circle",
style: "width: {size}px; height: {size}px; border-radius: 50%; background: {bg_gradient}; display: flex; align-items: center; justify-content: center;",
div {
style: "width: {inner_size}px; height: {inner_size}px; border-radius: 50%; background: var(--el-bg-color); display: flex; align-items: center; justify-content: center;",
if props.show_text {
div {
class: "el-progress__text",
if props.status == ProgressStatus::Success {
i { class: "el-icon-circle-check" }
} else if props.status == ProgressStatus::Exception {
i { class: "el-icon-circle-close" }
} else {
"{display_text}"
}
}
}
}
}
}
}
}
}