Files
2021-04-21 21:47:04 -05:00

187 lines
3.9 KiB
Vue

<template>
<div
@click="tryClose"
data-notify="container"
class="alert open"
:class="[
{ 'alert-with-icon': icon },
verticalAlign,
horizontalAlign,
alertType
]"
role="alert"
:style="customPosition"
data-notify-position="top-center"
>
<button
v-if="showClose"
type="button"
aria-hidden="true"
class="close col-xs-1"
data-notify="dismiss"
@click="close"
>
<i class="tim-icons icon-simple-remove"></i>
</button>
<span v-if="icon" data-notify="icon" :class="['alert-icon', icon]"></span>
<span data-notify="message">
<span v-if="title" class="title"
><b>{{ title }}<br /></b
></span>
<span v-if="message" v-html="message"></span>
<content-render
v-if="!message && component"
:component="component"
></content-render>
</span>
</div>
</template>
<script>
export default {
name: 'notification',
components: {
contentRender: {
props: ['component'],
render: h => h(this.component)
}
},
props: {
message: String,
title: String,
icon: String,
verticalAlign: {
type: String,
default: 'top',
validator: value => {
let acceptedValues = ['top', 'bottom'];
return acceptedValues.indexOf(value) !== -1;
}
},
horizontalAlign: {
type: String,
default: 'right',
validator: value => {
let acceptedValues = ['left', 'center', 'right'];
return acceptedValues.indexOf(value) !== -1;
}
},
type: {
type: String,
default: 'info',
validator: value => {
let acceptedValues = [
'info',
'primary',
'danger',
'warning',
'success'
];
return acceptedValues.indexOf(value) !== -1;
}
},
timeout: {
type: Number,
default: 5000,
validator: value => {
return value >= 0;
}
},
timestamp: {
type: Date,
default: () => new Date()
},
component: {
type: [Object, Function]
},
showClose: {
type: Boolean,
default: true
},
closeOnClick: {
type: Boolean,
default: true
},
clickHandler: Function
},
data() {
return {
elmHeight: 0
};
},
computed: {
hasIcon() {
return this.icon && this.icon.length > 0;
},
alertType() {
return `alert-${this.type}`;
},
customPosition() {
let initialMargin = 20;
let alertHeight = this.elmHeight + 10;
let sameAlerts = this.$notifications.state.filter(alert => {
return (
alert.horizontalAlign === this.horizontalAlign &&
alert.verticalAlign === this.verticalAlign
);
});
let sameAlertsCount = 1
let currentIndex = sameAlerts.findIndex(n => n.timestamp === this.timestamp)
if (this.$notifications.settings.overlap) {
sameAlertsCount = 1;
}
if (currentIndex !== -1) {
sameAlertsCount = currentIndex + 1
}
let pixels = (sameAlertsCount - 1) * alertHeight + initialMargin;
let styles = {};
if (this.verticalAlign === 'top') {
styles.top = `${pixels}px`;
} else {
styles.bottom = `${pixels}px`;
}
return styles;
}
},
methods: {
close() {
this.$emit('close', this.timestamp);
},
tryClose(evt) {
if (this.clickHandler) {
this.clickHandler(evt, this);
}
if (this.closeOnClick) {
this.close();
}
}
},
mounted() {
this.elmHeight = this.$el.clientHeight;
if (this.timeout) {
setTimeout(this.close, this.timeout);
}
}
};
</script>
<style lang="scss">
.notifications .alert {
position: fixed;
z-index: 10000;
&[data-notify='container'] {
width: 400px;
}
&.center {
margin: 0 auto;
}
&.left {
left: 20px;
}
&.right {
right: 20px;
}
}
</style>