See #262: light messaging area and helpers for the front-end
This commit is contained in:
parent
4c81de9226
commit
3634c00ee6
|
@ -1,6 +1,7 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<sidebar></sidebar>
|
||||
<service-messages v-if="messages.length > 0" />
|
||||
<router-view :key="$route.fullPath"></router-view>
|
||||
<div class="ui fitted divider"></div>
|
||||
<div id="footer" class="ui vertical footer segment">
|
||||
|
@ -44,9 +45,11 @@
|
|||
<script>
|
||||
import axios from 'axios'
|
||||
import _ from 'lodash'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
import Sidebar from '@/components/Sidebar'
|
||||
import Raven from '@/components/Raven'
|
||||
import ServiceMessages from '@/components/ServiceMessages'
|
||||
|
||||
import PlaylistModal from '@/components/playlists/PlaylistModal'
|
||||
|
||||
|
@ -55,7 +58,8 @@ export default {
|
|||
components: {
|
||||
Sidebar,
|
||||
Raven,
|
||||
PlaylistModal
|
||||
PlaylistModal,
|
||||
ServiceMessages
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
@ -80,6 +84,9 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
messages: state => state.ui.messages
|
||||
}),
|
||||
version () {
|
||||
if (!this.nodeinfo) {
|
||||
return null
|
||||
|
@ -115,6 +122,14 @@ html, body {
|
|||
}
|
||||
transform: none !important;
|
||||
}
|
||||
.service-messages {
|
||||
position: fixed;
|
||||
bottom: 1em;
|
||||
left: 1em;
|
||||
@include media(">desktop") {
|
||||
left: 350px;
|
||||
}
|
||||
}
|
||||
.main-pusher {
|
||||
padding: 1.5rem 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<template>
|
||||
<div class="service-messages">
|
||||
<message v-for="message in displayedMessages" :key="String(message.date)" :class="['large', getLevel(message)]">
|
||||
<p>{{ message.content }}</p>
|
||||
</message>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
date: new Date(),
|
||||
interval: null
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.setupInterval()
|
||||
},
|
||||
destroyed () {
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
messages: state => state.ui.messages,
|
||||
displayDuration: state => state.ui.messageDisplayDuration
|
||||
}),
|
||||
displayedMessages () {
|
||||
let now = this.date
|
||||
let interval = this.displayDuration
|
||||
let toDisplay = this.messages.filter(m => {
|
||||
return now - m.date <= interval
|
||||
})
|
||||
return _.reverse(toDisplay).slice(0, 5)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setupInterval () {
|
||||
if (this.interval) {
|
||||
return
|
||||
}
|
||||
let self = this
|
||||
this.interval = setInterval(() => {
|
||||
if (self.displayedMessages.length === 0) {
|
||||
clearInterval(self.interval)
|
||||
this.interval = null
|
||||
}
|
||||
self.date = new Date()
|
||||
}, 1000)
|
||||
},
|
||||
getLevel (message) {
|
||||
return message.level || 'blue'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
messages: {
|
||||
handler (v) {
|
||||
if (v.length > 0 && !this.interval) {
|
||||
this.setupInterval()
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.service-messages {
|
||||
z-index: 9999;
|
||||
margin-left: 1em;
|
||||
min-width: 20em;
|
||||
max-width: 40em;
|
||||
}
|
||||
.service-messages .message:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<div class="ui message">
|
||||
<div class="content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<i class="close icon"></i>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import $ from 'jquery'
|
||||
|
||||
export default {
|
||||
mounted () {
|
||||
let self = this
|
||||
$(this.$el).find('.close.icon').on('click', function () {
|
||||
$(self.$el).transition('fade', 125)
|
||||
})
|
||||
$(this.$el).on('click', function () {
|
||||
$(self.$el).transition('fade', 125)
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.ui.message .content {
|
||||
padding-right: 0.5em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ui.message .content :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ui.message .content :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
|
@ -12,4 +12,8 @@ import DangerousButton from '@/components/common/DangerousButton'
|
|||
|
||||
Vue.component('dangerous-button', DangerousButton)
|
||||
|
||||
import Message from '@/components/common/Message'
|
||||
|
||||
Vue.component('message', Message)
|
||||
|
||||
export default {}
|
||||
|
|
|
@ -2,11 +2,20 @@
|
|||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
lastDate: new Date()
|
||||
lastDate: new Date(),
|
||||
maxMessages: 100,
|
||||
messageDisplayDuration: 10000,
|
||||
messages: []
|
||||
},
|
||||
mutations: {
|
||||
computeLastDate: (state) => {
|
||||
state.lastDate = new Date()
|
||||
},
|
||||
addMessage (state, message) {
|
||||
state.messages.push(message)
|
||||
if (state.messages.length > state.maxMessages) {
|
||||
state.messages.shift()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import store from '@/store/ui'
|
||||
|
||||
import { testAction } from '../../utils'
|
||||
|
||||
describe('store/ui', () => {
|
||||
describe('mutations', () => {
|
||||
it('addMessage', () => {
|
||||
const state = {maxMessages: 100, messages: []}
|
||||
store.mutations.addMessage(state, 'hello')
|
||||
expect(state.messages).to.deep.equal(['hello'])
|
||||
})
|
||||
it('addMessage', () => {
|
||||
const state = {maxMessages: 1, messages: ['hello']}
|
||||
store.mutations.addMessage(state, 'world')
|
||||
expect(state.messages).to.deep.equal(['world'])
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue