204 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | ||
|   <div
 | ||
|     @click="tryClose"
 | ||
|     data-notify="container"
 | ||
|     class="alert alert-notify fixed w-full sm:w-500 flex items-center justify-between ltr:right-0 rtl:left-0 sm:ltr:right-4 sm:rtl:left-4 p-4 text-black font-bold rounded-lg z-30"
 | ||
|     :class="[
 | ||
|       { 'alert-with-icon': icon },
 | ||
|       verticalAlign,
 | ||
|       horizontalAlign,
 | ||
|       alertType
 | ||
|     ]"
 | ||
|     role="alert"
 | ||
|     :style="customPosition"
 | ||
|     data-notify-position="top-center"
 | ||
|   >
 | ||
|   <div class="flex items-center ltr:pr-3 rtl:pl-3">
 | ||
|     <template v-if="icon || $slots.icon">
 | ||
|       <slot name="icon">
 | ||
|             <span class="alert-icon flex items-center ltr:mr-2 rtl:ml-2" data-notify="icon">
 | ||
|               <span class="material-icons text-2xl">{{ icon }}</span>
 | ||
|             </span>
 | ||
|       </slot>
 | ||
|     </template>
 | ||
| 
 | ||
|     <span class="alert-text">
 | ||
|       <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>
 | ||
| 
 | ||
|     <slot name="dismiss-icon">
 | ||
|       <button type="button"
 | ||
|               class="close text-2xl"
 | ||
|               data-dismiss="alert"
 | ||
|               aria-label="Close"
 | ||
|               @click="close">
 | ||
|         <span aria-hidden="true">×</span>
 | ||
|       </button>
 | ||
|     </slot>
 | ||
|   </div>
 | ||
| </template>
 | ||
| <script>
 | ||
|   export default {
 | ||
|     name: 'notification',
 | ||
|     components: {
 | ||
|       contentRender: {
 | ||
|         props: ['component'],
 | ||
|         render: h => h(this.component)
 | ||
|       }
 | ||
|     },
 | ||
|     props: {
 | ||
|       message: String,
 | ||
|       title: {
 | ||
|         type: String,
 | ||
|         description: 'Notification title'
 | ||
|       },
 | ||
|       icon: {
 | ||
|         type: String,
 | ||
|         description: 'Notification icon'
 | ||
|       },
 | ||
|       verticalAlign: {
 | ||
|         type: String,
 | ||
|         default: 'top',
 | ||
|         validator: value => {
 | ||
|           let acceptedValues = ['top', 'bottom'];
 | ||
|           return acceptedValues.indexOf(value) !== -1;
 | ||
|         },
 | ||
|         description: 'Vertical alignment of notification (top|bottom)'
 | ||
|       },
 | ||
|       horizontalAlign: {
 | ||
|         type: String,
 | ||
|         default: 'right',
 | ||
|         validator: value => {
 | ||
|           let acceptedValues = ['left', 'center', 'right'];
 | ||
|           return acceptedValues.indexOf(value) !== -1;
 | ||
|         },
 | ||
|         description: 'Horizontal alignment of notification (left|center|right)'
 | ||
|       },
 | ||
|       type: {
 | ||
|         type: String,
 | ||
|         default: 'info',
 | ||
|         validator: value => {
 | ||
|           let acceptedValues = [
 | ||
|             'default',
 | ||
|             'info',
 | ||
|             'primary',
 | ||
|             'danger',
 | ||
|             'warning',
 | ||
|             'success'
 | ||
|           ];
 | ||
|           return acceptedValues.indexOf(value) !== -1;
 | ||
|         },
 | ||
|         description: 'Notification type of notification (gray-300|blue-300|gray-300|red-300|orange-300|green-300)'
 | ||
|       },
 | ||
|       timeout: {
 | ||
|         type: Number,
 | ||
|         default: 5000,
 | ||
|         validator: value => {
 | ||
|           return value >= 0;
 | ||
|         },
 | ||
|         description: 'Notification timeout (closes after X milliseconds). Default is 5000 (5s)'
 | ||
|       },
 | ||
|       timestamp: {
 | ||
|         type: Date,
 | ||
|         default: () => new Date(),
 | ||
|         description: 'Notification timestamp (used internally to handle notification removal correctly)'
 | ||
|       },
 | ||
|       component: {
 | ||
|         type: [Object, Function],
 | ||
|         description: 'Custom content component. Cane be a `.vue` component or render function'
 | ||
|       },
 | ||
|       showClose: {
 | ||
|         type: Boolean,
 | ||
|         default: true,
 | ||
|         description: 'Whether to show close button'
 | ||
|       },
 | ||
|       closeOnClick: {
 | ||
|         type: Boolean,
 | ||
|         default: true,
 | ||
|         description: 'Whether to close notification when clicking it\' body'
 | ||
|       },
 | ||
|       clickHandler: {
 | ||
|         type: Function,
 | ||
|         description: 'Custom notification click handler'
 | ||
|       }
 | ||
|     },
 | ||
|     data() {
 | ||
|       return {
 | ||
|         elmHeight: 0,
 | ||
|         typeByClass: {
 | ||
|           'default': 'black-100',
 | ||
|           'info':    'blue-100',
 | ||
|           'primary': 'black-100',
 | ||
|           'danger':  'red-100',
 | ||
|           'warning': 'orange-100',
 | ||
|           'success': 'green-100',
 | ||
|         },
 | ||
|         textByClass: {
 | ||
|           'default': 'black-600',
 | ||
|           'info':    'blue-600',
 | ||
|           'primary': 'black-600',
 | ||
|           'danger':  'red-600',
 | ||
|           'warning': 'orange-600',
 | ||
|           'success': 'green-600',
 | ||
|         }
 | ||
|       };
 | ||
|     },
 | ||
|     computed: {
 | ||
|       hasIcon() {
 | ||
|         return this.icon && this.icon.length > 0;
 | ||
|       },
 | ||
|       alertType() {
 | ||
|         return `bg-${this.typeByClass[this.type]} text-${this.textByClass[this.type]}`;
 | ||
|       },
 | ||
|       customPosition() {
 | ||
|         let initialMargin = 20;
 | ||
|         let alertHeight = this.elmHeight + 10;
 | ||
|         let sameAlertsCount = this.$notifications.state.filter(alert => {
 | ||
|           return (
 | ||
|             alert.horizontalAlign === this.horizontalAlign &&
 | ||
|             alert.verticalAlign === this.verticalAlign &&
 | ||
|             alert.timestamp <= this.timestamp
 | ||
|           );
 | ||
|         }).length;
 | ||
|         if (this.$notifications.settings.overlap) {
 | ||
|           sameAlertsCount = 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> |