From a44d0a9c380ed2f7f3c88d9c922d22371ca8657c Mon Sep 17 00:00:00 2001 From: luoxiaozero <48741584+luoxiaozero@users.noreply.github.com> Date: Tue, 27 Feb 2024 22:06:12 +0800 Subject: [PATCH] Feat/progress circle (#124) * feat: Adds ProgressCircle component * feat: ProgressCircle adds children prop * feat: ProgressCircle adds class and size prop --- demo_markdown/docs/progress/mod.md | 41 ++++++++-- thaw/src/progress/mod.rs | 5 +- thaw/src/progress/progress-circle.css | 30 ++++++++ thaw/src/progress/progress_circle.rs | 107 ++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 thaw/src/progress/progress-circle.css create mode 100644 thaw/src/progress/progress_circle.rs diff --git a/demo_markdown/docs/progress/mod.md b/demo_markdown/docs/progress/mod.md index 90a82f5..68a2279 100644 --- a/demo_markdown/docs/progress/mod.md +++ b/demo_markdown/docs/progress/mod.md @@ -19,11 +19,40 @@ view! { } ``` +### Circle + +```rust demo +let percentage = create_rw_signal(0.0f32); + +view! { + + + + + + + + + + +} +``` + ### Progress Props -| Name | Type | Default | Description | -| ------------------- | ----------------------------------------- | ------------------------------------- | ------------------------------ | -| percentage | `MaybeSignal` | `Default::default()` | Percentage value. | -| color | `MaybeSignal` | `ProgressColor::Primary` | Progress color. | -| show_indicator | `MaybeSignal` | `true` | Whether to display indicators. | -| indicator_placement | `MaybeSignal` | `ProgressIndicatorPlacement::Outside` | Indicator placement. | +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| percentage | `MaybeSignal` | `Default::default()` | Percentage value. | +| color | `MaybeSignal` | `ProgressColor::Primary` | Progress color. | +| show_indicator | `MaybeSignal` | `true` | Whether to display indicators. | +| indicator_placement | `MaybeSignal` | `ProgressIndicatorPlacement::Outside` | Indicator placement. | + +### ProgressCircle Props + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| class | `OptionalProp>` | `Default::default()` | Addtional classes for the progress element. | +| percentage | `MaybeSignal` | `Default::default()` | Percentage value. | +| color | `MaybeSignal` | `ProgressColor::Primary` | ProgressCircle color. | +| size | `MaybeSignal` | `120px` | ProgressCircle size. | +| children | `Option` | `None` | ProgressCircle's content. | diff --git a/thaw/src/progress/mod.rs b/thaw/src/progress/mod.rs index d815b65..07ffe0c 100644 --- a/thaw/src/progress/mod.rs +++ b/thaw/src/progress/mod.rs @@ -1,8 +1,11 @@ +mod progress_circle; mod theme; +pub use progress_circle::ProgressCircle; +pub use theme::ProgressTheme; + use crate::{use_theme, utils::mount_style, Theme}; use leptos::*; -pub use theme::ProgressTheme; #[derive(Default, Clone, PartialEq)] pub enum ProgressIndicatorPlacement { diff --git a/thaw/src/progress/progress-circle.css b/thaw/src/progress/progress-circle.css new file mode 100644 index 0000000..f8319a9 --- /dev/null +++ b/thaw/src/progress/progress-circle.css @@ -0,0 +1,30 @@ +.thaw-progress-circle { + width: var(--thaw-size); + height: var(--thaw-size); + display: inline-block; + position: relative; +} + +.thaw-progress-circle__fill { + transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), + stroke 0.3s cubic-bezier(0.4, 0, 0.2, 1), + stroke-dasharray 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.thaw-progress-circle__fill--empty { + opacity: 0; +} + +.thaw-progress-circle__content { + position: absolute; + left: 50%; + top: 50%; + transform: translateX(-50%) translateY(-50%); + display: flex; + align-items: center; + justify-content: center; +} + +.thaw-progress-circle__content--text { + font-size: 28px; +} diff --git a/thaw/src/progress/progress_circle.rs b/thaw/src/progress/progress_circle.rs new file mode 100644 index 0000000..e8fed09 --- /dev/null +++ b/thaw/src/progress/progress_circle.rs @@ -0,0 +1,107 @@ +use super::ProgressColor; +use crate::{ + use_theme, + utils::{class_list::class_list, mount_style, OptionalProp}, + Theme, +}; +use leptos::*; + +#[component] +pub fn ProgressCircle( + #[prop(optional, into)] class: OptionalProp>, + #[prop(into, optional)] percentage: MaybeSignal, + #[prop(into, optional)] color: MaybeSignal, + #[prop(into, default = "120px".into())] size: MaybeSignal, + #[prop(optional)] children: Option, +) -> impl IntoView { + mount_style("progress-circle", include_str!("./progress-circle.css")); + let theme = use_theme(Theme::light); + + let stroke_width = 7; + let view_box_width = 100; + + let radius = 50; + let begin_position_x = 0; + let begin_position_y = radius; + let end_position_x = 0; + let end_position_y = 2 * radius; + let center_x = 50 + stroke_width / 2; + let rail_path = format!("M {center_x},{center_x} m {begin_position_x},{begin_position_y} a {radius},{radius} 0 1 1 {end_position_x},{} a {radius},{radius} 0 1 1 {},{end_position_y}", -end_position_y, -end_position_x); + + let len = std::f64::consts::PI * 2.0 * f64::from(radius); + let rail_stroke_dasharray = format!("{len}px {}px", view_box_width * 8); + let rail_stroke_color = + Memo::new(move |_| theme.with(|theme| theme.progress.background_color.clone())); + + let fill_path = rail_path.clone(); + let fill_stroke_dasharray = Memo::new(move |_| { + let percentage = percentage.get(); + let percentage = if percentage < 0.0 { + 0.0 + } else if percentage > 100.0 { + 100.0 + } else { + percentage + }; + format!( + "{}px {}px", + f64::from(percentage / 100.0) * len, + view_box_width * 8 + ) + }); + let fill_stroke_color = + Memo::new(move |_| theme.with(|theme| color.get().theme_background_color(theme))); + + view! { +
+ + + + + + + + + { + if let Some(children) = children { + view! { +
+ {children()} +
+ } + } else { + view! { +
+ {move || percentage.get()}"%" +
+ } + } + } +
+ } +}