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
0839db8ec4
commit
1d7237e6de
10 changed files with 320 additions and 66 deletions
|
@ -1,14 +1,64 @@
|
||||||
# Toast
|
# Toast
|
||||||
|
|
||||||
```rust demo
|
```rust demo
|
||||||
let toaster = ToasterInjection::use_();
|
let toaster = ToasterInjection::expect_context();
|
||||||
|
|
||||||
let on_click = move |_| {
|
let on_click = move |_| {
|
||||||
toaster.dispatch_toast(view! { <span>"Hello"</span> }.into_any(), Default::default());
|
toaster.dispatch_toast(view! {
|
||||||
|
<Toast>
|
||||||
|
<ToastTitle>"Email sent"</ToastTitle>
|
||||||
|
<ToastBody>
|
||||||
|
"This is a toast body"
|
||||||
|
<ToastBodySubtitle slot>
|
||||||
|
"Subtitle"
|
||||||
|
</ToastBodySubtitle>
|
||||||
|
</ToastBody>
|
||||||
|
<ToastFooter>
|
||||||
|
"Footer"
|
||||||
|
// <Link>Action</Link>
|
||||||
|
// <Link>Action</Link>
|
||||||
|
</ToastFooter>
|
||||||
|
</Toast>
|
||||||
|
}.into_any(), Default::default());
|
||||||
};
|
};
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<Button on_click=on_click>"Make toast"</Button>
|
<Button on_click=on_click>"Make toast"</Button>
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Toast Positions
|
||||||
|
|
||||||
|
```rust demo
|
||||||
|
let toaster = ToasterInjection::expect_context();
|
||||||
|
|
||||||
|
let dispatch_toast = Callback::new(move |position| {
|
||||||
|
toaster.dispatch_toast(view! {
|
||||||
|
<Toast>
|
||||||
|
<ToastTitle>"Email sent"</ToastTitle>
|
||||||
|
<ToastBody>
|
||||||
|
"This is a toast body"
|
||||||
|
<ToastBodySubtitle slot>
|
||||||
|
"Subtitle"
|
||||||
|
</ToastBodySubtitle>
|
||||||
|
</ToastBody>
|
||||||
|
<ToastFooter>
|
||||||
|
"Footer"
|
||||||
|
// <Link>Action</Link>
|
||||||
|
// <Link>Action</Link>
|
||||||
|
</ToastFooter>
|
||||||
|
</Toast>
|
||||||
|
}.into_any(), ToastOptions::default().with_position(position));
|
||||||
|
});
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<Space>
|
||||||
|
<Button on_click=move |_| dispatch_toast.call(ToastPosition::Bottom)>"Bottom"</Button>
|
||||||
|
<Button on_click=move |_| dispatch_toast.call(ToastPosition::BottomStart)>"BottomStart"</Button>
|
||||||
|
<Button on_click=move |_| dispatch_toast.call(ToastPosition::BottomEnd)>"BottomEnd"</Button>
|
||||||
|
<Button on_click=move |_| dispatch_toast.call(ToastPosition::Top)>"Top"</Button>
|
||||||
|
<Button on_click=move |_| dispatch_toast.call(ToastPosition::TopStart)>"Topstart"</Button>
|
||||||
|
<Button on_click=move |_| dispatch_toast.call(ToastPosition::TopEnd)>"TopEnd"</Button>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
```
|
```
|
|
@ -71,6 +71,10 @@ impl ConfigInjection {
|
||||||
pub fn use_() -> ConfigInjection {
|
pub fn use_() -> ConfigInjection {
|
||||||
expect_context()
|
expect_context()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expect_context() -> Self {
|
||||||
|
expect_context()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
@ -109,6 +109,7 @@ pub struct ColorTheme {
|
||||||
pub color_transparent_stroke: String,
|
pub color_transparent_stroke: String,
|
||||||
|
|
||||||
pub shadow4: String,
|
pub shadow4: String,
|
||||||
|
pub shadow8: String,
|
||||||
pub shadow16: String,
|
pub shadow16: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,6 +224,7 @@ impl ColorTheme {
|
||||||
color_transparent_stroke: "transparent".into(),
|
color_transparent_stroke: "transparent".into(),
|
||||||
|
|
||||||
shadow4: "0 0 2px rgba(0,0,0,0.12), 0 2px 4px rgba(0,0,0,0.14)".into(),
|
shadow4: "0 0 2px rgba(0,0,0,0.12), 0 2px 4px rgba(0,0,0,0.14)".into(),
|
||||||
|
shadow8: "0 0 2px rgba(0,0,0,0.12), 0 4px 8px rgba(0,0,0,0.14)".into(),
|
||||||
shadow16: "0 0 2px rgba(0,0,0,0.12), 0 8px 16px rgba(0,0,0,0.14)".into(),
|
shadow16: "0 0 2px rgba(0,0,0,0.12), 0 8px 16px rgba(0,0,0,0.14)".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,6 +339,7 @@ impl ColorTheme {
|
||||||
color_transparent_stroke: "transparent".into(),
|
color_transparent_stroke: "transparent".into(),
|
||||||
|
|
||||||
shadow4: "0 0 2px rgba(0,0,0,0.24), 0 2px 4px rgba(0,0,0,0.28)".into(),
|
shadow4: "0 0 2px rgba(0,0,0,0.24), 0 2px 4px rgba(0,0,0,0.28)".into(),
|
||||||
|
shadow8: "0 0 2px rgba(0,0,0,0.24), 0 4px 8px rgba(0,0,0,0.28)".into(),
|
||||||
shadow16: "0 0 2px rgba(0,0,0,0.24), 0 8px 16px rgba(0,0,0,0.28)".into(),
|
shadow16: "0 0 2px rgba(0,0,0,0.24), 0 8px 16px rgba(0,0,0,0.28)".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub struct ToasterInjection {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToasterInjection {
|
impl ToasterInjection {
|
||||||
pub fn use_() -> Self {
|
pub fn expect_context() -> Self {
|
||||||
expect_context()
|
expect_context()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,20 +25,29 @@ impl ToastPosition {
|
||||||
pub fn as_str(&self) -> &'static str {
|
pub fn as_str(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Top => "top",
|
Self::Top => "top",
|
||||||
Self::TopStart => "top-left",
|
Self::TopStart => "top-start",
|
||||||
Self::TopEnd => "top-right",
|
Self::TopEnd => "top-dnc",
|
||||||
Self::Bottom => "bottom",
|
Self::Bottom => "bottom",
|
||||||
Self::BottomStart => "bottom-left",
|
Self::BottomStart => "bottom-start",
|
||||||
Self::BottomEnd => "bottom-right",
|
Self::BottomEnd => "bottom-end",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ToastIntent {
|
||||||
|
Success,
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ToastOptions {
|
pub struct ToastOptions {
|
||||||
pub(crate) id: uuid::Uuid,
|
pub(crate) id: uuid::Uuid,
|
||||||
pub(crate) position: Option<ToastPosition>,
|
pub(crate) position: Option<ToastPosition>,
|
||||||
pub(crate) timeout: Option<Duration>,
|
pub(crate) timeout: Option<Duration>,
|
||||||
|
pub(crate) intent: Option<ToastIntent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ToastOptions {
|
impl Default for ToastOptions {
|
||||||
|
@ -47,6 +56,24 @@ impl Default for ToastOptions {
|
||||||
id: uuid::Uuid::new_v4(),
|
id: uuid::Uuid::new_v4(),
|
||||||
position: None,
|
position: None,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
|
intent: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToastOptions {
|
||||||
|
pub fn with_position(mut self, position: ToastPosition) -> Self {
|
||||||
|
self.position = Some(position);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_timeout(mut self, timeout: Duration) -> Self {
|
||||||
|
self.timeout = Some(timeout);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_intent(mut self, intent: ToastIntent) -> Self {
|
||||||
|
self.intent = Some(intent);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,9 +7,13 @@ pub fn ToastBody(
|
||||||
children: Children,
|
children: Children,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
view! {
|
view! {
|
||||||
|
<div class="thaw-toast-body">
|
||||||
{children()}
|
{children()}
|
||||||
|
</div>
|
||||||
<OptionComp value=toast_body_subtitle let:subtitle>
|
<OptionComp value=toast_body_subtitle let:subtitle>
|
||||||
|
<div class="thaw-toast-body__subtitle">
|
||||||
{(subtitle.children)()}
|
{(subtitle.children)()}
|
||||||
|
</div>
|
||||||
</OptionComp>
|
</OptionComp>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,9 @@ use leptos::prelude::*;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ToastFooter(children: Children) -> impl IntoView {
|
pub fn ToastFooter(children: Children) -> impl IntoView {
|
||||||
children()
|
view! {
|
||||||
|
<div class="thaw-toast-footer">
|
||||||
|
{children()}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use leptos::prelude::*;
|
use leptos::{either::Either, prelude::*};
|
||||||
use thaw_components::OptionComp;
|
use thaw_components::OptionComp;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
|
@ -9,13 +9,25 @@ pub fn ToastTitle(
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
view! {
|
view! {
|
||||||
<div class="thaw-toast-title__media">
|
<div class="thaw-toast-title__media">
|
||||||
|
{
|
||||||
|
if let Some(media) = toast_title_media {
|
||||||
|
Either::Left((media.children)())
|
||||||
|
} else {
|
||||||
|
Either::Right(view! {
|
||||||
<svg fill="currentColor" aria-hidden="true" width="1em" height="1em" viewBox="0 0 20 20">
|
<svg fill="currentColor" aria-hidden="true" width="1em" height="1em" viewBox="0 0 20 20">
|
||||||
<path d="M18 10a8 8 0 1 0-16 0 8 8 0 0 0 16 0ZM9.5 8.91a.5.5 0 0 1 1 0V13.6a.5.5 0 0 1-1 0V8.9Zm-.25-2.16a.75.75 0 1 1 1.5 0 .75.75 0 0 1-1.5 0Z" fill="currentColor"></path>
|
<path d="M18 10a8 8 0 1 0-16 0 8 8 0 0 0 16 0ZM9.5 8.91a.5.5 0 0 1 1 0V13.6a.5.5 0 0 1-1 0V8.9Zm-.25-2.16a.75.75 0 1 1 1.5 0 .75.75 0 0 1-1.5 0Z" fill="currentColor"></path>
|
||||||
</svg>
|
</svg>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="thaw-toast-title">
|
||||||
{children()}
|
{children()}
|
||||||
|
</div>
|
||||||
<OptionComp value=toast_title_action let:action>
|
<OptionComp value=toast_title_action let:action>
|
||||||
|
<div class="thaw-toast-title__action">
|
||||||
{(action.children)()}
|
{(action.children)()}
|
||||||
|
</div>
|
||||||
</OptionComp>
|
</OptionComp>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
div.thaw-toaster {
|
div.thaw-toaster-wrapper {
|
||||||
z-index: 1000000;
|
z-index: 1000000;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
|
@ -13,15 +13,51 @@ div.thaw-toaster {
|
||||||
color: var(--colorNeutralForeground1);
|
color: var(--colorNeutralForeground1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.thaw-toaster-container {
|
.thaw-toaster {
|
||||||
bottom: 16px;
|
|
||||||
right: 20px;
|
|
||||||
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 292px;
|
width: 292px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.thaw-toaster--top {
|
||||||
|
top: 16px;
|
||||||
|
left: calc(50% + 20px);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-toaster--top-start {
|
||||||
|
top: 16px;
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-toaster--top-end {
|
||||||
|
top: 16px;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-toaster--bottom {
|
||||||
|
bottom: 16px;
|
||||||
|
left: calc(50% + 20px);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-toaster--bottom-start {
|
||||||
|
bottom: 16px;
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-toaster--bottom-end {
|
||||||
|
bottom: 16px;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-toaster-container {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-top: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
border-radius: var(--borderRadiusMedium);
|
||||||
|
}
|
||||||
|
|
||||||
.thaw-toaster-container.fade-in-height-expand-transition-leave-from,
|
.thaw-toaster-container.fade-in-height-expand-transition-leave-from,
|
||||||
.thaw-toaster-container.fade-in-height-expand-transition-enter-to {
|
.thaw-toaster-container.fade-in-height-expand-transition-enter-to {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
|
@ -95,3 +131,33 @@ div.thaw-toaster {
|
||||||
grid-column-end: -1;
|
grid-column-end: -1;
|
||||||
color: var(--colorBrandForeground1);
|
color: var(--colorBrandForeground1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.thaw-toast-body {
|
||||||
|
grid-column-start: 2;
|
||||||
|
grid-column-end: 3;
|
||||||
|
padding-top: 6px;
|
||||||
|
font-size: var(--fontSizeBase300);
|
||||||
|
line-height: var(--fontSizeBase300);
|
||||||
|
font-weight: var(--fontWeightRegular);
|
||||||
|
color: var(--colorNeutralForeground1);
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-toast-body__subtitle {
|
||||||
|
padding-top: 4px;
|
||||||
|
grid-column-start: 2;
|
||||||
|
grid-column-end: 3;
|
||||||
|
font-size: var(--fontSizeBase200);
|
||||||
|
line-height: var(--fontSizeBase200);
|
||||||
|
font-weight: var(--fontWeightRegular);
|
||||||
|
color: var(--colorNeutralForeground2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-toast-footer {
|
||||||
|
padding-top: 16px;
|
||||||
|
grid-column-start: 2;
|
||||||
|
grid-column-end: 3;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use super::{ToastOptions, ToastPosition, ToasterReceiver};
|
use super::{ToastOptions, ToastPosition, ToasterReceiver};
|
||||||
|
use crate::ConfigInjection;
|
||||||
use leptos::{either::Either, html, prelude::*, tachys::view::any_view::AnyView};
|
use leptos::{either::Either, html, prelude::*, tachys::view::any_view::AnyView};
|
||||||
use send_wrapper::SendWrapper;
|
use send_wrapper::SendWrapper;
|
||||||
use std::{collections::HashMap, time::Duration};
|
use std::{collections::HashMap, time::Duration};
|
||||||
|
@ -9,14 +10,29 @@ use thaw_utils::mount_style;
|
||||||
pub fn Toaster(
|
pub fn Toaster(
|
||||||
receiver: ToasterReceiver,
|
receiver: ToasterReceiver,
|
||||||
#[prop(optional)] position: ToastPosition,
|
#[prop(optional)] position: ToastPosition,
|
||||||
#[prop(default = Duration::from_secs(3))] timeout: Duration,
|
#[prop(default = Duration::from_secs(3000))] timeout: Duration,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
mount_style("toaster", include_str!("./toaster.css"));
|
mount_style("toaster", include_str!("./toaster.css"));
|
||||||
|
let config_provider = ConfigInjection::expect_context();
|
||||||
|
let top_id_list = RwSignal::<Vec<uuid::Uuid>>::new(Default::default());
|
||||||
|
let top_start_id_list = RwSignal::<Vec<uuid::Uuid>>::new(Default::default());
|
||||||
|
let top_end_id_list = RwSignal::<Vec<uuid::Uuid>>::new(Default::default());
|
||||||
|
let bottom_id_list = RwSignal::<Vec<uuid::Uuid>>::new(Default::default());
|
||||||
let bottom_start_id_list = RwSignal::<Vec<uuid::Uuid>>::new(Default::default());
|
let bottom_start_id_list = RwSignal::<Vec<uuid::Uuid>>::new(Default::default());
|
||||||
|
let bottom_end_id_list = RwSignal::<Vec<uuid::Uuid>>::new(Default::default());
|
||||||
let toasts = StoredValue::<HashMap<uuid::Uuid, (SendWrapper<AnyView<Dom>>, ToastOptions)>>::new(
|
let toasts = StoredValue::<HashMap<uuid::Uuid, (SendWrapper<AnyView<Dom>>, ToastOptions)>>::new(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let id_list = move |position: &ToastPosition| match position {
|
||||||
|
ToastPosition::Top => top_id_list,
|
||||||
|
ToastPosition::TopStart => top_start_id_list,
|
||||||
|
ToastPosition::TopEnd => top_end_id_list,
|
||||||
|
ToastPosition::Bottom => bottom_id_list,
|
||||||
|
ToastPosition::BottomStart => bottom_start_id_list,
|
||||||
|
ToastPosition::BottomEnd => bottom_end_id_list,
|
||||||
|
};
|
||||||
|
|
||||||
Effect::new(move |_| {
|
Effect::new(move |_| {
|
||||||
for (view, mut options) in receiver.try_recv() {
|
for (view, mut options) in receiver.try_recv() {
|
||||||
if options.position.is_none() {
|
if options.position.is_none() {
|
||||||
|
@ -25,44 +41,95 @@ pub fn Toaster(
|
||||||
if options.timeout.is_none() {
|
if options.timeout.is_none() {
|
||||||
options.timeout = Some(timeout);
|
options.timeout = Some(timeout);
|
||||||
}
|
}
|
||||||
match options.position.unwrap() {
|
|
||||||
ToastPosition::Top => todo!(),
|
let list = id_list(&options.position.unwrap());
|
||||||
ToastPosition::TopStart => todo!(),
|
|
||||||
ToastPosition::TopEnd => todo!(),
|
|
||||||
ToastPosition::Bottom => todo!(),
|
|
||||||
ToastPosition::BottomStart => {
|
|
||||||
let id = options.id;
|
let id = options.id;
|
||||||
toasts.update_value(|map| {
|
toasts.update_value(|map| {
|
||||||
map.insert(id, (SendWrapper::new(view), options));
|
map.insert(id, (SendWrapper::new(view), options));
|
||||||
});
|
});
|
||||||
bottom_start_id_list.update(|list| {
|
list.update(|list| {
|
||||||
list.push(id);
|
list.push(id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ToastPosition::BottomEnd => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let on_close = move |(id, position)| match position {
|
let on_close = move |(id, position)| {
|
||||||
ToastPosition::Top => todo!(),
|
let list = id_list(&position);
|
||||||
ToastPosition::TopStart => todo!(),
|
list.update(move |list| {
|
||||||
ToastPosition::TopEnd => todo!(),
|
|
||||||
ToastPosition::Bottom => todo!(),
|
|
||||||
ToastPosition::BottomStart => {
|
|
||||||
bottom_start_id_list.update(move |list| {
|
|
||||||
let Some(index) = list.iter().position(|item_id| &id == item_id) else {
|
let Some(index) = list.iter().position(|item_id| &id == item_id) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
list.remove(index);
|
list.remove(index);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
ToastPosition::BottomEnd => todo!(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<Teleport>
|
<Teleport>
|
||||||
<div class="thaw-config-provider thaw-toaster">
|
<div
|
||||||
|
class="thaw-config-provider thaw-toaster-wrapper"
|
||||||
|
data-thaw-id=config_provider.id().clone()
|
||||||
|
>
|
||||||
|
<div class="thaw-toaster thaw-toaster--top">
|
||||||
|
<For
|
||||||
|
each=move || top_id_list.get()
|
||||||
|
key=|id| id.clone()
|
||||||
|
let:id
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if let Some((view, options)) = toasts.try_update_value(|map| { map.remove(&id) }).flatten() {
|
||||||
|
Either::Left(view! { <ToasterContainer on_close view=view.take() options/> })
|
||||||
|
} else {
|
||||||
|
Either::Right(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
<div class="thaw-toaster thaw-toaster--top-start">
|
||||||
|
<For
|
||||||
|
each=move || top_start_id_list.get()
|
||||||
|
key=|id| id.clone()
|
||||||
|
let:id
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if let Some((view, options)) = toasts.try_update_value(|map| { map.remove(&id) }).flatten() {
|
||||||
|
Either::Left(view! { <ToasterContainer on_close view=view.take() options/> })
|
||||||
|
} else {
|
||||||
|
Either::Right(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
<div class="thaw-toaster thaw-toaster--top-end">
|
||||||
|
<For
|
||||||
|
each=move || top_end_id_list.get()
|
||||||
|
key=|id| id.clone()
|
||||||
|
let:id
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if let Some((view, options)) = toasts.try_update_value(|map| { map.remove(&id) }).flatten() {
|
||||||
|
Either::Left(view! { <ToasterContainer on_close view=view.take() options/> })
|
||||||
|
} else {
|
||||||
|
Either::Right(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
<div class="thaw-toaster thaw-toaster--bottom">
|
||||||
|
<For
|
||||||
|
each=move || bottom_id_list.get()
|
||||||
|
key=|id| id.clone()
|
||||||
|
let:id
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if let Some((view, options)) = toasts.try_update_value(|map| { map.remove(&id) }).flatten() {
|
||||||
|
Either::Left(view! { <ToasterContainer on_close view=view.take() options/> })
|
||||||
|
} else {
|
||||||
|
Either::Right(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
<div class="thaw-toaster thaw-toaster--bottom-start">
|
||||||
<For
|
<For
|
||||||
each=move || bottom_start_id_list.get()
|
each=move || bottom_start_id_list.get()
|
||||||
key=|id| id.clone()
|
key=|id| id.clone()
|
||||||
|
@ -77,6 +144,22 @@ pub fn Toaster(
|
||||||
}
|
}
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="thaw-toaster thaw-toaster--bottom-end">
|
||||||
|
<For
|
||||||
|
each=move || bottom_end_id_list.get()
|
||||||
|
key=|id| id.clone()
|
||||||
|
let:id
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if let Some((view, options)) = toasts.try_update_value(|map| { map.remove(&id) }).flatten() {
|
||||||
|
Either::Left(view! { <ToasterContainer on_close view=view.take() options/> })
|
||||||
|
} else {
|
||||||
|
Either::Right(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +176,7 @@ fn ToasterContainer(
|
||||||
id,
|
id,
|
||||||
timeout,
|
timeout,
|
||||||
position,
|
position,
|
||||||
|
..
|
||||||
} = options;
|
} = options;
|
||||||
let timeout = timeout.unwrap();
|
let timeout = timeout.unwrap();
|
||||||
let position = position.unwrap();
|
let position = position.unwrap();
|
||||||
|
|
Loading…
Add table
Reference in a new issue