mirror of
https://github.com/adoyle0/thaw.git
synced 2025-03-13 05:59:49 -04:00
feat: add loading bar component
This commit is contained in:
parent
29068acd1a
commit
a05cda35d7
5 changed files with 208 additions and 40 deletions
|
@ -24,50 +24,57 @@ pub fn App() -> impl IntoView {
|
||||||
provide_context(theme);
|
provide_context(theme);
|
||||||
view! {
|
view! {
|
||||||
<Provider theme>
|
<Provider theme>
|
||||||
<Router base="/thaw">
|
<TheRouter />
|
||||||
<Routes base="/thaw".to_string()>
|
|
||||||
<Route path="/" view=Home/>
|
|
||||||
<Route path="/components" view=ComponentsPage>
|
|
||||||
<Route path="/menu" view=MenuPage/>
|
|
||||||
<Route path="/slider" view=SliderPage/>
|
|
||||||
<Route path="/tabbar" view=TabbarPage/>
|
|
||||||
<Route path="/nav-bar" view=NavBarPage/>
|
|
||||||
<Route path="/input" view=InputPage/>
|
|
||||||
<Route path="/image" view=ImagePage/>
|
|
||||||
<Route path="/modal" view=ModalPage/>
|
|
||||||
<Route path="/button" view=ButtonPage/>
|
|
||||||
<Route path="/checkbox" view=CheckboxPage/>
|
|
||||||
<Route path="/toast" view=ToastPage/>
|
|
||||||
<Route path="/tabs" view=TabsPage/>
|
|
||||||
<Route path="/select" view=SelectPage/>
|
|
||||||
<Route path="/space" view=SpacePage/>
|
|
||||||
<Route path="/table" view=TablePage/>
|
|
||||||
<Route path="/color-picker" view=ColorPickerPage/>
|
|
||||||
<Route path="/alert" view=AlertPage/>
|
|
||||||
<Route path="/grid" view=GridPage/>
|
|
||||||
<Route path="/auto-complete" view=AutoCompletePage/>
|
|
||||||
<Route path="/avatar" view=AvatarPage/>
|
|
||||||
<Route path="/badge" view=BadgePage/>
|
|
||||||
<Route path="/card" view=CardPage/>
|
|
||||||
<Route path="/divider" view=DividerPage/>
|
|
||||||
<Route path="/input-number" view=InputNumberPage/>
|
|
||||||
<Route path="/icon" view=IconPage/>
|
|
||||||
<Route path="/message" view=MessagePage/>
|
|
||||||
<Route path="/radio" view=RadioPage/>
|
|
||||||
<Route path="/skeleton" view=SkeletonPage/>
|
|
||||||
<Route path="/switch" view=SwitchPage/>
|
|
||||||
<Route path="/tag" view=TagPage/>
|
|
||||||
<Route path="/upload" view=UploadPage/>
|
|
||||||
</Route>
|
|
||||||
<Route path="/mobile/tabbar" view=TabbarDemoPage/>
|
|
||||||
<Route path="/mobile/nav-bar" view=NavBarDemoPage/>
|
|
||||||
<Route path="/mobile/toast" view=ToastDemoPage/>
|
|
||||||
</Routes>
|
|
||||||
</Router>
|
|
||||||
</Provider>
|
</Provider>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn TheRouter() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<Router base="/thaw">
|
||||||
|
<Routes base="/thaw".to_string()>
|
||||||
|
<Route path="/" view=Home/>
|
||||||
|
<Route path="/components" view=ComponentsPage>
|
||||||
|
<Route path="/menu" view=MenuPage/>
|
||||||
|
<Route path="/slider" view=SliderPage/>
|
||||||
|
<Route path="/tabbar" view=TabbarPage/>
|
||||||
|
<Route path="/nav-bar" view=NavBarPage/>
|
||||||
|
<Route path="/input" view=InputPage/>
|
||||||
|
<Route path="/image" view=ImagePage/>
|
||||||
|
<Route path="/modal" view=ModalPage/>
|
||||||
|
<Route path="/button" view=ButtonPage/>
|
||||||
|
<Route path="/checkbox" view=CheckboxPage/>
|
||||||
|
<Route path="/toast" view=ToastPage/>
|
||||||
|
<Route path="/tabs" view=TabsPage/>
|
||||||
|
<Route path="/select" view=SelectPage/>
|
||||||
|
<Route path="/space" view=SpacePage/>
|
||||||
|
<Route path="/table" view=TablePage/>
|
||||||
|
<Route path="/color-picker" view=ColorPickerPage/>
|
||||||
|
<Route path="/alert" view=AlertPage/>
|
||||||
|
<Route path="/grid" view=GridPage/>
|
||||||
|
<Route path="/auto-complete" view=AutoCompletePage/>
|
||||||
|
<Route path="/avatar" view=AvatarPage/>
|
||||||
|
<Route path="/badge" view=BadgePage/>
|
||||||
|
<Route path="/card" view=CardPage/>
|
||||||
|
<Route path="/divider" view=DividerPage/>
|
||||||
|
<Route path="/input-number" view=InputNumberPage/>
|
||||||
|
<Route path="/icon" view=IconPage/>
|
||||||
|
<Route path="/message" view=MessagePage/>
|
||||||
|
<Route path="/radio" view=RadioPage/>
|
||||||
|
<Route path="/skeleton" view=SkeletonPage/>
|
||||||
|
<Route path="/switch" view=SwitchPage/>
|
||||||
|
<Route path="/tag" view=TagPage/>
|
||||||
|
<Route path="/upload" view=UploadPage/>
|
||||||
|
</Route>
|
||||||
|
<Route path="/mobile/tabbar" view=TabbarDemoPage/>
|
||||||
|
<Route path="/mobile/nav-bar" view=NavBarDemoPage/>
|
||||||
|
<Route path="/mobile/toast" view=ToastDemoPage/>
|
||||||
|
</Routes>
|
||||||
|
</Router>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn Provider(theme: RwSignal<Theme>, children: Children) -> impl IntoView {
|
fn Provider(theme: RwSignal<Theme>, children: Children) -> impl IntoView {
|
||||||
view! {
|
view! {
|
||||||
|
|
|
@ -16,6 +16,7 @@ mod image;
|
||||||
mod input;
|
mod input;
|
||||||
mod input_number;
|
mod input_number;
|
||||||
mod layout;
|
mod layout;
|
||||||
|
mod loading_bar;
|
||||||
mod menu;
|
mod menu;
|
||||||
mod message;
|
mod message;
|
||||||
pub mod mobile;
|
pub mod mobile;
|
||||||
|
@ -53,6 +54,7 @@ pub use image::*;
|
||||||
pub use input::*;
|
pub use input::*;
|
||||||
pub use input_number::*;
|
pub use input_number::*;
|
||||||
pub use layout::*;
|
pub use layout::*;
|
||||||
|
pub use loading_bar::*;
|
||||||
pub use menu::*;
|
pub use menu::*;
|
||||||
pub use message::*;
|
pub use message::*;
|
||||||
pub use modal::*;
|
pub use modal::*;
|
||||||
|
|
11
src/loading_bar/loading-bar.css
Normal file
11
src/loading_bar/loading-bar.css
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
.thaw-loading-bar-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.thaw-loading-bar {
|
||||||
|
height: 2px;
|
||||||
|
max-width: 0;
|
||||||
|
}
|
46
src/loading_bar/loading_bar_provider.rs
Normal file
46
src/loading_bar/loading_bar_provider.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
use super::{LoadingBar, LoadingBarRef};
|
||||||
|
use crate::{teleport::Teleport, utils::ComponentRef};
|
||||||
|
use leptos::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn LoadingBarProvider(children: Children) -> impl IntoView {
|
||||||
|
let loading_bar_ref = ComponentRef::<LoadingBarRef>::default();
|
||||||
|
provide_context(LoadingBarInjection { loading_bar_ref });
|
||||||
|
|
||||||
|
view! {
|
||||||
|
{children()}
|
||||||
|
<Teleport>
|
||||||
|
<LoadingBar comp_ref=loading_bar_ref/>
|
||||||
|
</Teleport>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LoadingBarInjection {
|
||||||
|
loading_bar_ref: ComponentRef<LoadingBarRef>,
|
||||||
|
}
|
||||||
|
impl Copy for LoadingBarInjection {}
|
||||||
|
|
||||||
|
impl LoadingBarInjection {
|
||||||
|
pub fn start(&self) {
|
||||||
|
if let Some(loading_bar_ref) = self.loading_bar_ref.get_untracked() {
|
||||||
|
loading_bar_ref.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(&self) {
|
||||||
|
if let Some(loading_bar_ref) = self.loading_bar_ref.get_untracked() {
|
||||||
|
loading_bar_ref.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error(&self) {
|
||||||
|
if let Some(loading_bar_ref) = self.loading_bar_ref.get_untracked() {
|
||||||
|
loading_bar_ref.error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_loading_bar() -> LoadingBarInjection {
|
||||||
|
expect_context::<LoadingBarInjection>()
|
||||||
|
}
|
102
src/loading_bar/mod.rs
Normal file
102
src/loading_bar/mod.rs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
mod loading_bar_provider;
|
||||||
|
|
||||||
|
use crate::{mount_style, use_theme, utils::ComponentRef, Theme};
|
||||||
|
use leptos::*;
|
||||||
|
pub use loading_bar_provider::{use_loading_bar, LoadingBarProvider};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LoadingBarRef {
|
||||||
|
start: Callback<()>,
|
||||||
|
finish: Callback<()>,
|
||||||
|
error: Callback<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoadingBarRef {
|
||||||
|
pub fn start(&self) {
|
||||||
|
self.start.call(());
|
||||||
|
}
|
||||||
|
pub fn finish(&self) {
|
||||||
|
self.finish.call(());
|
||||||
|
}
|
||||||
|
pub fn error(&self) {
|
||||||
|
self.error.call(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn LoadingBar(#[prop(optional)] comp_ref: ComponentRef<LoadingBarRef>) -> impl IntoView {
|
||||||
|
mount_style("loading-bar", include_str!("./loading-bar.css"));
|
||||||
|
let theme = use_theme(Theme::light);
|
||||||
|
let css_vars = create_memo(move |_| {
|
||||||
|
let mut css_vars = String::new();
|
||||||
|
theme.with(|theme| {
|
||||||
|
css_vars.push_str(&format!(
|
||||||
|
"--thaw-background-color: {};",
|
||||||
|
theme.common.color_success
|
||||||
|
));
|
||||||
|
css_vars.push_str(&format!(
|
||||||
|
"--thaw-background-color-error: {};",
|
||||||
|
theme.common.color_error
|
||||||
|
));
|
||||||
|
});
|
||||||
|
css_vars
|
||||||
|
});
|
||||||
|
let loading_bar_ref = create_node_ref::<html::Div>();
|
||||||
|
let loading = create_rw_signal(false);
|
||||||
|
|
||||||
|
let start = Callback::new(move |_| {
|
||||||
|
loading.set(true);
|
||||||
|
if let Some(loading_bar_ref) = loading_bar_ref.get_untracked() {
|
||||||
|
let loading_bar_ref = loading_bar_ref
|
||||||
|
.style("background-color", "var(--thaw-background-color)")
|
||||||
|
.style("transition", "none")
|
||||||
|
.style("max-width", "0");
|
||||||
|
_ = loading_bar_ref.offset_width();
|
||||||
|
loading_bar_ref
|
||||||
|
.style("transition", "max-width 4s linear")
|
||||||
|
.style("max-width", "80%");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let finish = Callback::new(move |_| {
|
||||||
|
if let Some(loading_bar_ref) = loading_bar_ref.get_untracked() {
|
||||||
|
let loading_bar_ref = loading_bar_ref
|
||||||
|
.style("background-color", "var(--thaw-background-color)")
|
||||||
|
.style("transition", "max-width 0.5s linear")
|
||||||
|
.style("max-width", "1000%");
|
||||||
|
loading_bar_ref.on(ev::transitionend, move |_| {
|
||||||
|
loading.set(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let error = Callback::new(move |_| {
|
||||||
|
if let Some(loading_bar_ref) = loading_bar_ref.get_untracked() {
|
||||||
|
if !loading.get() {
|
||||||
|
loading.set(true);
|
||||||
|
let loading_bar_ref = loading_bar_ref.clone();
|
||||||
|
let loading_bar_ref = loading_bar_ref
|
||||||
|
.style("transition", "none")
|
||||||
|
.style("max-width", "0");
|
||||||
|
_ = loading_bar_ref.offset_width();
|
||||||
|
}
|
||||||
|
let loading_bar_ref = loading_bar_ref
|
||||||
|
.style("background-color", "var(--thaw-background-color-error)")
|
||||||
|
.style("transition", "max-width 0.5s linear")
|
||||||
|
.style("max-width", "100%");
|
||||||
|
loading_bar_ref.on(ev::transitionend, move |_| {
|
||||||
|
loading.set(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
comp_ref.load(LoadingBarRef {
|
||||||
|
start,
|
||||||
|
finish,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
view! {
|
||||||
|
<div class="thaw-loading-bar-container">
|
||||||
|
<div class="thaw-loading-bar" ref=loading_bar_ref style=move || css_vars.get()>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue