Notifications as object for better targetting; Notifications closing vs removing for animation window
This commit is contained in:
2
src/js/bootstrap.js
vendored
2
src/js/bootstrap.js
vendored
@ -50,7 +50,7 @@ var initialState = {
|
||||
show_initial_setup: true,
|
||||
slim_mode: false,
|
||||
selected_tracks: [],
|
||||
notifications: [],
|
||||
notifications: {},
|
||||
processes: {}
|
||||
},
|
||||
mopidy: {
|
||||
|
||||
@ -11,21 +11,28 @@ export default class Notifications extends React.Component{
|
||||
renderNotifications(){
|
||||
if (!this.props.notifications || this.props.notifications.length <= 0) return null
|
||||
|
||||
var notifications = []
|
||||
for (var key in this.props.notifications){
|
||||
if (this.props.notifications.hasOwnProperty(key)){
|
||||
notifications.push(this.props.notifications[key])
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
{
|
||||
this.props.notifications.map(notification => {
|
||||
notifications.map(notification => {
|
||||
switch (notification.type){
|
||||
case 'shortcut':
|
||||
return (
|
||||
<div className="notification shortcut-notification" key={notification.key} data-duration={notification.duration}>
|
||||
<div className={"notification shortcut-notification"+(notification.closing ? ' closing' : '')} key={notification.key} data-duration={notification.duration}>
|
||||
<FontAwesome name={notification.content} />
|
||||
</div>
|
||||
)
|
||||
|
||||
default:
|
||||
return (
|
||||
<div className={notification.type+" notification"} key={notification.key} data-key={notification.key} data-duration={notification.duration}>
|
||||
<div className={notification.type+" notification"+(notification.closing ? ' closing' : '')} key={notification.key} data-key={notification.key} data-duration={notification.duration}>
|
||||
<FontAwesome name="close" className="close-button" onClick={ e => this.props.uiActions.removeNotification(notification.key) } />
|
||||
{notification.title ? <h4>{notification.title}</h4> : null}
|
||||
<p className="content" dangerouslySetInnerHTML={{__html: notification.content}}></p>
|
||||
@ -49,7 +56,7 @@ export default class Notifications extends React.Component{
|
||||
switch (process.status){
|
||||
case 'running':
|
||||
return(
|
||||
<div className="process notification" key={process.key}>
|
||||
<div className={"process notification"+(notification.closing ? ' closing' : '')} key={process.key}>
|
||||
<div className="loader">
|
||||
<div className="progress">
|
||||
<div className="fill" style={{width: progress+'%'}}></div>
|
||||
@ -62,7 +69,7 @@ export default class Notifications extends React.Component{
|
||||
|
||||
case 'cancelling':
|
||||
return(
|
||||
<div className="process notification cancelling" key={process.key}>
|
||||
<div className={"process notification cancelling"+(notification.closing ? ' closing' : '')} key={process.key}>
|
||||
<div className="loader"></div>
|
||||
Cancelling
|
||||
</div>
|
||||
|
||||
@ -188,13 +188,21 @@ export function createNotification(data){
|
||||
title: null,
|
||||
content: null,
|
||||
description: null,
|
||||
sticky: false
|
||||
sticky: false,
|
||||
closing: false
|
||||
},
|
||||
data
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function closeNotification(key){
|
||||
return {
|
||||
type: 'CLOSE_NOTIFICATION',
|
||||
key: key
|
||||
}
|
||||
}
|
||||
|
||||
export function removeNotification(key){
|
||||
return {
|
||||
type: 'REMOVE_NOTIFICATION',
|
||||
|
||||
@ -70,40 +70,41 @@ const UIMiddleware = (function(){
|
||||
|
||||
case 'CREATE_NOTIFICATION':
|
||||
|
||||
// start a timeout to remove this notification
|
||||
// start a timeout to close this notification
|
||||
if (!action.notification.sticky){
|
||||
var timeout = setTimeout(
|
||||
function(){
|
||||
store.dispatch(uiActions.removeNotification(action.notification.key))
|
||||
store.dispatch(uiActions.closeNotification(action.notification.key))
|
||||
},
|
||||
action.notification.duration * 1000
|
||||
)
|
||||
}
|
||||
|
||||
next(action)
|
||||
break
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'REMOVE_NOTIFICATION':
|
||||
var notifications = Object.assign([], store.getState().ui.notifications)
|
||||
|
||||
function getByKey(notification){
|
||||
return notification.key === action.key
|
||||
}
|
||||
var index = notifications.findIndex(getByKey)
|
||||
|
||||
// Save our index for the reducer to use. Saves us from re-finding by key
|
||||
action.index = index
|
||||
case 'CLOSE_NOTIFICATION':
|
||||
var notifications = Object.assign({}, store.getState().ui.notifications);
|
||||
|
||||
// If a broadcast, add to suppressed_broadcasts
|
||||
if (index > -1 && typeof(notifications[index]) !== 'undefined' && notifications[index].type == 'broadcast'){
|
||||
if (notifications[action.key] && notifications[action.key].type == 'broadcast'){
|
||||
store.dispatch({
|
||||
type: 'SUPPRESS_BROADCAST',
|
||||
key: notifications[index].key
|
||||
key: action.key
|
||||
})
|
||||
}
|
||||
|
||||
next(action)
|
||||
break
|
||||
// start a timeout to remove this notification
|
||||
// This gives us time to animate out the notification before we remove the data
|
||||
var timeout = setTimeout(
|
||||
function(){
|
||||
store.dispatch(uiActions.removeNotification(action.key))
|
||||
},
|
||||
200
|
||||
)
|
||||
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'BROADCASTS_LOADED':
|
||||
var suppressed_broadcasts = []
|
||||
|
||||
@ -98,18 +98,21 @@ export default function reducer(ui = {}, action){
|
||||
**/
|
||||
|
||||
case 'CREATE_NOTIFICATION':
|
||||
var notifications = [...ui.notifications, action.notification]
|
||||
notifications = helpers.mergeDuplicates(notifications,'key')
|
||||
return Object.assign({}, ui, { notifications: notifications })
|
||||
var notifications = Object.assign({}, ui.notifications);
|
||||
notifications[action.notification.key] = action.notification;
|
||||
return Object.assign({}, ui, { notifications: notifications });
|
||||
|
||||
case 'CLOSE_NOTIFICATION':
|
||||
var notifications = Object.assign({}, ui.notifications);
|
||||
if (notifications[action.key]){
|
||||
notifications[action.key].closing = true;
|
||||
}
|
||||
return Object.assign({}, ui, { notifications: notifications });
|
||||
|
||||
case 'REMOVE_NOTIFICATION':
|
||||
var notifications = Object.assign([], ui.notifications)
|
||||
|
||||
if (action.index > -1){
|
||||
notifications.splice(action.index, 1)
|
||||
}
|
||||
|
||||
return Object.assign({}, ui, {notifications: notifications})
|
||||
var notifications = Object.assign({}, ui.notifications);
|
||||
delete notifications[action.key];
|
||||
return Object.assign({}, ui, {notifications: notifications});
|
||||
|
||||
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
width: 300px;
|
||||
|
||||
.notification {
|
||||
@include fadein();
|
||||
display: block;
|
||||
position: relative;
|
||||
background: $blue;
|
||||
@ -17,14 +18,6 @@
|
||||
color: $white;
|
||||
pointer-events: all;
|
||||
border-radius: 3px;
|
||||
|
||||
&[data-duration="1"]{
|
||||
@include fadeinout(1s);
|
||||
}
|
||||
|
||||
&[data-duration="3"]{
|
||||
@include fadeinout(3s);
|
||||
}
|
||||
|
||||
h4 {
|
||||
padding-top: 0;
|
||||
@ -78,6 +71,10 @@
|
||||
background: $red;
|
||||
}
|
||||
|
||||
&.closing {
|
||||
@include fadeout();
|
||||
}
|
||||
|
||||
&.process {
|
||||
position: relative;
|
||||
padding-right: 18px;
|
||||
|
||||
@ -122,17 +122,9 @@ $bp_shallow: 650px;
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
@mixin fadeinout($duration: 3s){
|
||||
@keyframes fadeinout {
|
||||
@mixin fadeout($duration: 0.2s){
|
||||
@keyframes fadeout {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(5px);
|
||||
}
|
||||
6% {
|
||||
opacity: 1;
|
||||
transform: translateY(0px);
|
||||
}
|
||||
94% {
|
||||
opacity: 1;
|
||||
transform: translateY(0px);
|
||||
}
|
||||
@ -142,7 +134,7 @@ $bp_shallow: 650px;
|
||||
}
|
||||
}
|
||||
|
||||
animation-name: fadeinout;
|
||||
animation-name: fadeout;
|
||||
animation-duration: $duration;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: 1;
|
||||
|
||||
Reference in New Issue
Block a user