pinafore/src/routes/_components/Toast.html

95 lines
2.0 KiB
HTML

<div class="toast-modal {shown ? 'shown' : ''}" role="alert" aria-hidden={shown}>
<div class="toast-container">
{text}
</div>
</div>
<style>
.toast-modal {
position: fixed;
bottom: 40px;
left: 0;
right: 0;
opacity: 0;
transition: opacity 333ms linear;
display: flex;
flex-direction: column;
align-items: center;
pointer-events: none;
z-index: 100000;
}
.toast-container {
max-width: 600px;
max-height: 20vh;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
border: 2px solid var(--toast-border);
background: var(--toast-bg);
border-radius: 5px;
margin: 0 40px;
padding: 20px;
font-size: 1.3em;
color: var(--toast-text);
}
.toast-modal.shown {
opacity: 0.9;
}
@media (max-width: 767px) {
.toast-container {
max-width: 80vw;
}
}
</style>
<script>
import { splice, push, observe } from 'svelte-extras'
const TIME_TO_SHOW_TOAST = 5000
const DELAY_BETWEEN_TOASTS = 1000
export default {
oncreate () {
this._queue = Promise.resolve()
this.observe('messages', (messages) => {
if (messages.length) {
this.onNewToast(messages[0])
this.splice('messages', 0, 1)
}
})
},
data: () => ({
text: '',
shown: false,
messages: []
}),
methods: {
observe,
push,
splice,
say (text) {
this.push('messages', text)
},
onNewToast (text) {
this._queue = this._queue.then(() => {
this.set({
'text': text,
shown: true
})
return new Promise(resolve => {
setTimeout(resolve, TIME_TO_SHOW_TOAST)
})
}).then(() => {
this.set({
shown: false
})
return new Promise(resolve => {
setTimeout(resolve, DELAY_BETWEEN_TOASTS)
})
})
}
}
}
</script>