mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09: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! {
|
||||
<ConfigProvider theme>
|
||||
// <MessageProvider>
|
||||
<LoadingBarProvider>{children()}</LoadingBarProvider>
|
||||
// </MessageProvider>
|
||||
<ToasterProvider>
|
||||
<LoadingBarProvider>{children()}</LoadingBarProvider>
|
||||
</ToasterProvider>
|
||||
</ConfigProvider>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
|
||||
```
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
}
|
||||
|
|
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