Skip to content
This repository was archived by the owner on Aug 28, 2020. It is now read-only.

Commit 9125e2c

Browse files
committed
Merge branch 'release/1.0.0-beta.1'
2 parents 827c8f2 + a3a9bfe commit 9125e2c

19 files changed

+5239
-2178
lines changed

LICENSE

Lines changed: 661 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
1-
# display-vue
1+
# Vue.js Display Frontend
22

3-
## Project setup
4-
```
5-
npm install
6-
```
3+
This is the web application, that runs on each Display unit.
4+
The app maintains a [Socket.IO](https://socket.io/) connection to the [Display Backend](https://github.com/alarmdisplay/display-backend) to get its configuration and data updates.
75

8-
### Compiles and hot-reloads for development
9-
```
10-
npm run serve
11-
```
6+
## Development
7+
In order to run a development version on your local system, you need a [Node.js](https://nodejs.org/) environment.
8+
Clone the repository and run `npm install` inside the project folder to install all the dependencies.
129

13-
### Compiles and minifies for production
14-
```
15-
npm run build
16-
```
10+
Start the development server by running `npm run serve`, it will automatically restart when files have changed.
11+
Now you can access the server on http://localhost:8080 (may be a different port on your system, check the console output).
12+
If you run a development server of [Display Backend](https://github.com/alarmdisplay/display-backend) on http://localhost:3000, the requests are automatically proxied there.
13+
This allows for parallel development of the frontend and the backend.
1714

18-
### Lints and fixes files
19-
```
20-
npm run lint
21-
```
22-
23-
### Customize configuration
24-
See [Configuration Reference](https://cli.vuejs.org/config/).
15+
## Deployment
16+
Run `npm run build`, which compiles and minifies the app for production.
17+
You find the result of the build process in a folder called `dist`.
18+
This folder only contains HTML, CSS, and JS files, which means they can be hosted as static files.
19+
By default, the app expects to be accessible under the path `/display/`.
20+
You can change this behaviour by adapting the `publicPath` in [vue.config.js](vue.config.js).

package-lock.json

Lines changed: 3412 additions & 2081 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,37 @@
11
{
22
"name": "display-vue",
3-
"version": "0.1.0",
4-
"private": true,
3+
"version": "1.0.0-beta.1",
4+
"private": false,
55
"scripts": {
66
"serve": "vue-cli-service serve",
77
"build": "vue-cli-service build",
88
"lint": "vue-cli-service lint"
99
},
10+
"repository": {
11+
"type": "git",
12+
"url": "https://github.com/alarmdisplay/display-frontend-vue.git"
13+
},
14+
"keywords": [],
15+
"author": "Andreas Brain",
16+
"license": "AGPL-3.0-only",
1017
"dependencies": {
11-
"core-js": "^3.6.4",
12-
"vue": "^2.6.11"
18+
"@fortawesome/fontawesome-svg-core": "^1.2.29",
19+
"@fortawesome/free-solid-svg-icons": "^5.13.1",
20+
"@fortawesome/vue-fontawesome": "^0.1.10",
21+
"core-js": "^3.6.5",
22+
"moment": "^2.27.0",
23+
"socket.io-client": "^2.3.0",
24+
"vue": "^2.6.11",
25+
"vue-moment": "^4.1.0",
26+
"vue-toast-notification": "0.0.3"
1327
},
1428
"devDependencies": {
15-
"@vue/cli-plugin-babel": "~4.2.0",
16-
"@vue/cli-plugin-eslint": "~4.2.0",
17-
"@vue/cli-service": "~4.2.0",
29+
"@vue/cli-plugin-babel": "^4.4.6",
30+
"@vue/cli-plugin-eslint": "^4.4.6",
31+
"@vue/cli-service": "^4.4.6",
1832
"babel-eslint": "^10.0.3",
1933
"eslint": "^6.7.2",
20-
"eslint-plugin-vue": "^6.1.2",
34+
"eslint-plugin-vue": "^6.2.2",
2135
"vue-template-compiler": "^2.6.11"
2236
},
2337
"eslintConfig": {

src/App.vue

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,59 @@
11
<template>
22
<div id="app">
3-
<img alt="Vue logo" src="./assets/logo.png">
4-
<HelloWorld msg="Welcome to Your Vue.js App"/>
3+
<SplashScreen v-if="showSplashScreen === true"/>
4+
<DisplayApp v-else-if="authenticated === true" v-bind:views="views" :alerts="alerts"/>
5+
<DisplaySetup v-else v-bind:display-identifier="displayId"/>
56
</div>
67
</template>
78

89
<script>
9-
import HelloWorld from './components/HelloWorld.vue'
10+
import DisplayApp from "@/components/DisplayApp";
11+
import DisplaySetup from "@/components/DisplaySetup";
12+
import SplashScreen from "@/components/SplashScreen";
1013
1114
export default {
1215
name: 'App',
1316
components: {
14-
HelloWorld
17+
DisplayApp,
18+
DisplaySetup,
19+
SplashScreen
20+
},
21+
props: {
22+
alerts: Array,
23+
authenticated: Boolean,
24+
displayId: String,
25+
showSplashScreen: Boolean,
26+
views: Array
1527
}
1628
}
1729
</script>
1830

1931
<style>
2032
#app {
21-
font-family: Avenir, Helvetica, Arial, sans-serif;
33+
font-family: 'Open Sans', sans-serif;
2234
-webkit-font-smoothing: antialiased;
2335
-moz-osx-font-smoothing: grayscale;
36+
margin: 0;
37+
padding: 0;
38+
height: 100%;
39+
overflow: hidden;
40+
}
41+
42+
body {
43+
height: 100%;
44+
margin: 0;
45+
padding: 0;
46+
}
47+
48+
html {
49+
height: 100vh;
50+
background-color: #777777;
51+
color: #dddddd;
52+
}
53+
54+
.gridview-component {
55+
overflow: hidden;
56+
padding: 1em;
2457
text-align: center;
25-
color: #2c3e50;
26-
margin-top: 60px;
2758
}
2859
</style>

src/components/AlertScreen.vue

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<template>
2+
<DefaultAlertView :alert="mostRecentAlert"/>
3+
</template>
4+
5+
<script>
6+
import DefaultAlertView from "@/components/DefaultAlertView";
7+
8+
export default {
9+
name: "AlertScreen",
10+
components: {
11+
DefaultAlertView
12+
},
13+
computed: {
14+
mostRecentAlert: function () {
15+
let alerts = Array.from(this.alerts)
16+
alerts.sort((a, b) => b.time - a.time);
17+
return alerts[0];
18+
}
19+
},
20+
props: {
21+
alerts: Array
22+
}
23+
}
24+
</script>
25+
26+
<style scoped>
27+
</style>

src/components/Clock.vue

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<template>
2+
<div class="gridview-component clock">
3+
<div v-if="showTime" class="time">{{ time }}</div>
4+
<div v-if="showDate" class="date">{{ date }}</div>
5+
</div>
6+
</template>
7+
8+
<script>
9+
export default {
10+
name: 'Clock',
11+
computed: {
12+
dateFormat: function () {
13+
return Object.prototype.hasOwnProperty.call(this.options, 'dateFormat') ? this.options.dateFormat : 'll'
14+
},
15+
showDate: function () {
16+
return Object.prototype.hasOwnProperty.call(this.options, 'showDate') ? this.options.showDate : true
17+
},
18+
showTime: function () {
19+
return Object.prototype.hasOwnProperty.call(this.options, 'showTime') ? this.options.showTime : true
20+
},
21+
timeFormat: function () {
22+
return Object.prototype.hasOwnProperty.call(this.options, 'timeFormat') ? this.options.timeFormat : 'LT'
23+
}
24+
},
25+
data() {
26+
return {
27+
time: '',
28+
date: ''
29+
}
30+
},
31+
mounted: function() {
32+
setInterval(this.updateTime, 1000);
33+
},
34+
methods: {
35+
updateTime() {
36+
this.time = this.$moment(Date.now()).format(this.timeFormat);
37+
this.date = this.$moment(Date.now()).format(this.dateFormat);
38+
}
39+
},
40+
props: {
41+
instanceId: Number,
42+
options: Object
43+
},
44+
watch: {
45+
options: 'updateTime'
46+
}
47+
}
48+
</script>
49+
50+
<style scoped>
51+
.clock {
52+
color: white;
53+
display: flex;
54+
flex-direction: column;
55+
justify-content: center;
56+
align-items: center;
57+
}
58+
59+
.time {
60+
font-size: 6em;
61+
font-weight: bold;
62+
}
63+
64+
.date {
65+
font-size: 2.5em;
66+
}
67+
</style>

src/components/DWDWarningMap.vue

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<template>
2+
<div class="gridview-component">
3+
<img :src="imgurl" alt="">
4+
</div>
5+
</template>
6+
7+
<script>
8+
export default {
9+
name: "DWDWarningMap",
10+
computed: {
11+
areaCode: function () {
12+
return this.options.areaCode || 'DE';
13+
},
14+
baseUrl: function () {
15+
switch (this.mapType) {
16+
case 'simple':
17+
return `https://www.dwd.de/DWD/warnungen/warnapp_gemeinden/json/warnungen_gemeinde_map_${this.stateCode}.png`;
18+
case 'area':
19+
return `https://www.dwd.de/DWD/warnungen/warnstatus/Schilder${this.schilderCode}.jpg`;
20+
default:
21+
return 'https://www.dwd.de/DWD/warnungen/warnapp_gemeinden/json/warnungen_gemeinde_map_de.png';
22+
}
23+
},
24+
imgurl: function () {
25+
return `${this.baseUrl}?${this.cacheBustingQuery}`;
26+
},
27+
mapType: function () {
28+
return this.options.mapType || 'area';
29+
},
30+
schilderCode: function () {
31+
32+
switch (this.areaCode) {
33+
case 'DE':
34+
return 'D';
35+
case 'DE-BW':
36+
return 'SU';
37+
case 'DE-BY':
38+
return 'MS';
39+
case 'DE-BE':
40+
case 'DE-BB':
41+
case 'DE-MV':
42+
return 'PD';
43+
case 'DE-HB':
44+
case 'DE-HH':
45+
case 'DE-NI':
46+
case 'DE-SH':
47+
return 'HA';
48+
case 'DE-HE':
49+
case 'DE-RP':
50+
case 'DE-SL':
51+
return 'OF';
52+
case 'DE-NW':
53+
return 'EM';
54+
case 'DE-SN':
55+
case 'DE-ST':
56+
case 'DE-TH':
57+
return 'LZ';
58+
case 'Bodensee':
59+
return 'Bodensee';
60+
default:
61+
return 'D';
62+
}
63+
},
64+
stateCode: function () {
65+
switch (this.areaCode) {
66+
case 'DE-BW':
67+
case 'Bodensee':
68+
return 'baw';
69+
case 'DE-BY':
70+
return 'bay';
71+
case 'DE-BE':
72+
case 'DE-BB':
73+
return 'bbb';
74+
case 'DE-HB':
75+
case 'DE-NI':
76+
return 'nib';
77+
case 'DE-HH':
78+
case 'DE-SH':
79+
return 'shh';
80+
case 'DE-HE':
81+
return 'hes';
82+
case 'DE-MV':
83+
return 'mvp';
84+
case 'DE-NW':
85+
return 'nrw';
86+
case 'DE-RP':
87+
case 'DE-SL':
88+
return 'rps';
89+
case 'DE-SN':
90+
return 'sac';
91+
case 'DE-ST':
92+
return 'saa';
93+
case 'DE-TH':
94+
return 'thu';
95+
default:
96+
return 'de';
97+
}
98+
}
99+
},
100+
data: function () {
101+
return {
102+
cacheBustingQuery: Date.now()
103+
}
104+
},
105+
mounted: function() {
106+
// update the query part of the URL every 10 minutes, so it gets reloaded
107+
setInterval(() => {
108+
this.cacheBustingQuery = Date.now();
109+
}, 600000);
110+
},
111+
props: {
112+
/**
113+
* Possible options:
114+
* - areaCode: An ISO 3166-2 code for one of the 16 german states, 'DE' for entire Germany, or (only with
115+
* mapType = area) 'Bodensee' for the Bodensee region
116+
* - mapType: Can be 'simple' for a map of a single state or entire Germany, or 'area' for a map of one or
117+
* more states including more detail about the warnings
118+
*/
119+
options: Object
120+
}
121+
}
122+
</script>
123+
124+
<style scoped>
125+
img {
126+
background-color: #ccc;
127+
box-shadow: 0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19);
128+
max-height: 100%;
129+
max-width: 100%;
130+
object-fit: scale-down;
131+
}
132+
</style>

0 commit comments

Comments
 (0)