diff --git a/api/models/Display.js b/api/models/Display.js
index 5b6defd..3208045 100644
--- a/api/models/Display.js
+++ b/api/models/Display.js
@@ -1,12 +1,19 @@
const mongoose = require('mongoose')
+const shortid = require('shortid')
+
const Schema = mongoose.Schema
const Display = new Schema({
name: { type: String },
layout: { type: String, default: 'spaced', enum: ['compact', 'spaced'] },
statusBar: {
- type: [{ type: String, enum: ['time', 'date', 'connection', 'spacer'] }],
- default: ['date', 'spacer', 'connection', 'time']
+ type: [{ type: String }],
+ default: () => [
+ 'date_' + shortid.generate(),
+ 'spacer_' + shortid.generate(),
+ 'connection_' + shortid.generate(),
+ 'time_' + shortid.generate()
+ ]
},
widgets: [{ type: Schema.Types.ObjectId, ref: 'Widget' }]
})
diff --git a/components/Admin/EditableWidget.js b/components/Admin/EditableWidget.js
index 9275499..e274f28 100644
--- a/components/Admin/EditableWidget.js
+++ b/components/Admin/EditableWidget.js
@@ -58,7 +58,6 @@ class EditableWidget extends React.Component {
{widget.name || 'Broken Widget'}
- {/* NEWS */}
diff --git a/components/Admin/StatusBarElement.js b/components/Admin/StatusBarElement.js
new file mode 100644
index 0000000..d491f97
--- /dev/null
+++ b/components/Admin/StatusBarElement.js
@@ -0,0 +1,127 @@
+import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { library, config } from '@fortawesome/fontawesome-svg-core'
+import { faTimes } from '@fortawesome/free-solid-svg-icons'
+import { Draggable } from 'react-beautiful-dnd'
+
+import { StatusBarElementTypes } from '../../helpers/statusbar.js'
+
+config.autoAddCss = false
+library.add(faTimes)
+
+class StatusBarElement extends React.Component {
+ constructor(props) {
+ super(props)
+ }
+
+ deleteClicked = e => {
+ if (e) e.stopPropagation()
+ const { onDelete = () => {} } = this.props
+ onDelete()
+ }
+
+ render() {
+ const { item, index } = this.props
+ const type = item.split('_')[0]
+ return (
+
+ {provided => (
+
+
+
+
+
+
+
{type || 'Unknown'}
+
+
+
+ )}
+
+ )
+ }
+}
+
+export default StatusBarElement
diff --git a/components/Display/Frame.js b/components/Display/Frame.js
index 5b47ee9..8c6aedc 100644
--- a/components/Display/Frame.js
+++ b/components/Display/Frame.js
@@ -13,41 +13,28 @@ class Frame extends React.Component {
super(props)
}
- renderStatusBarElement = type => {
- return (
-
{statusBar && statusBar.length > 0 && (
- {statusBar.map(type => (
-
- {type == 'date' ? (
-
- ) : type == 'connection' ? (
-
- ) : type == 'time' ? (
-
- ) : (
- ' '
- )}
-
- ))}
+ {statusBar.map(item => {
+ const type = item.split('_')[0]
+ return (
+
+ {type == 'date' ? (
+
+ ) : type == 'connection' ? (
+
+ ) : type == 'time' ? (
+
+ ) : (
+ ' '
+ )}
+
+ )
+ })}
)}
{children}
diff --git a/helpers/statusbar.js b/helpers/statusbar.js
new file mode 100644
index 0000000..f1df6ad
--- /dev/null
+++ b/helpers/statusbar.js
@@ -0,0 +1,27 @@
+import { library, config } from '@fortawesome/fontawesome-svg-core'
+import { faRss, faGripVertical, faClock, faCalendarAlt } from '@fortawesome/free-solid-svg-icons'
+
+config.autoAddCss = false
+library.add(faRss)
+library.add(faGripVertical)
+library.add(faClock)
+library.add(faCalendarAlt)
+
+export const StatusBarElementTypes = {
+ time: {
+ name: 'time',
+ icon: faClock
+ },
+ date: {
+ name: 'date',
+ icon: faCalendarAlt
+ },
+ spacer: {
+ name: 'spacer',
+ icon: faGripVertical
+ },
+ connection: {
+ name: 'connection',
+ icon: faRss
+ }
+}
diff --git a/package.json b/package.json
index cbad24a..8e74b40 100644
--- a/package.json
+++ b/package.json
@@ -61,6 +61,7 @@
"passport-local": "^1.0.0",
"passport-local-mongoose": "^5.0.1",
"react": "^16.8.6",
+ "react-beautiful-dnd": "^11.0.4",
"react-color": "^2.17.0",
"react-content-loader": "^4.2.1",
"react-dom": "^16.8.2",
@@ -74,10 +75,12 @@
"react-sortable-hoc": "^1.8.3",
"react-switch": "^5.0.0",
"react-youtube": "^7.9.0",
+ "shortid": "^2.2.14",
"socket.io": "^2.2.0",
"socket.io-client": "^2.2.0",
"styled-components": "^4.2.0",
"superagent": "^5.0.5",
+ "uuid": "^3.3.2",
"webfontloader": "^1.6.28"
},
"devDependencies": {
diff --git a/pages/index.js b/pages/index.js
index 11e784a..6d4fbc7 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -22,7 +22,7 @@ class Index extends React.Component {
}
navigateToDisplay = id => {
- Router.push('/display?display=' + id)
+ Router.push('/display/' + id)
}
render() {
diff --git a/pages/layout.js b/pages/layout.js
index bcda892..3492005 100644
--- a/pages/layout.js
+++ b/pages/layout.js
@@ -1,15 +1,20 @@
import React from 'react'
-import { faThLarge, faTh } from '@fortawesome/free-solid-svg-icons'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faThLarge, faTh, faPencilAlt } from '@fortawesome/free-solid-svg-icons'
import GridLayout from 'react-grid-layout'
import { view } from 'react-easy-state'
+import { DragDropContext, Droppable } from 'react-beautiful-dnd'
import Frame from '../components/Admin/Frame.js'
import EditableWidget from '../components/Admin/EditableWidget'
+import StatusBarElement from '../components/Admin/StatusBarElement'
import WidthProvider from '../components/Widgets/WidthProvider'
import DropdownButton from '../components/DropdownButton'
import { Form, Switch } from '../components/Form'
+import { StatusBarElementTypes } from '../helpers/statusbar.js'
+
import Widgets from '../widgets'
import { addWidget, getWidgets, deleteWidget, updateWidget } from '../actions/widgets'
@@ -66,6 +71,14 @@ class Layout extends React.Component {
}
}
+ onDragEnd = result => {
+ if (!result.destination) {
+ return
+ }
+
+ display.reorderStatusBarItems(result.source.index, result.destination.index)
+ }
+
render() {
const { widgets } = this.state
const { loggedIn } = this.props
@@ -81,6 +94,70 @@ class Layout extends React.Component {
Layout
+
+
{
+ const target = event.target
+ const title = target && target.value
+ display.updateName(title)
+ }}
+ onClick={e => {
+ if (e) e.stopPropagation()
+ }}
+ size={display && display.name && display.name.length}
+ />
+
+
+
+
+
+
+ ({
+ key: statusBarEl,
+ name: StatusBarElementTypes[statusBarEl].name,
+ icon: StatusBarElementTypes[statusBarEl].icon
+ }))}
+ />
+
+
+ {display && display.statusBar && (
+
+
+ {provided => (
+
+ {display.statusBar.map((item, index) => (
+
+ ))}
+ {provided.placeholder}
+
+ )}
+
+
+ )}
diff --git a/routes.js b/routes.js
index 5643335..7cd43d8 100644
--- a/routes.js
+++ b/routes.js
@@ -1,3 +1,5 @@
const routes = require('next-routes')
-module.exports = routes().add('/slideshow/:id', 'slideshow')
+module.exports = routes()
+ .add('/slideshow/:id', 'slideshow')
+ .add('/display/:display', 'display')
diff --git a/stores/display.js b/stores/display.js
index 243cff5..6c3e31f 100644
--- a/stores/display.js
+++ b/stores/display.js
@@ -2,6 +2,7 @@ const ReactEasyState = require('react-easy-state')
const store = ReactEasyState.store
const _ = require('lodash')
const DisplayActions = require('../actions/display')
+const shortid = require('shortid')
const updateDisplayThrottled = _.debounce((id, data) => {
return DisplayActions.updateDisplay(id, data)
@@ -35,6 +36,23 @@ const display = store({
if (!layout || !['spaced', 'compact'].includes(layout)) return
display.layout = layout
updateDisplayThrottled(display.id, { layout })
+ },
+ addStatusBarItem(type) {
+ display.statusBar = [...display.statusBar, type + '_' + shortid.generate()]
+ updateDisplayThrottled(display.id, { statusBar: display.statusBar })
+ return Promise.resolve()
+ },
+ removeStatusBarItem(id) {
+ display.statusBar = [...display.statusBar.slice(0, id).concat(display.statusBar.slice(id + 1))]
+ updateDisplayThrottled(display.id, { statusBar: display.statusBar })
+ },
+ reorderStatusBarItems(startIndex, endIndex) {
+ const result = Array.from(display.statusBar)
+ const [removed] = result.splice(startIndex, 1)
+ result.splice(endIndex, 0, removed)
+
+ display.statusBar = result
+ updateDisplayThrottled(display.id, { statusBar: display.statusBar })
}
})