wip bsky client for the web & android bbell.vt3e.cat
at main 128 lines 2.4 kB view raw
1<script setup lang="ts"> 2import { useToastStore } from '@/stores/toast' 3 4function onBeforeLeave(el: Element) { 5 const htmlEl = el as HTMLElement 6 const { offsetTop, offsetLeft, offsetWidth } = htmlEl 7 htmlEl.style.top = `${offsetTop}px` 8 htmlEl.style.left = `${offsetLeft}px` 9 htmlEl.style.width = `${offsetWidth}px` 10} 11const toast = useToastStore() 12</script> 13 14<template> 15 <Transition tag="div" name="stack"> 16 <div v-if="toast.toasts.length" class="toast-stack"> 17 <TransitionGroup name="toast" @before-leave="onBeforeLeave"> 18 <div 19 v-for="t in toast.toasts" 20 :key="t.id" 21 :class="['toast', t.type]" 22 @click="toast.handleClick(t.id)" 23 > 24 <div class="icon"> 25 <component :is="t.icon" /> 26 </div> 27 <span class="message">{{ t.message }}</span> 28 </div> 29 </TransitionGroup> 30 </div> 31 </Transition> 32</template> 33 34<style scoped lang="scss"> 35.toast-stack { 36 position: absolute; 37 bottom: calc(5rem + env(safe-area-inset-bottom)); 38 left: 0.5rem; 39 z-index: 1000; 40 41 display: flex; 42 flex-direction: column; 43 align-items: flex-start; 44 gap: 0.75rem; 45 46 width: 100%; 47 pointer-events: none; 48} 49@media (min-width: 800px) { 50 .toast-stack { 51 position: fixed; 52 bottom: 1.5rem; 53 } 54} 55 56.toast { 57 --accent-colour: var(--accent); 58 max-width: var(--content-width); 59 background-color: hsla(var(--surface0) / 1); 60 61 display: inline-flex; 62 align-items: center; 63 justify-content: center; 64 65 padding: 0.25rem 0.5rem; 66 padding-right: 1rem; 67 gap: 0.5rem; 68 border-radius: 2rem; 69 70 cursor: pointer; 71 pointer-events: all; 72 user-select: none; 73 74 max-height: 5rem; 75 overflow: hidden; 76 77 border: 1px solid hsla(var(--accent-colour) / 0.25); 78 79 .icon { 80 font-size: 1.5rem; 81 display: flex; 82 align-items: center; 83 justify-content: center; 84 color: hsl(var(--accent-colour)); 85 } 86 87 &.success { 88 --accent-colour: var(--green); 89 } 90 &.error { 91 --accent-colour: var(--red); 92 } 93 &.info { 94 --accent-colour: var(--blue); 95 } 96} 97 98.stack-enter-active, 99.stack-leave-active { 100 transition: opacity 0.2s ease; 101} 102.stack-enter-from, 103.stack-leave-to { 104 opacity: 0; 105} 106 107.toast-move, 108.toast-enter-active, 109.toast-leave-active { 110 transition: all 0.25s ease; 111} 112 113.toast-enter-from { 114 opacity: 0; 115 transform: translateY(1rem) scale(0.95); 116} 117 118.toast-leave-to { 119 opacity: 0; 120 transform: translateX(-2rem) scale(0.95); 121 filter: blur(2px); 122 max-height: 0; 123 padding-top: 0; 124 padding-bottom: 0; 125 margin-top: -0.75rem; 126 border-width: 0; 127} 128</style>