further work on dashboard
This commit is contained in:
parent
ac8c6e31be
commit
02de2c652d
@ -1,7 +1,7 @@
|
|||||||
.icon-mail {
|
.icon-radio {
|
||||||
background-image: url(./../img/radio-trans.svg);
|
background-image: url(./../img/radio-trans.svg);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.theme--dark .icon-mail {
|
body.theme--dark .icon-radio {
|
||||||
background-image: url(./../img/radio.svg);
|
background-image: url(./../img/radio.svg);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ namespace OCA\Radio\Dashboard;
|
|||||||
|
|
||||||
use OCP\Dashboard\IWidget;
|
use OCP\Dashboard\IWidget;
|
||||||
use OCP\IL10N;
|
use OCP\IL10N;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
use OCP\Util;
|
||||||
|
|
||||||
use OCA\Radio\AppInfo\Application;
|
use OCA\Radio\AppInfo\Application;
|
||||||
|
|
||||||
@ -22,14 +24,14 @@ class RadioWidget implements IWidget {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
return 'radio';
|
return Application::APP_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function getTitle(): string {
|
public function getTitle(): string {
|
||||||
return $this->l10n->t('Favorite Radio stations');
|
return $this->l10n->t('Radio stations');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,14 +52,15 @@ class RadioWidget implements IWidget {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function getUrl(): ?string {
|
public function getUrl(): ?string {
|
||||||
return \OC::$server->getURLGenerator()->linkToRoute('settings.PersonalSettings.index', ['section' => 'connected-accounts']);
|
return \OC::$server->getURLGenerator()->linkToRoute('radio.page.index');
|
||||||
|
// return $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('radio.page.index'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function load(): void {
|
public function load(): void {
|
||||||
\OC_Util::addScript(Application::APP_ID, Application::APP_ID . '-dashboard');
|
Util::addScript(Application::APP_ID, 'dashboard');
|
||||||
\OC_Util::addStyle(Application::APP_ID, 'dashboard');
|
Util::addStyle(Application::APP_ID, 'dashboard');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
61
package-lock.json
generated
61
package-lock.json
generated
@ -2568,6 +2568,47 @@
|
|||||||
"node-gettext": "^3.0.0"
|
"node-gettext": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@nextcloud/moment": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nextcloud/moment/-/moment-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-lh7Xn9Ver12pLfE0rpjxE6x/ipscAV+7fw1u+7TJak1QR1T1UDRMZ9dA7z77W8mZH2C3yveTh/VEHZIflKBrng==",
|
||||||
|
"requires": {
|
||||||
|
"@nextcloud/l10n": "1.2.0",
|
||||||
|
"core-js": "3.6.4",
|
||||||
|
"jed": "^1.1.1",
|
||||||
|
"moment": "2.24.0",
|
||||||
|
"node-gettext": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nextcloud/l10n": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-aPsVAewCYMNe2h0yse3Fj7LofvnvFPimojw24K47ip1+I1gawMIsQL+BYAnN8wzlcbsDTEc7I1FxtOh+8dHHIA==",
|
||||||
|
"requires": {
|
||||||
|
"core-js": "^3.6.4",
|
||||||
|
"node-gettext": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"node-gettext": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-gettext/-/node-gettext-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-/VRYibXmVoN6tnSAY2JWhNRhWYJ8Cd844jrZU/DwLVoI4vBI6ceYbd8i42sYZ9uOgDH3S7vslIKOWV/ZrT2YBA==",
|
||||||
|
"requires": {
|
||||||
|
"lodash.get": "^4.4.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-gettext": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-gettext/-/node-gettext-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-vsHImHl+Py0vB7M2UXcFEJ5NJ3950gcja45YclBFtYxYeZiqdfQdcu+G9s4L7jpRFSh/J/7VoS3upR4JM1nS+g==",
|
||||||
|
"requires": {
|
||||||
|
"lodash.get": "^4.4.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@nextcloud/router": {
|
"@nextcloud/router": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-1.2.0.tgz",
|
||||||
@ -2630,6 +2671,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@nextcloud/vue-dashboard": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nextcloud/vue-dashboard/-/vue-dashboard-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-QKOf0qm4UYobuC3djLYwICSuj29H6xnm24IHetc0AMsrfhwPNN1/CC5IWEl1uKCCvwI0NA02HXCVFLtUErlgyg==",
|
||||||
|
"requires": {
|
||||||
|
"@nextcloud/vue": "^2.3.0",
|
||||||
|
"core-js": "^3.6.4",
|
||||||
|
"vue": "^2.6.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@nextcloud/webpack-vue-config": {
|
"@nextcloud/webpack-vue-config": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@nextcloud/webpack-vue-config/-/webpack-vue-config-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@nextcloud/webpack-vue-config/-/webpack-vue-config-1.1.0.tgz",
|
||||||
@ -7179,6 +7230,11 @@
|
|||||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"jed": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jed/-/jed-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-elSbvZ/+FYWwzQoZHiAwVb7ldLQ="
|
||||||
|
},
|
||||||
"js-base64": {
|
"js-base64": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.2.tgz",
|
||||||
@ -7908,6 +7964,11 @@
|
|||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
||||||
|
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
|
||||||
|
},
|
||||||
"move-concurrently": {
|
"move-concurrently": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||||
|
@ -33,8 +33,10 @@
|
|||||||
"@nextcloud/axios": "^1.4.0",
|
"@nextcloud/axios": "^1.4.0",
|
||||||
"@nextcloud/dialogs": "^3.0.0",
|
"@nextcloud/dialogs": "^3.0.0",
|
||||||
"@nextcloud/l10n": "^1.4.1",
|
"@nextcloud/l10n": "^1.4.1",
|
||||||
|
"@nextcloud/moment": "^1.1.1",
|
||||||
"@nextcloud/router": "^1.2.0",
|
"@nextcloud/router": "^1.2.0",
|
||||||
"@nextcloud/vue": "^2.7.0",
|
"@nextcloud/vue": "^2.7.0",
|
||||||
|
"@nextcloud/vue-dashboard": "^1.0.1",
|
||||||
"howler": "^2.2.1",
|
"howler": "^2.2.1",
|
||||||
"music-metadata": "^7.4.1",
|
"music-metadata": "^7.4.1",
|
||||||
"vue": "^2.6.12",
|
"vue": "^2.6.12",
|
||||||
|
245
src/components/Dashboard.vue
Normal file
245
src/components/Dashboard.vue
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
<template>
|
||||||
|
<DashboardWidget :items="items"
|
||||||
|
:show-more-url="showMoreUrl"
|
||||||
|
:show-more-text="title"
|
||||||
|
:loading="state === 'loading'">
|
||||||
|
<template #empty-content>
|
||||||
|
<EmptyContent
|
||||||
|
v-if="emptyContentMessage"
|
||||||
|
:icon="emptyContentIcon">
|
||||||
|
<template #desc>
|
||||||
|
{{ emptyContentMessage }}
|
||||||
|
<div v-if="state === 'no-token' || state === 'error'" class="connect-button">
|
||||||
|
<a class="button" :href="settingsUrl">
|
||||||
|
{{ t('integration_twitter', 'Connect to Twitter') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</EmptyContent>
|
||||||
|
</template>
|
||||||
|
</DashboardWidget>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from '@nextcloud/axios'
|
||||||
|
import { generateUrl, imagePath } from '@nextcloud/router'
|
||||||
|
import { showError } from '@nextcloud/dialogs'
|
||||||
|
import moment from '@nextcloud/moment'
|
||||||
|
import { DashboardWidget } from '@nextcloud/vue-dashboard'
|
||||||
|
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Dashboard',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
DashboardWidget, EmptyContent,
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
notifications: [],
|
||||||
|
showMoreUrl: 'https://twitter.com/notifications',
|
||||||
|
// lastDate could be computed but we want to keep the value when first notification is removed
|
||||||
|
// to avoid getting it again on next request
|
||||||
|
lastDate: null,
|
||||||
|
loop: null,
|
||||||
|
state: 'loading',
|
||||||
|
settingsUrl: generateUrl('/settings/user/connected-accounts#twitter_prefs'),
|
||||||
|
darkThemeColor: OCA.Accessibility.theme === 'dark' ? 'ffffff' : '000000',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
items() {
|
||||||
|
// get rid of follow request counts
|
||||||
|
let items = this.notifications.filter((n) => {
|
||||||
|
return (!['follow_request'].includes(n.type))
|
||||||
|
})
|
||||||
|
|
||||||
|
// if we have follow requests, show them in first
|
||||||
|
if (this.followRequestItem && this.followRequestItem.number > 0) {
|
||||||
|
items.unshift(this.followRequestItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
// then filter out unnecessary private messages
|
||||||
|
const privMsgAuthorIds = []
|
||||||
|
items = items.filter((n) => {
|
||||||
|
if (n.type !== 'message') {
|
||||||
|
return true
|
||||||
|
} else if (privMsgAuthorIds.includes(n.sender_screen_name)) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
privMsgAuthorIds.push(n.sender_screen_name)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return items.map((n) => {
|
||||||
|
return {
|
||||||
|
id: n.id,
|
||||||
|
targetUrl: this.getNotificationTarget(n),
|
||||||
|
avatarUrl: this.getUserAvatarUrl(n),
|
||||||
|
avatarUsername: this.getAvatarText(n),
|
||||||
|
overlayIconUrl: this.getNotificationTypeImage(n),
|
||||||
|
mainText: this.getMainText(n),
|
||||||
|
subText: this.getSubline(n),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
followRequestItem() {
|
||||||
|
// find the last follow request notif
|
||||||
|
return this.notifications.find((n) => {
|
||||||
|
return n.type === 'follow_request'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
lastMoment() {
|
||||||
|
return moment(this.lastDate)
|
||||||
|
},
|
||||||
|
emptyContentMessage() {
|
||||||
|
if (this.state === 'no-token') {
|
||||||
|
return t('radio', 'No Twitter account connected')
|
||||||
|
} else if (this.state === 'error') {
|
||||||
|
return t('radio', 'Error connecting to Twitter')
|
||||||
|
} else if (this.state === 'ok') {
|
||||||
|
return t('radio', 'No Twitter notifications!')
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
emptyContentIcon() {
|
||||||
|
if (this.state === 'no-token') {
|
||||||
|
return 'icon-radio'
|
||||||
|
} else if (this.state === 'error') {
|
||||||
|
return 'icon-close'
|
||||||
|
} else if (this.state === 'ok') {
|
||||||
|
return 'icon-checkmark'
|
||||||
|
}
|
||||||
|
return 'icon-checkmark'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeMount() {
|
||||||
|
this.fetchNotifications()
|
||||||
|
this.loop = setInterval(() => this.fetchNotifications(), 120000)
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
fetchNotifications() {
|
||||||
|
const req = {}
|
||||||
|
if (this.lastDate) {
|
||||||
|
req.params = {
|
||||||
|
since: this.lastDate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
axios.get(generateUrl('/apps/radio/favorites'), req).then((response) => {
|
||||||
|
this.processNotifications(response.data)
|
||||||
|
this.state = 'ok'
|
||||||
|
}).catch((error) => {
|
||||||
|
clearInterval(this.loop)
|
||||||
|
if (error.response && error.response.status === 400) {
|
||||||
|
this.state = 'no-token'
|
||||||
|
} else if (error.response && error.response.status === 401) {
|
||||||
|
showError(t('integration_twitter', 'Failed to get Twitter notifications'))
|
||||||
|
this.state = 'error'
|
||||||
|
} else {
|
||||||
|
// there was an error in notif processing
|
||||||
|
console.debug(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
processNotifications(newNotifications) {
|
||||||
|
if (this.lastDate) {
|
||||||
|
// just add those which are more recent than our most recent one
|
||||||
|
let i = 0
|
||||||
|
while (i < newNotifications.length && this.lastDate < newNotifications[i].timestamp) {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
const toAdd = this.filter(newNotifications.slice(0, i))
|
||||||
|
this.notifications = toAdd.concat(this.notifications)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// first time we don't check the date
|
||||||
|
this.notifications = this.filter(newNotifications)
|
||||||
|
}
|
||||||
|
// update lastDate manually (explained in data)
|
||||||
|
const nbNotif = this.notifications.length
|
||||||
|
this.lastDate = (nbNotif > 0) ? this.notifications[0].timestamp : null
|
||||||
|
},
|
||||||
|
filter(notifications) {
|
||||||
|
return notifications
|
||||||
|
},
|
||||||
|
getUserAvatarUrl(n) {
|
||||||
|
return (n.profile_image_url_https && n.sender_id_str)
|
||||||
|
? generateUrl('/apps/integration_twitter/avatar?') + encodeURIComponent('userId') + '=' + encodeURIComponent(n.sender_id_str)
|
||||||
|
: n.type === 'follow_request'
|
||||||
|
? imagePath('integration_twitter', 'twitter.png')
|
||||||
|
: ''
|
||||||
|
},
|
||||||
|
getAvatarText(n) {
|
||||||
|
if (['follow_request'].includes(n.type)) {
|
||||||
|
return '!'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
getNotificationTarget(n) {
|
||||||
|
if (['retweet', 'mention'].includes(n.type)) {
|
||||||
|
return 'https://twitter.com/' + n.sender_screen_name + '/status/' + n.id_str
|
||||||
|
} else if (['message'].includes(n.type)) {
|
||||||
|
return 'https://twitter.com/messages'
|
||||||
|
} else if (['follow_request'].includes(n.type)) {
|
||||||
|
return 'https://twitter.com/follower_requests'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
getMainText(n) {
|
||||||
|
if (['follow_request'].includes(n.type)) {
|
||||||
|
return t('integration_twitter', '{nb} follow requests', { nb: n.number })
|
||||||
|
} else if (['retweet', 'mention'].includes(n.type)) {
|
||||||
|
let text = n.text
|
||||||
|
while (text.startsWith('@')) {
|
||||||
|
text = text.replace(/^@[^\s]*\s?/, '')
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
return n.text
|
||||||
|
},
|
||||||
|
getSubline(n) {
|
||||||
|
if (['follow_request'].includes(n.type)) {
|
||||||
|
return t('integration_twitter', 'System')
|
||||||
|
}
|
||||||
|
return '@' + n.sender_screen_name
|
||||||
|
},
|
||||||
|
getNotificationTypeImage(n) {
|
||||||
|
if (n.type === 'mention') {
|
||||||
|
return generateUrl('/svg/integration_twitter/arobase?color=ffffff')
|
||||||
|
} else if (n.type === 'message') {
|
||||||
|
return generateUrl('/svg/integration_twitter/message?color=ffffff')
|
||||||
|
} else if (n.type === 'retweet') {
|
||||||
|
return generateUrl('/svg/integration_twitter/retweet?color=ffffff')
|
||||||
|
} else if (n.type === 'follow_request') {
|
||||||
|
return generateUrl('/svg/integration_twitter/follow_request?color=ffffff')
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
getFormattedDate(n) {
|
||||||
|
return moment(n.timestamp).format('LLL')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
::v-deep .connect-button {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -178,10 +178,15 @@ table {
|
|||||||
padding-right: 0px;
|
padding-right: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td.nameColumn {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
td.nameColumn .innernametext {
|
td.nameColumn .innernametext {
|
||||||
color: var(--color-main-text);
|
color: var(--color-main-text);
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
19
src/dashboard.js
Normal file
19
src/dashboard.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import { translate, translatePlural } from '@nextcloud/l10n'
|
||||||
|
import Dashboard from './components/Dashboard'
|
||||||
|
|
||||||
|
Vue.prototype.t = translate
|
||||||
|
Vue.prototype.n = translatePlural
|
||||||
|
Vue.prototype.OC = window.OC
|
||||||
|
Vue.prototype.OCA = window.OCA
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
OCA.Dashboard.register('radio', (el, { widget }) => {
|
||||||
|
const View = Vue.extend(Dashboard)
|
||||||
|
new View({
|
||||||
|
propsData: { title: widget.title },
|
||||||
|
}).$mount(el)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
@ -27,13 +27,16 @@ import { translate, translatePlural } from '@nextcloud/l10n'
|
|||||||
|
|
||||||
import App from './App'
|
import App from './App'
|
||||||
|
|
||||||
|
import './dashboard'
|
||||||
|
|
||||||
import VueBlurHash from 'vue-blurhash'
|
import VueBlurHash from 'vue-blurhash'
|
||||||
|
|
||||||
import 'vue-blurhash/dist/vue-blurhash.css'
|
import 'vue-blurhash/dist/vue-blurhash.css'
|
||||||
|
|
||||||
Vue.prototype.t = translate
|
Vue.prototype.t = translate
|
||||||
Vue.prototype.n = translatePlural
|
Vue.prototype.n = translatePlural
|
||||||
|
Vue.prototype.OC = window.OC
|
||||||
|
Vue.prototype.OCA = window.OCA
|
||||||
Vue.prototype.$apiUrl = 'https://de1.api.radio-browser.info'
|
Vue.prototype.$apiUrl = 'https://de1.api.radio-browser.info'
|
||||||
|
|
||||||
Vue.use(VueBlurHash)
|
Vue.use(VueBlurHash)
|
||||||
|
22
webpack.js
22
webpack.js
@ -1,23 +1,3 @@
|
|||||||
const { merge } = require('webpack-merge')
|
|
||||||
const webpackConfig = require('@nextcloud/webpack-vue-config')
|
const webpackConfig = require('@nextcloud/webpack-vue-config')
|
||||||
|
|
||||||
const config = {
|
module.exports = webpackConfig
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.(png|jpg|gif)$/,
|
|
||||||
loader: 'file-loader',
|
|
||||||
options: {
|
|
||||||
name: '[name].[ext]?[hash]',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const mergedConfigs = merge(config, webpackConfig)
|
|
||||||
|
|
||||||
// Remove duplicate rules by the `test` key
|
|
||||||
mergedConfigs.module.rules = mergedConfigs.module.rules.filter((v, i, a) => a.findIndex(t => (t.test.toString() === v.test.toString())) === i)
|
|
||||||
|
|
||||||
module.exports = mergedConfigs
|
|
||||||
|
Loading…
Reference in New Issue
Block a user