mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-23 06:19:22 -05:00
feat: optimize Toast component
This commit is contained in:
parent
82e6f68018
commit
c57748f9ea
7 changed files with 177 additions and 13 deletions
|
@ -110,9 +110,9 @@ fn TheProvider(children: Children) -> impl IntoView {
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<ConfigProvider theme>
|
<ConfigProvider theme>
|
||||||
// <MessageProvider>
|
<ToasterProvider>
|
||||||
<LoadingBarProvider>{children()}</LoadingBarProvider>
|
<LoadingBarProvider>{children()}</LoadingBarProvider>
|
||||||
// </MessageProvider>
|
</ToasterProvider>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
# Toast
|
# Toast
|
||||||
|
|
||||||
```rust
|
```rust demo
|
||||||
|
let toaster = ToasterInjection::use_();
|
||||||
|
|
||||||
|
let on_click = move |_| {
|
||||||
|
toaster.dispatch_toast(view! { <span>"Hello"</span> }.into_any(), Default::default());
|
||||||
|
};
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<Toaster toaster_id=toaster_id />
|
<Button on_click=on_click>"Make toast"</Button>
|
||||||
<Button>"Make toast"</Button>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
|
@ -1,7 +1,59 @@
|
||||||
mod toast;
|
mod toast;
|
||||||
mod toast_title;
|
|
||||||
mod toaster;
|
|
||||||
mod toast_body;
|
mod toast_body;
|
||||||
mod toast_footer;
|
mod toast_footer;
|
||||||
|
mod toast_title;
|
||||||
|
mod toaster;
|
||||||
|
mod toaster_provider;
|
||||||
|
|
||||||
|
pub use toast::*;
|
||||||
pub use toast_title::*;
|
pub use toast_title::*;
|
||||||
|
pub use toaster_provider::*;
|
||||||
|
|
||||||
|
use leptos::{html::AnyElement, *};
|
||||||
|
use std::sync::mpsc::{channel, Receiver, Sender, TryIter};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ToasterInjection {
|
||||||
|
sender: Sender<(HtmlElement<AnyElement>, ToastOptions)>,
|
||||||
|
trigger: Trigger,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToasterInjection {
|
||||||
|
pub fn use_() -> Self {
|
||||||
|
expect_context()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn channel() -> (Self, ToasterReceiver) {
|
||||||
|
let (sender, receiver) = channel::<(HtmlElement<AnyElement>, ToastOptions)>();
|
||||||
|
let trigger = Trigger::new();
|
||||||
|
|
||||||
|
(
|
||||||
|
Self { sender, trigger },
|
||||||
|
ToasterReceiver::new(receiver, trigger),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dispatch_toast(&self, any_element: HtmlElement<AnyElement>, options: ToastOptions) {
|
||||||
|
self.sender.send((any_element, options)).unwrap();
|
||||||
|
self.trigger.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ToasterReceiver {
|
||||||
|
receiver: Receiver<(HtmlElement<AnyElement>, ToastOptions)>,
|
||||||
|
trigger: Trigger,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToasterReceiver {
|
||||||
|
pub fn new(
|
||||||
|
receiver: Receiver<(HtmlElement<AnyElement>, ToastOptions)>,
|
||||||
|
trigger: Trigger,
|
||||||
|
) -> Self {
|
||||||
|
Self { receiver, trigger }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_recv(&self) -> TryIter<'_, (HtmlElement<AnyElement>, ToastOptions)> {
|
||||||
|
self.trigger.track();
|
||||||
|
self.receiver.try_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,49 @@
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Toast(id: String) -> impl IntoView {
|
pub fn Toast(children: Children) -> impl IntoView {
|
||||||
view! {
|
view! {
|
||||||
|
<div class="thaw-toast">
|
||||||
|
{children()}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub enum ToastPosition {
|
||||||
|
Top,
|
||||||
|
TopStart,
|
||||||
|
#[default]
|
||||||
|
TopEnd,
|
||||||
|
Bottom,
|
||||||
|
BottomStart,
|
||||||
|
BottomEnd,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToastPosition {
|
||||||
|
pub fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Top => "top",
|
||||||
|
Self::TopStart => "top-left",
|
||||||
|
Self::TopEnd => "top-right",
|
||||||
|
Self::Bottom => "bottom",
|
||||||
|
Self::BottomStart => "bottom-left",
|
||||||
|
Self::BottomEnd => "bottom-right",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ToastOptions {
|
||||||
|
pub id: uuid::Uuid,
|
||||||
|
pub postition: Option<ToastPosition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ToastOptions {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
id: uuid::Uuid::new_v4(),
|
||||||
|
postition: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,27 @@
|
||||||
|
div.thaw-toaster-container {
|
||||||
|
z-index: 1000000;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
line-height: var(--lineHeightBase300);
|
||||||
|
font-weight: var(--fontWeightRegular);
|
||||||
|
font-size: var(--fontSizeBase300);
|
||||||
|
font-family: var(--fontFamilyBase);
|
||||||
|
text-align: left;
|
||||||
|
background-color: var(--colorNeutralBackground1);
|
||||||
|
color: var(--colorNeutralForeground1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-toaster {
|
||||||
|
bottom: 16px;
|
||||||
|
right: 20px;
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
width: 292px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.thaw-toast {
|
.thaw-toast {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto 1fr auto;
|
grid-template-columns: auto 1fr auto;
|
||||||
|
|
|
@ -1,10 +1,36 @@
|
||||||
|
use super::{ToastPosition, ToasterReceiver};
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use thaw_utils::mount_style;
|
use thaw_components::Teleport;
|
||||||
|
use thaw_utils::{class_list, mount_style};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Toaster(toaster_id: String) -> impl IntoView {
|
pub fn Toaster(
|
||||||
|
receiver: ToasterReceiver,
|
||||||
|
#[prop(optional)] position: ToastPosition,
|
||||||
|
) -> impl IntoView {
|
||||||
mount_style("toaster", include_str!("./toaster.css"));
|
mount_style("toaster", include_str!("./toaster.css"));
|
||||||
view! {
|
let toast_list = RwSignal::new(vec![]);
|
||||||
|
|
||||||
|
Effect::new(move |_| {
|
||||||
|
for view in receiver.try_recv() {
|
||||||
|
toast_list.update(move |list| {
|
||||||
|
list.push(view);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
view! {
|
||||||
|
<Teleport>
|
||||||
|
<div class="thaw-config-provider thaw-toaster-container">
|
||||||
|
<For
|
||||||
|
each=move || toast_list.get()
|
||||||
|
key=|toast| toast.1.id
|
||||||
|
let:toast
|
||||||
|
>
|
||||||
|
<div class=class_list!["thaw-toaster", "thaw-toaster"]>
|
||||||
|
{toast.0}
|
||||||
|
</div>
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
thaw/src/toast/toaster_provider.rs
Normal file
16
thaw/src/toast/toaster_provider.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use super::{toaster::Toaster, ToastPosition, ToasterInjection};
|
||||||
|
use leptos::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn ToasterProvider(
|
||||||
|
#[prop(optional)] position: ToastPosition,
|
||||||
|
children: Children,
|
||||||
|
) -> impl IntoView {
|
||||||
|
let (injection, receiver) = ToasterInjection::channel();
|
||||||
|
view! {
|
||||||
|
<Toaster receiver position/>
|
||||||
|
<Provider value=injection>
|
||||||
|
{children()}
|
||||||
|
</Provider>
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue