use snowpack
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"semi": 2
|
||||
},
|
||||
"plugins": [
|
||||
"html"
|
||||
]
|
||||
}
|
1
web/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
build/
|
489
web/List.vue
|
@ -1,489 +0,0 @@
|
|||
<template>
|
||||
<div id="list">
|
||||
<div id="channelSelector">
|
||||
<router-link v-for="channel in channels" :key="channel.shortname"
|
||||
:to="{ name: 'List', params: { channel: channel.shortname }}"
|
||||
:style="{borderColor:channel.primary_color}">
|
||||
<img :src="require('./icons/'+icon(channel.shortname)).default"
|
||||
:alt="channel.stationname" :title="channel.stationname"
|
||||
:class="channel.has_data?[]:['noData']">
|
||||
|
||||
</router-link>
|
||||
<!--
|
||||
<audio controls>
|
||||
<source :src="channel.streamurl +';'" type="audio/mpeg">
|
||||
</audio>
|
||||
-->
|
||||
</div>
|
||||
<header v-if="channelData"
|
||||
:style="{backgroundColor:channelData.primary_color,color:channelData.secondary_color}">
|
||||
<h2 v-if="channelData">{{channelData.stationname}}</h2>
|
||||
<div role="button" tabindex="0" v-on:click="toogleVisibility" v-on:keyup.enter="toogleVisibility">
|
||||
Meistgespielte Lieder {{formatDate()}}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 560" :class="showDate?[]:['disabled']">
|
||||
<path d="M480 344.181L268.869 131.889c-15.756-15.859-41.3-15.859-57.054 0-15.754 15.857-15.754 41.57 0 57.431l237.632 238.937c8.395 8.451 19.562 12.254 30.553 11.698 10.993.556 22.159-3.247 30.555-11.698L748.186 189.32c15.756-15.86 15.756-41.571 0-57.431s-41.299-15.859-57.051 0L480 344.181z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</header>
|
||||
<transition name="expand">
|
||||
<div id="date" class="customRow" v-if="showDate">
|
||||
<div>
|
||||
<datepicker :language="de" v-model="date" :mondayFirst="true" :inline="true"
|
||||
:highlighted="highlighted"></datepicker>
|
||||
|
||||
<div v-if="showMore" v-on:click="getMany" class="getMany">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 8 8">
|
||||
<path d="M3 0v3h-2l3 3 3-3h-2v-3h-2zm-3 7v1h8v-1h-8z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="day" value="day" v-model="dateType">
|
||||
<label class="label-inline" for="day">Tag</label>
|
||||
<br>
|
||||
<input type="radio" id="week" value="week" v-model="dateType">
|
||||
<label class="label-inline" for="week">Woche</label>
|
||||
<br>
|
||||
<input type="radio" id="month" value="month" v-model="dateType">
|
||||
<label class="label-inline" for="month">Monat</label>
|
||||
<br>
|
||||
<input type="radio" id="alltime" value="alltime" v-model="dateType">
|
||||
<label class="label-inline" for="alltime">Gesamter Zeitraum</label>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<main>
|
||||
<div id="httpError" v-if="httpError" class="message">
|
||||
<strong>Beim Laden ist ein Fehler aufgetreten:</strong> {{httpError.message}}
|
||||
</div>
|
||||
<div id="noData" class="message" v-if="(!channelData||!channelData.has_data)&&!httpError">
|
||||
<strong>Keine Daten!</strong> Leider gibt es für diesen Sender noch keine Daten.
|
||||
</div>
|
||||
<table>
|
||||
<template v-for="song in popular">
|
||||
<tr v-on:click="toogleDetails($event,song.song.id)" class="clickable">
|
||||
<td>
|
||||
<img v-if="song.song.image_small" :src="song.song.image_small">
|
||||
<div v-else class="imgPlaceholder"></div>
|
||||
</td>
|
||||
<td>
|
||||
{{song.song.title}}
|
||||
<router-link :to="{ name: 'DetailView',params:{channel:channel, songId:song.song.id} }"
|
||||
replace style="display: none;">{{song.song.title}}
|
||||
</router-link>
|
||||
</td>
|
||||
<td>{{song.song.artist}}</td>
|
||||
<td>{{song.count}}</td>
|
||||
</tr>
|
||||
<tr v-if="parseInt($route.params.songId) === song.song.id">
|
||||
<td colspan="4" class="detailWrapper">
|
||||
<router-view :songs="songs"
|
||||
:color="{backgroundColor:channelData.primary_color,color:channelData.secondary_color}"
|
||||
:momentDate="momentDate" :dateType="dateType">
|
||||
<!-- here the ItemModal component will be rendered -->
|
||||
</router-view>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</table>
|
||||
<div id="loadMore" role="button" tabindex="0" v-on:click="getAdditional" v-on:keyup.enter="getAdditional"
|
||||
v-if="showMore &&channelData&&channelData.has_data">
|
||||
Mehr anzeigen
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<info v-if="channelData"
|
||||
:color="{backgroundColor:channelData.primary_color,color:channelData.secondary_color}"></info>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import moment from "moment";
|
||||
import "moment/locale/de-at";
|
||||
import Datepicker from 'vuejs-datepicker';
|
||||
import {de} from 'vuejs-datepicker/dist/locale';
|
||||
import Info from "./Info.vue";
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
axios.defaults.headers.common['X-Requested-With'] = "XMLHttpRequest";
|
||||
}
|
||||
|
||||
const baseURL = (process.env.NODE_ENV === "production") ? "/api/" : "http://127.0.0.1:5000/api/";
|
||||
|
||||
export default {
|
||||
components: {Datepicker, Info},
|
||||
name: 'list',
|
||||
data() {
|
||||
return {
|
||||
channels: [],
|
||||
songs: [],
|
||||
offset: 0,
|
||||
showMore: true,
|
||||
httpError: false,
|
||||
date: new Date(),
|
||||
dateType: "week",
|
||||
highlighted: {
|
||||
from: new Date(),
|
||||
to: new Date(),
|
||||
},
|
||||
showDate: false,
|
||||
de: de
|
||||
};
|
||||
},
|
||||
props: ["channel"],
|
||||
computed: {
|
||||
channelData: function() {
|
||||
return this.channels[this.channel];
|
||||
},
|
||||
momentDate: function() {
|
||||
return moment(this.date);
|
||||
},
|
||||
popular: function() {
|
||||
function compare(a, b) {
|
||||
if (a.order < b.order)
|
||||
return -1;
|
||||
if (a.order > b.order)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
let songArray = Object.values(this.songs);
|
||||
return songArray.sort(compare);
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
getChannels: function() {
|
||||
axios.get(baseURL, {
|
||||
params: {}
|
||||
})
|
||||
.then(response => {
|
||||
const all = response.data["all"];
|
||||
this.channels = response.data;
|
||||
delete response.data["all"];
|
||||
response.data["all"] = all;
|
||||
document.title = "Radiostats - " + this.channels[this.channel].stationname;
|
||||
this.getPopular();
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
this.httpError = error;
|
||||
});
|
||||
},
|
||||
getPopular: function() {
|
||||
this.offset = 0;
|
||||
this.showMore = true;
|
||||
this.httpError = false;
|
||||
|
||||
if (!this.channelData || !this.channelData.has_data) {
|
||||
this.songs = [];
|
||||
return false;
|
||||
}
|
||||
axios.get(baseURL + this.channel, {
|
||||
params: {
|
||||
date: this.momentDate.format("YYYY-MM-DD"),
|
||||
dateType: this.dateType
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.offset += 10;
|
||||
this.songs = response.data;
|
||||
if (Object.keys(response.data).length < 10) {
|
||||
this.showMore = false;
|
||||
}
|
||||
let urlsongID = parseInt(this.$route.params.songId);
|
||||
if (urlsongID && typeof this.songs[urlsongID] === "undefined") {
|
||||
axios.get(baseURL + this.channel + "/details/" + urlsongID, {
|
||||
params: {
|
||||
date: this.momentDate.format("YYYY-MM-DD"),
|
||||
dateType: this.dateType
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.$set(this.songs, urlsongID, response.data);
|
||||
});
|
||||
|
||||
console.log("Song not in view: " + urlsongID);
|
||||
}
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
this.httpError = error;
|
||||
});
|
||||
},
|
||||
getAdditional: function(many) {
|
||||
const loadNumber = (many === true) ? 1000 : 10;
|
||||
axios.get(baseURL + this.channel, {
|
||||
params: {
|
||||
offset: this.offset,
|
||||
date: this.momentDate.format("YYYY-MM-DD"),
|
||||
dateType: this.dateType,
|
||||
highlimit: many === true
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.offset += loadNumber;
|
||||
this.songs = Object.assign({}, this.songs, response.data);
|
||||
if (Object.keys(response.data).length < loadNumber) {
|
||||
this.showMore = false;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.httpError = error;
|
||||
});
|
||||
|
||||
},
|
||||
getMany: function() {
|
||||
this.getAdditional(true)
|
||||
},
|
||||
icon: function(id) {
|
||||
if (id === "fm4" || id === "oe3" || id === "kht") {
|
||||
return id + ".svg";
|
||||
} else {
|
||||
return id + ".png";
|
||||
}
|
||||
},
|
||||
updateSelection: function() {
|
||||
let from, to;
|
||||
let date = moment(this.date);
|
||||
if (this.dateType !== "alltime") {
|
||||
from = moment(date);
|
||||
to = moment(date);
|
||||
from.startOf(this.dateType);
|
||||
to.endOf(this.dateType);
|
||||
} else {
|
||||
from = moment("2000-01-01");
|
||||
to = moment("2025-01-01");
|
||||
}
|
||||
this.highlighted = {
|
||||
"from": from.toDate(),
|
||||
"to": to.toDate(),
|
||||
};
|
||||
},
|
||||
formatDate: function() {
|
||||
switch (this.dateType) {
|
||||
case "day":
|
||||
return "am " + this.momentDate.format("D. MMMM");
|
||||
case "week":
|
||||
return "in der Woche des " + this.momentDate.format("D. MMMM");
|
||||
case "month":
|
||||
return "im " + this.momentDate.format("MMMM YYYY");
|
||||
case "alltime":
|
||||
return "im gesamten Zeitraum";
|
||||
}
|
||||
},
|
||||
toogleVisibility: function() {
|
||||
this.showDate = !this.showDate;
|
||||
},
|
||||
toogleDetails: function($event, songId) {
|
||||
if (this.$route.name !== "DetailView" || this.$route.params.songId !== songId) {
|
||||
this.$router.replace({name: 'DetailView', params: {channel: this.channel, songId: songId}});
|
||||
} else {
|
||||
this.$router.replace({name: 'List', params: {channel: this.channel}});
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
channel: function() {
|
||||
document.title = "Radiostats - " + this.channelData.stationname;
|
||||
this.getPopular();
|
||||
},
|
||||
'$route.name': function(id) {
|
||||
document.title = "Radiostats - " + this.channelData.stationname;
|
||||
},
|
||||
dateType: function() {
|
||||
this.updateSelection();
|
||||
this.getPopular();
|
||||
},
|
||||
date: function() {
|
||||
this.updateSelection();
|
||||
this.getPopular();
|
||||
}
|
||||
|
||||
},
|
||||
mounted: function() {
|
||||
this.getChannels();
|
||||
this.updateSelection();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "variables";
|
||||
@import "node_modules/milligram/src/Color";
|
||||
@import "node_modules/milligram/src/Utility";
|
||||
|
||||
body {
|
||||
background-color: #ffffff;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='5' height='5'%3E%3Crect width='2.5' height='5' fill='white' /%3E%3Crect x='2.5' y='0' width='2.5' height='5' fill='%23f5f5f5' /%3E%3C/svg%3E");
|
||||
font-family: -apple-system, "Helvetica Neue Light", "HelveticaNeue", "Helvetica Neue", "Roboto", "Liberation Sans", Arial, sans-serif;
|
||||
color: #212121;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 2.5rem;
|
||||
transition: color .2s, background-color .2s;
|
||||
|
||||
h2, div {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div {
|
||||
cursor: pointer;
|
||||
font-size: 3.0rem;
|
||||
line-height: 1.3;
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
width: 32px;
|
||||
height: 18.66px;
|
||||
transition: transform .3s;
|
||||
|
||||
&.disabled {
|
||||
transform: rotate(-90deg);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
background-color: white;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
#channelSelector {
|
||||
margin: 16px 0;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
@media screen and (max-width: 500px) {
|
||||
flex-wrap: wrap;
|
||||
a {
|
||||
margin: 10px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
/*border-bottom: solid 5px;*/
|
||||
|
||||
&.router-link-active {
|
||||
border-bottom: solid 5px;
|
||||
}
|
||||
|
||||
display: block;
|
||||
|
||||
img {
|
||||
margin-bottom: 5px;
|
||||
display: block;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
transition: filter .2s;
|
||||
|
||||
&.noData:not(:hover) {
|
||||
filter: grayscale(0.7);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 0;
|
||||
|
||||
img, .imgPlaceholder {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background-color: #eee;
|
||||
display: block;
|
||||
}
|
||||
|
||||
tr.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
#loadMore {
|
||||
padding: 10px 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: background-color .2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
#httpError {
|
||||
background-color: #f0ad4e;
|
||||
}
|
||||
|
||||
#date {
|
||||
.vdp-datepicker__calendar {
|
||||
margin-right: 0;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
> div {
|
||||
.vdp-datepicker {
|
||||
margin: 0 auto;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.customRow {
|
||||
background-color: #eee;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
> div {
|
||||
width: 50%;
|
||||
padding: 0 15px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
flex-direction: column;
|
||||
> div {
|
||||
width: 100%;
|
||||
padding: 15px 0 15px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.expand-enter-active, .expand-leave-active {
|
||||
transition: max-height .3s;
|
||||
|
||||
max-height: 307px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.expand-enter, .expand-leave-to {
|
||||
|
||||
max-height: 0;
|
||||
}
|
||||
|
||||
.getMany {
|
||||
max-width: 300px;
|
||||
margin-left: auto;
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
margin: 10px auto;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
|
||||
</div>
|
||||
<% if (htmlWebpackPlugin.options.devServer) { %>
|
||||
<script src="<%= htmlWebpackPlugin.options.devServer %>/webpack-dev-server.js" type="text/javascript"></script>
|
||||
<% } %>
|
||||
</body>
|
||||
</html>
|
|
@ -5,9 +5,8 @@
|
|||
"author": "Lukas Winkler <l.winkler23@mailbox.org>",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "cross-env NODE_ENV=development webpack-dev-server --content-base dist/ --open --hot",
|
||||
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules",
|
||||
"json": "cross-env NODE_ENV=production webpack --profile --json > stats.json"
|
||||
"serve": "snowpack dev",
|
||||
"build": "snowpack build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/browser": "^5.5.0",
|
||||
|
@ -24,29 +23,13 @@
|
|||
"vuejs-datepicker": "^1.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.0.0-beta.40",
|
||||
"@babel/polyfill": "^7.0.0-beta.40",
|
||||
"@babel/preset-env": "^7.0.0-beta.40",
|
||||
"@sentry/webpack-plugin": "^1.6.1",
|
||||
"autoprefixer": "^9.0.1",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-loader": "^8.0.0-beta.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"compression-webpack-plugin": "^3.0.0",
|
||||
"cross-env": "^7.0.0",
|
||||
"css-loader": "^3.0.0",
|
||||
"eslint": "^6.0.1",
|
||||
"eslint-loader": "^3.0.3",
|
||||
"eslint-plugin-html": "^6.0.0",
|
||||
"file-loader": "^5.0.2",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"image-webpack-loader": "^6.0.0",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"@morgul/snowpack-plugin-vue2": "^0.4.0",
|
||||
"@snowpack/plugin-sass": "^1.4.0",
|
||||
"node-sass": "^4.7.2",
|
||||
"postcss-loader": "3",
|
||||
"sass-loader": "^8.0.2",
|
||||
"vue-loader": "^15.2.4",
|
||||
"vue-template-compiler": "^2.5.13",
|
||||
"snowpack": "^3.3.7",
|
||||
"snowpack-plugin-replace": "^1.0.4",
|
||||
"webpack": "^4.12.0",
|
||||
"webpack-cli": "^3.0.8",
|
||||
"webpack-dev-server": "^3.1.4",
|
||||
|
|
12
web/public/index.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Radiostats</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/dist/index.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,2 +0,0 @@
|
|||
defaults.org = sentry
|
||||
defaults.project = radiostats-frontend
|
49
web/snowpack.config.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
const httpProxy = require('http-proxy');
|
||||
const proxy = httpProxy.createProxyServer({
|
||||
target: 'http://localhost:5000',
|
||||
timeout: 30 * 1000
|
||||
});
|
||||
|
||||
/** @type {import("snowpack").SnowpackUserConfig } */
|
||||
module.exports = {
|
||||
mount: {
|
||||
public: {url: '/', static: true},
|
||||
"src/icons": {url: "/icons/", static: true},
|
||||
src: {url: '/dist'},
|
||||
},
|
||||
routes: [
|
||||
/* Enable an SPA Fallback in development: */
|
||||
{
|
||||
src: '/api/.*',
|
||||
dest: (req, res) => {
|
||||
proxy.web(req, res, e => console.log(e));
|
||||
},
|
||||
},
|
||||
{"match": "routes", "src": ".*", "dest": "/index.html"},
|
||||
],
|
||||
plugins: [
|
||||
"./workaroundPlugin",
|
||||
"@morgul/snowpack-plugin-vue2",
|
||||
'@snowpack/plugin-sass',
|
||||
[
|
||||
'snowpack-plugin-replace',
|
||||
{
|
||||
list: [
|
||||
{
|
||||
from: 'process.env.NODE_ENV',
|
||||
to: JSON.stringify('production')
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
],
|
||||
optimize: {
|
||||
/* Example: Bundle your final build: */
|
||||
bundle: true,
|
||||
minify: true,
|
||||
target: "es2018"
|
||||
},
|
||||
devOptions: {
|
||||
open: "none"
|
||||
}
|
||||
}
|
|
@ -24,24 +24,23 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'app',
|
||||
props: ["language"],
|
||||
computed: {
|
||||
isIE() {
|
||||
let ua = window.navigator.userAgent;
|
||||
return /MSIE|Trident/.test(ua);
|
||||
}
|
||||
// import "./node_modules/normalize.css/normalize.css"
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
props: ["language"],
|
||||
computed: {
|
||||
isIE() {
|
||||
let ua = window.navigator.userAgent;
|
||||
return /MSIE|Trident/.test(ua);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" src="./node_modules/normalize.css/normalize.css">
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
@import "variables";
|
||||
@import "node_modules/milligram/src/milligram";
|
||||
@import "./variables";
|
||||
@import "./node_modules/milligram/src/milligram";
|
||||
|
||||
.iewarning {
|
||||
margin: 2rem;
|
|
@ -33,11 +33,11 @@
|
|||
import moment from "moment";
|
||||
import "moment/locale/de-at";
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
if (import.meta.env.NODE_ENV === "production") {
|
||||
axios.defaults.headers.common['X-Requested-With'] = "XMLHttpRequest";
|
||||
}
|
||||
|
||||
const baseURL = (process.env.NODE_ENV === "production") ? "/api/" : "http://127.0.0.1:5000/api/";
|
||||
const baseURL = (import.meta.env.NODE_ENV === "production") ? "/api/" : "http://127.0.0.1:5000/api/";
|
||||
|
||||
export default {
|
||||
name: "detailview",
|
||||
|
@ -89,7 +89,7 @@
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "variables";
|
||||
@import "./variables";
|
||||
|
||||
.detailWrapper {
|
||||
padding: 0;
|
493
web/src/List.vue
Normal file
|
@ -0,0 +1,493 @@
|
|||
<template>
|
||||
<div id="list">
|
||||
<div id="channelSelector">
|
||||
<router-link v-for="channel in channels" :key="channel.shortname"
|
||||
:to="{ name: 'List', params: { channel: channel.shortname }}"
|
||||
:style="{borderColor:channel.primary_color}">
|
||||
<img :src="icon(channel.shortname)"
|
||||
:alt="channel.stationname" :title="channel.stationname"
|
||||
:class="channel.has_data?[]:['noData']">
|
||||
|
||||
</router-link>
|
||||
<!--
|
||||
<audio controls>
|
||||
<source :src="channel.streamurl +';'" type="audio/mpeg">
|
||||
</audio>
|
||||
-->
|
||||
</div>
|
||||
<header v-if="channelData"
|
||||
:style="{backgroundColor:channelData.primary_color,color:channelData.secondary_color}">
|
||||
<h2 v-if="channelData">{{ channelData.stationname }}</h2>
|
||||
<div role="button" tabindex="0" v-on:click="toogleVisibility" v-on:keyup.enter="toogleVisibility">
|
||||
Meistgespielte Lieder {{ formatDate() }}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 560" :class="showDate?[]:['disabled']">
|
||||
<path d="M480 344.181L268.869 131.889c-15.756-15.859-41.3-15.859-57.054 0-15.754 15.857-15.754 41.57 0 57.431l237.632 238.937c8.395 8.451 19.562 12.254 30.553 11.698 10.993.556 22.159-3.247 30.555-11.698L748.186 189.32c15.756-15.86 15.756-41.571 0-57.431s-41.299-15.859-57.051 0L480 344.181z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</header>
|
||||
<transition name="expand">
|
||||
<div id="date" class="customRow" v-if="showDate">
|
||||
<div>
|
||||
<datepicker :language="de" v-model="date" :mondayFirst="true" :inline="true"
|
||||
:highlighted="highlighted"></datepicker>
|
||||
|
||||
<div v-if="showMore" v-on:click="getMany" class="getMany">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 8 8">
|
||||
<path d="M3 0v3h-2l3 3 3-3h-2v-3h-2zm-3 7v1h8v-1h-8z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="day" value="day" v-model="dateType">
|
||||
<label class="label-inline" for="day">Tag</label>
|
||||
<br>
|
||||
<input type="radio" id="week" value="week" v-model="dateType">
|
||||
<label class="label-inline" for="week">Woche</label>
|
||||
<br>
|
||||
<input type="radio" id="month" value="month" v-model="dateType">
|
||||
<label class="label-inline" for="month">Monat</label>
|
||||
<br>
|
||||
<input type="radio" id="alltime" value="alltime" v-model="dateType">
|
||||
<label class="label-inline" for="alltime">Gesamter Zeitraum</label>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<main>
|
||||
<div id="httpError" v-if="httpError" class="message">
|
||||
<strong>Beim Laden ist ein Fehler aufgetreten:</strong> {{ httpError.message }}
|
||||
</div>
|
||||
<div id="noData" class="message" v-if="(!channelData||!channelData.has_data)&&!httpError">
|
||||
<strong>Keine Daten!</strong> Leider gibt es für diesen Sender noch keine Daten.
|
||||
</div>
|
||||
<table>
|
||||
<template v-for="song in popular">
|
||||
<tr v-on:click="toogleDetails($event,song.song.id)" class="clickable">
|
||||
<td>
|
||||
<img v-if="song.song.image_small" :src="song.song.image_small">
|
||||
<div v-else class="imgPlaceholder"></div>
|
||||
</td>
|
||||
<td>
|
||||
{{ song.song.title }}
|
||||
<router-link :to="{ name: 'DetailView',params:{channel:channel, songId:song.song.id} }"
|
||||
replace style="display: none;">{{ song.song.title }}
|
||||
</router-link>
|
||||
</td>
|
||||
<td>{{ song.song.artist }}</td>
|
||||
<td>{{ song.count }}</td>
|
||||
</tr>
|
||||
<tr v-if="parseInt($route.params.songId) === song.song.id">
|
||||
<td colspan="4" class="detailWrapper">
|
||||
<router-view :songs="songs"
|
||||
:color="{backgroundColor:channelData.primary_color,color:channelData.secondary_color}"
|
||||
:momentDate="momentDate" :dateType="dateType">
|
||||
<!-- here the ItemModal component will be rendered -->
|
||||
</router-view>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</table>
|
||||
<div id="loadMore" role="button" tabindex="0" v-on:click="getAdditional" v-on:keyup.enter="getAdditional"
|
||||
v-if="showMore &&channelData&&channelData.has_data">
|
||||
Mehr anzeigen
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<info v-if="channelData"
|
||||
:color="{backgroundColor:channelData.primary_color,color:channelData.secondary_color}"></info>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import moment from "moment";
|
||||
import "moment/locale/de-at";
|
||||
import Datepicker from 'vuejs-datepicker';
|
||||
import {de} from 'vuejs-datepicker/dist/locale';
|
||||
import Info from "./Info.vue";
|
||||
import {icon} from "./utils";
|
||||
|
||||
if (import.meta.env.NODE_ENV === "production") {
|
||||
axios.defaults.headers.common['X-Requested-With'] = "XMLHttpRequest";
|
||||
}
|
||||
|
||||
const baseURL = "/api/";
|
||||
|
||||
export default {
|
||||
components: {Datepicker, Info},
|
||||
name: 'list',
|
||||
data() {
|
||||
return {
|
||||
channels: [],
|
||||
songs: [],
|
||||
offset: 0,
|
||||
showMore: true,
|
||||
httpError: false,
|
||||
date: new Date(),
|
||||
dateType: "week",
|
||||
highlighted: {
|
||||
from: new Date(),
|
||||
to: new Date(),
|
||||
},
|
||||
showDate: false,
|
||||
de: de
|
||||
};
|
||||
},
|
||||
props: ["channel"],
|
||||
computed: {
|
||||
channelData: function () {
|
||||
return this.channels[this.channel];
|
||||
},
|
||||
momentDate: function () {
|
||||
return moment(this.date);
|
||||
},
|
||||
popular: function () {
|
||||
function compare(a, b) {
|
||||
if (a.order < b.order)
|
||||
return -1;
|
||||
if (a.order > b.order)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
let songArray = Object.values(this.songs);
|
||||
return songArray.sort(compare);
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
getChannels: function () {
|
||||
axios.get(baseURL, {
|
||||
params: {}
|
||||
})
|
||||
.then(response => {
|
||||
const all = response.data["all"];
|
||||
this.channels = response.data;
|
||||
delete response.data["all"];
|
||||
response.data["all"] = all;
|
||||
document.title = "Radiostats - " + this.channels[this.channel].stationname;
|
||||
this.getPopular();
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
this.httpError = error;
|
||||
});
|
||||
},
|
||||
getPopular: function () {
|
||||
this.offset = 0;
|
||||
this.showMore = true;
|
||||
this.httpError = false;
|
||||
|
||||
if (!this.channelData || !this.channelData.has_data) {
|
||||
this.songs = [];
|
||||
return false;
|
||||
}
|
||||
axios.get(baseURL + this.channel, {
|
||||
params: {
|
||||
date: this.momentDate.format("YYYY-MM-DD"),
|
||||
dateType: this.dateType
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.offset += 10;
|
||||
this.songs = response.data;
|
||||
if (Object.keys(response.data).length < 10) {
|
||||
this.showMore = false;
|
||||
}
|
||||
let urlsongID = parseInt(this.$route.params.songId);
|
||||
if (urlsongID && typeof this.songs[urlsongID] === "undefined") {
|
||||
axios.get(baseURL + this.channel + "/details/" + urlsongID, {
|
||||
params: {
|
||||
date: this.momentDate.format("YYYY-MM-DD"),
|
||||
dateType: this.dateType
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.$set(this.songs, urlsongID, response.data);
|
||||
});
|
||||
|
||||
console.log("Song not in view: " + urlsongID);
|
||||
}
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
this.httpError = error;
|
||||
});
|
||||
},
|
||||
getAdditional: function (many) {
|
||||
const loadNumber = (many === true) ? 1000 : 10;
|
||||
axios.get(baseURL + this.channel, {
|
||||
params: {
|
||||
offset: this.offset,
|
||||
date: this.momentDate.format("YYYY-MM-DD"),
|
||||
dateType: this.dateType,
|
||||
highlimit: many === true
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.offset += loadNumber;
|
||||
this.songs = Object.assign({}, this.songs, response.data);
|
||||
if (Object.keys(response.data).length < loadNumber) {
|
||||
this.showMore = false;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.httpError = error;
|
||||
});
|
||||
|
||||
},
|
||||
getMany: function () {
|
||||
this.getAdditional(true)
|
||||
},
|
||||
icon(id) {
|
||||
return icon(id)
|
||||
},
|
||||
iconFile: function (id) {
|
||||
if (id === "fm4" || id === "oe3" || id === "kht") {
|
||||
return id + ".svg";
|
||||
} else {
|
||||
return id + ".png";
|
||||
}
|
||||
},
|
||||
updateSelection: function () {
|
||||
let from, to;
|
||||
let date = moment(this.date);
|
||||
if (this.dateType !== "alltime") {
|
||||
from = moment(date);
|
||||
to = moment(date);
|
||||
from.startOf(this.dateType);
|
||||
to.endOf(this.dateType);
|
||||
} else {
|
||||
from = moment("2000-01-01");
|
||||
to = moment("2025-01-01");
|
||||
}
|
||||
this.highlighted = {
|
||||
"from": from.toDate(),
|
||||
"to": to.toDate(),
|
||||
};
|
||||
},
|
||||
formatDate: function () {
|
||||
switch (this.dateType) {
|
||||
case "day":
|
||||
return "am " + this.momentDate.format("D. MMMM");
|
||||
case "week":
|
||||
return "in der Woche des " + this.momentDate.format("D. MMMM");
|
||||
case "month":
|
||||
return "im " + this.momentDate.format("MMMM YYYY");
|
||||
case "alltime":
|
||||
return "im gesamten Zeitraum";
|
||||
}
|
||||
},
|
||||
toogleVisibility: function () {
|
||||
this.showDate = !this.showDate;
|
||||
},
|
||||
toogleDetails: function ($event, songId) {
|
||||
if (this.$route.name !== "DetailView" || this.$route.params.songId !== songId) {
|
||||
this.$router.replace({name: 'DetailView', params: {channel: this.channel, songId: songId}});
|
||||
} else {
|
||||
this.$router.replace({name: 'List', params: {channel: this.channel}});
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
channel: function () {
|
||||
document.title = "Radiostats - " + this.channelData.stationname;
|
||||
this.getPopular();
|
||||
},
|
||||
'$route.name': function (id) {
|
||||
document.title = "Radiostats - " + this.channelData.stationname;
|
||||
},
|
||||
dateType: function () {
|
||||
this.updateSelection();
|
||||
this.getPopular();
|
||||
},
|
||||
date: function () {
|
||||
this.updateSelection();
|
||||
this.getPopular();
|
||||
}
|
||||
|
||||
},
|
||||
mounted: function () {
|
||||
this.getChannels();
|
||||
this.updateSelection();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./variables";
|
||||
@import "./node_modules/milligram/src/Color";
|
||||
@import "./node_modules/milligram/src/Utility";
|
||||
|
||||
body {
|
||||
background-color: #ffffff;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='5' height='5'%3E%3Crect width='2.5' height='5' fill='white' /%3E%3Crect x='2.5' y='0' width='2.5' height='5' fill='%23f5f5f5' /%3E%3C/svg%3E");
|
||||
font-family: -apple-system, "Helvetica Neue Light", "HelveticaNeue", "Helvetica Neue", "Roboto", "Liberation Sans", Arial, sans-serif;
|
||||
color: #212121;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 2.5rem;
|
||||
transition: color .2s, background-color .2s;
|
||||
|
||||
h2, div {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div {
|
||||
cursor: pointer;
|
||||
font-size: 3.0rem;
|
||||
line-height: 1.3;
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
width: 32px;
|
||||
height: 18.66px;
|
||||
transition: transform .3s;
|
||||
|
||||
&.disabled {
|
||||
transform: rotate(-90deg);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
background-color: white;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
#channelSelector {
|
||||
margin: 16px 0;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
@media screen and (max-width: 500px) {
|
||||
flex-wrap: wrap;
|
||||
a {
|
||||
margin: 10px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
/*border-bottom: solid 5px;*/
|
||||
|
||||
&.router-link-active {
|
||||
border-bottom: solid 5px;
|
||||
}
|
||||
|
||||
display: block;
|
||||
|
||||
img {
|
||||
margin-bottom: 5px;
|
||||
display: block;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
transition: filter .2s;
|
||||
|
||||
&.noData:not(:hover) {
|
||||
filter: grayscale(0.7);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 0;
|
||||
|
||||
img, .imgPlaceholder {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background-color: #eee;
|
||||
display: block;
|
||||
}
|
||||
|
||||
tr.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
#loadMore {
|
||||
padding: 10px 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: background-color .2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
#httpError {
|
||||
background-color: #f0ad4e;
|
||||
}
|
||||
|
||||
#date {
|
||||
.vdp-datepicker__calendar {
|
||||
margin-right: 0;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
> div {
|
||||
.vdp-datepicker {
|
||||
margin: 0 auto;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.customRow {
|
||||
background-color: #eee;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
> div {
|
||||
width: 50%;
|
||||
padding: 0 15px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
flex-direction: column;
|
||||
> div {
|
||||
width: 100%;
|
||||
padding: 15px 0 15px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.expand-enter-active, .expand-leave-active {
|
||||
transition: max-height .3s;
|
||||
|
||||
max-height: 307px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.expand-enter, .expand-leave-to {
|
||||
|
||||
max-height: 0;
|
||||
}
|
||||
|
||||
.getMany {
|
||||
max-width: 300px;
|
||||
margin-left: auto;
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
margin: 10px auto;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,16 +1,15 @@
|
|||
export default class MatomoTracker {
|
||||
init() {
|
||||
if (typeof _paq === 'undefined') { // should only occur with hot reloading
|
||||
let _paq = _paq || [];
|
||||
_paq.push(['disableCookies']);
|
||||
var _paq = window._paq = window._paq || []; _paq.push(['disableCookies']);
|
||||
_paq.push(['enableHeartBeatTimer']);
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
if (import.meta.env.NODE_ENV === "production") {
|
||||
_paq.push(["setDoNotTrack", true]);
|
||||
}
|
||||
(function() {
|
||||
let u = (process.env.NODE_ENV === "production") ? "https://matomo.lw1.at/" : "//localhost/piwik/";
|
||||
let u ="https://matomo.lw1.at/" ;
|
||||
_paq.push(['setTrackerUrl', u + 'piwik.php']);
|
||||
_paq.push(['setSiteId', (process.env.NODE_ENV === "production") ? 15 : 6]);
|
||||
_paq.push(['setSiteId', (import.meta.env.NODE_ENV === "production") ? 15 : 6]);
|
||||
let d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
|
||||
g.type = 'text/javascript';
|
||||
g.async = true;
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 149 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 1,015 B After Width: | Height: | Size: 1,015 B |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
@ -3,15 +3,6 @@ import VueHead from 'vue-head';
|
|||
import App from './App.vue';
|
||||
import router from './routes';
|
||||
import MatomoTracker from './MatomoTracker';
|
||||
import {init} from '@sentry/browser';
|
||||
import * as Integrations from '@sentry/integrations';
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
init({
|
||||
dsn: 'https://91af780499634f98a17afe160c6ace89@sentry.lw1.at/12',
|
||||
integrations: [new Integrations.Vue({Vue})],
|
||||
release: COMMIT_HASH
|
||||
});
|
||||
}
|
||||
|
||||
Vue.use(VueHead);
|
||||
let matomo = new MatomoTracker;
|
57
web/src/utils.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
import aas from "./icons/886.png"
|
||||
import all from "./icons/all.png"
|
||||
import ara from "./icons/ara.png"
|
||||
import bgl from "./icons/bgl.png"
|
||||
import eng from "./icons/eng.png"
|
||||
import fm4 from "./icons/fm4.svg"
|
||||
import kht from "./icons/kht.svg"
|
||||
import ktn from "./icons/ktn.png"
|
||||
import noe from "./icons/noe.png"
|
||||
import oe1 from "./icons/oe1.png"
|
||||
import oe3 from "./icons/oe3.svg"
|
||||
import ooe from "./icons/ooe.png"
|
||||
import sbg from "./icons/sbg.png"
|
||||
import stm from "./icons/stm.png"
|
||||
import tir from "./icons/tir.png"
|
||||
import vbg from "./icons/vbg.png"
|
||||
import wie from "./icons/wie.png"
|
||||
|
||||
|
||||
export function icon(id) {
|
||||
switch (id) {
|
||||
case "886":
|
||||
return aas
|
||||
case "all":
|
||||
return all
|
||||
case "ara":
|
||||
return ara
|
||||
case "bgl":
|
||||
return bgl
|
||||
case "eng":
|
||||
return eng
|
||||
case "fm4":
|
||||
return fm4
|
||||
case "kht":
|
||||
return kht
|
||||
case "ktn":
|
||||
return ktn
|
||||
case "noe":
|
||||
return noe
|
||||
case "oe1":
|
||||
return oe1
|
||||
case "oe3":
|
||||
return oe3
|
||||
case "ooe":
|
||||
return ooe
|
||||
case "sbg":
|
||||
return sbg
|
||||
case "stm":
|
||||
return stm
|
||||
case "tir":
|
||||
return tir
|
||||
case "vbg":
|
||||
return vbg
|
||||
case "wie":
|
||||
return wie
|
||||
}
|
||||
}
|
|
@ -2,3 +2,6 @@ $color-primary: #F57C00;
|
|||
$borderRadius: 5px;
|
||||
$imageheight: 150px;
|
||||
|
||||
.bla{
|
||||
color: green;
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
#!/bin/bash
|
||||
rsync -rvzP ../dist/ lukas@lw1.at:/srv/server/RadioStats/dist/ --fuzzy --delete-after -v
|
||||
rsync -rvzP ./build/ lukas@lw1.at:/srv/server/RadioStats/dist/ --fuzzy --delete-after -v
|
||||
|
|
|
@ -19,7 +19,7 @@ module.exports = {
|
|||
crossOriginLoading: "anonymous",
|
||||
globalObject: 'this' // https://github.com/webpack-contrib/worker-loader/issues/166
|
||||
},
|
||||
mode: process.env.NODE_ENV,
|
||||
mode: import.meta.env.NODE_ENV,
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ module.exports = {
|
|||
loader: 'vue-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
extractCSS: process.env.NODE_ENV === 'production',
|
||||
extractCSS: import.meta.env.NODE_ENV === 'production',
|
||||
cssSourceMap: true,
|
||||
transformToRequire: {
|
||||
video: ['src', 'poster'],
|
||||
|
@ -93,7 +93,7 @@ module.exports = {
|
|||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
process.env.NODE_ENV !== 'production'
|
||||
import.meta.env.NODE_ENV !== 'production'
|
||||
? 'vue-style-loader'
|
||||
: MiniCssExtractPlugin.loader,
|
||||
'css-loader',
|
||||
|
@ -109,7 +109,7 @@ module.exports = {
|
|||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
process.env.NODE_ENV !== 'production'
|
||||
import.meta.env.NODE_ENV !== 'production'
|
||||
? 'vue-style-loader'
|
||||
: MiniCssExtractPlugin.loader,
|
||||
{
|
||||
|
@ -144,7 +144,7 @@ module.exports = {
|
|||
new webpack.NamedModulesPlugin(),
|
||||
new SriPlugin({
|
||||
hashFuncNames: ['sha256'],
|
||||
enabled: process.env.NODE_ENV === 'production',
|
||||
enabled: import.meta.env.NODE_ENV === 'production',
|
||||
}),
|
||||
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /de|en/),
|
||||
|
||||
|
@ -152,7 +152,7 @@ module.exports = {
|
|||
],
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
if (import.meta.env.NODE_ENV === 'production') {
|
||||
module.exports.optimization = {
|
||||
splitChunks: {
|
||||
name: "commons"
|
||||
|
|
10
web/workaroundPlugin.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
module.exports = function config() {
|
||||
return {
|
||||
name: 'snowpack-config-resolveProxyImports-plugin',
|
||||
config(config) {
|
||||
setTimeout(() => {
|
||||
config.buildOptions.resolveProxyImports = true
|
||||
})
|
||||
},
|
||||
};
|
||||
}
|