mirror of
https://github.com/adoyle0/thaw.git
synced 2025-03-12 21:49:49 -04:00
commit
f0e56c065f
9 changed files with 298 additions and 42 deletions
|
@ -1 +0,0 @@
|
|||
Subproject commit faaa4dfa5547b4c3e117999f4ed4cf2332006f2b
|
100
demo/src/app.rs
100
demo/src/app.rs
|
@ -24,57 +24,75 @@ 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 {
|
||||
let loading_bar = use_loading_bar();
|
||||
let set_is_routing = SignalSetter::map(move |is_routing| {
|
||||
if is_routing {
|
||||
loading_bar.start();
|
||||
} else {
|
||||
loading_bar.finish();
|
||||
}
|
||||
});
|
||||
view! {
|
||||
<Router base="/thaw" set_is_routing>
|
||||
<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 path="/loading-bar" view=LoadingBarPage/>
|
||||
</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! {
|
||||
<ThemeProvider theme>
|
||||
<GlobalStyle />
|
||||
<MessageProvider>
|
||||
{children()}
|
||||
<LoadingBarProvider>
|
||||
{children()}
|
||||
</LoadingBarProvider>
|
||||
</MessageProvider>
|
||||
</ThemeProvider>
|
||||
}
|
||||
|
|
|
@ -167,6 +167,10 @@ fn gen_menu_data() -> Vec<MenuGroupOption> {
|
|||
MenuGroupOption {
|
||||
label: "Navigation Components".into(),
|
||||
children: vec![
|
||||
MenuItemOption {
|
||||
value: "loading-bar".into(),
|
||||
label: "Loading Bar".into(),
|
||||
},
|
||||
MenuItemOption {
|
||||
value: "menu".into(),
|
||||
label: "Menu".into(),
|
||||
|
|
62
demo/src/pages/loading_bar/mod.rs
Normal file
62
demo/src/pages/loading_bar/mod.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use crate::components::{Demo, DemoCode};
|
||||
use leptos::*;
|
||||
use prisms::highlight_str;
|
||||
use thaw::*;
|
||||
|
||||
#[component]
|
||||
pub fn LoadingBarPage() -> impl IntoView {
|
||||
let loading_bar = use_loading_bar();
|
||||
let start = move |_| {
|
||||
loading_bar.start();
|
||||
};
|
||||
let finish = move |_| {
|
||||
loading_bar.finish();
|
||||
};
|
||||
let error = move |_| {
|
||||
loading_bar.error();
|
||||
};
|
||||
view! {
|
||||
<div style="width: 896px; margin: 0 auto;">
|
||||
<h1>"Loading Bar"</h1>
|
||||
<Alert variant=AlertVariant::Warning title="Prerequisite">
|
||||
"If you want to use loading bar, you need to wrap the component where you call related methods inside LoadingBarProvider and use use_loading_bar to get the API."
|
||||
</Alert>
|
||||
<Demo>
|
||||
<Space>
|
||||
<Button on_click=start>"start"</Button>
|
||||
<Button on_click=finish>"finish"</Button>
|
||||
<Button on_click=error>"error"</Button>
|
||||
</Space>
|
||||
<DemoCode
|
||||
slot
|
||||
html=highlight_str!(
|
||||
r#"
|
||||
let loading_bar = use_loading_bar();
|
||||
let start = move |_| {
|
||||
loading_bar.start();
|
||||
};
|
||||
let finish = move |_| {
|
||||
loading_bar.finish();
|
||||
};
|
||||
let error = move |_| {
|
||||
loading_bar.error();
|
||||
};
|
||||
view! {
|
||||
<Space>
|
||||
<Button on_click=start>"start"</Button>
|
||||
<Button on_click=finish>"finish"</Button>
|
||||
<Button on_click=error>"error"</Button>
|
||||
</Space>
|
||||
}
|
||||
"#,
|
||||
"rust"
|
||||
)
|
||||
>
|
||||
|
||||
""
|
||||
""
|
||||
</DemoCode>
|
||||
</Demo>
|
||||
</div>
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ mod icon;
|
|||
mod image;
|
||||
mod input;
|
||||
mod input_number;
|
||||
mod loading_bar;
|
||||
mod menu;
|
||||
mod message;
|
||||
mod mobile;
|
||||
|
@ -48,6 +49,7 @@ pub use icon::*;
|
|||
pub use image::*;
|
||||
pub use input::*;
|
||||
pub use input_number::*;
|
||||
pub use loading_bar::*;
|
||||
pub use menu::*;
|
||||
pub use message::*;
|
||||
pub use mobile::*;
|
||||
|
|
|
@ -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>()
|
||||
}
|
112
src/loading_bar/mod.rs
Normal file
112
src/loading_bar/mod.rs
Normal file
|
@ -0,0 +1,112 @@
|
|||
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(crate) 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(crate) 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 is_on_transitionend = store_value(false);
|
||||
let on_transitionend = move |_| {
|
||||
if is_on_transitionend.get_value() {
|
||||
is_on_transitionend.set_value(false);
|
||||
loading.set(false);
|
||||
}
|
||||
};
|
||||
let finish = Callback::new(move |_| {
|
||||
if let Some(loading_bar_ref) = loading_bar_ref.get_untracked() {
|
||||
loading_bar_ref
|
||||
.style("background-color", "var(--thaw-background-color)")
|
||||
.style("transition", "max-width 0.5s linear")
|
||||
.style("max-width", "100%");
|
||||
is_on_transitionend.set_value(true);
|
||||
}
|
||||
});
|
||||
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();
|
||||
}
|
||||
loading_bar_ref
|
||||
.style("background-color", "var(--thaw-background-color-error)")
|
||||
.style("transition", "max-width 0.5s linear")
|
||||
.style("max-width", "100%");
|
||||
is_on_transitionend.set_value(true);
|
||||
}
|
||||
});
|
||||
|
||||
comp_ref.load(LoadingBarRef {
|
||||
start,
|
||||
finish,
|
||||
error,
|
||||
});
|
||||
view! {
|
||||
<div
|
||||
class="thaw-loading-bar-container"
|
||||
style=move || (!loading.get()).then(|| "display: none;")
|
||||
>
|
||||
<div
|
||||
class="thaw-loading-bar"
|
||||
ref=loading_bar_ref
|
||||
style=move || css_vars.get()
|
||||
on:transitionend=on_transitionend
|
||||
></div>
|
||||
</div>
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue