Skip to content

Instantly share code, notes, and snippets.

@puncoz
Created October 14, 2021 11:15
Show Gist options
  • Save puncoz/dc21eb08ff35180a4a1531a2587eefd8 to your computer and use it in GitHub Desktop.
Save puncoz/dc21eb08ff35180a4a1531a2587eefd8 to your computer and use it in GitHub Desktop.
Notification in vue3
import useNotification from "./useNotification.js"
const notification = useNotification()
notification.success("sucess message")
<template>
<div class="flex items-center rounded p-3 shadow-md mb-2 w-64"
:class="{
'bg-green-500' : notification.type === 'success',
'bg-red-500' : notification.type === 'error',
'bg-yellow-500' : notification.type === 'warning',
'bg-blue-500' : notification.type === 'info',
'bg-primary-500' : notification.type === 'message',
}">
<div class="flex-1 flex items-center">
<!-- icons -->
<div class="text-white mr-3">
<template v-if="notification.type === 'success'">
<check-circle-icon solid/>
</template>
<template v-else-if="notification.type === 'error'">
<exclamation-circle-icon solid/>
</template>
<template v-else-if="notification.type === 'warning'">
<warning-icon solid/>
</template>
<template v-else-if="notification.type === 'info'">
<info-icon solid/>
</template>
<template v-else>
<info-icon solid/>
</template>
</div>
<!-- message -->
<div class="text-white max-w-xs" v-text="notification.message"/>
</div>
<button-component class="py-1 px-1 text-white hover:opacity-75" @click.prevent="handleClose">
<close-icon solid class="h-4"/>
</button-component>
</div>
</template>
<script>
import ButtonComponent from "../Buttons/Button"
import {
CheckCircleIcon,
ExclamationCircleIcon,
InfoIcon,
WarningIcon,
} from "../Icons"
import CloseIcon from "../Icons/CloseIcon"
export default {
name: "NotificationItem",
components: { CloseIcon, ButtonComponent, InfoIcon, WarningIcon, ExclamationCircleIcon, CheckCircleIcon },
props: {
notification: { type: Object, required: true },
},
emits: ["close"],
setup(props, { emit }) {
const handleClose = () => {
emit("close", props.notification.id)
}
setTimeout(handleClose, 10000)
return { handleClose }
},
}
</script>
<template>
<div class="relative">
<div class="absolute right-[20px] top-[20px] z-100">
<notification-item v-for="notification in notifications"
:key="notification.id"
:notification="notification"
@close="handleOnClose"/>
</div>
</div>
</template>
<script type="text/ecmascript-6">
import { usePage } from "@inertiajs/inertia-vue3"
import {
inject,
ref,
watch,
} from "vue"
import NotificationItem from "./NotificationItem"
export default {
name: "Notifications",
components: { NotificationItem },
setup() {
const page = usePage()
const notifications = ref([])
const emitter = inject("emitter")
watch(() => page.props.value.flash, (flashes) => {
const flashList = Object.entries(flashes).reduce((list, [type, message], index) => {
if (!message) {
return list
}
return [...list, { type, message, id: `${Date.now()}-${index}` }]
}, [])
notifications.value = [...notifications.value, ...flashList]
}, {
immediate: true,
})
emitter.on("notification", (obj) => {
notifications.value.push({
...obj,
id: Date.now(),
})
})
const handleOnClose = (id) => {
notifications.value = notifications.value.filter(
notification => notification.id !== id,
)
}
return { notifications, handleOnClose }
},
}
</script>
"use strict"
import { inject } from "vue"
export default () => {
const emitter = inject("emitter")
return {
success: (message) => {
emitter.emit("notification", { type: "success", message })
},
error: (message) => {
emitter.emit("notification", { type: "error", message })
},
warning: (message) => {
emitter.emit("notification", { type: "warning", message })
},
info: (message) => {
emitter.emit("notification", { type: "info", message })
},
message: (message) => {
emitter.emit("notification", { type: "message", message })
},
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment