<template> <div :class="message.type" class="message" title="Click to dismiss" @click="dismiss"> <aside> <Icon :icon="typeIcon" class="icon" /> <Icon :icon="faTimesCircle" class="icon-dismiss" /> </aside> <main>{{ message.content }}</main> </div> </template> <script lang="ts" setup> import { computed, onMounted, toRefs } from 'vue' import { faCircleCheck, faCircleExclamation, faCircleInfo, faTimesCircle, faTriangleExclamation } from '@fortawesome/free-solid-svg-icons' const props = defineProps<{ message: ToastMessage }>() const { message } = toRefs(props) const typeIcon = computed(() => { switch (message.value.type) { case 'info': return faCircleInfo case 'success': return faCircleCheck case 'warning': return faTriangleExclamation default: return faCircleExclamation } }) let timeoutHandler: number const emit = defineEmits<{ (e: 'dismiss', message: ToastMessage): void }>() const dismiss = () => { emit('dismiss', message.value) window.clearTimeout(timeoutHandler) } onMounted(() => { timeoutHandler = window.setTimeout(() => dismiss(), message.value.timeout * 1000) }) </script> <style lang="scss" scoped> .message { border-radius: 4px 0 0 4px; cursor: pointer; display: flex; align-items: stretch; opacity: .9; transition: transform .3s; .icon-dismiss { display: none; } &:hover { opacity: 1; transform: scale(1.1); transform-origin: right; .icon { display: none; } .icon-dismiss { display: block; } } } aside { display: flex; align-items: center; padding: 0 8px; background: rgba(0, 0, 0, .1) } main { flex: 1; padding: 7px 14px 7px 10px; } .info { background-color: rgb(12 74 110); color: rgb(224 242 254); } .danger { background-color: rgb(185 28 28); color: rgb(254 226 226); } .success { background-color: rgb(5 150 105); color: rgb(209 250 229); } .warning { background-color: rgb(249 115 22); color: rgb(255 237 213); } </style>