semantic-ui-toastr for vue.js
by gongzza
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/Faker/3.1.0/faker.js"></script>
<div id="app">
<div class="ui vertical buttons">
<button class="ui primary button" @click="newItem('i')">Info</button>
<button class="ui yellow button" @click="newItem('w')">Warning</button>
<button class="ui positive button" @click="newItem('s')">Success</button>
<button class="ui negative button" @click="newItem('e')">Error</button>
</div>
</div>
<template id="toastr">
<transition name="toastr" appear @after-leave="afterLeave">
<div class="ui animated toastr message" @click="close" :class="[messageType, horizontal, vertical]" v-if="show">
<div class="header" v-if="header">{{header}}</div>
<p v-if="html" v-html="message"></p>
<p v-else>{{ message }}</p>
</div>
</transition>
</template>
CSS
@import url('https://unpkg.com/[email protected]/semantic.css');
/* toastr-container */
.toastr-container {
position: fixed;
width: 0;
}
.toastr-container.right {
right: 0;
}
.toastr-container.left {
left: 300px;
}
.toastr-container.top {
top: 0;
}
.toastr-container.bottom {
bottom: 0;
}
.toastr-container.middle {
top: 50%;
margin-top: -35px;
}
.toastr-container.center {
left: 50%;
margin-left: 150px;
}
/* toastr */
.ui.message.toastr {
min-width: 300px;
cursor: pointer;
box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.22) inset, 0px 2px 4px 0px rgba(34, 36, 38, 0.12), 0px 2px 10px 0px rgba(34, 36, 38, 0.15);
float: right;
}
.ui.message.toastr.top {
margin-top: 5px;
margin-bottom: 0px;
}
.ui.message.toastr.left {
margin-right: -5px;
}
.ui.message.toastr.right {
margin-right: 5px;
}
.ui.message.toastr.bottom {
margin-top: 0px;
margin-bottom: 5px;
}
.ui.message.toastr.middle {
margin-top: 0px;
margin-bottom: 5px;
}
/* transition */
.ui.toastr.animated.message {
transition: all 0.35s;
}
.toastr-enter,
.toastr-leave-to {
opacity: 0;
}
.left > .toastr-enter,
.left > .toastr-leave-to {
transform: translateX(-30px);
}
.right > .toastr-enter,
.right > .toastr-leave-to {
transform: translateX(30px);
}
.top.center > .toastr-enter,
.top.center > .toastr-leave-to {
transform: translateY(-30px);
}
.bottom.center > .toastr-enter,
.bottom.center > .toastr-leave-to {
transform: translateY(30px);
}
JavaScript
const HORIZONTAL = ['left', 'center', 'right']
const VERTICAL = ['top', 'middle', 'bottom']
const Toastr = {
template: '#toastr',
props: {
header: String,
message: String,
type: String,
duration: {
type: Number,
default: 3000
},
html: {
type: Boolean,
default: false
},
container: {
type: String,
default: '.toastr-container'
},
position: {
type: String,
default: 'right top',
validator(val) {
return HORIZONTAL.some(h => val.includes(h))
&& VERTICAL.some(v => val.includes(v))
}
}
},
data() {
return {
$_parent_: null,
$_el_: null,
show: true
}
},
computed: {
messageType() {
if (this.type) {
return {
[this.type]: true
}
}
},
horizontal() {
for (h of HORIZONTAL) {
if (this.position.includes(h)) {
return h
}
}
},
vertical() {
for (v of VERTICAL) {
if (this.position.includes(v)) {
return v
}
}
}
},
created() {
let $parent = this.$parent
if (!$parent) {
let parent = document.querySelector(this.container)
if (!parent) {
// Lazy creating `div.conatiner` container.
const className = this.container.replace('.', '')
const horizontal = this.horizontal
const vertical = this.vertical
const Container = Vue.extend({
name: 'Container',
render (h) {
return h('div', {
class: {
[`${className}`]: true,
[`${horizontal}`]: true,
[`${vertical}`]: true
}
})
}
})
$parent = new Container().$mount()
document.body.appendChild($parent.$el)
} else {
$parent = parent.__vue__
}
// Hacked.
this.$_parent_ = $parent
this.$_el_ = $parent
?...