Никита Круглицкий b3c99a667a Initial commit
2024-11-26 16:15:12 +03:00

129 lines
2.2 KiB
Vue

<template>
<Transition
:name="cn.b()"
@before-leave="$emit('close')"
@after-leave="$emit('destroy')"
>
<UiAlert
v-show="visible"
:id="id"
:class="[cn.b(), verticalSide, horizontalSide]"
:title="title"
:type="type"
@mouseenter="clearTimer"
@mouseleave="startTimer"
>
<slot />
</UiAlert>
</Transition>
</template>
<script setup lang="ts">
import type { NotificationPlacement, NotificationType } from './types'
import { computed, onMounted, ref } from 'vue'
export interface Props {
duration?: number
id?: string | number
offset?: number
placement?: NotificationPlacement
type?: NotificationType
title?: string
zIndex?: number
}
defineOptions({
name: 'UiNotification',
})
const props = withDefaults(defineProps<Props>(), {
type: 'neutral',
duration: 5000,
offset: 0,
placement: 'top-right',
zIndex: 0,
})
defineEmits(['close', 'destroy'])
const cn = useClassname('ui-notification')
const timerId = ref()
const visible = ref(false)
const verticalSide = computed(() => props.placement.split('-')[0])
const horizontalSide = computed(() => props.placement.split('-')[1])
function close() {
visible.value = false
}
function startTimer() {
if (props.duration > 0) {
timerId.value = setTimeout(() => {
if (visible.value)
close()
}, props.duration)
}
}
function clearTimer() {
if (timerId.value)
clearTimeout(timerId.value)
}
onMounted(() => {
startTimer()
visible.value = true
})
defineExpose({
visible,
close,
})
</script>
<style lang="scss">
.ui-notification {
position: fixed;
transition-duration: $transition-duration;
transition-property: opacity, transform, left, right, top, bottom;
z-index: calc(8000 + v-bind('zIndex'));
width: 400px;
transform-origin: right top;
@include mobile {
width: calc(100% - 32px);
}
&.top {
top: calc(v-bind('`${offset}px`') + 80px);
@include mobile {
top: auto;
bottom: v-bind('`${offset}px`');
}
}
&.bottom {
bottom: v-bind('`${offset}px`');
}
&.left {
left: 32px;
@include mobile {
left: 16px;
}
}
&.right {
right: 32px;
@include mobile {
right: 16px;
}
}
}
</style>