1
0
mirror of https://github.com/devfake/flox.git synced 2024-11-14 22:22:39 +01:00

change settings page (#31)

* prepare languages

* prepare routes

* split settings into smaller components

* move debounce and vue-router into vendor

* remove dependency from index

* refactor

* update method comment
This commit is contained in:
Viktor Geringer 2017-01-27 10:25:43 +01:00 committed by Tim Meier
parent a43b3bc3cd
commit a50a7d7c5b
22 changed files with 523 additions and 260 deletions

View File

@ -70,7 +70,7 @@
$this->item->truncate();
foreach($data->items as $item) {
$this->item->create((array) $item);
$this->storage->createPosterFile($item->poster);
$this->storage->downloadPoster($item->poster);
}
$this->episodes->truncate();
@ -149,9 +149,19 @@
}
/**
* Save new user settings.
* @return array
*/
public function changeSettings()
public function getVersion()
{
return [
'version' => $this->version,
];
}
/**
* Update new settings.
*/
public function updateSettings()
{
$this->setting->first()->update([
'show_genre' => Input::get('genre'),

View File

@ -37,6 +37,16 @@
return response('Unauthorized', 401);
}
/**
* @return array
*/
public function getUserData()
{
return [
'username' => Auth::user()->username,
];
}
/**
* Save new user credentials.
*

View File

@ -23,9 +23,12 @@
Route::get('/sync-scout', 'SettingController@syncScout');
Route::patch('/update-genre', 'SettingController@updateGenre');
Route::patch('/settings', 'SettingController@changeSettings');
Route::patch('/settings', 'SettingController@updateSettings');
Route::patch('/update-alternative-titles/{tmdbID?}', 'ItemController@updateAlternativeTitles');
Route::get('/version', 'SettingController@getVersion');
Route::get('/userdata', 'UserController@getUserData');
Route::patch('/userdata', 'UserController@changeUserData');
Route::patch('/toggle-episode/{id}', 'ItemController@toggleEpisode');
Route::patch('/toggle-season', 'ItemController@toggleSeason');

View File

@ -33,20 +33,26 @@
<script>
import http from 'axios';
import debounce from 'debounce';
import Helper from '../../helper';
import { mapMutations, mapActions } from 'vuex';
const debounceMilliseconds = 700;
export default {
mixins: [Helper],
props: ['item', 'genre', 'date'],
created() {
this.saveNewRating = debounce(this.saveNewRating, debounceMilliseconds);
},
data() {
return {
localItem: this.item,
latestEpisode: this.item.latest_episode,
saveTimeout: null,
auth: config.auth,
prevRating: null,
rated: false,
@ -131,14 +137,10 @@
changeRating() {
if(this.auth) {
clearTimeout(this.saveTimeout);
this.prevRating = this.localItem.rating;
this.localItem.rating = this.prevRating == 3 ? 1 : +this.prevRating + 1;
this.saveTimeout = setTimeout(() => {
this.saveNewRating();
}, 500);
this.saveNewRating();
}
},

View File

@ -1,203 +0,0 @@
<template>
<main>
<div class="wrap-content" v-if=" ! loading">
<div class="version-wrap">
<span class="current-version">{{ lang('current version') }} <span>{{ version }}</span></span>
<span class="update-check" v-if=" ! isUpdate">{{ updateMessage }}</span>
<span class="update-check" v-if="isUpdate">
<a href="https://github.com/devfake/flox/releases" target="_blank" class="new-update">{{ lang('new update') }}</a>
</span>
</div>
<div class="settings-box">
<span class="nothing-found">{{ lang('headline user') }}</span>
<form class="login-form" @submit.prevent="editUser()">
<input type="text" :placeholder="lang('username')" v-model="username">
<input type="password" :placeholder="lang('password')" v-model="password" autocomplete="off">
<span class="userdata-info">{{ lang('password message') }}</span>
<span class="userdata-changed"><span v-if="success">{{ lang('success message') }}</span></span>
<input type="submit" :value="lang('save button')">
</form>
</div>
<div class="settings-box">
<span class="nothing-found">{{ lang('headline export import') }}</span>
<a :href="exportLink" class="export-btn">{{ lang('export button') }}</a>
<form class="login-form" @submit.prevent="importMovies()">
<span class="import-info">{{ lang('or divider') }}</span>
<input type="file" @change="upload" class="file-btn" required>
<span class="userdata-changed"><span v-if="uploadSuccess">{{ lang('success import') }}</span></span>
<input type="submit" :value="lang('import button')">
</form>
</div>
<div class="settings-box">
<span class="nothing-found">{{ lang('headline misc') }}</span>
<button @click="updateGenre()" class="export-btn">{{ lang('update genre') }}</button>
<span class="import-info">{{ lang('or divider') }}</span>
<button @click="updateAlternativeTitles()" class="export-btn">Update alternative titles</button>
<span class="import-info">{{ lang('or divider') }}</span>
<button @click="syncScout()" class="export-btn">{{ lang('sync scout') }}</button>
<span class="import-info">{{ lang('or divider') }}</span>
<div class="checkbox">
<input type="checkbox" value="genre" v-model="displayGenre" id="genre" @change="updateSettings"><label for="genre">{{ lang('display genre') }}</label>
</div>
<div class="checkbox">
<input type="checkbox" value="date" v-model="displayDate" id="date" @change="updateSettings"><label for="date">{{ lang('display date') }}</label>
</div>
<div class="checkbox">
<input type="checkbox" value="spoiler" v-model="spoilerProtection" id="spoiler" @change="updateSettings"><label for="spoiler">{{ lang('spoiler') }}</label>
</div>
</div>
</div>
<span class="loader fullsize-loader" v-if="loading"><i></i></span>
</main>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
import Helper from '../../helper';
import http from 'axios';
export default {
mixins: [Helper],
created() {
this.checkUpdate();
this.fetchSettings();
},
data() {
return {
username: '',
password: '',
version: '',
isUpdate: null,
displayGenre: null,
displayDate: null,
spoilerProtection: null,
success: false,
uploadSuccess: false,
uploadedFile: null
}
},
computed: {
...mapState({
loading: state => state.loading
}),
exportLink() {
return config.api + '/export';
},
updateMessage() {
if(this.isUpdate === false) {
return this.lang('no update');
}
return this.lang('checking update');
}
},
methods: {
...mapMutations([ 'SET_LOADING' ]),
upload(event) {
const file = event.target.files || event.dataTransfer.files;
this.uploadedFile = new FormData();
this.uploadedFile.append('import', file[0]);
},
updateSettings() {
const date = this.displayDate;
const genre = this.displayGenre;
const spoiler = this.spoilerProtection;
http.patch(`${config.api}/settings`, {date, genre, spoiler}).catch(error => {
alert('Error');
});
},
importMovies() {
if(this.uploadedFile) {
const confirm = window.confirm(this.lang('import warn'));
if(confirm) {
this.SET_LOADING(true);
http.post(`${config.api}/import`, this.uploadedFile).then(value => {
this.SET_LOADING(false);
this.uploadSuccess = true;
}, error => {
this.SET_LOADING(false);
alert('Error: ' + error.data);
});
}
}
},
checkUpdate() {
http(`${config.api}/check-update`).then(response => {
this.isUpdate = response.data;
});
},
fetchSettings() {
this.SET_LOADING(true);
http(`${config.api}/settings`).then(value => {
const data = value.data;
this.SET_LOADING(false);
this.username = data.username;
this.displayGenre = data.genre;
this.displayDate = data.date;
this.version = data.version;
this.spoilerProtection = data.spoiler;
});
},
editUser() {
const username = this.username;
const password = this.password;
if(username != '') {
http.patch(`${config.api}/userdata`, {username, password}).then(value => {
this.success = true;
this.clearSuccessMessage();
});
}
},
updateGenre() {
this.SET_LOADING(true);
http.patch(`${config.api}/update-genre`).then(value => {
this.SET_LOADING(false);
});
},
updateAlternativeTitles() {
this.SET_LOADING(true);
http.patch(`${config.api}/update-alternative-titles`).then(value => {
this.SET_LOADING(false);
});
},
syncScout() {
this.SET_LOADING(true);
http(`${config.api}/sync-scout`).then(value => {
this.SET_LOADING(false);
});
},
clearSuccessMessage() {
setTimeout(() => {
this.success = false;
}, 2000);
}
}
}
</script>

View File

@ -0,0 +1,71 @@
<template>
<div class="settings-box" v-if=" ! loading">
<a :href="exportLink" class="export-btn">{{ lang('export button') }}</a>
<form class="login-form" @submit.prevent="importMovies()">
<span class="import-info">{{ lang('or divider') }}</span>
<input type="file" @change="upload" class="file-btn" required>
<span class="userdata-changed"><span v-if="uploadSuccess">{{ lang('success import') }}</span></span>
<input type="submit" :value="lang('import button')">
</form>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
import Helper from '../../../helper';
import http from 'axios';
export default {
mixins: [Helper],
data() {
return {
uploadSuccess: false,
uploadedFile: null
}
},
computed: {
...mapState({
loading: state => state.loading
}),
exportLink() {
return config.api + '/export';
}
},
methods: {
...mapMutations([ 'SET_LOADING' ]),
upload(event) {
const file = event.target.files || event.dataTransfer.files;
this.uploadedFile = new FormData();
this.uploadedFile.append('import', file[0]);
},
importMovies() {
if(this.uploadedFile) {
const confirm = window.confirm(this.lang('import warn'));
if(confirm) {
this.SET_LOADING(true);
http.post(`${config.api}/import`, this.uploadedFile).then(() => {
this.SET_LOADING(false);
this.uploadSuccess = true;
}, error => {
this.SET_LOADING(false);
alert('Error: ' + error.data);
});
}
}
}
}
}
</script>

View File

@ -0,0 +1,57 @@
<template>
<main>
<div class="wrap-content">
<div class="navigation-tab no-select">
<span :class="{active: activeTab == 'user'}" @click="changeActiveTab('user')">{{ lang('tab user') }}</span>
<span :class="{active: activeTab == 'options'}" @click="changeActiveTab('options')">{{ lang('tab options') }}</span>
<span :class="{active: activeTab == 'backup'}" @click="changeActiveTab('backup')">{{ lang('tab backup') }}</span>
<span :class="{active: activeTab == 'misc'}" @click="changeActiveTab('misc')">{{ lang('tab misc') }}</span>
</div>
<span class="loader fullsize-loader" v-if="loading"><i></i></span>
<user v-if="activeTab == 'user'"></user>
<options v-if="activeTab == 'options'"></options>
<backup v-if="activeTab == 'backup'"></backup>
<misc v-if="activeTab == 'misc'"></misc>
</div>
</main>
</template>
<script>
import User from './User.vue';
import Options from './Options.vue';
import Backup from './Backup.vue';
import Misc from './Misc.vue';
import { mapState } from 'vuex';
import Helper from '../../../helper';
export default {
mixins: [Helper],
components: {
User, Options, Backup, Misc
},
data() {
return {
activeTab: 'user'
}
},
computed: {
...mapState({
loading: state => state.loading
})
},
methods: {
changeActiveTab(tab) {
this.activeTab = tab;
}
}
}
</script>

View File

@ -0,0 +1,100 @@
<template>
<div class="settings-box" v-if=" ! loading">
<div class="version-wrap">
<span class="current-version">{{ lang('current version') }} <span>{{ version }}</span></span>
<span class="update-check" v-if=" ! isUpdate">{{ updateMessage }}</span>
<span class="update-check" v-if="isUpdate">
<a href="https://github.com/devfake/flox/releases" target="_blank" class="new-update">{{ lang('new update') }}</a>
</span>
</div>
<div class="misc-btn-wrap">
<button @click="updateGenre()" class="export-btn">{{ lang('update genre') }}</button>
<button @click="updateAlternativeTitles()" class="export-btn">Update alternative titles</button>
<button @click="syncScout()" class="export-btn">{{ lang('sync scout') }}</button>
</div>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
import Helper from '../../../helper';
import http from 'axios';
export default {
mixins: [Helper],
created() {
this.checkUpdate();
this.fetchVersion();
},
data() {
return {
version: '',
isUpdate: null
}
},
computed: {
...mapState({
loading: state => state.loading
}),
updateMessage() {
if(this.isUpdate === false) {
return this.lang('no update');
}
return this.lang('checking update');
}
},
methods: {
...mapMutations([ 'SET_LOADING' ]),
checkUpdate() {
http(`${config.api}/check-update`).then(response => {
this.isUpdate = response.data;
});
},
fetchVersion() {
this.SET_LOADING(true);
http(`${config.api}/version`).then(response => {
this.SET_LOADING(false);
this.version = response.data.version;
});
},
updateGenre() {
this.SET_LOADING(true);
http.patch(`${config.api}/update-genre`).then(() => {
this.SET_LOADING(false);
});
},
updateAlternativeTitles() {
this.SET_LOADING(true);
http.patch(`${config.api}/update-alternative-titles`).then(() => {
this.SET_LOADING(false);
});
},
syncScout() {
this.SET_LOADING(true);
http(`${config.api}/sync-scout`).then(() => {
this.SET_LOADING(false);
});
}
}
}
</script>

View File

@ -0,0 +1,75 @@
<template>
<div class="settings-box no-select" v-if=" ! loading">
<div class="checkbox">
<input type="checkbox" value="genre" v-model="genre" id="genre" @change="updateOptions"><label for="genre">{{ lang('display genre') }}</label>
</div>
<div class="checkbox">
<input type="checkbox" value="date" v-model="date" id="date" @change="updateOptions"><label for="date">{{ lang('display date') }}</label>
</div>
<div class="checkbox">
<input type="checkbox" value="spoiler" v-model="spoiler" id="spoiler" @change="updateOptions"><label for="spoiler">{{ lang('spoiler') }}</label>
</div>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
import Helper from '../../../helper';
import http from 'axios';
import debounce from 'debounce';
const debounceMilliseconds = 700;
export default {
mixins: [Helper],
created() {
this.fetchOptions();
this.updateOptions = debounce(this.updateOptions, debounceMilliseconds);
},
data() {
return {
genre: null,
date: null,
spoiler: null,
}
},
computed: {
...mapState({
loading: state => state.loading
})
},
methods: {
...mapMutations([ 'SET_LOADING' ]),
fetchOptions() {
this.SET_LOADING(true);
http(`${config.api}/settings`).then(response => {
const data = response.data;
this.SET_LOADING(false);
this.genre = data.genre;
this.date = data.date;
this.spoiler = data.spoiler;
});
},
updateOptions() {
const date = this.date;
const genre = this.genre;
const spoiler = this.spoiler;
http.patch(`${config.api}/settings`, {date, genre, spoiler}).catch(() => {
alert('Error');
});
},
}
}
</script>

View File

@ -0,0 +1,75 @@
<template>
<div class="settings-box" v-if=" ! loading">
<form class="login-form" @submit.prevent="editUser()">
<input type="text" :placeholder="lang('username')" v-model="username">
<input type="password" :placeholder="lang('password')" v-model="password" autocomplete="off">
<span class="userdata-info">{{ lang('password message') }}</span>
<span class="userdata-changed"><span v-if="success">{{ lang('success message') }}</span></span>
<input type="submit" :value="lang('save button')">
</form>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
import Helper from '../../../helper';
import http from 'axios';
import debounce from 'debounce';
const debounceMilliseconds = 2000;
export default {
mixins: [Helper],
created() {
this.fetchUserData();
this.clearSuccessMessage = debounce(this.clearSuccessMessage, debounceMilliseconds);
},
data() {
return {
username: '',
password: '',
success: false
}
},
computed: {
...mapState({
loading: state => state.loading
})
},
methods: {
...mapMutations([ 'SET_LOADING' ]),
fetchUserData() {
this.SET_LOADING(true);
http(`${config.api}/settings`).then(response => {
this.SET_LOADING(false);
this.username = response.data.username;
});
},
editUser() {
const username = this.username;
const password = this.password;
if(username != '') {
http.patch(`${config.api}/userdata`, {username, password}).then(() => {
this.success = true;
this.clearSuccessMessage();
});
}
},
clearSuccessMessage() {
this.success = false;
}
}
}
</script>

View File

@ -5,7 +5,7 @@ import config from './config';
import Content from './components/Content/Content.vue';
import SearchContent from './components/Content/SearchContent.vue';
import Settings from './components/Content/Settings.vue';
import Settings from './components/Content/Settings/Index.vue';
import TMDBContent from './components/Content/TMDBContent.vue';
Vue.use(Router);

View File

@ -7,6 +7,7 @@
"dependencies": {
"axios": "^0.15.2",
"babel-runtime": "^6.11.6",
"debounce": "^1.0.0",
"vue": "^2.0.1",
"vue-router": "^2.0.0",
"vuex": "^2.0.0"

View File

@ -22,9 +22,11 @@
"settings": "إعدادات",
"logout": "تسجيل الخروج",
"headline user": "ألمستخدم",
"headline export import": "الاستيراد والتصدير",
"headline misc": "متنوع",
"tab user": "ألمستخدم",
"tab options": "Options",
"tab backup": "Backup",
"tab misc": "متنوع",
"save button": "حفظ",
"password message": "أترك الحقل كلمة المرور فارغا إذا كنت لا ترغب في تغييرها",
"success message": "تم التغيير بنجاح",
@ -35,7 +37,7 @@
"sync scout": "مزامنة Laravel Scout",
"display genre": "عرص الصنف",
"display date": "عرض التاريخ",
"success import": "تم استراد الأفلام بناجاح",
"success import": "Successful imported",
"import warn": "سيتم استبدال جميع الأفلام. تأكد من أنك قد قدمت نسخة احتياطية!",
"current version": "النسخة الحالية:",
"new update": "هناك تحديثا جديدا لflox!",

View File

@ -22,9 +22,11 @@
"settings": "Indstillinger",
"logout": "Log ud",
"headline user": "Bruger",
"headline export import": "Exportér / Importér",
"headline misc": "Diverse",
"tab user": "Bruger",
"tab options": "Options",
"tab backup": "Backup",
"tab misc": "Diverse",
"save button": "Gem",
"password message": "Efterlad dette adgangkodefelt blankt hvis du ikke vil ændre det",
"success message": "Succesfuldt ændret",
@ -35,7 +37,7 @@
"sync scout": "Synkronisér Laravel Scout",
"display genre": "Vis genre",
"display date": "Vis dato",
"success import": "Film succesfuldt importeret",
"success import": "Succesfuldt importeret",
"import warn": "Alle film vil blive erstattet. Vær sikker på du laver en sikkerhedskopi!",
"current version": "Nuværende version:",
"new update": "Der er en ny opdatering til flox!",

View File

@ -22,9 +22,11 @@
"settings": "Einstellungen",
"logout": "Ausloggen",
"headline user": "Benutzer",
"headline export import": "Exportieren / Importieren",
"headline misc": "Sonstiges",
"tab user": "Benutzer",
"tab options": "Optionen",
"tab backup": "Backup",
"tab misc": "Sonstiges",
"save button": "Speichern",
"password message": "Lasse das Passwort-Feld leer, wenn du es nicht ändern willst",
"success message": "Erfolgreich gespeichert",
@ -32,10 +34,10 @@
"import button": "Importieren",
"or divider": "ODER",
"update genre": "Genre aktualisieren",
"sync scout": "Synchronisieren Laravel Scout",
"sync scout": "Sync Laravel Scout",
"display genre": "Genre anzeigen",
"display date": "Datum anzeigen",
"success import": "Filme wurden erfolgreich importiert",
"success import": "Erfolgreich importiert",
"import warn": "Durch den Import werden alle Filme ersetzt. Erstelle vorher ein Backup!",
"current version": "Aktuelle Version:",
"new update": "Ein neues Update ist vorhanden",

View File

@ -22,9 +22,11 @@
"settings": "Ρυθμίσεις",
"logout": "Αποσύνδεση",
"headline user": "Χρήστης",
"headline export import": "Εξαγωγή / ΕΙσαγωγή",
"headline misc": "Διάφορα",
"tab user": "Χρήστης",
"tab options": "Options",
"tab backup": "Backup",
"tab misc": "Διάφορα",
"save button": "Αποθήκευση",
"password message": "Άφησε το πεδίο του κωδικού κενό αν δεν θέλεις να το αλλάξεις",
"success message": "Επιτυχής αλλαγή",
@ -35,7 +37,7 @@
"sync scout": "Συγχρονισμός Laravel Scout",
"display genre": "Εμφάνιση είδους",
"display date": "Εμφάνιση ημερομηνίας",
"success import": "Επιτυχής εισαγωγή ταινιών",
"success import": "Successful imported",
"import warn": "Όλες οι ταινίες θα αντικατασταθούν. Σιγουρέψου ότι έχεις κρατήσει αντίγραφο ασφαλείας!",
"current version": "Τρέχουσα έκδοση:",
"new update": "Υπάρχει μια νέα ενημερωμένη έκδοση για Flox!",

View File

@ -22,9 +22,11 @@
"settings": "Settings",
"logout": "Logout",
"headline user": "User",
"headline export import": "Export / Import",
"headline misc": "Misc",
"tab user": "User",
"tab options": "Options",
"tab backup": "Backup",
"tab misc": "Misc",
"save button": "Save",
"password message": "Leave the password field blank if you don't want to change it",
"success message": "Successful changed",
@ -35,7 +37,7 @@
"sync scout": "Sync Laravel Scout",
"display genre": "Display genre",
"display date": "Display date",
"success import": "Movies successful imported",
"success import": "Successful imported",
"import warn": "All movies will be replaced. Be sure you have made an backup!",
"current version": "Current version:",
"new update": "There is a new update for flox!",

View File

@ -22,9 +22,11 @@
"settings": "Préférences",
"logout": "Se déconnecter",
"headline user": "Utilisateur",
"headline export import": "Exporter / Importer",
"headline misc": "Divers",
"tab user": "Utilisateur",
"tab options": "Options",
"tab backup": "Backup",
"tab misc": "Divers",
"save button": "Sauvegarder",
"password message": "Laisser vide le champ du mot de passe sil ne faut pas le changer",
"success message": "Sauvegarde réussie",
@ -35,7 +37,7 @@
"sync scout": "Synchroniser Laravel Scout",
"display genre": "Afficher genre",
"display date": "Afficher date",
"success import": "Films importés avec succès",
"success import": "Importés avec succès",
"import warn": "Tous les films seront remplacés. Il est recommandé de faire une sauvegarde avant de continuer",
"current version": "Version actuelle:",
"new update": "Il existe une nouvelle mise à jour pour flox!",

View File

@ -22,9 +22,11 @@
"settings": "Instellingen",
"logout": "Logout",
"headline user": "Gebruiker",
"headline export import": "Exporteer / Importeer",
"headline misc": "Diversen",
"tab user": "Gebruiker",
"tab options": "Options",
"tab backup": "Backup",
"tab misc": "Diversen",
"save button": "Sla op",
"password message": "Laat het wachtwoord vak leeg als je het niet wil veranderen",
"success message": "Successvol veranderd",
@ -35,7 +37,7 @@
"sync scout": "Synchroniseer Laravel Scout",
"display genre": "Weergeef genre",
"display date": "Weergeef datum",
"success import": "Films successful geïmporteerd",
"success import": "Successful geïmporteerd",
"import warn": "Alle films worden vervangen. Zorg dat je een backup hebt!",
"current version": "Huidige versie:",
"new update": "Er is een nieuwe update voor Flox!",

View File

@ -90,7 +90,7 @@ main {
height: 270px;
background: $dark;
float: left;
box-shadow: 0 5px 10px 0 rgba(0,0,0,.5);
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .5);
}
.item-content {
@ -154,7 +154,7 @@ main {
width: 50px;
height: 50px;
transform: translate(-50%, -50%);
box-shadow: 0 0 15px 0 rgba(0,0,0,.7);
box-shadow: 0 0 15px 0 rgba(0, 0, 0, .7);
border-radius: 25px;
.logged & {
@ -189,6 +189,7 @@ main {
background: url(../../../public/assets/img/rating-1.png);
}
}
.rating-2 {
background: $rating2;
@ -196,6 +197,7 @@ main {
background: url(../../../public/assets/img/rating-2.png);
}
}
.rating-3 {
background: $rating3;
@ -307,7 +309,6 @@ main {
@include transition(opacity, bottom);
&:hover {
.logged & {
opacity: 1 !important;
@ -381,10 +382,48 @@ main {
}
}
.navigation-tab {
float: left;
width: 100%;
margin: 0 0 80px 0;
span {
color: gray;
font-size: 17px;
float: left;
margin: 0 20px 0 0;
border-bottom: 2px solid transparent;
cursor: pointer;
@include media(6) {
width: 50%;
text-align: center;
margin: 0 0 20px 0;
}
&:active {
opacity: .6;
}
&.active {
color: $main2;
border-bottom: 2px solid $main2;
@include media(6) {
border-bottom: 2px solid transparent;
}
}
&:last-child {
margin: 0;
}
}
}
.version-wrap {
float: left;
width: 100%;
margin: 0 0 30px 0;
margin: 0 0 50px 0;
color: gray;
}
@ -444,8 +483,7 @@ main {
.settings-box {
float: left;
width: 250px;
margin: 0 160px 0 0;
width: 100%;
&:last-child {
margin: 0;
@ -455,11 +493,6 @@ main {
clear: both;
margin: 0 0 30px 0;
}
@include media(4) {
width: 100%;
margin: 0 0 50px 0 !important;
}
}
.checkbox {
@ -467,6 +500,10 @@ main {
width: 100%;
margin: 0 0 10px 0;
&:active {
opacity: .6;
}
input {
float: left;
margin: 5px 0 0 0;
@ -476,11 +513,8 @@ main {
float: left;
font-size: 15px;
margin: 0 0 0 10px;
max-width: 200px;
@include media(4) {
max-width: none;
}
cursor: pointer;
width: calc(100% - 30px);
}
.dark & {
@ -526,6 +560,19 @@ main {
}
}
.misc-btn-wrap {
float: left;
width: 100%;
.export-btn {
margin: 0 20px 20px 0;
&:last-child {
margin-right: 0;
}
}
}
.export-btn {
background: $main2;
background: linear-gradient(to right, $main1, $main2);

View File

@ -21,6 +21,7 @@
.login-form {
float: left;
max-width: 300px;
width: 100%;
input[type="text"],

View File

@ -7,7 +7,7 @@ const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: {
app: './app/app.js',
vendor: ['vue', 'axios', 'vuex']
vendor: ['vue', 'axios', 'vuex', 'debounce', 'vue-router']
},
output: {
path: path.resolve('../public/assets'),