feat: optimize Toast component

This commit is contained in:
luoxiao 2024-07-03 17:27:29 +08:00
parent 82e6f68018
commit c57748f9ea
7 changed files with 177 additions and 13 deletions

View file

@ -110,9 +110,9 @@ fn TheProvider(children: Children) -> impl IntoView {
view! {
<ConfigProvider theme>
// <MessageProvider>
<LoadingBarProvider>{children()}</LoadingBarProvider>
// </MessageProvider>
<ToasterProvider>
<LoadingBarProvider>{children()}</LoadingBarProvider>
</ToasterProvider>
</ConfigProvider>
}
}

View file

@ -1,9 +1,14 @@
# Toast
```rust
```rust demo
let toaster = ToasterInjection::use_();
let on_click = move |_| {
toaster.dispatch_toast(view! { <span>"Hello"</span> }.into_any(), Default::default());
};
view! {
<Toaster toaster_id=toaster_id />
<Button>"Make toast"</Button>
<Button on_click=on_click>"Make toast"</Button>
}
```

View file

@ -1,7 +1,59 @@
mod toast;
mod toast_title;
mod toaster;
mod toast_body;
mod toast_footer;
mod toast_title;
mod toaster;
mod toaster_provider;
pub use toast::*;
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()
}
}

View file

@ -1,8 +1,49 @@
use leptos::*;
#[component]
pub fn Toast(id: String) -> impl IntoView {
pub fn Toast(children: Children) -> impl IntoView {
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,
}
}
}

View file

@ -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 {
display: grid;
grid-template-columns: auto 1fr auto;

View file

@ -1,10 +1,36 @@
use super::{ToastPosition, ToasterReceiver};
use leptos::*;
use thaw_utils::mount_style;
use thaw_components::Teleport;
use thaw_utils::{class_list, mount_style};
#[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"));
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>
}
}

View 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>
}
}