forked from platypush/platypush
New support for notifications in webpanel in vue.js
This commit is contained in:
parent
e1c3951456
commit
444fe6331d
11 changed files with 260 additions and 70 deletions
|
@ -0,0 +1,37 @@
|
|||
.fade-in {
|
||||
--duration: $fade-in-transition-duration;
|
||||
opacity: 1;
|
||||
animation-name: fadeInOpacity;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: ease-in;
|
||||
animation-duration: var(--duration);
|
||||
}
|
||||
|
||||
@keyframes fadeInOpacity {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-out {
|
||||
--duration: $fade-out-transition-duration;
|
||||
opacity: 1;
|
||||
animation-name: fadeOutOpacity;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: ease-out;
|
||||
animation-duration: var(--duration);
|
||||
}
|
||||
|
||||
@keyframes fadeOutOpacity {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
@ -86,3 +86,10 @@ $widths: (
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.horizontal-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
#notification-container {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 25em;
|
||||
|
||||
.notification {
|
||||
background: rgba(180,245,188,0.85);
|
||||
border: 1px solid #bbb;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 1rem;
|
||||
margin-right: 1rem;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.notification:hover {
|
||||
background: rgba(160,235,168,0.9);
|
||||
}
|
||||
|
||||
.notification-title {
|
||||
padding: 4px 10px;
|
||||
font-weight: bold;
|
||||
text-transform: capitalize;
|
||||
line-height: 30px;
|
||||
letter-spacing: .1rem;
|
||||
}
|
||||
|
||||
.notification-body {
|
||||
height: 6em;
|
||||
overflow: hidden;
|
||||
padding-bottom: 1rem;
|
||||
letter-spacing: .05rem;
|
||||
}
|
||||
|
||||
.notification-text {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.notification-image {
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
padding-top: .6em;
|
||||
padding-bottom: .6em;
|
||||
|
||||
.notification-image-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.fa.notification-image-item {
|
||||
margin-top: .8em;
|
||||
margin-left: .2em;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#notifications {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 25em;
|
||||
|
||||
.notification {
|
||||
background: $notification-bg;
|
||||
border: $notification-border;
|
||||
border-radius: .5rem;
|
||||
margin-bottom: 1rem;
|
||||
margin-right: 1rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: $notification-hover-bg;
|
||||
&.warning { background: $notification-warning-hover-bg; }
|
||||
&.error { background: $notification-error-hover-bg; }
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background: $notification-warning-bg;
|
||||
border: $notification-warning-border;
|
||||
.image { --color: $notification-warning-icon-color; }
|
||||
}
|
||||
|
||||
&.error {
|
||||
background: $notification-error-bg;
|
||||
border: $notification-error-border;
|
||||
.image { --color: $notification-error-icon-color; }
|
||||
}
|
||||
|
||||
.title {
|
||||
border-bottom: $notification-title-border;
|
||||
padding: .4rem;
|
||||
text-transform: uppercase;
|
||||
line-height: 3rem;
|
||||
letter-spacing: .1rem;
|
||||
}
|
||||
|
||||
.body {
|
||||
@extend .vertical-center;
|
||||
height: 6em;
|
||||
overflow: hidden;
|
||||
padding-bottom: 1rem;
|
||||
letter-spacing: .05rem;
|
||||
}
|
||||
|
||||
.image {
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
--color: $notification-icon-color;
|
||||
|
||||
.row {
|
||||
@extend .vertical-center;
|
||||
@extend .horizontal-center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.fa {
|
||||
font-size: 2.5rem;
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
img {
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,27 @@ $nav-date-time-shadow: 2px 2px 2px #ccc !default;
|
|||
|
||||
$modal-bg: #f0f0f0 !default;
|
||||
|
||||
//// Animations defaults
|
||||
$transition-duration: .5s !default;
|
||||
$fade-transition-duration: .5s !default;
|
||||
$fade-in-transition-duration: $fade-transition-duration !default;
|
||||
$fade-out-transition-duration: $fade-transition-duration !default;
|
||||
|
||||
//// Notifications
|
||||
$notification-bg: rgba(185, 255, 193, 0.85) !default;
|
||||
$notification-hover-bg: rgba(160,245,178,0.9) !default;
|
||||
$notification-warning-bg: rgba(228, 255, 78, 0.85) !default;
|
||||
$notification-warning-hover-bg: rgba(218, 245, 68, 0.9) !default;
|
||||
$notification-error-bg: rgba(255, 100, 100, 0.85) !default;
|
||||
$notification-error-hover-bg: rgba(245, 90, 90, 0.9) !default;
|
||||
$notification-border: 1px solid rgba(109, 205, 134, 0.62) !default;
|
||||
$notification-warning-border: 1px solid rgba(205, 205, 109, 0.62) !default;
|
||||
$notification-error-border: 1px solid rgba(205, 109, 109, 0.62) !default;
|
||||
$notification-title-border: 1px solid rgba(83, 158, 102, 0.43) !default;
|
||||
$notification-icon-color: black !default;
|
||||
$notification-warning-icon-color: #662 !default;
|
||||
$notification-error-icon-color: #8b0000 !default;
|
||||
|
||||
//// Switch element
|
||||
$switch-bg-1: #f9f8f6 !default;
|
||||
$switch-bg-2: #38ffa0 !default;
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
@import 'common/mixins';
|
||||
@import 'common/layout';
|
||||
@import 'common/elements';
|
||||
@import 'common/animations';
|
||||
@import 'common/modal';
|
||||
@import 'common/notification';
|
||||
@import 'common/notifications';
|
||||
|
||||
@import 'header';
|
||||
@import 'nav';
|
||||
|
|
|
@ -22,12 +22,21 @@ function execute(request) {
|
|||
if (!response.errors.length) {
|
||||
resolve(response.output);
|
||||
} else {
|
||||
// TODO Handle error
|
||||
reject(response.errors[0]);
|
||||
const error = response.errors[0];
|
||||
createNotification({
|
||||
text: error,
|
||||
error: true,
|
||||
});
|
||||
|
||||
reject(error);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// TODO Handle error
|
||||
createNotification({
|
||||
text: error,
|
||||
error: true,
|
||||
});
|
||||
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,7 +26,7 @@ Vue.component('plugin', {
|
|||
});
|
||||
|
||||
// Declaration of the main vue app
|
||||
var app = new Vue({
|
||||
window.vm = new Vue({
|
||||
el: '#app',
|
||||
// Override {{ }} delimiters to prevent clash with Flask templates
|
||||
delimiters: ['[[',']]'],
|
||||
|
|
63
platypush/backend/http/static/js/notifications.js
Normal file
63
platypush/backend/http/static/js/notifications.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
Vue.component('notifications', {
|
||||
template: '#tmpl-notifications',
|
||||
props: {
|
||||
duration: {
|
||||
// Default notification duration in milliseconds
|
||||
type: Number,
|
||||
default: 10000,
|
||||
}
|
||||
},
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
index: 0,
|
||||
notifications: {},
|
||||
timeouts: {},
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
create: function(args) {
|
||||
var id = this.index++;
|
||||
Vue.set(this.notifications, id, args);
|
||||
|
||||
if (args.duration == null) {
|
||||
args.duration = this.duration;
|
||||
}
|
||||
|
||||
if (args.duration != 0) {
|
||||
this.timeouts[id] = setTimeout(this.destroy.bind(null, id), args.duration);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function(id) {
|
||||
Vue.delete(this.notifications, id);
|
||||
delete this.timeouts[id];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Vue.component('notification', {
|
||||
template: '#tmpl-notification',
|
||||
props: ['id','text','html','title','image','link','error','warning'],
|
||||
|
||||
methods: {
|
||||
mousein: function(event) {
|
||||
},
|
||||
|
||||
mouseout: function(event) {
|
||||
},
|
||||
clicked: function(event) {
|
||||
if (this.link) {
|
||||
window.open(this.link, '_blank');
|
||||
}
|
||||
|
||||
this.$emit('clicked', this.id);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function createNotification(args) {
|
||||
window.vm.$refs.notifications.create(args);
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/api.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/events.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/notifications.js') }}"></script>
|
||||
|
||||
{% for style in styles.values() %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename=style['_style_file']) }}">
|
||||
|
@ -60,6 +61,8 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{% include 'notifications.html' %}
|
||||
</div>
|
||||
|
||||
{% include 'plugins/template.html' %}
|
||||
|
|
41
platypush/backend/http/templates/notifications.html
Normal file
41
platypush/backend/http/templates/notifications.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
<script type="text/x-template" id="tmpl-notifications">
|
||||
<div id="notifications">
|
||||
<notification v-for="(notification, id, index) in notifications"
|
||||
:key="index"
|
||||
:id="id"
|
||||
:text="notification.text"
|
||||
:html="notification.html"
|
||||
:title="notification.title"
|
||||
:link="notification.link"
|
||||
:image="notification.image"
|
||||
:warning="notification.warning"
|
||||
:error="notification.error"
|
||||
@clicked="destroy">
|
||||
</notification>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="tmpl-notification">
|
||||
<div class="notification fade-in" :class="{warning: warning, error: error}"
|
||||
@mouseover="mousein" @mouseleave="mouseout" @click="clicked">
|
||||
<div class="title" v-if="title" v-text="title"></div>
|
||||
<div class="body">
|
||||
<div class="image col-3" v-if="image || warning || error">
|
||||
<div class="row">
|
||||
<img :src="image.src" v-if="image && image.src">
|
||||
<i :class="['fa', 'fa-' + image.icon]" :style="image.color ? '--color: ' + image.color : ''"
|
||||
v-else-if="image && image.icon"></i>
|
||||
<i class="fa fa-exclamation" v-else-if="warning"></i>
|
||||
<i class="fa fa-times" v-else-if="error"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text col-9" v-if="text && !!image" v-text="text"></div>
|
||||
<div class="text col-9" v-if="html && !!image" v-html="html"></div>
|
||||
<div class="text row horizontal-center" v-if="text && !image" v-text="text"></div>
|
||||
<div class="text row horizontal-center" v-if="html && !image" v-html="html"></div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<notifications ref="notifications"></notifications>
|
||||
|
Loading…
Reference in a new issue