resources/assets/js/components/ui/message-toaster/MessageToast.vue

Summary

Maintainability
Test Coverage
<template>
  <article
    :class="message.type"
    class="group rounded-l-md cursor-pointer flex items-stretch opacity-90 transition-transform duration-300 origin-right
    hover:opacity-100 hover:scale-110"
    title="Click to dismiss"
    @click="dismiss"
    @mouseenter="cancelAutoDismiss"
    @mouseleave="setAutoDismiss"
  >
    <aside class="flex items-center px-3 py-0 bg-black/10">
      <Icon :icon="typeIcon" class="group-hover:hidden" />
      <Icon :icon="faTimesCircle" class="hidden group-hover:block" />
    </aside>
    <main class="flex-1 py-2 pl-3 pr-4">{{ message.content }}</main>
  </article>
</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)
}

const cancelAutoDismiss = () => window.clearTimeout(timeoutHandler)
const setAutoDismiss = () => (timeoutHandler = window.setTimeout(() => dismiss(), message.value.timeout * 1000))

onMounted(() => setAutoDismiss())
</script>

<style lang="postcss" scoped>
.info {
  @apply bg-blue-600 text-blue-100;
}

.danger {
  @apply bg-red-700 text-red-100;
}

.success {
  @apply bg-green-600 text-green-100;
}

.warning {
  @apply bg-orange-600 text-orange-100;
}
</style>