chore(toast): improve notifications

This commit is contained in:
Benjamin Canac
2022-07-21 00:39:06 +02:00
parent 487f253e14
commit 1ff9fd4f69
3 changed files with 64 additions and 54 deletions

View File

@@ -15,30 +15,39 @@
> >
<div class="relative overflow-hidden rounded-lg ring-1 u-ring-gray-200"> <div class="relative overflow-hidden rounded-lg ring-1 u-ring-gray-200">
<div class="p-4"> <div class="p-4">
<div class="flex"> <div class="flex" :class="{ 'items-center': !description }">
<div class="flex-shrink-0"> <div class="flex-shrink-0">
<Icon :name="iconName" class="w-6 h-6" :class="iconClass" /> <Icon :name="iconName" class="w-6 h-6" :class="iconClass" />
</div> </div>
<div class="ml-3 w-0 flex-1 pt-0.5"> <div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm font-medium leading-5 u-text-gray-900"> <p class="text-sm font-medium u-text-gray-900">
{{ title }} {{ title }}
</p> </p>
<p v-if="description" class="mt-1 text-sm leading-5 u-text-gray-500"> <p v-if="description" class="mt-1 text-sm leading-5 u-text-gray-500">
{{ description }} {{ description }}
</p> </p>
<Button
v-if="undo" <div v-if="description" class="mt-3 flex items-center gap-7">
variant="white" <button v-if="undo" type="button" class="text-sm font-medium text-primary-500 hover:text-primary-600 dark:hover:text-primary-400 focus:outline-none" @click.stop="onUndo">
size="xs" Undo
class="mt-2" </button>
@click.stop="onUndo" <button v-if="dismiss" type="button" class="text-sm font-medium u-text-gray-700 hover:u-text-gray-500 focus:outline-none" @click.stop="onDismiss">
> Dismiss
Undo </button>
</Button> </div>
</div> </div>
<div class="flex-shrink-0 ml-4"> <div class="flex-shrink-0 flex items-center ml-4">
<div v-if="!description" class="flex items-center gap-2">
<button v-if="undo" type="button" class="text-sm font-medium text-primary-500 hover:text-primary-600 dark:hover:text-primary-400 focus:outline-none" @click.stop="onUndo">
Undo
</button>
<button v-if="dismiss" type="button" class="text-sm font-medium u-text-gray-700 hover:u-text-gray-500 focus:outline-none" @click.stop="onDismiss">
Dismiss
</button>
</div>
<button <button
class="transition duration-150 ease-in-out u-text-gray-400 focus:outline-none hover:u-text-gray-500 focus:u-text-gray-500" class="transition duration-150 ease-in-out u-text-gray-400 focus:outline-none hover:u-text-gray-500 focus:u-text-gray-500 ml-4"
@click.stop="onClose" @click.stop="onClose"
> >
<span class="sr-only">Close</span> <span class="sr-only">Close</span>
@@ -59,8 +68,8 @@
import { ref, computed, onMounted, onUnmounted, watchEffect } from 'vue' import { ref, computed, onMounted, onUnmounted, watchEffect } from 'vue'
import Icon from '../elements/Icon' import Icon from '../elements/Icon'
import Button from '../elements/Button'
import { useTimer } from '../../composables/useTimer' import { useTimer } from '../../composables/useTimer'
import { classNames } from '../../utils'
const props = defineProps({ const props = defineProps({
id: { id: {
@@ -69,10 +78,9 @@ const props = defineProps({
}, },
type: { type: {
type: String, type: String,
required: true, default: null,
default: 'info', validator (value: string | null) {
validator (value: string) { return [null, 'info', 'success', 'error', 'warning'].includes(value)
return ['info', 'success', 'error', 'warning'].includes(value)
} }
}, },
title: { title: {
@@ -87,6 +95,10 @@ const props = defineProps({
type: String, type: String,
default: null default: null
}, },
iconClass: {
type: String,
default: null
},
timeout: { timeout: {
type: Number, type: Number,
default: 5000 default: 5000
@@ -95,6 +107,10 @@ const props = defineProps({
type: Function, type: Function,
default: null default: null
}, },
dismiss: {
type: Function,
default: null
},
callback: { callback: {
type: Function, type: Function,
default: null default: null
@@ -116,12 +132,15 @@ const iconName = computed(() => {
}) })
const iconClass = computed(() => { const iconClass = computed(() => {
return ({ return classNames(
warning: 'text-orange-400', ({
info: 'text-blue-400', warning: 'text-orange-400',
success: 'text-green-400', info: 'text-blue-400',
error: 'text-red-400' success: 'text-green-400',
})[props.type] || 'u-text-gray-400' error: 'text-red-400'
})[props.type] || 'u-text-gray-400',
props.iconClass
)
}) })
const progressBarStyle = computed(() => { const progressBarStyle = computed(() => {
@@ -165,6 +184,18 @@ function onUndo () {
emit('close') emit('close')
} }
function onDismiss () {
if (timer) {
timer.stop()
}
if (props.dismiss) {
props.dismiss()
}
emit('close')
}
onMounted(() => { onMounted(() => {
if (!props.timeout) { if (!props.timeout) {
return return

View File

@@ -2,8 +2,7 @@
<div class="fixed bottom-0 right-0 flex flex-col justify-end w-full z-[55] sm:w-96"> <div class="fixed bottom-0 right-0 flex flex-col justify-end w-full z-[55] sm:w-96">
<div v-if="notifications.length" class="px-4 py-6 space-y-3 overflow-y-auto sm:px-6"> <div v-if="notifications.length" class="px-4 py-6 space-y-3 overflow-y-auto sm:px-6">
<div <div
v-for="(notification, index) of notifications" v-for="notification of notifications"
v-show="index === notifications.length - 1"
:key="notification.id" :key="notification.id"
> >
<Notification <Notification

View File

@@ -28,37 +28,17 @@ export default defineNuxtPlugin(() => {
toast: { toast: {
addNotification, addNotification,
removeNotification, removeNotification,
success ({ title, description, timeout }: { title?: string, description?: string, timeout?: number } = {}) { success (notification: Partial<ToastNotification> = {}) {
addNotification({ return addNotification({ type: 'success', ...notification })
type: 'success',
title,
description,
timeout
})
}, },
info ({ title, description, timeout }: { title?: string, description?: string, timeout?: number } = {}) { info (notification: Partial<ToastNotification> = {}) {
addNotification({ return addNotification({ type: 'info', ...notification })
type: 'info',
title,
description,
timeout
})
}, },
warning ({ title, description, timeout }: { title?: string, description?: string, timeout?: number } = {}) { warning (notification: Partial<ToastNotification> = {}) {
addNotification({ return addNotification({ type: 'warning', ...notification })
type: 'warning',
title,
description,
timeout
})
}, },
error ({ title = 'An error occurred!', description, timeout }: { title?: string, description?: string, timeout?: number } = {}) { error (notification: Partial<ToastNotification>) {
addNotification({ return addNotification({ type: 'error', title: 'An error occurred!', ...notification })
type: 'error',
title,
description,
timeout
})
} }
} }
} }