added dark mode toggle with animation, continued re-organization of settings tab

This commit is contained in:
Roberto Tonino 2020-05-03 22:08:59 +02:00
parent d3b87a008c
commit 289ffb3ecc
9 changed files with 180 additions and 114 deletions

View File

@ -1,15 +1,10 @@
/* Normalizing */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
transition: background-color 500ms ease-in-out;
}
body {
font-size: 16px;
}
html {
height: 100%;
:root {
--main-background: #ffffff;
--secondary-background: #eeeeee;
--main-text: #333333;
@ -26,8 +21,7 @@ body {
--toast-text: #ffffffde;
}
/* Add to body to switch to dark mode */
.dark-theme {
html[data-theme='dark'] {
--main-background: #141414;
--secondary-background: #242424;
--main-text: #eeeeee;
@ -35,23 +29,12 @@ body {
--panels-text: #ffffff;
}
html {
height: 100%;
}
body {
margin: 0px;
width: 100%;
height: 100%;
font-family: 'Open Sans';
overflow: hidden;
background-color: var(--main-background);
background: var(--main-background);
color: var(--main-text);
}
#main_content {
margin-left: 48px;
width: calc(100% - 48px);
height: 100%;
display: flex;
}

View File

@ -1,4 +1,10 @@
/* Global stuff */
#main_content {
margin-left: 48px;
width: calc(100% - 48px);
height: 100%;
display: flex;
}
img.rounded {
border-radius: 5px;
}
@ -260,3 +266,21 @@ th.sort-desc:after {
font-size: 24px;
padding: 16px;
}
.with_checkbox {
display: flex;
align-items: center;
}
.with_checkbox [type='checkbox'] {
cursor: pointer;
}
.with_checkbox .checkbox_text {
margin-left: 10px;
cursor: pointer;
}
.with_checkbox .checkbox_text::selection {
background: none;
}

View File

@ -7,7 +7,7 @@
}
/* Center section */
#search>#searchbar {
#search > #searchbar {
width: calc(100% - 32px);
height: 32px;
padding: 0px 8px;
@ -15,7 +15,7 @@
border: 0px;
border-radius: 6px;
background-color: var(--secondary-background);
color: var(--primary-text)
color: var(--primary-text);
}
#content {
@ -24,7 +24,7 @@
height: calc(100% - 48px);
overflow-y: scroll;
overflow-x: hidden;
padding-left: 10px
padding-left: 10px;
}
#content::-webkit-scrollbar {
@ -58,8 +58,8 @@
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
background-color: rgb(0, 0, 0); /* Fallback color */
background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */
animation-duration: 0.3s;
}
@ -73,25 +73,28 @@
top: 50%;
transform: translateY(-50%);
}
.smallmodal-content button{
.smallmodal-content button {
width: 100%;
margin-bottom: 8px;
}
@media only screen and (min-width: 601px) {
#container, .smallmodal-content {
#container,
.smallmodal-content {
width: 85%;
}
}
@media only screen and (min-width: 993px) {
#container, .smallmodal-content {
#container,
.smallmodal-content {
width: 70%;
}
}
@media only screen and (max-width: 600px) {
#container, .smallmodal-content {
#container,
.smallmodal-content {
width: 100%;
}
}

9
public/css/modules/normalize.css vendored Normal file
View File

@ -0,0 +1,9 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-size: 16px;
}

View File

@ -57,3 +57,11 @@
.settings_group > * {
margin-bottom: 15px;
}
.input_group {
margin-bottom: 25px;
}
.input_group .input_group_text {
margin-bottom: 7px;
}

View File

@ -3,6 +3,7 @@
@import './vendor/OpenSans.css';
@import './vendor/toastify.css';
@import './modules/normalize.css';
@import './modules/base.css';
@import './modules/globals.css';
@import './modules/progressbar.css';

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<html lang="en" dir="ltr" data-theme="default">
<head>
<meta charset="utf-8">
@ -9,7 +9,7 @@
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=0">
<script>
if ('true' === localStorage.getItem('darkMode')) {
document.documentElement.classList.add('dark-theme')
document.documentElement.setAttribute('data-theme', 'dark')
}
</script>
</head>
@ -165,7 +165,9 @@ <h1>No Tracks found</h1>
v-if="track.preview" class="material-icons preview_controls">play_arrow</i><img
class="rounded coverart" :src="track.album.cover_small">
</td>
<td class="breakline">{{track.title + (track.title_version ? ' '+track.title_version : '')}}</td>
<td class="breakline">
{{ track.title + (track.title_version && track.title.indexOf(track.title_version) == -1 ? ' '+ track.title_version : '') }}
</td>
<td class="breakline clickable" @click="artistView" :data-id="track.artist.id">
{{track.artist.name}}</td>
<td class="breakline clickable" @click="albumView" :data-id="track.album.id">
@ -260,7 +262,9 @@ <h2>Top Tracks</h2>
v-if="track.preview" class="material-icons preview_controls">play_arrow</i><img
class="rounded coverart" :src="track.album.cover_small">
</td>
<td class="breakline">{{track.title + (track.title_version ? ' '+track.title_version : '')}}</td>
<td class="breakline">
{{ track.title + (track.title_version && track.title.indexOf(track.title_version) == -1 ? ' '+ track.title_version : '') }}
</td>
<td class="breakline clickable" @click="artistView" :data-id="track.artist.id">
{{track.artist.name}}</td>
<td class="breakline clickable" @click="albumView" :data-id="track.album.id">
@ -323,15 +327,16 @@ <h2>Top Playlists</h2>
<h1>Charts</h1>
<div v-if='country == ""' id="charts_selection">
<div class="release_grid">
<div v-for="release in countries" class="release clickable" @click="getTrackList" :data-title="release.title" :data-id="release.id">
<div v-for="release in countries" class="release clickable" @click="getTrackList"
:data-title="release.title" :data-id="release.id">
<img class="rounded coverart" :src="release.picture_medium">
</div>
</div>
</div>
<div v-else id="charts_table">
<button @click="changeCountry">Change Country</button>
<button @contextmenu.prevent="openQualityModal"
@click.stop="addToQueue" :data-link="'https://www.deezer.com/playlist/'+id">Download Chart</button>
<button @contextmenu.prevent="openQualityModal" @click.stop="addToQueue"
:data-link="'https://www.deezer.com/playlist/'+id">Download Chart</button>
<table>
<tr v-for="track in chart" class="track_row">
<td class="top-tracks-position" :class="{ first: track.position === 1 }">{{ track.position }}</td>
@ -341,7 +346,9 @@ <h1>Charts</h1>
v-if="track.preview" class="material-icons preview_controls">play_arrow</i><img
class="rounded coverart" :src="track.album.cover_small">
</td>
<td class="breakline">{{track.title + (track.title_version ? ' '+track.title_version : '')}}</td>
<td class="breakline">
{{ track.title + (track.title_version && track.title.indexOf(track.title_version) == -1 ? ' '+ track.title_version : '') }}
</td>
<td class="breakline clickable" @click="artistView" :data-id="track.artist.id">
{{track.artist.name}}</td>
<td class="breakline clickable" @click="albumView" :data-id="track.album.id">
@ -420,6 +427,13 @@ <h2 id="settings_heading">Settings</h2>
<button id="settings_btn_logout" @click="logout">Logout</button>
</div>
<div class="settings_group">
<label class="with_checkbox">
<input type="checkbox" v-model="darkMode">
<span class="checkbox_text">Dark Mode</span>
</label>
</div>
<div class="settings_group">
<h3>Login</h3>
<div class="inline-flex">
@ -455,70 +469,75 @@ <h3>Templates</h3>
<div class="settings_group">
<h3>Folders</h3>
<label class="with_checkbox">
<input type="checkbox" v-model="settings.createPlaylistFolder">
<span class="checkbox_text">Create folder for playlist</span>
</label>
<label><input type="checkbox" v-model="settings.createPlaylistFolder">Create folder for playlist</label>
<div v-if="settings.createPlaylistFolder">
<p>Playlist folder template</p>
<div class="input_group" v-if="settings.createPlaylistFolder">
<p class="input_group_text">Playlist folder template</p>
<input type="text" v-model="settings.playlistNameTemplate">
</div>
<div>
<p>Create folder for artist</p>
<label class="with_checkbox">
<input type="checkbox" v-model="settings.createArtistFolder">
</div>
<span class="checkbox_text">Create folder for artist</span>
</label>
<div v-if="settings.createArtistFolder">
<p>Artist folder template</p>
<div class="input_group" v-if="settings.createArtistFolder">
<p class="input_group_text">Artist folder template</p>
<input type="text" v-model="settings.artistNameTemplate">
</div>
<div>
<p>Create folder for album</p>
<label class="with_checkbox">
<input type="checkbox" v-model="settings.createAlbumFolder">
</div>
<span class="checkbox_text">Create folder for album</span>
</label>
<div v-if="settings.createAlbumFolder">
<p>Album folder template</p>
<div class="input_group" v-if="settings.createAlbumFolder">
<p class="input_group_text">Album folder template</p>
<input type="text" v-model="settings.albumNameTemplate">
</div>
<div>
<p>Create folder for CDs</p>
<label class="with_checkbox">
<input type="checkbox" v-model="settings.createCDFolder">
</div>
<span class="checkbox_text">Create folder for CDs</span>
</label>
<div>
<p>Create folder structure for playlists</p>
<label class="with_checkbox">
<input type="checkbox" v-model="settings.createStructurePlaylist">
</div>
<span class="checkbox_text">Create folder structure for playlists</span>
</label>
<div>
<p>Create folder structure for singles</p>
<label class="with_checkbox">
<input type="checkbox" v-model="settings.createSingleFolder">
</div>
<span class="checkbox_text">Create folder structure for singles</span>
</label>
</div>
<div id="settings_generic_tab">
<div class="input_group">
<div class="settings_group">
<h3>Track titles</h3>
<div>
<p>Pad tracks</p>
<input type="checkbox" v-model="settings.padTracks">
</div>
<div class="input_group">
<div>
<p>Overwrite padding size</p>
<input type="number" v-model="settings.paddingSize">
</div>
<div class="input_group">
<div>
<p>Illegal Character replacer</p>
<input type="text" v-model="settings.illegalCharacterReplacer">
</div>
<div class="input_group">
</div>
<div class="settings_group">
<h3>Downloads</h3>
<div>
<p>Concurrent Downloads</p>
<input type="number" v-model.number="settings.queueConcurrency">
</div>
<div class="input_group">
<div>
<p>Preferred Bitrate</p>
<select v-model="settings.maxBitrate">
<option value="9">FLAC 1411kbps</option>
@ -526,75 +545,84 @@ <h3>Folders</h3>
<option value="1">MP3 128kbps</option>
</select>
</div>
<div class="input_group">
<div>
<p>Bitrate fallback</p>
<input type="checkbox" v-model="settings.fallbackBitrate">
</div>
<div class="input_group">
<div>
<p>Search fallback</p>
<input type="checkbox" v-model="settings.fallbackSearch">
</div>
<div class="input_group">
<div>
<p>Create log file for errors</p>
<input type="checkbox" v-model="settings.logErrors">
</div>
<div class="input_group">
<div>
<p>Create log file for searched tracks</p>
<input type="checkbox" v-model="settings.logSearched">
</div>
<div class="input_group">
<div>
<p>Create playlist file</p>
<input type="checkbox" v-model="settings.createM3U8File">
</div>
<div class="input_group">
<div>
<p>Create .lyr files (Sync Lyrics)</p>
<input type="checkbox" v-model="settings.syncedLyrics">
</div>
<div class="input_group">
</div>
<div class="settings_group">
<h3>Album covers</h3>
<div>
<p>Save covers</p>
<input type="checkbox" v-model="settings.saveArtwork">
</div>
<div class="input_group">
<div>
<p>Cover name template</p>
<input type="text" v-model="settings.coverImageTemplate">
</div>
<div class="input_group">
<div>
<p>Save artist image</p>
<input type="checkbox" v-model="settings.saveArtworkArtist">
</div>
<div class="input_group">
<div>
<p>Artist image name template</p>
<input type="text" v-model="settings.artistImageTemplate">
</div>
<div class="input_group">
<div>
<p>Local artwork size</p>
<input type="number" min="100" max="1800" step="100" v-model.number="settings.localArtworkSize">
</div>
<div class="input_group">
<div>
<p>Embedded artwork size</p>
<input type="number" min="100" max="1800" step="100" v-model.number="settings.embeddedArtworkSize">
</div>
<div class="input_group">
<div>
<p>Save images as png</p>
<input type="checkbox" v-model="settings.PNGcovers">
</div>
<div class="input_group">
<div>
<p>JPEG image quality</p>
<input type="number" min="1" max="100" v-model.number="settings.jpegImageQuality">
</div>
<div class="input_group">
</div>
<div class="settings_group">
<div>
<p>Save playlists as compilation</p>
<input type="checkbox" v-model="settings.tags.savePlaylistAsCompilation">
</div>
<div class="input_group">
<div>
<p>Use null separator</p>
<input type="checkbox" v-model="settings.tags.useNullSeparator">
</div>
<div class="input_group">
<div>
<p>Save ID3v1 as well</p>
<input type="checkbox" v-model="settings.tags.saveID3v1">
</div>
<div class="input_group">
<div>
<p>How would you like to separate your artists?</p>
<select v-model="settings.tags.multitagSeparator">
<option value="default">Using standard specification</option>
@ -608,11 +636,11 @@ <h3>Folders</h3>
<option value="; ">Using "; "</option>
</select>
</div>
<div class="input_group">
<div>
<p>Remove album version from track title</p>
<input type="checkbox" v-model="settings.removeAlbumVersion">
</div>
<div class="input_group">
<div>
<p>Date format for FLAC files</p>
<select v-model="settings.dateFormat">
<option value="Y-M-D">YYYY-MM-DD</option>
@ -622,7 +650,7 @@ <h3>Folders</h3>
<option value="Y">YYYY</option>
</select>
</div>
<div class="input_group">
<div>
<p>What should I do with featured artists</p>
<select v-model="settings.featuredToTitle">
<option value="0">Nothing</option>
@ -630,7 +658,7 @@ <h3>Folders</h3>
<option value="2">Move it to the title</option>
</select>
</div>
<div class="input_group">
<div>
<p>Title casing</p>
<select v-model="settings.titleCasing">
<option value="nothing">Keep unchanged</option>
@ -640,7 +668,7 @@ <h3>Folders</h3>
<option value="sentence">Like a sentence</option>
</select>
</div>
<div class="input_group">
<div>
<p>Artist casing</p>
<select v-model="settings.artistCasing">
<option value="nothing">Keep unchanged</option>
@ -650,18 +678,18 @@ <h3>Folders</h3>
<option value="sentence">Like a sentence</option>
</select>
</div>
<div class="input_group">
<div>
<p>Command to execute after download</p>
<p class="secondary-text">Leave blank for no action</p>
<input type="text" v-model="settings.executeCommand">
</div>
</div>
<div id="settings_spotify_tab">
<div class="input_group">
<div>
<p>Spotify clientID</p>
<input type="text" v-model="spotifyFeatures.clientId">
</div>
<div class="input_group">
<div>
<p>Spotify Client Secret</p>
<input type="password" v-model="spotifyFeatures.clientSecret">
</div>
@ -748,7 +776,7 @@ <h2 class="inline-flex"><span v-if="metadata">{{ metadata }}</span><span class="
:data-preview="track.preview">play_arrow</i></td>
<td>{{ track.track_position }}</td>
<td class="inline-flex"><i v-if="track.explicit_lyrics"
class="material-icons">explicit</i>{{ track.title + (track.title_version && track.title.indexOf(track.title_version) == -1 ? ' '+track.title_version : '') }}
class="material-icons">explicit</i>{{ track.title + (track.title_version && track.title.indexOf(track.title_version) == -1 ? ' '+ track.title_version : '') }}
</td>
<td class="clickable" @click="artistView" :data-id="track.artist.id">
{{ track.artist.name }}</td>
@ -814,4 +842,4 @@ <h2 class="inline-flex"><span v-if="metadata">{{ metadata }}</span><span class="
<script type="module" src="/public/js/app.js"></script>
</html>
</html>

View File

@ -2,13 +2,23 @@ import { toast } from '../toasts.js'
import { socket } from '../socket.js'
const SettingsTab = new Vue({
data() {
return {
settings: { tags: {} },
lastSettings: {},
lastCredentials: {},
spotifyFeatures: {},
defaultSettings: {}
data: () => ({
settings: { tags: {} },
lastSettings: {},
lastCredentials: {},
spotifyFeatures: {},
defaultSettings: {}
}),
computed: {
darkMode: {
get() {
return 'true' === localStorage.getItem('darkMode')
},
set(wantDarkMode) {
document.documentElement.setAttribute('data-theme', wantDarkMode ? 'dark' : 'default')
localStorage.setItem('darkMode', wantDarkMode)
}
}
},
methods: {
@ -28,7 +38,7 @@ const SettingsTab = new Vue({
this.lastCredentials = { ...SettingsTab.spotifyFeatures }
socket.emit('saveSettings', this.lastSettings, this.lastCredentials)
},
loadSettings(settings, spotifyCredentials, defaults=null) {
loadSettings(settings, spotifyCredentials, defaults = null) {
if (defaults) this.defaultSettings = { ...defaults }
this.lastSettings = { ...settings }
this.lastCredentials = { ...spotifyCredentials }
@ -52,7 +62,7 @@ const SettingsTab = new Vue({
this.loadSettings(settings, credentials)
toast('Settings updated!', 'settings')
},
resetSettings(){
resetSettings() {
this.settings = { ...this.defaultSettings }
}
},

View File

@ -5,7 +5,7 @@ import QualityModal from '../quality-modal.js'
import TrackPreview from '../track-preview.js'
const TracklistTab = new Vue({
data: {
data: () => ({
title: '',
metadata: '',
release_date: '',
@ -16,7 +16,7 @@ const TracklistTab = new Vue({
link: '',
head: null,
body: []
},
}),
methods: {
artistView,
albumView,
@ -32,21 +32,21 @@ const TracklistTab = new Vue({
this.head = []
this.body = []
},
addToQueue: function (e) {
addToQueue(e) {
e.stopPropagation()
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
},
openQualityModal: function (e) {
openQualityModal(e) {
QualityModal.open(e.currentTarget.dataset.link)
},
toggleAll: function (e) {
toggleAll(e) {
this.body.forEach(item => {
if (item.type == 'track') {
item.selected = e.currentTarget.checked
}
})
},
selectedLinks: function () {
selectedLinks() {
var selected = []
if (this.body) {
this.body.forEach(item => {