Merge branch 'webpack-tweaking' into 'develop'
Improve front-end performance See merge request funkwhale/funkwhale!499
This commit is contained in:
commit
e1450d28b8
|
|
@ -93,5 +93,6 @@ po/*.po
|
|||
docs/swagger
|
||||
_build
|
||||
front/src/translations.json
|
||||
front/src/translations/*.json
|
||||
front/locales/en_US/LC_MESSAGES/app.po
|
||||
*.prof
|
||||
|
|
|
|||
|
|
@ -58,15 +58,6 @@ class RavenDSN(types.StringPreference):
|
|||
field_kwargs = {"required": False}
|
||||
|
||||
|
||||
@global_preferences_registry.register
|
||||
class RavenEnabled(types.BooleanPreference):
|
||||
show_in_api = True
|
||||
section = raven
|
||||
name = "front_enabled"
|
||||
default = False
|
||||
verbose_name = "Report front-end errors with Raven"
|
||||
|
||||
|
||||
@global_preferences_registry.register
|
||||
class InstanceNodeinfoEnabled(types.BooleanPreference):
|
||||
show_in_api = False
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
Improved front-end performance by stripping unused dependencies, reducing bundle size
|
||||
and enabling gzip compression
|
||||
|
||||
Enable gzip compression [manual action suggested]
|
||||
-------------------------------------------------
|
||||
|
||||
Gzip compression will be enabled on new instances by default
|
||||
and will reduce the amount of bandwidth consumed by your instance.
|
||||
|
||||
If you with to benefit from gzip compression on your instance,
|
||||
edit your reverse proxy virtualhost file (located at ``/etc/nginx/sites-available/funkwhale.conf``) and add the following snippet
|
||||
in the server block, then reload your nginx server::
|
||||
|
||||
server {
|
||||
# ... exiting configuration
|
||||
|
||||
# compression settings
|
||||
gzip on;
|
||||
gzip_comp_level 5;
|
||||
gzip_min_length 256;
|
||||
gzip_proxied any;
|
||||
gzip_vary on;
|
||||
|
||||
gzip_types
|
||||
application/atom+xml
|
||||
application/javascript
|
||||
application/json
|
||||
application/ld+json
|
||||
application/activity+json
|
||||
application/manifest+json
|
||||
application/rss+xml
|
||||
application/vnd.geo+json
|
||||
application/vnd.ms-fontobject
|
||||
application/x-font-ttf
|
||||
application/x-web-app-manifest+json
|
||||
application/xhtml+xml
|
||||
application/xml
|
||||
font/opentype
|
||||
image/bmp
|
||||
image/svg+xml
|
||||
image/x-icon
|
||||
text/cache-manifest
|
||||
text/css
|
||||
text/plain
|
||||
text/vcard
|
||||
text/vnd.rim.location.xloc
|
||||
text/vtt
|
||||
text/x-component
|
||||
text/x-cross-domain-policy;
|
||||
# end of compression settings
|
||||
}
|
||||
|
|
@ -29,6 +29,40 @@ server {
|
|||
# HSTS
|
||||
add_header Strict-Transport-Security "max-age=31536000";
|
||||
|
||||
# compression settings
|
||||
gzip on;
|
||||
gzip_comp_level 5;
|
||||
gzip_min_length 256;
|
||||
gzip_proxied any;
|
||||
gzip_vary on;
|
||||
|
||||
gzip_types
|
||||
application/atom+xml
|
||||
application/javascript
|
||||
application/json
|
||||
application/ld+json
|
||||
application/activity+json
|
||||
application/manifest+json
|
||||
application/rss+xml
|
||||
application/vnd.geo+json
|
||||
application/vnd.ms-fontobject
|
||||
application/x-font-ttf
|
||||
application/x-web-app-manifest+json
|
||||
application/xhtml+xml
|
||||
application/xml
|
||||
font/opentype
|
||||
image/bmp
|
||||
image/svg+xml
|
||||
image/x-icon
|
||||
text/cache-manifest
|
||||
text/css
|
||||
text/plain
|
||||
text/vcard
|
||||
text/vnd.rim.location.xloc
|
||||
text/vtt
|
||||
text/x-component
|
||||
text/x-cross-domain-policy;
|
||||
|
||||
location / {
|
||||
include /etc/nginx/funkwhale_proxy.conf;
|
||||
proxy_pass http://fw/;
|
||||
|
|
|
|||
|
|
@ -43,6 +43,41 @@ server {
|
|||
|
||||
root ${FUNKWHALE_FRONTEND_PATH};
|
||||
|
||||
# compression settings
|
||||
gzip on;
|
||||
gzip_comp_level 5;
|
||||
gzip_min_length 256;
|
||||
gzip_proxied any;
|
||||
gzip_vary on;
|
||||
|
||||
gzip_types
|
||||
application/atom+xml
|
||||
application/javascript
|
||||
application/json
|
||||
application/ld+json
|
||||
application/activity+json
|
||||
application/manifest+json
|
||||
application/rss+xml
|
||||
application/vnd.geo+json
|
||||
application/vnd.ms-fontobject
|
||||
application/x-font-ttf
|
||||
application/x-web-app-manifest+json
|
||||
application/xhtml+xml
|
||||
application/xml
|
||||
font/opentype
|
||||
image/bmp
|
||||
image/svg+xml
|
||||
image/x-icon
|
||||
text/cache-manifest
|
||||
text/css
|
||||
text/plain
|
||||
text/vcard
|
||||
text/vnd.rim.location.xloc
|
||||
text/vtt
|
||||
text/x-component
|
||||
text/x-cross-domain-policy;
|
||||
|
||||
# end of compression settings
|
||||
location / {
|
||||
include /etc/nginx/funkwhale_proxy.conf;
|
||||
# this is needed if you have file import via upload enabled
|
||||
|
|
|
|||
|
|
@ -43,6 +43,39 @@ http {
|
|||
charset utf-8;
|
||||
client_max_body_size 30M;
|
||||
include /etc/nginx/funkwhale_proxy.conf;
|
||||
# compression settings
|
||||
gzip on;
|
||||
gzip_comp_level 5;
|
||||
gzip_min_length 256;
|
||||
gzip_proxied any;
|
||||
gzip_vary on;
|
||||
|
||||
gzip_types
|
||||
application/atom+xml
|
||||
application/javascript
|
||||
application/json
|
||||
application/ld+json
|
||||
application/activity+json
|
||||
application/manifest+json
|
||||
application/rss+xml
|
||||
application/vnd.geo+json
|
||||
application/vnd.ms-fontobject
|
||||
application/x-font-ttf
|
||||
application/x-web-app-manifest+json
|
||||
application/xhtml+xml
|
||||
application/xml
|
||||
font/opentype
|
||||
image/bmp
|
||||
image/svg+xml
|
||||
image/x-icon
|
||||
text/cache-manifest
|
||||
text/css
|
||||
text/plain
|
||||
text/vcard
|
||||
text/vnd.rim.location.xloc
|
||||
text/vtt
|
||||
text/x-component
|
||||
text/x-cross-domain-policy;
|
||||
|
||||
location /front/ {
|
||||
proxy_pass http://funkwhale-front/front/;
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ work. We will store the necessary files in the ``/srv/funkwhale/custom`` directo
|
|||
mkdir custom
|
||||
cat <<EOF > custom/settings.json
|
||||
{
|
||||
"additionalStylesheets": ["/custom/custom.css"]
|
||||
"additionalStylesheets": ["/front/custom/custom.css"]
|
||||
}
|
||||
EOF
|
||||
cat <<EOF > custom/custom.css
|
||||
|
|
@ -194,7 +194,7 @@ work. We will store the necessary files in the ``/srv/funkwhale/custom`` directo
|
|||
By executing the previous commands, you will end up with two files in your ``/srv/funkwhale/custom``
|
||||
directory:
|
||||
|
||||
- ``settings.json`` will tell the front-end what stylesheets you want to load (``/custom/custom.css`` in this example)
|
||||
- ``settings.json`` will tell the front-end what stylesheets you want to load (``/front/custom/custom.css`` in this example)
|
||||
- ``custom.css`` will hold your custom CSS
|
||||
|
||||
The last step to make this work is to ensure both files are served by the reverse proxy.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "scripts/i18n-compile.sh && vue-cli-service serve --port ${VUE_PORT:-8000} --host ${VUE_HOST:-0.0.0.0}",
|
||||
"serve": "vue-cli-service serve --port ${VUE_PORT:-8000} --host ${VUE_HOST:-0.0.0.0}",
|
||||
"build": "scripts/i18n-compile.sh && vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"i18n-extract": "scripts/i18n-extract.sh",
|
||||
|
|
@ -20,8 +20,7 @@
|
|||
"lodash": "^4.17.10",
|
||||
"masonry-layout": "^4.2.2",
|
||||
"moment": "^2.22.2",
|
||||
"raven-js": "^3.26.4",
|
||||
"semantic-ui-css": "^2.3.3",
|
||||
"semantic-ui-css": "^2.4.1",
|
||||
"showdown": "^1.8.6",
|
||||
"vue": "^2.5.17",
|
||||
"vue-gettext": "^2.1.0",
|
||||
|
|
@ -49,7 +48,8 @@
|
|||
"node-sass": "^4.9.3",
|
||||
"sass-loader": "^7.1.0",
|
||||
"sinon": "^6.1.5",
|
||||
"vue-template-compiler": "^2.5.17"
|
||||
"vue-template-compiler": "^2.5.17",
|
||||
"webpack-bundle-size-analyzer": "^3.0.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
{
|
||||
"additionalStylesheets": ["/custom.css"]
|
||||
"additionalStylesheets": [
|
||||
"/front/custom.css"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
#!/bin/bash -eux
|
||||
locales=$(tail -n +2 src/locales.js | sed -e 's/export default //' | jq '.locales[].code' | xargs echo)
|
||||
find locales -name '*.po' | xargs $(yarn bin)/gettext-compile --output src/translations.json
|
||||
locales=$(tail -n +2 src/locales.js | sed -e 's/export default //' | jq '.locales[].code' | grep -v 'en_US' | xargs echo)
|
||||
for locale in $locales; do
|
||||
find "locales/$locale" -name '*.po' | $(yarn bin)/gettext-compile locales/$locale/LC_MESSAGES/app.po --output src/translations/$locale.json
|
||||
done
|
||||
|
||||
# find locales -name '*.po' | xargs $(yarn bin)/gettext-compile --output src/translations.json
|
||||
|
|
|
|||
|
|
@ -43,10 +43,6 @@
|
|||
:version="version"
|
||||
@show:shortcuts-modal="showShortcutsModal = !showShortcutsModal"
|
||||
></app-footer>
|
||||
<raven
|
||||
v-if="$store.state.instance.settings.raven.front_enabled.value"
|
||||
:dsn="$store.state.instance.settings.raven.front_dsn.value"
|
||||
></raven>
|
||||
<playlist-modal v-if="$store.state.auth.authenticated"></playlist-modal>
|
||||
<shortcuts-modal @update:show="showShortcutsModal = $event" :show="showShortcutsModal"></shortcuts-modal>
|
||||
<GlobalEvents @keydown.h.exact="showShortcutsModal = !showShortcutsModal"/>
|
||||
|
|
@ -56,18 +52,16 @@
|
|||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import {mapState} from 'vuex'
|
||||
import { WebSocketBridge } from 'django-channels'
|
||||
import GlobalEvents from '@/components/utils/global-events'
|
||||
|
||||
import translations from '@/translations'
|
||||
|
||||
import Sidebar from '@/components/Sidebar'
|
||||
import AppFooter from '@/components/Footer'
|
||||
import Raven from '@/components/Raven'
|
||||
import ServiceMessages from '@/components/ServiceMessages'
|
||||
|
||||
import locales from './locales'
|
||||
import PlaylistModal from '@/components/playlists/PlaylistModal'
|
||||
import ShortcutsModal from '@/components/ShortcutsModal'
|
||||
|
||||
|
|
@ -76,7 +70,6 @@ export default {
|
|||
components: {
|
||||
Sidebar,
|
||||
AppFooter,
|
||||
Raven,
|
||||
PlaylistModal,
|
||||
ShortcutsModal,
|
||||
GlobalEvents,
|
||||
|
|
@ -139,7 +132,7 @@ export default {
|
|||
},
|
||||
autodetectLanguage () {
|
||||
let userLanguage = navigator.language || navigator.userLanguage
|
||||
let available = _.keys(translations)
|
||||
let available = locales.locales.map(e => { return e.code })
|
||||
let matching = available.filter((a) => {
|
||||
return userLanguage.replace('-', '_') === a
|
||||
})
|
||||
|
|
@ -223,181 +216,5 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
// we do the import here instead in main.js
|
||||
// as resolve order is not deterministric in webpack
|
||||
// and we end up with CSS rules not applied,
|
||||
// see https://github.com/webpack/webpack/issues/215
|
||||
@import "semantic/semantic.css";
|
||||
@import "style/vendor/media";
|
||||
|
||||
html,
|
||||
body {
|
||||
@include media("<desktop") {
|
||||
font-size: 90%;
|
||||
}
|
||||
}
|
||||
#app {
|
||||
font-family: "Avenir", Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.instance-chooser {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.main.pusher,
|
||||
.footer {
|
||||
@include media(">desktop") {
|
||||
margin-left: 350px !important;
|
||||
margin-top: 50px;
|
||||
}
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.main.pusher > .ui.secondary.menu {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
border: none;
|
||||
box-shadow: inset 0px -2px 0px 0px rgba(34, 36, 38, 0.15);
|
||||
.ui.item {
|
||||
border: none;
|
||||
border-bottom-style: none;
|
||||
margin-bottom: 0px;
|
||||
&.active {
|
||||
box-shadow: inset 0px -2px 0px 0px #000;
|
||||
}
|
||||
}
|
||||
@include media(">tablet") {
|
||||
padding: 0 2.5rem;
|
||||
}
|
||||
@include media(">desktop") {
|
||||
position: fixed;
|
||||
left: 350px;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
z-index: 99;
|
||||
}
|
||||
background-color: white;
|
||||
.item {
|
||||
padding-top: 1.5em;
|
||||
padding-bottom: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.service-messages {
|
||||
position: fixed;
|
||||
bottom: 1em;
|
||||
left: 1em;
|
||||
@include media(">desktop") {
|
||||
left: 350px;
|
||||
}
|
||||
}
|
||||
.main-pusher {
|
||||
padding: 1.5rem 0;
|
||||
}
|
||||
.ui.stripe.segment,
|
||||
#footer {
|
||||
padding: 2em;
|
||||
@include media(">tablet") {
|
||||
padding: 4em;
|
||||
}
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ui.small.text.container {
|
||||
max-width: 500px !important;
|
||||
}
|
||||
|
||||
.button.icon.tiny {
|
||||
padding: 0.5em !important;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
.logo {
|
||||
path {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.discrete {
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
.link {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ui.really.basic.button {
|
||||
&:not(:focus) {
|
||||
box-shadow: none !important;
|
||||
background-color: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.floated.buttons .button ~ .dropdown {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.ui.icon.header .circular.icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.segment-content .button {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
.segment.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.reset {
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
overflow: visible;
|
||||
|
||||
background: transparent;
|
||||
|
||||
/* inherit font & color from ancestor */
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
|
||||
/* Normalize `line-height`. Cannot be changed from `normal` in Firefox 4+. */
|
||||
line-height: normal;
|
||||
|
||||
/* Corrects font smoothing for webkit */
|
||||
-webkit-font-smoothing: inherit;
|
||||
-moz-osx-font-smoothing: inherit;
|
||||
/* Corrects inability to style clickable `input` types in iOS */
|
||||
-webkit-appearance: none;
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
.ui.table > caption {
|
||||
font-weight: bold;
|
||||
padding: 0.5em;
|
||||
text-align: left;
|
||||
}
|
||||
[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.left.floated {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.right.floated {
|
||||
float: right;
|
||||
}
|
||||
@import "style/_main";
|
||||
</style>
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 21 KiB |
|
|
@ -27,9 +27,9 @@
|
|||
<p>{{ instance.short_description.value }}</p>
|
||||
</div>
|
||||
<div
|
||||
v-if="instance.long_description.value"
|
||||
v-if="markdown && instance.long_description.value"
|
||||
class="ui middle aligned stackable text container"
|
||||
v-html="$options.filters.markdown(instance.long_description.value)">
|
||||
v-html="markdown.makeHtml(instance.long_description.value)">
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
|
@ -43,8 +43,17 @@ export default {
|
|||
components: {
|
||||
Stats
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
markdown: null
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch("instance/fetchSettings")
|
||||
let self = this
|
||||
import('showdown').then(module => {
|
||||
self.markdown = new module.default.Converter()
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<div class="ui form">
|
||||
<div class="ui field">
|
||||
<label><translate>Change language</translate></label>
|
||||
<select class="ui dropdown" v-model="$language.current">
|
||||
<select class="ui dropdown" :value="$language.current" @change="updateLanguage($event.target.value)">
|
||||
<option v-for="(language, key) in $language.available" :key="key" :value="key">{{ language }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
@ -60,7 +60,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from "vue"
|
||||
import { mapState } from "vuex"
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
props: ["version"],
|
||||
|
|
@ -74,6 +76,13 @@ export default {
|
|||
if (confirm) {
|
||||
this.$store.commit("instance/instanceUrl", null)
|
||||
}
|
||||
},
|
||||
updateLanguage(value) {
|
||||
let self = this
|
||||
import(`../translations/${value}.json`).then((response) =>{
|
||||
Vue.$translations[value] = response.default[value]
|
||||
self.$language.current = value
|
||||
})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from "lodash"
|
||||
import _ from "@/lodash"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
<template>
|
||||
<div class="raven"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Raven from 'raven-js'
|
||||
import RavenVue from 'raven-js/plugins/vue'
|
||||
import Vue from 'vue'
|
||||
import logger from '@/logging'
|
||||
|
||||
export default {
|
||||
props: ['dsn'],
|
||||
created () {
|
||||
Raven.uninstall()
|
||||
this.setUp()
|
||||
},
|
||||
destroyed () {
|
||||
Raven.uninstall()
|
||||
},
|
||||
methods: {
|
||||
setUp () {
|
||||
Raven.uninstall()
|
||||
logger.default.info('Installing raven...')
|
||||
Raven.config(this.dsn).addPlugin(RavenVue, Vue).install()
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dsn: function () {
|
||||
this.setUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped >
|
||||
.raven {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
<div class="menu-area">
|
||||
<div class="ui compact fluid two item inverted menu">
|
||||
<a class="active item" role="button" @click.prevent.stop="selectedTab = 'library'" data-tab="library"><translate>Browse</translate></a>
|
||||
<a class="item" role="button" @click.prevent.stop="selectedTab = 'queue'" data-tab="queue">
|
||||
<a :class="[{active: selectedTab === 'library'}, 'item']" role="button" @click.prevent.stop="selectedTab = 'library'" data-tab="library"><translate>Browse</translate></a>
|
||||
<a :class="[{active: selectedTab === 'queue'}, 'item']" role="button" @click.prevent.stop="selectedTab = 'queue'" data-tab="queue">
|
||||
<translate>Queue</translate>
|
||||
<template v-if="queue.tracks.length === 0">
|
||||
<translate>(empty)</translate>
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="tabs">
|
||||
<section class="ui bottom attached active tab" data-tab="library" :aria-label="labels.mainMenu">
|
||||
<section :class="['ui', 'bottom', 'attached', {active: selectedTab === 'library'}, 'tab']" :aria-label="labels.mainMenu">
|
||||
<nav class="ui inverted vertical large fluid menu" role="navigation" :aria-label="labels.mainMenu">
|
||||
<div class="item">
|
||||
<header class="header"><translate>My account</translate></header>
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
<translate :translate-params="{username: $store.state.auth.username}">
|
||||
Logged in as %{ username }
|
||||
</translate>
|
||||
<img class="ui right floated circular tiny avatar image" v-if="$store.state.auth.profile.avatar.square_crop" :src="$store.getters['instance/absoluteUrl']($store.state.auth.profile.avatar.square_crop)" />
|
||||
<img class="ui right floated circular tiny avatar image" v-if="$store.state.auth.profile.avatar.square_crop" v-lazy="$store.getters['instance/absoluteUrl']($store.state.auth.profile.avatar.square_crop)" />
|
||||
</router-link>
|
||||
<router-link class="item" v-if="$store.state.auth.authenticated" :to="{path: '/settings'}"><i class="setting icon"></i><translate>Settings</translate></router-link>
|
||||
<router-link class="item" v-if="$store.state.auth.authenticated" :to="{name: 'notifications'}">
|
||||
|
|
@ -113,7 +113,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section class="ui bottom attached tab" data-tab="queue">
|
||||
<section :class="['ui', 'bottom', 'attached', {active: selectedTab === 'queue'}, 'tab']">
|
||||
<table class="ui compact inverted very basic fixed single line unstackable table">
|
||||
<draggable v-model="tracks" element="tbody" @update="reorder">
|
||||
<tr
|
||||
|
|
@ -188,11 +188,6 @@ export default {
|
|||
fetchInterval: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
$(this.$el)
|
||||
.find(".menu .item")
|
||||
.tab()
|
||||
},
|
||||
destroy() {
|
||||
if (this.fetchInterval) {
|
||||
clearInterval(this.fetchInterval)
|
||||
|
|
@ -206,10 +201,8 @@ export default {
|
|||
labels() {
|
||||
let mainMenu = this.$gettext("Main menu")
|
||||
let selectTrack = this.$gettext("Play this track")
|
||||
let pendingRequests = this.$gettext("Pending import requests")
|
||||
let pendingFollows = this.$gettext("Pending follow requests")
|
||||
return {
|
||||
pendingRequests,
|
||||
pendingFollows,
|
||||
mainMenu,
|
||||
selectTrack
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import AlbumCard from '@/components/audio/album/Card'
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import url from '@/utils/url'
|
||||
import {Howl} from 'howler'
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<div class="ui loader"></div>
|
||||
</div>
|
||||
<div class="card" v-for="album in albums" :key="album.id">
|
||||
<div :class="['ui', 'image', 'with-overlay', {'default-cover': !album.cover.original}]" :style="getImageStyle(album)">
|
||||
<div :class="['ui', 'image', 'with-overlay', {'default-cover': !album.cover.original}]" v-lazy:background-image="getImageUrl(album)">
|
||||
<play-button class="play-overlay" :icon-only="true" :is-playable="album.is_playable" :button-classes="['ui', 'circular', 'large', 'orange', 'icon', 'button']" :album="album.id"></play-button>
|
||||
</div>
|
||||
<div class="content">
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import axios from 'axios'
|
||||
import PlayButton from '@/components/audio/PlayButton'
|
||||
|
||||
|
|
@ -87,17 +87,15 @@ export default {
|
|||
this.offset = Math.max(this.offset - this.limit, 0)
|
||||
}
|
||||
},
|
||||
getImageStyle (album) {
|
||||
getImageUrl (album) {
|
||||
let url = '../../../assets/audio/default-cover.png'
|
||||
|
||||
if (album.cover.original) {
|
||||
url = this.$store.getters['instance/absoluteUrl'](album.cover.medium_square_crop)
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
return {
|
||||
'background-image': `url("${url}")`
|
||||
return null
|
||||
}
|
||||
return url
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -108,10 +106,10 @@ export default {
|
|||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import '../../../style/vendor/media';
|
||||
@import "../../../style/vendor/media";
|
||||
|
||||
.default-cover {
|
||||
background-image: url('../../../assets/audio/default-cover.png') !important;
|
||||
background-image: url("../../../assets/audio/default-cover.png") !important;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<tbody>
|
||||
<tr v-for="album in albums">
|
||||
<td>
|
||||
<img class="ui mini image" v-if="album.cover.original" :src="$store.getters['instance/absoluteUrl'](album.cover.small_square_crop)">
|
||||
<img class="ui mini image" v-if="album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](album.cover.small_square_crop)">
|
||||
<img class="ui mini image" v-else src="../../../assets/audio/default-cover.png">
|
||||
</td>
|
||||
<td colspan="4">
|
||||
|
|
@ -82,5 +82,4 @@ export default {
|
|||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import axios from 'axios'
|
||||
import PlayButton from '@/components/audio/PlayButton'
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../style/vendor/media';
|
||||
@import "../../../style/vendor/media";
|
||||
|
||||
.play-overlay {
|
||||
position: absolute;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<div :class="['ui', 'head', 'vertical', 'center', 'aligned', 'stripe', 'segment']">
|
||||
<h2 class="ui center aligned icon header">
|
||||
<i v-if="!profile.avatar.square_crop" class="circular inverted user green icon"></i>
|
||||
<img class="ui big circular image" v-else :src="$store.getters['instance/absoluteUrl'](profile.avatar.square_crop)" />
|
||||
<img class="ui big circular image" v-else v-lazy="$store.getters['instance/absoluteUrl'](profile.avatar.square_crop)" />
|
||||
<div class="content">
|
||||
{{ profile.username }}
|
||||
<div class="sub header" v-translate="{date: signupDate}">Registered since %{ date }</div>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
</div>
|
||||
<div class="ui six wide column">
|
||||
<h3 class="ui header"><translate>Current avatar</translate></h3>
|
||||
<img class="ui circular image" v-if="currentAvatar && currentAvatar.square_crop" :src="$store.getters['instance/absoluteUrl'](currentAvatar.medium_square_crop)" />
|
||||
<img class="ui circular image" v-if="currentAvatar && currentAvatar.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](currentAvatar.medium_square_crop)" />
|
||||
<div class="ui hidden divider"></div>
|
||||
<button @click="removeAvatar" v-if="currentAvatar && currentAvatar.square_crop" :class="['ui', {'loading': isLoadingAvatar}, ,'yellow', 'button']">
|
||||
<translate>Remove avatar</translate>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<img
|
||||
class="ui tiny circular avatar"
|
||||
v-if="user.avatar && user.avatar.small_square_crop"
|
||||
:src="$store.getters['instance/absoluteUrl'](user.avatar.small_square_crop)" />
|
||||
v-lazy="$store.getters['instance/absoluteUrl'](user.avatar.small_square_crop)" />
|
||||
<span v-else :style="defaultAvatarStyle" class="ui circular label">{{ user.username[0]}}</span>
|
||||
@{{ user.username }}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
<template>
|
||||
<div class="comment">
|
||||
<div class="content">
|
||||
<a class="author">{{ user.username }}</a>
|
||||
<div class="metadata">
|
||||
<div class="date"><human-date :date="date"></human-date></div>
|
||||
</div>
|
||||
<div class="text" v-html="comment"></div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<span
|
||||
@click="collapsed = false"
|
||||
v-if="truncated && collapsed"
|
||||
class="expand">
|
||||
<translate>Expand</translate>
|
||||
</span>
|
||||
<span
|
||||
@click="collapsed = true"
|
||||
v-if="truncated && !collapsed"
|
||||
class="collapse">
|
||||
<translate>Collapse</translate>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
user: {type: Object, required: true},
|
||||
date: {required: true},
|
||||
content: {type: String, required: true}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
collapsed: true,
|
||||
length: 50
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
comment () {
|
||||
let text = this.content
|
||||
if (this.collapsed) {
|
||||
text = this.$options.filters.truncate(text, this.length)
|
||||
}
|
||||
return this.$options.filters.markdown(text)
|
||||
},
|
||||
truncated () {
|
||||
return this.content.length > this.length
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import axios from 'axios'
|
||||
import LibraryCard from '@/views/content/remote/Card'
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from "lodash"
|
||||
import _ from "@/lodash"
|
||||
import axios from "axios"
|
||||
import logger from "@/logging"
|
||||
import backend from "@/audio/backend"
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@
|
|||
|
||||
<script>
|
||||
import axios from "axios"
|
||||
import _ from "lodash"
|
||||
import _ from "@/lodash"
|
||||
import $ from "jquery"
|
||||
|
||||
import logger from "@/logging"
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from "@/lodash"
|
||||
import $ from "jquery";
|
||||
import axios from "axios";
|
||||
import logger from "@/logging";
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@
|
|||
|
||||
<script>
|
||||
import axios from "axios"
|
||||
import _ from "lodash"
|
||||
import _ from "@/lodash"
|
||||
import $ from "jquery"
|
||||
|
||||
import logger from "@/logging"
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@
|
|||
<script>
|
||||
import axios from "axios"
|
||||
import $ from "jquery"
|
||||
import _ from "lodash"
|
||||
import _ from "@/lodash"
|
||||
import BuilderFilter from "./Filter"
|
||||
import TrackTable from "@/components/audio/track/Table"
|
||||
import RadioButton from "@/components/radios/Button"
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
<script>
|
||||
import axios from 'axios'
|
||||
import $ from 'jquery'
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
|
||||
import Modal from '@/components/semantic/Modal'
|
||||
import TrackTable from '@/components/audio/track/Table'
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@
|
|||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import time from '@/utils/time'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import ActionTable from '@/components/common/ActionTable'
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@
|
|||
<script>
|
||||
import axios from 'axios'
|
||||
import moment from 'moment'
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import ActionTable from '@/components/common/ActionTable'
|
||||
import OrderingMixin from '@/components/mixins/Ordering'
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@
|
|||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import time from '@/utils/time'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import ActionTable from '@/components/common/ActionTable'
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import axios from 'axios'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import axios from 'axios'
|
||||
import PlaylistCard from '@/components/playlists/Card'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
<template>
|
||||
<div :class="['ui', {collapsed: collapsed}, 'card']">
|
||||
<div class="content">
|
||||
<div class="header">{{ request.artist_name }}</div>
|
||||
<div class="description">
|
||||
<div
|
||||
v-if="request.albums" v-html="$options.filters.markdown(request.albums)"></div>
|
||||
<div class="ui comments">
|
||||
<comment
|
||||
:user="request.user"
|
||||
:content="request.comment || ''"
|
||||
:date="request.creation_date"></comment>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="extra content">
|
||||
<span >
|
||||
<i v-if="request.status === 'pending'" class="hourglass start icon"></i>
|
||||
<i v-if="request.status === 'accepted'" class="hourglass half icon"></i>
|
||||
<i v-if="request.status === 'imported'" class="check icon"></i>
|
||||
{{ request.status | capitalize }}
|
||||
</span>
|
||||
<button
|
||||
@click="createImport"
|
||||
v-if="request.status === 'pending' && importAction && $store.state.auth.availablePermissions['library']"
|
||||
class="ui mini basic green right floated button"><translate>Create import</translate></button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Comment from '@/components/discussion/Comment'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
request: {type: Object, required: true},
|
||||
importAction: {type: Boolean, default: true}
|
||||
},
|
||||
components: {
|
||||
Comment
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
collapsed: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createImport () {
|
||||
this.$router.push({
|
||||
name: 'library.import.launch',
|
||||
query: {request: this.request.id}})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<form v-if="!over" class="ui form" @submit.prevent="submit">
|
||||
<p><translate>Something's missing in the library? Let us know what you would like to listen!</translate></p>
|
||||
<div class="required field">
|
||||
<label><translate>Artist name</translate></label>
|
||||
<input v-model="currentArtistName" :placeholder="labels.artistNamePlaceholder" required maxlength="200">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label><translate>Albums</translate></label>
|
||||
<p><translate>Leave this field empty if you're requesting the whole discography.</translate></p>
|
||||
<input v-model="currentAlbums" :placeholder="labels.albumTitlePlaceholder" maxlength="2000">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label><translate>Comment</translate></label>
|
||||
<textarea v-model="currentComment" rows="3" :placeholder="labels.commentPlaceholder" maxlength="2000"></textarea>
|
||||
</div>
|
||||
<button class="ui submit button" type="submit"><translate>Submit</translate></button>
|
||||
</form>
|
||||
<div v-else class="ui success message">
|
||||
<div class="header"><translate>Request submitted!</translate></div>
|
||||
<p><translate>We've received your request, you'll get some groove soon ;)</translate></p>
|
||||
<button @click="reset" class="ui button"><translate>Submit another request</translate></button>
|
||||
</div>
|
||||
<div v-if="requests.length > 0">
|
||||
<div class="ui divider"></div>
|
||||
<h3 class="ui header"><translate>Pending requests</translate></h3>
|
||||
<div class="ui list">
|
||||
<div v-for="request in requests" class="item">
|
||||
<div class="content">
|
||||
<div class="header">{{ request.artist_name }}</div>
|
||||
<div v-if="request.albums" class="description">
|
||||
{{ request.albums|truncate }}</div>
|
||||
<div v-if="request.comment" class="description">
|
||||
{{ request.comment|truncate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import $ from 'jquery'
|
||||
import axios from 'axios'
|
||||
|
||||
import logger from '@/logging'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
defaultArtistName: {type: String, default: ''},
|
||||
defaultAlbums: {type: String, default: ''},
|
||||
defaultComment: {type: String, default: ''}
|
||||
},
|
||||
created () {
|
||||
this.fetchRequests()
|
||||
},
|
||||
mounted () {
|
||||
$('.ui.radio.checkbox').checkbox()
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
currentArtistName: this.defaultArtistName,
|
||||
currentAlbums: this.defaultAlbums,
|
||||
currentComment: this.defaultComment,
|
||||
isLoading: false,
|
||||
over: false,
|
||||
requests: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
labels () {
|
||||
let artistNamePlaceholder = this.$gettext('The Beatles, Mickael Jackson…')
|
||||
let albumTitlePlaceholder = this.$gettext('The White Album, Thriller…')
|
||||
let commentPlaceholder = this.$gettext('Use this comment box to add details to your request if needed')
|
||||
return {
|
||||
artistNamePlaceholder,
|
||||
albumTitlePlaceholder,
|
||||
commentPlaceholder
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchRequests () {
|
||||
let self = this
|
||||
let url = 'requests/import-requests/'
|
||||
axios.get(url, {}).then((response) => {
|
||||
self.requests = response.data.results
|
||||
})
|
||||
},
|
||||
submit () {
|
||||
let self = this
|
||||
this.isLoading = true
|
||||
let url = 'requests/import-requests/'
|
||||
let payload = {
|
||||
artist_name: this.currentArtistName,
|
||||
albums: this.currentAlbums,
|
||||
comment: this.currentComment
|
||||
}
|
||||
axios.post(url, payload).then((response) => {
|
||||
logger.default.info('Submitted request!')
|
||||
self.isLoading = false
|
||||
self.over = true
|
||||
self.requests.unshift(response.data)
|
||||
}, (response) => {
|
||||
logger.default.error('error while submitting request')
|
||||
self.isLoading = false
|
||||
})
|
||||
},
|
||||
reset () {
|
||||
this.over = false
|
||||
this.currentArtistName = ''
|
||||
this.currentAlbums = ''
|
||||
this.currentComment = ''
|
||||
},
|
||||
truncate (string, length) {
|
||||
if (string.length > length) {
|
||||
return string.substring(0, length) + '…'
|
||||
}
|
||||
return string
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
import Vue from 'vue'
|
||||
import Embed from './Embed'
|
||||
import axios from 'axios'
|
||||
import VuePlyr from 'vue-plyr'
|
||||
|
||||
Vue.use(VuePlyr)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Vue from 'vue'
|
||||
|
||||
import moment from 'moment'
|
||||
import showdown from 'showdown'
|
||||
|
||||
export function truncate (str, max, ellipsis) {
|
||||
max = max || 100
|
||||
|
|
@ -14,13 +13,6 @@ export function truncate (str, max, ellipsis) {
|
|||
|
||||
Vue.filter('truncate', truncate)
|
||||
|
||||
export function markdown (str) {
|
||||
const converter = new showdown.Converter()
|
||||
return converter.makeHtml(str)
|
||||
}
|
||||
|
||||
Vue.filter('markdown', markdown)
|
||||
|
||||
export function ago (date) {
|
||||
const m = moment(date)
|
||||
return m.fromNow()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
// cherry-pick specific lodash methods here to reduce bundle size
|
||||
|
||||
export default {
|
||||
clone: require('lodash/clone'),
|
||||
debounce: require('lodash/debounce'),
|
||||
get: require('lodash/get'),
|
||||
merge: require('lodash/merge'),
|
||||
range: require('lodash/range'),
|
||||
shuffle: require('lodash/shuffle'),
|
||||
sortBy: require('lodash/sortBy'),
|
||||
throttle: require('lodash/throttle'),
|
||||
uniq: require('lodash/uniq'),
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ import VueLazyload from 'vue-lazyload'
|
|||
import store from './store'
|
||||
import GetTextPlugin from 'vue-gettext'
|
||||
import { sync } from 'vuex-router-sync'
|
||||
import translations from './translations.json'
|
||||
import locales from '@/locales'
|
||||
|
||||
import filters from '@/filters' // eslint-disable-line
|
||||
|
|
@ -23,12 +22,9 @@ import globals from '@/components/globals' // eslint-disable-line
|
|||
sync(store, router)
|
||||
|
||||
window.$ = window.jQuery = require('jquery')
|
||||
|
||||
// this is absolutely dirty but at the moment, semantic UI does not
|
||||
// play really nice with webpack and I want to get rid of Google Fonts
|
||||
// require('./semantic/semantic.css')
|
||||
require('semantic-ui-css/semantic.js')
|
||||
require('./semantic.js')
|
||||
require('masonry-layout')
|
||||
|
||||
let availableLanguages = (function () {
|
||||
let l = {}
|
||||
locales.locales.forEach(c => {
|
||||
|
|
@ -54,7 +50,7 @@ Vue.use(GetTextPlugin, {
|
|||
}
|
||||
}
|
||||
},
|
||||
translations: translations,
|
||||
translations: {},
|
||||
silent: true
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
// require('semantic-ui-css/components/accordion.min.js')
|
||||
require('semantic-ui-css/components/api.min.js')
|
||||
require('semantic-ui-css/components/checkbox.min.js')
|
||||
// require('semantic-ui-css/components/colorize.min.js')
|
||||
require('semantic-ui-css/components/dimmer.min.js')
|
||||
require('semantic-ui-css/components/dropdown.min.js')
|
||||
// require('semantic-ui-css/components/embed.min.js')
|
||||
// require('semantic-ui-css/components/form.min.js')
|
||||
require('semantic-ui-css/components/modal.min.js')
|
||||
// require('semantic-ui-css/components/nag.min.js')
|
||||
// require('semantic-ui-css/components/popup.min.js')
|
||||
require('semantic-ui-css/components/progress.min.js')
|
||||
// require('semantic-ui-css/components/rating.min.js')
|
||||
require('semantic-ui-css/components/search.min.js')
|
||||
// require('semantic-ui-css/components/shape.min.js')
|
||||
// require('semantic-ui-css/components/sidebar.min.js')
|
||||
require('semantic-ui-css/components/site.min.js')
|
||||
require('semantic-ui-css/components/state.min.js')
|
||||
require('semantic-ui-css/components/sticky.min.js')
|
||||
// require('semantic-ui-css/components/tab.min.js')
|
||||
require('semantic-ui-css/components/transition.min.js')
|
||||
// require('semantic-ui-css/components/video.min.js')
|
||||
require('semantic-ui-css/components/visibility.min.js')
|
||||
// require('semantic-ui-css/components/visit.min.js')
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 957 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB |
|
|
@ -1,6 +1,6 @@
|
|||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
|
||||
function getDefaultUrl () {
|
||||
return (
|
||||
|
|
@ -40,14 +40,6 @@ export default {
|
|||
enabled: {
|
||||
value: true
|
||||
}
|
||||
},
|
||||
raven: {
|
||||
front_enabled: {
|
||||
value: false
|
||||
},
|
||||
front_dsn: {
|
||||
value: null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -131,7 +123,7 @@ export default {
|
|||
})
|
||||
},
|
||||
fetchFrontSettings ({commit}) {
|
||||
return axios.get('/settings.json').then(response => {
|
||||
return axios.get('/front/settings.json').then(response => {
|
||||
commit('frontSettings', response.data)
|
||||
}, response => {
|
||||
logger.default.error('Error when fetching front-end configuration (or no customization available)')
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import logger from '@/logging'
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
|
|
@ -86,7 +86,7 @@ export default {
|
|||
if (callback && i + 1 === total) {
|
||||
p.then(callback)
|
||||
}
|
||||
if (shouldPlay && p) {
|
||||
if (shouldPlay && p && i + 1 === total) {
|
||||
p.then(() => {
|
||||
dispatch('next')
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
|
||||
███████╗███████╗███╗ ███╗ █████╗ ███╗ ██╗████████╗██╗ ██████╗ ██╗ ██╗██╗
|
||||
██╔════╝██╔════╝████╗ ████║██╔══██╗████╗ ██║╚══██╔══╝██║██╔════╝ ██║ ██║██║
|
||||
███████╗█████╗ ██╔████╔██║███████║██╔██╗ ██║ ██║ ██║██║ ██║ ██║██║
|
||||
╚════██║██╔══╝ ██║╚██╔╝██║██╔══██║██║╚██╗██║ ██║ ██║██║ ██║ ██║██║
|
||||
███████║███████╗██║ ╚═╝ ██║██║ ██║██║ ╚████║ ██║ ██║╚██████╗ ╚██████╔╝██║
|
||||
╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝
|
||||
|
||||
Import this file into your LESS project to use Semantic UI without build tools
|
||||
*/
|
||||
|
||||
/* Global */
|
||||
@import "~semantic-ui-css/components/reset.css";
|
||||
// we use our custom site css here to avoid loading google font
|
||||
@import "./site";
|
||||
|
||||
/* Elements */
|
||||
@import "~semantic-ui-css/components/button.css";
|
||||
@import "~semantic-ui-css/components/container.css";
|
||||
@import "~semantic-ui-css/components/divider.css";
|
||||
// @import "~semantic-ui-css/components/flag.css";
|
||||
@import "~semantic-ui-css/components/header.css";
|
||||
@import "~semantic-ui-css/components/icon.css";
|
||||
@import "~semantic-ui-css/components/image.css";
|
||||
@import "~semantic-ui-css/components/input.css";
|
||||
@import "~semantic-ui-css/components/label.css";
|
||||
@import "~semantic-ui-css/components/list.css";
|
||||
@import "~semantic-ui-css/components/loader.css";
|
||||
// @import "~semantic-ui-css/components/placeholder.css";
|
||||
// @import "~semantic-ui-css/components/rail.css";
|
||||
// @import "~semantic-ui-css/components/reveal.css";
|
||||
@import "~semantic-ui-css/components/segment.css";
|
||||
@import "~semantic-ui-css/components/step.css";
|
||||
|
||||
/* Collections */
|
||||
// @import "~semantic-ui-css/components/breadcrumb.css";
|
||||
@import "~semantic-ui-css/components/form.css";
|
||||
@import "~semantic-ui-css/components/grid.css";
|
||||
@import "~semantic-ui-css/components/menu.css";
|
||||
@import "~semantic-ui-css/components/message.css";
|
||||
@import "~semantic-ui-css/components/table.css";
|
||||
|
||||
/* Views */
|
||||
// @import "~semantic-ui-css/components/ad.css";
|
||||
@import "~semantic-ui-css/components/card.css";
|
||||
// @import "~semantic-ui-css/components/comment.css";
|
||||
// @import "~semantic-ui-css/components/feed.css";
|
||||
@import "~semantic-ui-css/components/item.css";
|
||||
@import "~semantic-ui-css/components/statistic.css";
|
||||
|
||||
/* Modules */
|
||||
// @import "~semantic-ui-css/components/accordion.css";
|
||||
@import "~semantic-ui-css/components/checkbox.css";
|
||||
@import "~semantic-ui-css/components/dimmer.css";
|
||||
@import "~semantic-ui-css/components/dropdown.css";
|
||||
// @import "~semantic-ui-css/components/embed.css";
|
||||
@import "~semantic-ui-css/components/modal.css";
|
||||
// @import "~semantic-ui-css/components/nag.css";
|
||||
@import "~semantic-ui-css/components/popup.css";
|
||||
@import "~semantic-ui-css/components/progress.css";
|
||||
// @import "~semantic-ui-css/components/rating.css";
|
||||
@import "~semantic-ui-css/components/search.css";
|
||||
// @import "~semantic-ui-css/components/shape.css";
|
||||
@import "~semantic-ui-css/components/sidebar.css";
|
||||
@import "~semantic-ui-css/components/sticky.css";
|
||||
@import "~semantic-ui-css/components/tab.css";
|
||||
@import "~semantic-ui-css/components/transition.css";
|
||||
|
||||
|
||||
|
||||
// we do the import here instead in main.js
|
||||
// as resolve order is not deterministric in webpack
|
||||
// and we end up with CSS rules not applied,
|
||||
// see https://github.com/webpack/webpack/issues/215
|
||||
@import "./vendor/media";
|
||||
|
||||
html,
|
||||
body {
|
||||
@include media("<desktop") {
|
||||
font-size: 90%;
|
||||
}
|
||||
}
|
||||
#app {
|
||||
font-family: "Avenir", Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.instance-chooser {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.main.pusher,
|
||||
.footer {
|
||||
@include media(">desktop") {
|
||||
margin-left: 350px !important;
|
||||
margin-top: 50px;
|
||||
}
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.main.pusher > .ui.secondary.menu {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
border: none;
|
||||
box-shadow: inset 0px -2px 0px 0px rgba(34, 36, 38, 0.15);
|
||||
.ui.item {
|
||||
border: none;
|
||||
border-bottom-style: none;
|
||||
margin-bottom: 0px;
|
||||
&.active {
|
||||
box-shadow: inset 0px -2px 0px 0px #000;
|
||||
}
|
||||
}
|
||||
@include media(">tablet") {
|
||||
padding: 0 2.5rem;
|
||||
}
|
||||
@include media(">desktop") {
|
||||
position: fixed;
|
||||
left: 350px;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
z-index: 99;
|
||||
}
|
||||
background-color: white;
|
||||
.item {
|
||||
padding-top: 1.5em;
|
||||
padding-bottom: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.service-messages {
|
||||
position: fixed;
|
||||
bottom: 1em;
|
||||
left: 1em;
|
||||
@include media(">desktop") {
|
||||
left: 350px;
|
||||
}
|
||||
}
|
||||
.main-pusher {
|
||||
padding: 1.5rem 0;
|
||||
}
|
||||
.ui.stripe.segment,
|
||||
#footer {
|
||||
padding: 2em;
|
||||
@include media(">tablet") {
|
||||
padding: 4em;
|
||||
}
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ui.small.text.container {
|
||||
max-width: 500px !important;
|
||||
}
|
||||
|
||||
.button.icon.tiny {
|
||||
padding: 0.5em !important;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
.logo {
|
||||
&.bordered.icon {
|
||||
padding: .5em .41em !important;
|
||||
}
|
||||
path {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.discrete {
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
.link {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ui.really.basic.button {
|
||||
&:not(:focus) {
|
||||
box-shadow: none !important;
|
||||
background-color: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.floated.buttons .button ~ .dropdown {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.ui.icon.header .circular.icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.segment-content .button {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
.segment.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.reset {
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
overflow: visible;
|
||||
|
||||
background: transparent;
|
||||
|
||||
/* inherit font & color from ancestor */
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
|
||||
/* Normalize `line-height`. Cannot be changed from `normal` in Firefox 4+. */
|
||||
line-height: normal;
|
||||
|
||||
/* Corrects font smoothing for webkit */
|
||||
-webkit-font-smoothing: inherit;
|
||||
-moz-osx-font-smoothing: inherit;
|
||||
/* Corrects inability to style clickable `input` types in iOS */
|
||||
-webkit-appearance: none;
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
.ui.table > caption {
|
||||
font-weight: bold;
|
||||
padding: 0.5em;
|
||||
text-align: left;
|
||||
}
|
||||
[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.left.floated {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.right.floated {
|
||||
float: right;
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
/*!
|
||||
* # Semantic UI 2.4.1 - Site
|
||||
* http://github.com/semantic-org/semantic-ui/
|
||||
*
|
||||
*
|
||||
* Released under the MIT license
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*******************************
|
||||
Page
|
||||
*******************************/
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
overflow-x: hidden;
|
||||
min-width: 320px;
|
||||
background: #FFFFFF;
|
||||
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.4285em;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
Headers
|
||||
*******************************/
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5 {
|
||||
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
line-height: 1.28571429em;
|
||||
margin: calc(2rem - 0.14285714em ) 0em 1rem;
|
||||
font-weight: bold;
|
||||
padding: 0em;
|
||||
}
|
||||
h1 {
|
||||
min-height: 1rem;
|
||||
font-size: 2rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.71428571rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.28571429rem;
|
||||
}
|
||||
h4 {
|
||||
font-size: 1.07142857rem;
|
||||
}
|
||||
h5 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
h1:first-child,
|
||||
h2:first-child,
|
||||
h3:first-child,
|
||||
h4:first-child,
|
||||
h5:first-child {
|
||||
margin-top: 0em;
|
||||
}
|
||||
h1:last-child,
|
||||
h2:last-child,
|
||||
h3:last-child,
|
||||
h4:last-child,
|
||||
h5:last-child {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
Text
|
||||
*******************************/
|
||||
|
||||
p {
|
||||
margin: 0em 0em 1em;
|
||||
line-height: 1.4285em;
|
||||
}
|
||||
p:first-child {
|
||||
margin-top: 0em;
|
||||
}
|
||||
p:last-child {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
/*-------------------
|
||||
Links
|
||||
--------------------*/
|
||||
|
||||
a {
|
||||
color: #4183C4;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
color: #1e70bf;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
Scrollbars
|
||||
*******************************/
|
||||
|
||||
|
||||
|
||||
/*******************************
|
||||
Highlighting
|
||||
*******************************/
|
||||
|
||||
|
||||
/* Site */
|
||||
::-webkit-selection {
|
||||
background-color: #CCE2FF;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
::-moz-selection {
|
||||
background-color: #CCE2FF;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
::selection {
|
||||
background-color: #CCE2FF;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
|
||||
/* Form */
|
||||
textarea::-webkit-selection,
|
||||
input::-webkit-selection {
|
||||
background-color: rgba(100, 100, 100, 0.4);
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
textarea::-moz-selection,
|
||||
input::-moz-selection {
|
||||
background-color: rgba(100, 100, 100, 0.4);
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
textarea::selection,
|
||||
input::selection {
|
||||
background-color: rgba(100, 100, 100, 0.4);
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
|
||||
/* Force Simple Scrollbars */
|
||||
body ::-webkit-scrollbar {
|
||||
-webkit-appearance: none;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
body ::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 0px;
|
||||
}
|
||||
body ::-webkit-scrollbar-thumb {
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
-webkit-transition: color 0.2s ease;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
body ::-webkit-scrollbar-thumb:window-inactive {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
body ::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(128, 135, 139, 0.8);
|
||||
}
|
||||
|
||||
/* Inverted UI */
|
||||
body .ui.inverted::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
body .ui.inverted::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
body .ui.inverted::-webkit-scrollbar-thumb:window-inactive {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
body .ui.inverted::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.35);
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
Global Overrides
|
||||
*******************************/
|
||||
|
||||
|
||||
|
||||
/*******************************
|
||||
Site Overrides
|
||||
*******************************/
|
||||
|
|
@ -16,7 +16,7 @@ export default {
|
|||
durationFormatted (v) {
|
||||
let duration = parseInt(v)
|
||||
if (duration % 1 !== 0) {
|
||||
return time.parse(0)
|
||||
return this.parse(0)
|
||||
}
|
||||
duration = Math.round(duration)
|
||||
return this.parse(duration)
|
||||
|
|
|
|||
|
|
@ -142,11 +142,6 @@ export default {
|
|||
"instance__nodeinfo_stats_enabled",
|
||||
"instance__nodeinfo_private"
|
||||
]
|
||||
},
|
||||
{
|
||||
label: errorLabel,
|
||||
id: "reporting",
|
||||
settings: ["raven__front_enabled", "raven__front_dsn"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@
|
|||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
import time from '@/utils/time'
|
||||
import {normalizeQuery, parseTokens, compileTokens} from '@/search'
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
|
||||
<script>
|
||||
import axios from "axios"
|
||||
import _ from "lodash"
|
||||
import _ from "@/lodash"
|
||||
import $ from "jquery"
|
||||
|
||||
import OrderingMixin from "@/components/mixins/Ordering"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {expect} from 'chai'
|
||||
|
||||
import {truncate, markdown, ago, capitalize, year} from '@/filters'
|
||||
import {truncate, ago, capitalize, year} from '@/filters'
|
||||
|
||||
describe('filters', () => {
|
||||
describe('truncate', () => {
|
||||
|
|
@ -20,13 +20,6 @@ describe('filters', () => {
|
|||
expect(output).to.equal('Hello pouet')
|
||||
})
|
||||
})
|
||||
describe('markdown', () => {
|
||||
it('renders markdown', () => {
|
||||
const input = 'Hello world'
|
||||
let output = markdown(input)
|
||||
expect(output).to.equal('<p>Hello world</p>')
|
||||
})
|
||||
})
|
||||
describe('ago', () => {
|
||||
it('works', () => {
|
||||
const input = new Date()
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ describe('store/instance', () => {
|
|||
|
||||
describe('mutations', () => {
|
||||
it('settings', () => {
|
||||
const state = {settings: {raven: {front_dsn: {value: 'test'}}}}
|
||||
let settings = {raven: {front_enabled: {value: true}}}
|
||||
const state = {settings: {users: {upload_quota: {value: 1}}}}
|
||||
let settings = {users: {registration_enabled: {value: true}}}
|
||||
store.mutations.settings(state, settings)
|
||||
expect(state.settings).to.deep.equal({
|
||||
raven: {front_dsn: {value: 'test'}, front_enabled: {value: true}}
|
||||
users: {upload_quota: {value: 1}, registration_enabled: {value: true}}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -32,13 +32,13 @@ describe('store/instance', () => {
|
|||
status: 200,
|
||||
response: [
|
||||
{
|
||||
section: 'raven',
|
||||
name: 'front_dsn',
|
||||
value: 'test'
|
||||
section: 'users',
|
||||
name: 'upload_quota',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
section: 'raven',
|
||||
name: 'front_enabled',
|
||||
section: 'users',
|
||||
name: 'registration_enabled',
|
||||
value: false
|
||||
}
|
||||
]
|
||||
|
|
@ -50,15 +50,15 @@ describe('store/instance', () => {
|
|||
{
|
||||
type: 'settings',
|
||||
payload: {
|
||||
raven: {
|
||||
front_dsn: {
|
||||
section: 'raven',
|
||||
name: 'front_dsn',
|
||||
value: 'test'
|
||||
users: {
|
||||
upload_quota: {
|
||||
section: 'users',
|
||||
name: 'upload_quota',
|
||||
value: 1
|
||||
},
|
||||
front_enabled: {
|
||||
section: 'raven',
|
||||
name: 'front_enabled',
|
||||
registration_enabled: {
|
||||
section: 'users',
|
||||
name: 'registration_enabled',
|
||||
value: false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
var sinon = require('sinon')
|
||||
import {expect} from 'chai'
|
||||
|
||||
import _ from 'lodash'
|
||||
import _ from '@/lodash'
|
||||
|
||||
import store from '@/store/queue'
|
||||
import { testAction } from '../../utils'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,14 @@
|
|||
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const webpack = require('webpack');
|
||||
|
||||
let plugins = [
|
||||
// do not include moment.js locales since it's quite heavy
|
||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||
]
|
||||
if (process.env.BUNDLE_ANALYZE === '1') {
|
||||
plugins.push(new BundleAnalyzerPlugin())
|
||||
}
|
||||
module.exports = {
|
||||
baseUrl: '/front/',
|
||||
pages: {
|
||||
|
|
@ -17,6 +27,7 @@ module.exports = {
|
|||
config.optimization.delete('splitChunks')
|
||||
},
|
||||
configureWebpack: {
|
||||
plugins: plugins,
|
||||
resolve: {
|
||||
alias: {
|
||||
'vue$': 'vue/dist/vue.esm.js'
|
||||
|
|
|
|||
5060
front/yarn.lock
5060
front/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue