forked from tsai/budibase
7 changed files with 111 additions and 29 deletions
@ -0,0 +1,71 @@ |
|||||
|
<script> |
||||
|
import { getContext } from "svelte" |
||||
|
import { fly } from "svelte/transition" |
||||
|
|
||||
|
export let themes = { |
||||
|
danger: "#E26D69", |
||||
|
success: "#84C991", |
||||
|
warning: "#f0ad4e", |
||||
|
info: "#5bc0de", |
||||
|
default: "#aaaaaa", |
||||
|
} |
||||
|
|
||||
|
export let timeout = 3000 |
||||
|
|
||||
|
const notificationStore = getContext("notification") |
||||
|
|
||||
|
$: if ($notificationStore.notifications.length) { |
||||
|
setTimeout(() => { |
||||
|
notificationStore.update(state => { |
||||
|
state.notifications.shift() |
||||
|
state.notifications = state.notifications |
||||
|
return state |
||||
|
}) |
||||
|
}, timeout) |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<div class="notifications"> |
||||
|
{#each $notificationStore.notifications as notification (notification.id)} |
||||
|
<div |
||||
|
class="toast" |
||||
|
style="background: {themes[notification.type]};" |
||||
|
transition:fly={{ y: -30 }}> |
||||
|
<div class="content">{notification.message}</div> |
||||
|
{#if notification.icon}<i class={notification.icon} />{/if} |
||||
|
</div> |
||||
|
{/each} |
||||
|
</div> |
||||
|
|
||||
|
<style> |
||||
|
.notifications { |
||||
|
position: fixed; |
||||
|
top: 10px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
margin: 0 auto; |
||||
|
padding: 0; |
||||
|
z-index: 9999; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: flex-start; |
||||
|
align-items: center; |
||||
|
pointer-events: none; |
||||
|
} |
||||
|
|
||||
|
.toast { |
||||
|
flex: 0 0 auto; |
||||
|
margin-bottom: 10px; |
||||
|
border-radius: var(--border-radius-s); |
||||
|
/* The toasts now support being auto sized, so this static width could be removed */ |
||||
|
width: 40vw; |
||||
|
} |
||||
|
|
||||
|
.content { |
||||
|
padding: 10px; |
||||
|
display: block; |
||||
|
color: white; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
@ -0,0 +1,36 @@ |
|||||
|
import { writable, derived } from "svelte/store" |
||||
|
|
||||
|
let NOTIFICATION_TIMEOUT = 3000 |
||||
|
|
||||
|
export const createNotificationStore = () => { |
||||
|
const _notifications = writable([]) |
||||
|
|
||||
|
const send = (message, type = "default") => { |
||||
|
_notifications.update(state => { |
||||
|
state = [ |
||||
|
...state, |
||||
|
{ id: 1, type, message }, |
||||
|
] |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
const notifications = derived(_notifications, ($_notifications, set) => { |
||||
|
const timeout = setTimeout({ |
||||
|
set($_notifications) |
||||
|
}, NOTIFICATION_TIMEOUT) |
||||
|
|
||||
|
return () => { |
||||
|
clearTimeout(timeout); |
||||
|
}; |
||||
|
}) |
||||
|
const {subscribe} = notifications |
||||
|
|
||||
|
return { |
||||
|
subscribe, |
||||
|
send, |
||||
|
danger: msg => send(msg, "danger"), |
||||
|
warning: msg => send(msg, "warning"), |
||||
|
info: msg => send(msg, "info"), |
||||
|
success: msg => send(msg, "success"), |
||||
|
} |
||||
|
} |
||||
@ -1,23 +0,0 @@ |
|||||
import { writable } from "svelte/store" |
|
||||
import { generate } from "shortid" |
|
||||
|
|
||||
export const notificationStore = writable({ |
|
||||
notifications: [], |
|
||||
}) |
|
||||
|
|
||||
export function send(message, type = "default") { |
|
||||
notificationStore.update(state => { |
|
||||
state.notifications = [ |
|
||||
...state.notifications, |
|
||||
{ id: generate(), type, message }, |
|
||||
] |
|
||||
return state |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
export const notifier = { |
|
||||
danger: msg => send(msg, "danger"), |
|
||||
warning: msg => send(msg, "warning"), |
|
||||
info: msg => send(msg, "info"), |
|
||||
success: msg => send(msg, "success"), |
|
||||
} |
|
||||
Loading…
Reference in new issue