Good working day
This commit is contained in:
parent
3c92244f5e
commit
2f52372e35
|
@ -0,0 +1,2 @@
|
||||||
|
*node_modules
|
||||||
|
*vscode
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -31,6 +31,8 @@
|
||||||
"@babel/preset-env": "^7.2.0",
|
"@babel/preset-env": "^7.2.0",
|
||||||
"autoprefixer": "^8.3.0",
|
"autoprefixer": "^8.3.0",
|
||||||
"babel-loader": "^8.0.5",
|
"babel-loader": "^8.0.5",
|
||||||
|
"chart.js": "^2.8.0",
|
||||||
|
"core-js": "^2.6.5",
|
||||||
"css-loader": "^0.28.11",
|
"css-loader": "^0.28.11",
|
||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||||
|
@ -38,16 +40,17 @@
|
||||||
"less-loader": "^4.1.0",
|
"less-loader": "^4.1.0",
|
||||||
"node-sass": "^4.11.0",
|
"node-sass": "^4.11.0",
|
||||||
"optimize-css-assets-webpack-plugin": "^4.0.0",
|
"optimize-css-assets-webpack-plugin": "^4.0.0",
|
||||||
|
"pug": "^2.0.3",
|
||||||
|
"pug-plain-loader": "^1.0.0",
|
||||||
"sass-loader": "^7.0.1",
|
"sass-loader": "^7.0.1",
|
||||||
"string-replace-webpack-plugin": "^0.1.3",
|
"string-replace-webpack-plugin": "^0.1.3",
|
||||||
"url-loader": "^1.0.1",
|
"url-loader": "^1.0.1",
|
||||||
|
"vue-chartjs": "^3.4.2",
|
||||||
"vue-loader": "^15.4.2",
|
"vue-loader": "^15.4.2",
|
||||||
"vue-style-loader": "^4.1.2",
|
"vue-style-loader": "^4.1.2",
|
||||||
"vue-template-compiler": "^2.5.22",
|
"vue-template-compiler": "^2.5.22",
|
||||||
"webpack": "^4.6.0",
|
"webpack": "^4.6.0",
|
||||||
"webpack-cli": "^3.2.1",
|
"webpack-cli": "^3.2.1"
|
||||||
"pug": "^2.0.3",
|
|
||||||
"pug-plain-loader": "^1.0.0"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vue": "^2.5.22"
|
"vue": "^2.5.22"
|
||||||
|
|
|
@ -6,10 +6,15 @@ export const emitErrorMixin = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const saveOptionsMixin = {
|
export const handleOptionsMixin = {
|
||||||
methods: {
|
methods: {
|
||||||
saveOptions(options) {
|
saveOptions(options) {
|
||||||
this.$emit("save", options)
|
this.$emit("save", options)
|
||||||
|
},
|
||||||
|
setOption(name, value) {
|
||||||
|
const options = {...this.$props}
|
||||||
|
options[name] = value
|
||||||
|
this.saveOptions(options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,25 +0,0 @@
|
||||||
<template lang="pug">
|
|
||||||
div(@click="changeName()").
|
|
||||||
Hello, compiler.
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name : 'example',
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
name : 'world'
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods : {
|
|
||||||
changeName() {
|
|
||||||
this.name = 'foobar';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
div
|
|
||||||
font-weight: bold
|
|
||||||
</style>
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
a.account(target="_blank" :href="account.url")
|
a.account(target="_blank" :href="account.url")
|
||||||
.avatar(:style="avatarStyle(account.avatar_static)")
|
.avatar(v-if="showMedia" :style="avatarStyle(account.avatar_static)")
|
||||||
.name(v-html="parseEmojis(account.display_name, account.emojis)")
|
.name(v-html="parseEmojis(account.display_name, account.emojis)")
|
||||||
.acct @{{ account.acct }}
|
.acct @{{ account.acct }}
|
||||||
</template>
|
</template>
|
||||||
|
@ -9,7 +9,13 @@ a.account(target="_blank" :href="account.url")
|
||||||
import { parseEmojisMixin } from './tools'
|
import { parseEmojisMixin } from './tools'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ["account"],
|
props: {
|
||||||
|
account: Object,
|
||||||
|
showMedia: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
mixins: [ parseEmojisMixin ],
|
mixins: [ parseEmojisMixin ],
|
||||||
methods: {
|
methods: {
|
||||||
avatarStyle(avatar) {
|
avatarStyle(avatar) {
|
||||||
|
|
|
@ -2,21 +2,22 @@
|
||||||
.client
|
.client
|
||||||
.statues
|
.statues
|
||||||
.header(v-if="notifications.length > 0") Accueil
|
.header(v-if="notifications.length > 0") Accueil
|
||||||
.list(v-if="statues.length > 0")
|
.list(v-if="statues.length > 0" @scroll="onScroll")
|
||||||
template(v-for="status in statues")
|
template(v-for="status in statues")
|
||||||
status(v-if="showStatus(status)" :key="status.id" :status="status" :now="now" @mark="onStatusMark")
|
status(v-if="showStatus(status)" :key="status.id" :status="status" :now="now" :showMedia="showMedia" @mark="onStatusMark")
|
||||||
|
.status(v-show="loadingOlder") Loading...
|
||||||
template(v-else) Loading...
|
template(v-else) Loading...
|
||||||
.notifications(v-if="notifications.length > 0")
|
.notifications(v-if="notifications.length > 0")
|
||||||
.header
|
.header
|
||||||
| Notifications
|
| Notifications
|
||||||
span.date(@click.stop.prevent="onNotificationsClear") ❌
|
span.date(@click.stop.prevent="onNotificationsClear") ❌
|
||||||
.list
|
.list
|
||||||
notification(v-for="notification in notifications" :key="notification.id" :notification="notification" :now="now" @dismiss="onNotificationDismiss")
|
notification(v-for="notification in notifications" :key="notification.id" :notification="notification" :now="now" :showMedia="showMedia" @dismiss="onNotificationDismiss")
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { timerMinin } from '../core/fromNow.vue'
|
import { timerMinin } from '../core/fromNow.vue'
|
||||||
import { emitErrorMixin, saveOptionsMixin } from '../core/tools'
|
import { emitErrorMixin } from '../core/tools'
|
||||||
import statusVue from './status.vue'
|
import statusVue from './status.vue'
|
||||||
import notificationVue from './notification.vue'
|
import notificationVue from './notification.vue'
|
||||||
|
|
||||||
|
@ -33,7 +34,8 @@ export default {
|
||||||
reconnect: Boolean,
|
reconnect: Boolean,
|
||||||
buffer: Number,
|
buffer: Number,
|
||||||
reblog: Boolean,
|
reblog: Boolean,
|
||||||
reply: Boolean
|
reply: Boolean,
|
||||||
|
showMedia: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -46,17 +48,25 @@ export default {
|
||||||
}),
|
}),
|
||||||
statues: [],
|
statues: [],
|
||||||
notifications: [],
|
notifications: [],
|
||||||
now: Date.now()
|
now: Date.now(),
|
||||||
|
loadingOlder: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addStatus(status) {
|
onScroll(event) {
|
||||||
this.statues.unshift(status)
|
if(!this.loadingOlder && event.target.scrollHeight - event.target.clientHeight - event.target.scrollTop - 100 < 0) {
|
||||||
this.statues.splice(this.buffer)
|
this.loadingOlder = true
|
||||||
},
|
this.rest
|
||||||
addNotification(notif) {
|
.get("/timelines/home", { params: { limit: this.buffer,
|
||||||
this.notifications.push(notif)
|
max_id: this.statues[this.statues.length - 1].id } })
|
||||||
this.notifications.splice(this.buffer)
|
.then(res => {
|
||||||
|
this.statues.push.apply(this.statues, res.data)
|
||||||
|
this.loadingOlder = false
|
||||||
|
})
|
||||||
|
.catch(this.emitError)
|
||||||
|
} else if(event.target.scrollTop < 20) {
|
||||||
|
this.statues.splice(this.buffer)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
removeStatus(id) {
|
removeStatus(id) {
|
||||||
for (var i = this.statues.length - 1; i >= 0; i--) {
|
for (var i = this.statues.length - 1; i >= 0; i--) {
|
||||||
|
@ -101,11 +111,11 @@ export default {
|
||||||
const payload = JSON.parse(event.payload)
|
const payload = JSON.parse(event.payload)
|
||||||
switch (event.event) {
|
switch (event.event) {
|
||||||
case "update":
|
case "update":
|
||||||
this.addStatus(payload)
|
this.statues.unshift(payload)
|
||||||
break
|
break
|
||||||
|
|
||||||
case "notification":
|
case "notification":
|
||||||
this.addNotification(payload)
|
this.notifications.unshift(payload)
|
||||||
break
|
break
|
||||||
|
|
||||||
case "delete":
|
case "delete":
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
.header(@click="showSettings = !showSettings")
|
.header(@click="showSettings = !showSettings")
|
||||||
| Mastodon:
|
| Mastodon:
|
||||||
span(v-html="parseEmojis(account.display_name, account.emojis)")
|
span(v-html="parseEmojis(account.display_name, account.emojis)")
|
||||||
| @{{ server }}
|
| {{ server ? '@' + server : '' }}
|
||||||
.settings(v-show="showSettings")
|
.settings(v-show="showSettings")
|
||||||
p
|
p
|
||||||
label(for="reconnect") Reconnect:
|
label(for="reconnect") Reconnect:
|
||||||
|
@ -17,6 +17,9 @@
|
||||||
p
|
p
|
||||||
label(for="buffer") Buffer:
|
label(for="buffer") Buffer:
|
||||||
input#buffer(type="number" :value="buffer" @keyup.enter="setOption('buffer', parseInt($event.target.value))")
|
input#buffer(type="number" :value="buffer" @keyup.enter="setOption('buffer', parseInt($event.target.value))")
|
||||||
|
p
|
||||||
|
label(for="showMedia") Show media:
|
||||||
|
input#showMedia(type="checkbox" :checked="showMedia" @change="setOption('showMedia', $event.target.checked)")
|
||||||
client(v-if="server && token" v-bind="$props")
|
client(v-if="server && token" v-bind="$props")
|
||||||
.auth(v-else)
|
.auth(v-else)
|
||||||
form(@submit.prevent="setServer")
|
form(@submit.prevent="setServer")
|
||||||
|
@ -31,13 +34,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { emitErrorMixin, saveOptionsMixin } from '../core/tools'
|
import { emitErrorMixin, handleOptionsMixin } from '../core/tools'
|
||||||
import { parseEmojisMixin } from './tools'
|
import { parseEmojisMixin } from './tools'
|
||||||
import clientVue from './client.vue'
|
import clientVue from './client.vue'
|
||||||
|
|
||||||
export default { //TODO: Use oauth
|
export default { //TODO: Use oauth
|
||||||
name: 'mastodon',
|
name: 'mastodon',
|
||||||
mixins: [ emitErrorMixin, saveOptionsMixin, parseEmojisMixin ],
|
mixins: [ emitErrorMixin, handleOptionsMixin, parseEmojisMixin ],
|
||||||
components: {
|
components: {
|
||||||
client: clientVue
|
client: clientVue
|
||||||
},
|
},
|
||||||
|
@ -63,6 +66,10 @@ export default { //TODO: Use oauth
|
||||||
reply: {
|
reply: {
|
||||||
default: false,
|
default: false,
|
||||||
type: Boolean
|
type: Boolean
|
||||||
|
},
|
||||||
|
showMedia: {
|
||||||
|
default: true,
|
||||||
|
type: Boolean
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -81,11 +88,6 @@ export default { //TODO: Use oauth
|
||||||
}).then(() => this.saveOptions({...this.$props,
|
}).then(() => this.saveOptions({...this.$props,
|
||||||
server: this.newServer, token: this.newToken}))
|
server: this.newServer, token: this.newToken}))
|
||||||
.catch(this.emitError)
|
.catch(this.emitError)
|
||||||
},
|
|
||||||
setOption(name, value) {
|
|
||||||
const options = {...this.$props}
|
|
||||||
options[name] = value
|
|
||||||
this.saveOptions(options)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.notification
|
.notification
|
||||||
account(:account="notification.account")
|
account(:account="notification.account" :showMedia="showMedia")
|
||||||
|
|
||||||
span.colored.text-icon.letter(v-if="notification.type == 'mention'") ✉
|
span.colored.text-icon.letter(v-if="notification.type == 'mention'") ✉
|
||||||
span.colored.text-icon.letter(v-if="notification.type == 'reblog'") ⟳
|
span.colored.text-icon.letter(v-if="notification.type == 'reblog'") ⟳
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
.content
|
.content
|
||||||
template(v-if="notification.type == 'follow'") Vous suit
|
template(v-if="notification.type == 'follow'") Vous suit
|
||||||
status.reblog(v-else-if="notification.status" :status="notification.status" :now="now"
|
status.reblog(v-else-if="notification.status" :status="notification.status" :now="now"
|
||||||
:withAccount="notification.type != 'mention'" @mark.stop.prevent="")
|
:showMedia="showMedia" :withAccount="notification.type != 'mention'" @mark.stop.prevent="")
|
||||||
|
|
||||||
a.date(@click.stop.prevent="makeDismiss" style="margin-top: -1em") ❌
|
a.date(@click.stop.prevent="makeDismiss" style="margin-top: -1em") ❌
|
||||||
</template>
|
</template>
|
||||||
|
@ -22,7 +22,13 @@ import accountVue from './account.vue'
|
||||||
import statusVue from './status.vue'
|
import statusVue from './status.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ["notification"],
|
props: {
|
||||||
|
notification: Object,
|
||||||
|
showMedia: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
mixins: [ timedMixin ],
|
mixins: [ timedMixin ],
|
||||||
components: {
|
components: {
|
||||||
fromNow: fromNowVue,
|
fromNow: fromNowVue,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
div
|
div
|
||||||
.status
|
.status
|
||||||
account(v-if="withAccount" :account="status.account")
|
account(v-if="withAccount" :account="status.account" :showMedia="showMedia")
|
||||||
|
|
||||||
span.text-icon.letter(v-if="status.reblog") ⟳
|
span.text-icon.letter(v-if="status.reblog") ⟳
|
||||||
|
|
||||||
|
@ -15,9 +15,11 @@ div
|
||||||
div(v-if="!status.spoiler_text || !status.sensitive")
|
div(v-if="!status.spoiler_text || !status.sensitive")
|
||||||
.text(v-html="parseEmojis(status.content, status.emojis)")
|
.text(v-html="parseEmojis(status.content, status.emojis)")
|
||||||
a.media(v-for="media in status.media_attachments" :href="media.url" target="_blank")
|
a.media(v-for="media in status.media_attachments" :href="media.url" target="_blank")
|
||||||
img(v-if="media.type == 'image' || media.type == 'gifv'" :src="media.preview_url" :alt="media.description" :title="media.description")
|
template(v-if="showMedia")
|
||||||
.gif(v-if="media.type == 'gifv'") GIF
|
img(v-if="media.type == 'image' || media.type == 'gifv'" :src="media.preview_url" :alt="media.description" :title="media.description")
|
||||||
status.reblog(v-else :status="status.reblog" :now="now")
|
.gif(v-if="media.type == 'gifv'") GIF
|
||||||
|
template(v-else) Hidden media
|
||||||
|
status.reblog(v-else :status="status.reblog" :now="now" :showMedia="showMedia")
|
||||||
|
|
||||||
.meta(v-if="!status.reblog")
|
.meta(v-if="!status.reblog")
|
||||||
a.replies(@click.stop.prevent="makeReply(status)")
|
a.replies(@click.stop.prevent="makeReply(status)")
|
||||||
|
@ -47,6 +49,10 @@ export default {
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
status: Object,
|
status: Object,
|
||||||
|
showMedia: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
withAccount: {
|
withAccount: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
|
|
|
@ -31,12 +31,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { emitErrorMixin, saveOptionsMixin } from '../core/tools'
|
import { emitErrorMixin, handleOptionsMixin } from '../core/tools'
|
||||||
import fromNowVue, { timerMinin } from '../core/fromNow.vue';
|
import fromNowVue, { timerMinin } from '../core/fromNow.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'nextcloud-news',
|
name: 'nextcloud-news',
|
||||||
mixins: [ emitErrorMixin, timerMinin, saveOptionsMixin ],
|
mixins: [ emitErrorMixin, timerMinin, handleOptionsMixin ],
|
||||||
components: {
|
components: {
|
||||||
fromNow: fromNowVue
|
fromNow: fromNowVue
|
||||||
},
|
},
|
||||||
|
@ -103,11 +103,6 @@ export default {
|
||||||
}).then(() => this.saveOptions({...this.$props,
|
}).then(() => this.saveOptions({...this.$props,
|
||||||
server: this.newServer, token: this.newToken, username: this.newUsername }))
|
server: this.newServer, token: this.newToken, username: this.newUsername }))
|
||||||
.catch(this.emitError)
|
.catch(this.emitError)
|
||||||
},
|
|
||||||
setOption(name, value) {
|
|
||||||
const options = {...this.$props}
|
|
||||||
options[name] = value
|
|
||||||
this.saveOptions(options)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
<script>
|
||||||
|
import { Bar, mixins } from 'vue-chartjs'
|
||||||
|
import moment from 'moment'
|
||||||
|
const { reactiveProp } = mixins
|
||||||
|
|
||||||
|
export default {
|
||||||
|
extends: Bar,
|
||||||
|
mixins: [ reactiveProp ],
|
||||||
|
mounted () {
|
||||||
|
this.renderChart(this.chartData, {
|
||||||
|
responsive: true,
|
||||||
|
legend: {
|
||||||
|
labels: {
|
||||||
|
fontColor: "white"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
xAxes: [{
|
||||||
|
type: 'time',
|
||||||
|
distribution: 'series',
|
||||||
|
ticks: {
|
||||||
|
fontColor: "white",
|
||||||
|
source: 'data',
|
||||||
|
autoSkip: true,
|
||||||
|
maxRotation: 0,
|
||||||
|
autoSkipPadding: 5
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
displayFormats: {
|
||||||
|
hour: 'HH[h]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
yAxes: [{
|
||||||
|
id: 'y-axis-temp',
|
||||||
|
display: true,
|
||||||
|
position: 'left',
|
||||||
|
ticks: {
|
||||||
|
fontColor: "white"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
id: 'y-axis-rain',
|
||||||
|
display: true,
|
||||||
|
position: 'right',
|
||||||
|
ticks: {
|
||||||
|
fontColor: "white",
|
||||||
|
beginAtZero: true,
|
||||||
|
suggestedMax: 1
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
tooltips: {
|
||||||
|
intersect: false,
|
||||||
|
callbacks: {
|
||||||
|
title: function(tooltipItem, myData) {
|
||||||
|
var item = myData.datasets[tooltipItem[0].datasetIndex].data[tooltipItem[0].index]
|
||||||
|
return moment(item.x || item.t).format('HH[h]')
|
||||||
|
},
|
||||||
|
label: function(tooltipItem, myData) {
|
||||||
|
var label = myData.datasets[tooltipItem.datasetIndex].label || '';
|
||||||
|
if (label) {
|
||||||
|
label += ': ';
|
||||||
|
}
|
||||||
|
label += tooltipItem.value;
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -8,6 +8,9 @@
|
||||||
p
|
p
|
||||||
label(for="update") Update interval:
|
label(for="update") Update interval:
|
||||||
input#update(type="number" :value="update" @keyup.enter="setOption('update', parseInt($event.target.value))")
|
input#update(type="number" :value="update" @keyup.enter="setOption('update', parseInt($event.target.value))")
|
||||||
|
p
|
||||||
|
label(for="forecastLimit") Forecast limit:
|
||||||
|
input#forecastLimit(type="number" :value="forecastLimit" @keyup.enter="setOption('forecastLimit', parseInt($event.target.value))")
|
||||||
p
|
p
|
||||||
button(@click="showAdd = true") Add city
|
button(@click="showAdd = true") Add city
|
||||||
template(v-if="weathers.length > 0 || cities.length == 0")
|
template(v-if="weathers.length > 0 || cities.length == 0")
|
||||||
|
@ -24,27 +27,21 @@
|
||||||
| {{ city.main.temp }}°C ─ {{ city.main.humidity }}%
|
| {{ city.main.temp }}°C ─ {{ city.main.humidity }}%
|
||||||
input.weather(v-show="showAdd" placeholder="city id" @keyup.enter="addCity(parseInt($event.target.value))")
|
input.weather(v-show="showAdd" placeholder="city id" @keyup.enter="addCity(parseInt($event.target.value))")
|
||||||
.forecast
|
.forecast
|
||||||
template(v-if="forecast")
|
chart(v-if="forecast" :chartData="forecastChart")
|
||||||
.list
|
|
||||||
.line(v-for="line in forecast")
|
|
||||||
| {{ formatDate(line.dt) }}
|
|
||||||
.data
|
|
||||||
| {{ line.main.temp }}°C ─ {{ line.main.humidity }}%
|
|
||||||
.main(v-for="main in line.weather")
|
|
||||||
.ic
|
|
||||||
img(:src="`https://openweathermap.org/img/w/${main.icon}.png`" :alt="main.main")
|
|
||||||
p {{ main.description }}
|
|
||||||
template(v-else) Loading...
|
template(v-else) Loading...
|
||||||
template(v-else) Loading...
|
template(v-else) Loading...
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { emitErrorMixin, saveOptionsMixin } from '../core/tools'
|
import { emitErrorMixin, handleOptionsMixin } from '../core/tools'
|
||||||
|
import chartVue from './chart.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'openweathermap',
|
name: 'openweathermap',
|
||||||
components: {},
|
components: {
|
||||||
mixins: [ emitErrorMixin, saveOptionsMixin ],
|
chart: chartVue
|
||||||
|
},
|
||||||
|
mixins: [ emitErrorMixin, handleOptionsMixin ],
|
||||||
props: {
|
props: {
|
||||||
token: String,
|
token: String,
|
||||||
cities: {
|
cities: {
|
||||||
|
@ -64,6 +61,10 @@ export default {
|
||||||
lang: {
|
lang: {
|
||||||
default: 'fr',
|
default: 'fr',
|
||||||
type: String
|
type: String
|
||||||
|
},
|
||||||
|
forecastLimit: {
|
||||||
|
default: 9,
|
||||||
|
type: Number
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -82,6 +83,31 @@ export default {
|
||||||
showAdd: this.cities.length == 0
|
showAdd: this.cities.length == 0
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
forecastChart() { return {
|
||||||
|
datasets: [{
|
||||||
|
type: 'line',
|
||||||
|
label: 'Temperature',
|
||||||
|
yAxisID: 'y-axis-temp',
|
||||||
|
borderColor: 'white',
|
||||||
|
borderWidth: 1,
|
||||||
|
fill: false,
|
||||||
|
data: this.forecast.map(function (line) { return {
|
||||||
|
x: line.dt * 1000, y: line.main.temp
|
||||||
|
} })
|
||||||
|
},{
|
||||||
|
type: 'bar',
|
||||||
|
label: 'Percipitation',
|
||||||
|
yAxisID: 'y-axis-rain',
|
||||||
|
borderColor: '#DDDDDD',
|
||||||
|
backgroundColor: '#DDDDDD33',
|
||||||
|
borderWidth: 1,
|
||||||
|
data: this.forecast.filter(f => 'rain' in f && '3h' in f.rain).map(function (line) { return {
|
||||||
|
x: line.dt * 1000, y: line.rain['3h']
|
||||||
|
} })
|
||||||
|
}]
|
||||||
|
} }
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
makeSelect(id) {
|
makeSelect(id) {
|
||||||
this.selected = id
|
this.selected = id
|
||||||
|
@ -103,7 +129,8 @@ export default {
|
||||||
loadForecast() {
|
loadForecast() {
|
||||||
if(this.weathers[this.selected]) {
|
if(this.weathers[this.selected]) {
|
||||||
this.rest.get('forecast', { params: {
|
this.rest.get('forecast', { params: {
|
||||||
id: this.weathers[this.selected].id
|
id: this.weathers[this.selected].id,
|
||||||
|
cnt: this.forecastLimit
|
||||||
}})
|
}})
|
||||||
.then(res => this.forecast = res.data.list)
|
.then(res => this.forecast = res.data.list)
|
||||||
.catch(this.emitError)
|
.catch(this.emitError)
|
||||||
|
@ -117,11 +144,6 @@ export default {
|
||||||
const options = {...this.$props}
|
const options = {...this.$props}
|
||||||
options.cities.push({id: id})
|
options.cities.push({id: id})
|
||||||
this.saveOptions(options)
|
this.saveOptions(options)
|
||||||
},
|
|
||||||
setOption(name, value) {
|
|
||||||
const options = {...this.$props}
|
|
||||||
options[name] = value
|
|
||||||
this.saveOptions(options)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|
|
@ -25,6 +25,10 @@ module.exports = (env) => {
|
||||||
entry : {
|
entry : {
|
||||||
[filename] : './entry.js'
|
[filename] : './entry.js'
|
||||||
},
|
},
|
||||||
|
performance: {
|
||||||
|
maxEntrypointSize: 512000,
|
||||||
|
maxAssetSize: 512000
|
||||||
|
},
|
||||||
output : {
|
output : {
|
||||||
filename : '[name].js',
|
filename : '[name].js',
|
||||||
path : path.resolve(__dirname, 'dist', filepath)
|
path : path.resolve(__dirname, 'dist', filepath)
|
||||||
|
|
64
main.css
64
main.css
|
@ -1,6 +1,7 @@
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
font-family: Verdana, Geneva, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@ -62,14 +63,14 @@ a {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mastodon .header, .mastodon .settings, .mastodon .client .list > div {
|
#services > div > .header, #services > div > .settings {
|
||||||
margin: 0.3em;
|
margin: 0.3em;
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
border-radius: 0.3em;
|
border-radius: 0.3em;
|
||||||
padding: 0.3em;
|
padding: 0.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mastodon .header {
|
#services > div > .header {
|
||||||
font-size: large;
|
font-size: large;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -91,6 +92,13 @@ a {
|
||||||
min-height: min-content;
|
min-height: min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mastodon .client .list > div {
|
||||||
|
margin: 0.3em;
|
||||||
|
background-color: #222;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
padding: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
.mastodon .client .statues {
|
.mastodon .client .statues {
|
||||||
-webkit-box-flex: 1;
|
-webkit-box-flex: 1;
|
||||||
-ms-flex: 1;
|
-ms-flex: 1;
|
||||||
|
@ -182,19 +190,6 @@ a {
|
||||||
max-width: 30%;
|
max-width: 30%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openweathermap > .header, .openweathermap .settings {
|
|
||||||
margin: 0.3em;
|
|
||||||
background-color: #222;
|
|
||||||
border-radius: 0.3em;
|
|
||||||
padding: 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openweathermap > .header {
|
|
||||||
font-size: large;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openweathermap .ic {
|
.openweathermap .ic {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
|
@ -227,35 +222,11 @@ a {
|
||||||
-webkit-box-flex: 1;
|
-webkit-box-flex: 1;
|
||||||
-ms-flex: 1;
|
-ms-flex: 1;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-ms-flex-wrap: wrap;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
overflow-y: scroll;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openweathermap .forecast .line {
|
|
||||||
-webkit-box-flex: 1;
|
|
||||||
-ms-flex: 1;
|
|
||||||
flex: 1;
|
|
||||||
min-width: 15em;
|
|
||||||
margin: 0.3em;
|
|
||||||
background-color: #222;
|
|
||||||
border-radius: 0.3em;
|
|
||||||
padding: 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openweathermap .forecast .line .data {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openweathermap .forecast .line .main p {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openweathermap .weather {
|
.openweathermap .weather {
|
||||||
min-width: 17em;
|
min-width: 17em;
|
||||||
border: 1px solid #222;
|
border: 1px solid #222;
|
||||||
|
@ -283,19 +254,6 @@ a {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nextcloud-news > .header, .nextcloud-news .settings {
|
|
||||||
margin: 0.3em;
|
|
||||||
background-color: #222;
|
|
||||||
border-radius: 0.3em;
|
|
||||||
padding: 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nextcloud-news > .header {
|
|
||||||
font-size: large;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nextcloud-news .news {
|
.nextcloud-news .news {
|
||||||
margin: 0.3em;
|
margin: 0.3em;
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
|
|
File diff suppressed because one or more lines are too long
5
main.js
5
main.js
|
@ -40,11 +40,11 @@ var app = new Vue({
|
||||||
this.saveServices()
|
this.saveServices()
|
||||||
},
|
},
|
||||||
setService(id, options) {
|
setService(id, options) {
|
||||||
this.services.push({
|
this.$set(this.services, id, {
|
||||||
type: this.services[id].type,
|
type: this.services[id].type,
|
||||||
options: options
|
options: options
|
||||||
})
|
})
|
||||||
this.removeService(id)
|
this.saveServices()
|
||||||
},
|
},
|
||||||
removeService(id) {
|
removeService(id) {
|
||||||
this.services.splice(id, 1)
|
this.services.splice(id, 1)
|
||||||
|
@ -52,6 +52,7 @@ var app = new Vue({
|
||||||
},
|
},
|
||||||
saveServices() {
|
saveServices() {
|
||||||
localStorage.setItem(servicesStorage, JSON.stringify(this.services))
|
localStorage.setItem(servicesStorage, JSON.stringify(this.services))
|
||||||
|
this.$forceUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
39
main.sass
39
main.sass
|
@ -16,6 +16,7 @@ $foreColor: #eee
|
||||||
*
|
*
|
||||||
margin: 0
|
margin: 0
|
||||||
padding: 0
|
padding: 0
|
||||||
|
font-family: Verdana, Geneva, sans-serif
|
||||||
|
|
||||||
body
|
body
|
||||||
background-color: $backColor
|
background-color: $backColor
|
||||||
|
@ -55,14 +56,14 @@ a
|
||||||
display: flex
|
display: flex
|
||||||
& > div
|
& > div
|
||||||
flex: 1
|
flex: 1
|
||||||
|
& > .header, & > .settings
|
||||||
|
@include tile
|
||||||
|
& > .header
|
||||||
|
font-size: large
|
||||||
|
text-align: center
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
.mastodon
|
.mastodon
|
||||||
.header, .settings, .client .list > div
|
|
||||||
@include tile
|
|
||||||
.header
|
|
||||||
font-size: large
|
|
||||||
text-align: center
|
|
||||||
font-weight: bold
|
|
||||||
.client
|
.client
|
||||||
display: flex
|
display: flex
|
||||||
height: 100vh
|
height: 100vh
|
||||||
|
@ -71,6 +72,8 @@ a
|
||||||
height: 100%
|
height: 100%
|
||||||
overflow-y: auto
|
overflow-y: auto
|
||||||
min-height: min-content
|
min-height: min-content
|
||||||
|
& > div
|
||||||
|
@include tile
|
||||||
.statues
|
.statues
|
||||||
flex: 1
|
flex: 1
|
||||||
.notifications
|
.notifications
|
||||||
|
@ -125,12 +128,6 @@ a
|
||||||
float: right
|
float: right
|
||||||
|
|
||||||
.openweathermap
|
.openweathermap
|
||||||
& > .header, .settings
|
|
||||||
@include tile
|
|
||||||
& > .header
|
|
||||||
font-size: large
|
|
||||||
text-align: center
|
|
||||||
font-weight: bold
|
|
||||||
.ic
|
.ic
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
height: 30px
|
height: 30px
|
||||||
|
@ -149,19 +146,9 @@ a
|
||||||
@include tile
|
@include tile
|
||||||
.forecast
|
.forecast
|
||||||
flex: 1
|
flex: 1
|
||||||
display: flex
|
|
||||||
flex-wrap: wrap
|
|
||||||
max-height: 100%
|
max-height: 100%
|
||||||
overflow-y: scroll
|
overflow-y: auto
|
||||||
overflow-x: hidden
|
overflow-x: hidden
|
||||||
.line
|
|
||||||
flex: 1
|
|
||||||
min-width: 15em
|
|
||||||
@include tile
|
|
||||||
.data
|
|
||||||
float: right
|
|
||||||
.main p
|
|
||||||
display: inline
|
|
||||||
.weather
|
.weather
|
||||||
min-width: 17em
|
min-width: 17em
|
||||||
border: 1px solid $tileColor
|
border: 1px solid $tileColor
|
||||||
|
@ -179,12 +166,6 @@ a
|
||||||
vertical-align: top
|
vertical-align: top
|
||||||
|
|
||||||
.nextcloud-news
|
.nextcloud-news
|
||||||
& > .header, .settings
|
|
||||||
@include tile
|
|
||||||
& > .header
|
|
||||||
font-size: large
|
|
||||||
text-align: center
|
|
||||||
font-weight: bold
|
|
||||||
.news
|
.news
|
||||||
@include tile
|
@include tile
|
||||||
.date
|
.date
|
||||||
|
|
Loading…
Reference in New Issue