feat: create Toast component
This commit is contained in:
111
apps/website/src/components/molecules/Toast.svelte
Normal file
111
apps/website/src/components/molecules/Toast.svelte
Normal file
@@ -0,0 +1,111 @@
|
||||
<style lang="scss">
|
||||
@import "../../style/molecules/toast";
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import { fade, fly } from 'svelte/transition'
|
||||
import { quartOut } from 'svelte/easing'
|
||||
import { browser } from '$app/environment'
|
||||
import { cx } from 'classix'
|
||||
// Components
|
||||
import Button from '$components/atoms/Button.svelte'
|
||||
import Image from '$components/atoms/Image.svelte'
|
||||
|
||||
export let id: string
|
||||
export let type: 'global' | 'local'
|
||||
export let text: string
|
||||
export let cta: {
|
||||
label: string
|
||||
url: string
|
||||
color: string
|
||||
} = undefined
|
||||
export let images: { id: string, title: string }[] = undefined
|
||||
export let show = false
|
||||
|
||||
$: if (browser) {
|
||||
show = !localStorage.getItem(`toast-${id}`)
|
||||
}
|
||||
|
||||
// Image rotation
|
||||
let imagesLoop: ReturnType<typeof setTimeout>
|
||||
let currentImageIndex = 0
|
||||
|
||||
const incrementCurrentImageIndex = () => {
|
||||
currentImageIndex = currentImageIndex === images.length - 1 ? 0 : currentImageIndex + 1
|
||||
imagesLoop = setTimeout(() => requestAnimationFrame(incrementCurrentImageIndex), 3000)
|
||||
}
|
||||
|
||||
// Close toast
|
||||
const close = () => {
|
||||
localStorage.setItem(`toast-${id}`, 'closed')
|
||||
show = false
|
||||
}
|
||||
|
||||
$: classes = cx(
|
||||
'toast',
|
||||
`toast--${type}`,
|
||||
'shadow-small',
|
||||
$$props.class,
|
||||
)
|
||||
|
||||
|
||||
onMount(() => {
|
||||
if (images.length > 1) {
|
||||
incrementCurrentImageIndex()
|
||||
}
|
||||
|
||||
return () => {
|
||||
// Clear rotating words timeout
|
||||
if (imagesLoop) {
|
||||
clearTimeout(imagesLoop)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if show}
|
||||
<div
|
||||
class={classes}
|
||||
in:fly={{ y: '10%', duration: 1200, easing: quartOut }}
|
||||
out:fade={{ duration: 800, easing: quartOut }}
|
||||
>
|
||||
{#if images}
|
||||
<div class="media">
|
||||
<a href={cta.url}>
|
||||
{#each images as { id, title }, index}
|
||||
<Image
|
||||
class={index === currentImageIndex ? 'is-visible' : null}
|
||||
{id}
|
||||
sizeKey="square"
|
||||
sizes={{
|
||||
small: { width: 200, height: 200 },
|
||||
large: { width: 350, height: 350 },
|
||||
}}
|
||||
alt={title}
|
||||
/>
|
||||
{/each}
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="content">
|
||||
<p class="text">{@html text}</p>
|
||||
|
||||
{#if cta}
|
||||
<Button
|
||||
size="xsmall"
|
||||
text={cta.label}
|
||||
url={cta.url}
|
||||
color="pink"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<button class="close" on:click={close} title="Close">
|
||||
<svg width="10" height="10">
|
||||
<use xlink:href="#cross" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
Reference in New Issue
Block a user