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);
|
||||
view! {
|
||||
<Provider theme>
|
||||
<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>
|
||||
<TheRouter />
|
||||
</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]
|
||||
fn Provider(theme: RwSignal<Theme>, children: Children) -> impl IntoView {
|
||||
view! {
|
||||
|
|
|
@ -16,6 +16,7 @@ mod image;
|
|||
mod input;
|
||||
mod input_number;
|
||||
mod layout;
|
||||
mod loading_bar;
|
||||
mod menu;
|
||||
mod message;
|
||||
pub mod mobile;
|
||||
|
@ -53,6 +54,7 @@ pub use image::*;
|
|||
pub use input::*;
|
||||
pub use input_number::*;
|
||||
pub use layout::*;
|
||||
pub use loading_bar::*;
|
||||
pub use menu::*;
|
||||
pub use message::*;
|
||||
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