use topcoat::{
Result,
icon::icon,
view::{Attributes, Child, StaticClass, View, attributes, class, component, view},
};
use crate::icons;
const TOASTER: StaticClass = class!(
"pointer-events-none fixed right-4 bottom-4 z-50 flex w-[356px] \
max-w-[calc(100vw-2rem)] flex-col gap-3.5 sm:right-6 sm:bottom-6",
);
const TOAST: StaticClass = class!(
"pointer-events-auto relative flex w-full translate-y-0 items-center gap-1.5 rounded-lg \
border border-border bg-background p-4 text-[13px] text-foreground shadow-lg \
[overflow-wrap:anywhere] \
transition-[translate,opacity] duration-[400ms] ease-[cubic-bezier(0.25,0.1,0.25,1)] \
focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:outline-none \
data-[mounted=false]:translate-y-full data-[mounted=false]:opacity-0 \
data-[removed=true]:translate-y-full data-[removed=true]:opacity-0",
);
const ICON: StaticClass = class!("flex size-4 shrink-0 items-center justify-center");
const CONTENT: StaticClass = class!("flex min-w-0 flex-1 flex-col gap-0.5");
const TITLE: StaticClass = class!("font-medium leading-normal");
const DESCRIPTION: StaticClass = class!("leading-snug text-muted-foreground");
const CLOSE: StaticClass = class!(
"absolute top-0 left-0 flex size-5 -translate-x-[35%] -translate-y-[35%] \
cursor-pointer items-center justify-center rounded-full border border-border \
bg-background text-foreground transition-colors hover:bg-muted",
);
#[component]
pub async fn toaster(
#[default] mut attrs: Attributes,
#[default] child: Child<'_>,
) -> Result<impl View> {
Ok(view! {
<section
aria-label="Notifications"
tabindex="-1"
aria-live="polite"
aria-relevant="additions text"
aria-atomic="false"
>
<noscript>
<style>
"[data-sonner-toast]{opacity:1 !important;transform:none !important}"
</style>
</noscript>
<ol
class=(class!(TOASTER, attrs.remove("class")))
data-sonner-toaster=""
data-y-position="bottom"
data-x-position="right"
(attrs)
>
(child)
</ol>
</section>
})
}
#[component]
pub async fn toast(
#[default] mut attrs: Attributes,
#[default] child: Child<'_>,
) -> Result<impl View> {
Ok(view! {
<li
tabindex="0"
class=(class!(TOAST, attrs.remove("class")))
data-sonner-toast=""
data-styled="true"
data-mounted="false"
data-visible="true"
data-y-position="bottom"
data-x-position="right"
data-front="true"
(attrs)
>
(child)
</li>
})
}
#[component]
pub async fn toast_icon(
#[default] mut attrs: Attributes,
#[default] child: Child<'_>,
) -> Result<impl View> {
Ok(view! {
<div
class=(class!(ICON, attrs.remove("class")))
data-icon=""
aria-hidden="true"
(attrs)
>
(child)
</div>
})
}
#[component]
pub async fn toast_content(
#[default] mut attrs: Attributes,
#[default] child: Child<'_>,
) -> Result<impl View> {
Ok(view! {
<div class=(class!(CONTENT, attrs.remove("class"))) data-content="" (attrs)>
(child)
</div>
})
}
#[component]
pub async fn toast_title(
#[default] mut attrs: Attributes,
#[default] child: Child<'_>,
) -> Result<impl View> {
Ok(view! {
<div class=(class!(TITLE, attrs.remove("class"))) data-title="" (attrs)>
(child)
</div>
})
}
#[component]
pub async fn toast_description(
#[default] mut attrs: Attributes,
#[default] child: Child<'_>,
) -> Result<impl View> {
Ok(view! {
<div
class=(class!(DESCRIPTION, attrs.remove("class")))
data-description=""
(attrs)
>
(child)
</div>
})
}
#[component]
pub async fn toast_close(#[default] mut attrs: Attributes) -> Result<impl View> {
Ok(view! {
<button
type="button"
aria-label="Close toast"
class=(class!(CLOSE, attrs.remove("class")))
data-close-button=""
(attrs)
>
icon(data: icons::X, attrs: attributes! { class="size-3" })
</button>
})
}