Merge master

This commit is contained in:
An Phan 2016-11-13 09:59:59 +08:00
commit 09ca3a4b9a
No known key found for this signature in database
GPG key ID: 05536BB4BCDC02A2
41 changed files with 223 additions and 6814 deletions

View file

@ -6,10 +6,7 @@ var gutils = require('gulp-util');
elixir.config.js.browserify.transformers.push({
name: 'vueify',
options: {
postcss: [cssnext()]
}
options: { postcss: [cssnext()] }
});
if (gutils.env._.indexOf('watch') > -1) {
@ -29,7 +26,6 @@ elixir(function (mix) {
mix.scripts([
'node_modules/babel-polyfill/dist/polyfill.min.js',
'node_modules/plyr/dist/plyr.js',
'node_modules/rangetouch/dist/rangetouch.js',
'resources/assets/js/libs/modernizr-custom.js'
], 'public/js/vendors.js', './')
.styles([

View file

@ -27,7 +27,8 @@
"gulp": "^3.9.0",
"gulp-util": "^3.0.7",
"ismobilejs": "^0.4.0",
"jquery": "^2.2.1",
"jquery": "^3.1.1",
"jsdom": "^9.2.1",
"laravel-elixir": "^5.0.0",
"local-storage": "^1.4.2",
"lodash": "^4.6.1",
@ -35,8 +36,7 @@
"nprogress": "^0.2.0",
"plyr": "1.5.x",
"postcss-cssnext": "^2.6.0",
"rangeslider.js": "^2.1.1",
"rangetouch": "0.0.9",
"rangeslider.js": "^2.2.1",
"select": "^1.0.6",
"sinon": "^1.17.2",
"sweetalert": "^1.1.3",

View file

@ -9,15 +9,15 @@
@keydown.mediaNext = "playNext"
@keydown.mediaToggle = "togglePlayback"
>
<site-header></site-header>
<main-wrapper></main-wrapper>
<site-footer></site-footer>
<overlay ref="overlay"></overlay>
<edit-songs-form ref="editSongsForm"></edit-songs-form>
<site-header/>
<main-wrapper/>
<site-footer/>
<overlay ref="overlay"/>
<edit-songs-form ref="editSongsForm"/>
</div>
<div class="login-wrapper" v-if="!authenticated">
<login-form></login-form>
<login-form/>
</div>
</div>
</template>

View file

@ -1,8 +1,8 @@
<template>
<form @submit.prevent="login" :class="{ error: failed }">
<input v-model="email" type="email" placeholder="Email Address" autofocus required>
<input v-model="password" type="password" placeholder="Password" required>
<button type="submit">Log In</button>
<input v-model="email" type="email" placeholder="Email Address" autofocus required>
<input v-model="password" type="password" placeholder="Password" required>
<button type="submit">Log In</button>
</form>
</template>

View file

@ -7,16 +7,13 @@
</h1>
<div v-if="album.info">
<img v-if="album.info.image" :src="album.info.image"
title=""
class="cover">
<img v-if="album.info.image" :src="album.info.image" class="cover">
<div class="wiki" v-if="album.info.wiki && album.info.wiki.summary">
<div class="summary" v-show="mode !== 'full' && !showingFullWiki" v-html="album.info.wiki.summary"></div>
<div class="full" v-show="mode === 'full' || showingFullWiki" v-html="album.info.wiki.full"></div>
<div class="summary" v-show="showSummary" v-html="album.info.wiki.summary"/>
<div class="full" v-show="showFull" v-html="album.info.wiki.full"/>
<button class="more" v-show="mode !== 'full' && !showingFullWiki"
@click.prevent="showingFullWiki = !showingFullWiki">
<button class="more" v-show="showSummary" @click.prevent="showingFullWiki = true">
Full Wiki
</button>
</div>
@ -57,6 +54,16 @@ export default {
},
},
computed: {
showSummary() {
return this.mode !== 'full' && !this.showingFullWiki;
},
showFull() {
return this.mode === 'full' || this.showingFullWiki;
},
},
methods: {
/**
* Shuffle all songs in the current album.

View file

@ -12,11 +12,10 @@
class="cool-guys-posing cover">
<div class="bio" v-if="artist.info.bio.summary">
<div class="summary" v-show="mode !== 'full' && !showingFullBio" v-html="artist.info.bio.summary"></div>
<div class="full" v-show="mode === 'full' || showingFullBio" v-html="artist.info.bio.full"></div>
<div class="summary" v-show="showSummary" v-html="artist.info.bio.summary"/>
<div class="full" v-show="showFull" v-html="artist.info.bio.full"/>
<button class="more" v-show="mode !== 'full' && !showingFullBio"
@click.prevent="showingFullBio = !showingFullBio">
<button class="more" v-show="showSummary" @click.prevent="showingFullBio = true">
Full Bio
</button>
</div>
@ -47,6 +46,16 @@ export default {
},
},
computed: {
showSummary() {
return this.mode !== 'full' && !this.showingFullBio;
},
showFull() {
return this.mode === 'full' || this.showingFullBio;
}
},
methods: {
/**
* Shuffle all songs performed by the current song's artist.

View file

@ -14,24 +14,21 @@
</div>
<div class="panes">
<lyrics :song="song" ref="lyrics" v-show="currentView === 'lyrics'"></lyrics>
<lyrics :song="song" ref="lyrics" v-show="currentView === 'lyrics'"/>
<artist-info v-if="song.artist.id"
:artist="song.artist"
:mode="'sidebar'"
ref="artist-info"
v-show="currentView === 'artistInfo'">
</artist-info>
v-show="currentView === 'artistInfo'"/>
<album-info v-if="song.album.id"
:album="song.album"
:mode="'sidebar'"
ref="album-info"
v-show="currentView === 'albumInfo'">
</album-info>
v-show="currentView === 'albumInfo'"/>
<youtube v-if="sharedState.useYouTube"
:song="song" :youtube="song.youtube"
ref="youtube"
v-show="currentView === 'youtube'">
</youtube>
v-show="currentView === 'youtube'"/>
</div>
</div>
</section>

View file

@ -1,7 +1,7 @@
<template>
<article id="lyrics">
<div class="content">
<div v-if="song.lyrics" v-html="song.lyrics"></div>
<div v-if="song.lyrics" v-html="song.lyrics"/>
<p class="none" v-else>No lyrics found. Are you not listening to Bach?</p>
</div>
</article>

View file

@ -1,7 +1,7 @@
<template>
<div id="youtube-wrapper">
<template v-if="videos && videos.length">
<a class="video" v-for="video in videos" href="#" @click.prevent="playYouTube(video.id.videoId)">
<a class="video" v-for="video in videos" href @click.prevent="playYouTube(video.id.videoId)">
<div class="thumb">
<img :src="video.snippet.thumbnails.default.url" width="90">
</div>
@ -12,7 +12,7 @@
</a>
<button @click="loadMore" v-if="!loading" class="more btn-blue">Load More</button>
</template>
<p class="nope" v-else>Play a song to retreive related YouTube videos.</p>
<p class="nope" v-else>Play a song to retrieve related YouTube videos.</p>
<p class="nope" v-show="loading">Loading</p>
</div>
</template>

View file

@ -1,8 +1,8 @@
<template>
<div id="mainWrapper">
<sidebar></sidebar>
<main-content></main-content>
<extra></extra>
<sidebar/>
<main-content/>
<extra/>
</div>
</template>

View file

@ -4,16 +4,12 @@
<span class="overview">
<img :src="album.cover" width="64" height="64" class="cover">
{{ album.name }}
<i class="fa fa-angle-down toggler"
v-show="isPhone && !showingControls"
@click="showingControls = true"></i>
<i class="fa fa-angle-up toggler"
v-show="isPhone && showingControls"
@click.prevent="showingControls = false"></i>
<i class="fa fa-angle-down toggler" v-show="isPhone && !showingControls" @click="showingControls = true"/>
<i class="fa fa-angle-up toggler" v-show="isPhone && showingControls" @click.prevent="showingControls = false"/>
<span class="meta" v-show="meta.songCount">
by
<a class="artist" v-if="isNormalArtist" :href="'/#!/artist/' + album.artist.id">{{ album.artist.name }}</a>
<a class="artist" v-if="isNormalArtist" :href="'/#!/artist/'+album.artist.id">{{ album.artist.name }}</a>
<span class="nope" v-else>{{ album.artist.name }}</span>
{{ meta.songCount | pluralize('song') }}
@ -22,11 +18,11 @@
<template v-if="sharedState.useLastfm">
<a href="#" @click.prevent="showInfo" title="View album's extra information">Info</a>
<a href @click.prevent="showInfo" title="View album's extra information">Info</a>
</template>
<template v-if="sharedState.allowDownload">
<a href="#" @click.prevent="download" title="Download all songs in album">Download</a>
<a href @click.prevent="download" title="Download all songs in album">Download</a>
</template>
</span>
</span>
@ -42,19 +38,17 @@
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
</button>
<add-to-menu :songs="selectedSongs" :showing="showingAddToMenu"></add-to-menu>
<add-to-menu :songs="selectedSongs" :showing="showingAddToMenu"/>
</div>
</h1>
<song-list :items="album.songs" type="album"></song-list>
<song-list :items="album.songs" type="album"/>
<section class="info-wrapper" v-if="sharedState.useLastfm && info.showing">
<a href="#" class="close" @click.prevent="info.showing = false"><i class="fa fa-times"></i></a>
<a href class="close" @click.prevent="info.showing = false"><i class="fa fa-times"></i></a>
<div class="inner">
<div class="loading" v-if="info.loading">
<sound-bar></sound-bar>
</div>
<album-info :album="album" :mode="'full'" v-else></album-info>
<div class="loading" v-if="info.loading"><sound-bar/></div>
<album-info :album="album" :mode="'full'" v-else/>
</div>
</section>
</section>

View file

@ -2,13 +2,13 @@
<section id="albumsWrapper">
<h1 class="heading">
<span>Albums</span>
<view-mode-switch :mode="viewMode" for="albums"></view-mode-switch>
<view-mode-switch :mode="viewMode" for="albums"/>
</h1>
<div class="albums main-scroll-wrap" :class="'as-' + viewMode" @scroll="scrolling">
<album-item v-for="item in displayedItems" :album="item"></album-item>
<span class="item filler" v-for="n in 6"></span>
<to-top-button :showing="showBackToTop"></to-top-button>
<div class="albums main-scroll-wrap" :class="'as-'+viewMode" @scroll="scrolling">
<album-item v-for="item in displayedItems" :album="item"/>
<span class="item filler" v-for="n in 6"/>
<to-top-button :showing="showBackToTop"/>
</div>
</section>
</template>

View file

@ -4,12 +4,8 @@
<span class="overview">
<img :src="artist.image" width="64" height="64" class="cover">
{{ artist.name }}
<i class="fa fa-angle-down toggler"
v-show="isPhone && !showingControls"
@click="showingControls = true"></i>
<i class="fa fa-angle-up toggler"
v-show="isPhone && showingControls"
@click.prevent="showingControls = false"></i>
<i class="fa fa-angle-down toggler" v-show="isPhone && !showingControls" @click="showingControls = true"/>
<i class="fa fa-angle-up toggler" v-show="isPhone && showingControls" @click.prevent="showingControls = false"/>
<span class="meta" v-show="meta.songCount">
{{ artist.albums.length | pluralize('album') }}
@ -20,12 +16,12 @@
<template v-if="sharedState.useLastfm">
<a href="#" @click.prevent="showInfo" title="View artist's extra information">Info</a>
<a href @click.prevent="showInfo" title="View artist's extra information">Info</a>
</template>
<template v-if="sharedState.allowDownload">
<a href="#" @click.prevent="download" title="Download all songs by this artist">Download</a>
<a href @click.prevent="download" title="Download all songs by this artist">Download</a>
</template>
</span>
</span>
@ -41,19 +37,17 @@
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
</button>
<add-to-menu :songs="selectedSongs" :showing="showingAddToMenu"><add-to-menu>
<add-to-menu :songs="selectedSongs" :showing="showingAddToMenu"/>
</div>
</h1>
<song-list :items="artist.songs" type="artist"></song-list>
<song-list :items="artist.songs" type="artist"/>
<section class="info-wrapper" v-if="sharedState.useLastfm && info.showing">
<a href="#" class="close" @click.prevent="info.showing = false"><i class="fa fa-times"></i></a>
<a href class="close" @click.prevent="info.showing = false"><i class="fa fa-times"></i></a>
<div class="inner">
<div class="loading" v-if="info.loading">
<sound-bar></sound-bar>
</div>
<artist-info :artist="artist" :mode="'full'" v-else></artist-info>
<div class="loading" v-if="info.loading"><sound-bar/></div>
<artist-info :artist="artist" :mode="'full'" v-else/>
</div>
</section>
</section>

View file

@ -2,13 +2,13 @@
<section id="artistsWrapper">
<h1 class="heading">
<span>Artists</span>
<view-mode-switch :mode="viewMode" for="artists"></view-mode-switch>
<view-mode-switch :mode="viewMode" for="artists"/>
</h1>
<div class="artists main-scroll-wrap" :class="'as-' + viewMode" @scroll="scrolling">
<artist-item v-for="item in displayedItems" :artist="item"></artist-item>
<span class="item filler" v-for="n in 6"></span>
<to-top-button :showing="showBackToTop"></to-top-button>
<div class="artists main-scroll-wrap" :class="'as-'+viewMode" @scroll="scrolling">
<artist-item v-for="item in displayedItems" :artist="item"/>
<span class="item filler" v-for="n in 6"/>
<to-top-button :showing="showBackToTop"/>
</div>
</section>
</template>

View file

@ -2,12 +2,8 @@
<section id="favoritesWrapper">
<h1 class="heading">
<span>Songs You Love
<i class="fa fa-angle-down toggler"
v-show="isPhone && !showingControls"
@click="showingControls = true"></i>
<i class="fa fa-angle-up toggler"
v-show="isPhone && showingControls"
@click.prevent="showingControls = false"></i>
<i class="fa fa-angle-down toggler" v-show="isPhone && !showingControls" @click="showingControls = true"/>
<i class="fa fa-angle-up toggler" v-show="isPhone && showingControls" @click.prevent="showingControls = false"/>
<span class="meta" v-show="meta.songCount">
{{ meta.songCount | pluralize('song') }}
@ -15,8 +11,7 @@
{{ meta.totalLength }}
<template v-if="sharedState.allowDownload && state.songs.length">
<a href="#" @click.prevent="download"
title="Download all songs in playlist">
<a href @click.prevent="download" title="Download all songs in playlist">
Download
</a>
</template>
@ -40,12 +35,11 @@
<add-to-menu
:songs="selectedSongs"
:showing="showingAddToMenu && state.songs.length"
:settings="{ canLike: false }">
<add-to-menu>
:settings="{ canLike: false }"/>
</div>
</h1>
<song-list v-show="state.songs.length" :items="state.songs" type="favorites"></song-list>
<song-list v-show="state.songs.length" :items="state.songs" type="favorites"/>
<div v-show="!state.songs.length" class="none">
Start loving!

View file

@ -13,7 +13,7 @@
<li v-for="song in top.songs"
:top-play-count="top.songs.length ? top.songs[0].playCount : 0"
:song="song"
is="song-item"></li>
is="song-item"/>
</ol>
</section>
@ -24,7 +24,7 @@
<li v-for="song in recentSongs"
:top-play-count="top.songs.length ? top.songs[0].playCount : 0"
:song="song"
is="song-item"></li>
is="song-item"/>
</ol>
<p class="none" v-show="!recentSongs.length">
@ -39,14 +39,12 @@
<div class="two-cols">
<div class="wrapper as-list">
<album-item v-for="album in recentlyAdded.albums" :album="album"></album-item>
<span class="item filler" v-for="n in 3"></span>
<album-item v-for="album in recentlyAdded.albums" :album="album"/>
<span class="item filler" v-for="n in 3"/>
</div>
<div>
<ul class="recently-added-song-list" v-show="recentlyAdded.songs.length">
<li v-for="song in recentlyAdded.songs"
:song="song"
is="song-item"></li>
<li v-for="song in recentlyAdded.songs" :song="song" is="song-item"/>
</ul>
</div>
</div>
@ -55,22 +53,22 @@
<section class="top-artists" v-show="top.artists.length">
<h1>Top Artists</h1>
<div class="wrapper" :class="'as-' + preferences.artistsViewMode">
<artist-item v-for="artist in top.artists" :artist="artist"></artist-item>
<span class="item filler" v-for="n in 3"></span>
<div class="wrapper" :class="'as-'+preferences.artistsViewMode">
<artist-item v-for="artist in top.artists" :artist="artist"/>
<span class="item filler" v-for="n in 3"/>
</div>
</section>
<section class="top-albums" :class="'as-' + preferences.albumsViewMode" v-show="top.albums.length">
<section class="top-albums" :class="'as-'+preferences.albumsViewMode" v-show="top.albums.length">
<h1>Top Albums</h1>
<div class="wrapper">
<album-item v-for="album in top.albums" :album="album"></album-item>
<span class="item filler" v-for="n in 3"></span>
<album-item v-for="album in top.albums" :album="album"/>
<span class="item filler" v-for="n in 3"/>
</div>
</section>
<to-top-button :showing="showBackToTop"></to-top-button>
<to-top-button :showing="showBackToTop"/>
</div>
</section>
</template>

View file

@ -1,19 +1,19 @@
<template>
<section id="mainContent">
<div class="translucent" :style="{ backgroundImage: albumCover ? 'url(' + albumCover + ')' : 'none' }"></div>
<home v-show="view === 'home'"></home>
<queue v-show="view === 'queue'"></queue>
<songs v-show="view === 'songs'"></songs>
<albums v-show="view === 'albums'"></albums>
<album v-show="view === 'album'"></album>
<artists v-show="view === 'artists'"></artists>
<artist v-show="view === 'artist'"></artist>
<users v-show="view === 'users'"></users>
<settings v-show="view === 'settings'"></settings>
<playlist v-show="view === 'playlist'"></playlist>
<favorites v-show="view === 'favorites'"></favorites>
<profile v-show="view === 'profile'"></profile>
<youtube-player v-if="sharedState.useYouTube" v-show="view === 'youtubePlayer'"></youtube-player>
<div class="translucent" :style="{ backgroundImage: albumCover ? 'url('+albumCover+')' : 'none' }"></div>
<home v-show="view === 'home'"/>
<queue v-show="view === 'queue'"/>
<songs v-show="view === 'songs'"/>
<albums v-show="view === 'albums'"/>
<album v-show="view === 'album'"/>
<artists v-show="view === 'artists'"/>
<artist v-show="view === 'artist'"/>
<users v-show="view === 'users'"/>
<settings v-show="view === 'settings'"/>
<playlist v-show="view === 'playlist'"/>
<favorites v-show="view === 'favorites'"/>
<profile v-show="view === 'profile'"/>
<youtube-player v-if="sharedState.useYouTube" v-show="view === 'youtubePlayer'"/>
</section>
</template>

View file

@ -2,12 +2,8 @@
<section id="playlistWrapper">
<h1 class="heading">
<span>{{ playlist.name }}
<i class="fa fa-angle-down toggler"
v-show="isPhone && !showingControls"
@click="showingControls = true"></i>
<i class="fa fa-angle-up toggler"
v-show="isPhone && showingControls"
@click.prevent="showingControls = false"></i>
<i class="fa fa-angle-down toggler" v-show="isPhone && !showingControls" @click="showingControls = true"/>
<i class="fa fa-angle-up toggler" v-show="isPhone && showingControls" @click.prevent="showingControls = false"/>
<span class="meta" v-show="meta.songCount">
{{ meta.songCount | pluralize('song') }}
@ -15,8 +11,7 @@
{{ meta.totalLength }}
<template v-if="sharedState.allowDownload && playlist.songs.length">
<a href="#" @click.prevent="download"
title="Download all songs in playlist">
<a href @click.prevent="download" title="Download all songs in playlist">
Download
</a>
</template>
@ -42,11 +37,11 @@
<i class="fa fa-times"></i> Playlist
</button>
<add-to-menu :songs="selectedSongs" :showing="showingAddToMenu && playlist.songs.length"><add-to-menu>
<add-to-menu :songs="selectedSongs" :showing="showingAddToMenu && playlist.songs.length"/>
</div>
</h1>
<song-list v-show="playlist.songs.length" :items="playlist.songs" :playlist="playlist" type="playlist"></song-list>
<song-list v-show="playlist.songs.length" :items="playlist.songs" :playlist="playlist" type="playlist"/>
<div v-show="!playlist.songs.length" class="none">
The playlist is currently empty. You can fill it up by dragging songs into its name in the sidebar,

View file

@ -2,12 +2,8 @@
<section id="queueWrapper">
<h1 class="heading">
<span title="That's a freaking lot of U's and E's">Current Queue
<i class="fa fa-angle-down toggler"
v-show="isPhone && !showingControls"
@click="showingControls = true"></i>
<i class="fa fa-angle-up toggler"
v-show="isPhone && showingControls"
@click.prevent="showingControls = false"></i>
<i class="fa fa-angle-down toggler" v-show="isPhone && !showingControls" @click="showingControls = true"/>
<i class="fa fa-angle-up toggler" v-show="isPhone && showingControls" @click.prevent="showingControls = false"/>
<span class="meta" v-show="meta.songCount">
{{ meta.songCount | pluralize('song') }}
@ -35,12 +31,11 @@
<add-to-menu
:songs="songsToAddTo"
:showing="showingAddToMenu && state.songs.length"
:settings="{ canQueue: false }">
</add-to-menu>
:settings="{ canQueue: false }"/>
</div>
</h1>
<song-list v-show="state.songs.length" :items="state.songs" :sortable="false" type="queue"></song-list>
<song-list v-show="state.songs.length" :items="state.songs" :sortable="false" type="queue"/>
<div v-show="!state.songs.length" class="none">
<p>Empty spaces. Abandoned places.</p>

View file

@ -2,12 +2,8 @@
<section id="songsWrapper">
<h1 class="heading">
<span>All Songs
<i class="fa fa-angle-down toggler"
v-show="isPhone && !showingControls"
@click="showingControls = true"></i>
<i class="fa fa-angle-up toggler"
v-show="isPhone && showingControls"
@click.prevent="showingControls = false"></i>
<i class="fa fa-angle-down toggler" v-show="isPhone && !showingControls" @click="showingControls = true"/>
<i class="fa fa-angle-up toggler" v-show="isPhone && showingControls" @click.prevent="showingControls = false"/>
<span class="meta" v-show="meta.songCount">
{{ meta.songCount | pluralize('song') }}
@ -32,11 +28,11 @@
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
</button>
<add-to-menu :songs="selectedSongs" :showing="showingAddToMenu"><add-to-menu>
<add-to-menu :songs="selectedSongs" :showing="showingAddToMenu"/>
</div>
</h1>
<song-list :items="state.songs" type="allSongs"></song-list>
<song-list :items="state.songs" type="allSongs"/>
</section>
</template>

View file

@ -2,12 +2,8 @@
<section id="usersWrapper">
<h1 class="heading">
<span>Users
<i class="fa fa-angle-down toggler"
v-show="isPhone && !showingControls"
@click="showingControls = true"></i>
<i class="fa fa-angle-up toggler"
v-show="isPhone && showingControls"
@click.prevent="showingControls = false"></i>
<i class="fa fa-angle-down toggler" v-show="isPhone && !showingControls" @click="showingControls = true"/>
<i class="fa fa-angle-up toggler" v-show="isPhone && showingControls" @click.prevent="showingControls = false"/>
</span>
<div class="buttons" v-show="!isPhone || showingControls">
@ -39,9 +35,9 @@
</div>
</form>
<user-item v-for="user in state.users" :user="user"></user-item>
<user-item v-for="user in state.users" :user="user"/>
<article class="user-item" v-for="n in 6"></article>
<article class="user-item" v-for="n in 6"/>
</div>
</div>
</section>

View file

@ -5,48 +5,47 @@
<ul class="menu">
<li>
<a class="home" :class="[currentView == 'home' ? 'active' : '']" href="/#!/home">Home</a>
<a :class="['home', currentView == 'home' ? 'active' : '']" href="/#!/home">Home</a>
</li>
<li>
<a class="queue"
:class="[currentView == 'queue' ? 'active' : '']"
<a :class="['queue', currentView == 'queue' ? 'active' : '']"
href="/#!/queue"
@dragleave="removeDroppableState"
@dragover.prevent="allowDrop"
@drop.stop.prevent="handleDrop">Current Queue</a>
</li>
<li>
<a class="songs" :class="[currentView == 'songs' ? 'active' : '']" href="/#!/songs">All Songs</a>
<a :class="['songs', currentView == 'songs' ? 'active' : '']" href="/#!/songs">All Songs</a>
</li>
<li>
<a class="albums" :class="[currentView == 'albums' ? 'active' : '']" href="/#!/albums">Albums</a>
<a :class="['albums', currentView == 'albums' ? 'active' : '']" href="/#!/albums">Albums</a>
</li>
<li>
<a class="artists" :class="[currentView == 'artists' ? 'active' : '']" href="/#!/artists">Artists</a>
<a :class="['artists', currentView == 'artists' ? 'active' : '']" href="/#!/artists">Artists</a>
</li>
<li v-if="sharedState.useYouTube">
<a class="youtube" :class="[currentView == 'youtubePlayer' ? 'active' : '']" href="/#!/youtube">YouTube Video</a>
<a :class="['youtube', currentView == 'youtubePlayer' ? 'active' : '']" href="/#!/youtube">YouTube Video</a>
</li>
</ul>
</section>
<playlists :current-view="currentView"></playlists>
<playlists :current-view="currentView"/>
<section v-if="user.current.is_admin" class="manage">
<h1>Manage</h1>
<ul class="menu">
<li>
<a class="settings" :class="[currentView == 'settings' ? 'active' : '']" href="/#!/settings">Settings</a>
<a :class="['settings', currentView == 'settings' ? 'active' : '']" href="/#!/settings">Settings</a>
</li>
<li>
<a class="users" :class="[currentView == 'users' ? 'active' : '']" href="/#!/users">Users</a>
<a :class="['users', currentView == 'users' ? 'active' : '']" href="/#!/users">Users</a>
</li>
</ul>
</section>
<a
:href="'https://github.com/phanan/koel/releases/tag/' + sharedState.latestVersion"
:href="latestVersionUrl"
target="_blank"
v-if="user.current.is_admin && sharedState.currentVersion < sharedState.latestVersion"
class="new-ver">
@ -75,6 +74,12 @@ export default {
};
},
computed: {
latestVersionUrl() {
return 'https://github.com/phanan/koel/releases/tag/' + this.sharedState.latestVersion;
},
},
methods: {
/**
* Remove the droppable state when a dragleave event occurs on the playlist's DOM element.

View file

@ -1,6 +1,6 @@
<template>
<li @dblclick.prevent="edit" class="playlist" :class="[type, editing ? 'editing' : '']">
<a :href="isFavorites ? '/#!/favorites' : '/#!/playlist/' + playlist.id"
<li @dblclick.prevent="edit" :class="['playlist', type, editing ? 'editing' : '']">
<a :href="playlistUrl"
@dragleave="removeDroppableState"
@dragover.prevent="allowDrop"
@drop.stop.prevent="handleDrop"
@ -44,6 +44,10 @@ export default {
isFavorites() {
return this.type === 'favorites';
},
playlistUrl() {
return this.isFavorites ? '/#!/favorites' : `/#!/playlist/${this.playlist.id}`;
},
},
methods: {

View file

@ -1,9 +1,7 @@
<template>
<section id="playlists">
<h1>Playlists
<i class="fa fa-plus-circle control create"
:class="{ creating: creating }"
@click="creating = !creating"></i>
<i class="fa fa-plus-circle control create" :class="{ creating: creating }" @click="creating = !creating"/>
</h1>
<form v-show="creating" @submit.prevent="store" class="create">
@ -17,13 +15,8 @@
</form>
<ul class="menu">
<playlist-item
type="favorites"
:playlist="{ name: 'Favorites', songs: favoriteState.songs }"></playlist-item>
<playlist-item
v-for="playlist in playlistState.playlists"
type="playlist"
:playlist="playlist"></playlist-item>
<playlist-item type="favorites" :playlist="{ name: 'Favorites', songs: favoriteState.songs }"/>
<playlist-item v-for="playlist in playlistState.playlists" type="playlist" :playlist="playlist"/>
</ul>
</section>
</template>

View file

@ -3,7 +3,7 @@
<sound-bar v-if="loading"></sound-bar>
<form v-else @submit.prevent="submit">
<header>
<img :src="inSameAlbum ? songs[0].album.cover : '/public/img/covers/unknown-album.png'" width="96" height="96">
<img :src="coverUrl" width="96" height="96">
<hgroup class="meta">
<h1 :class="{ mixed: !editSingle }">{{ displayedTitle }}</h1>
<h2 :class="{ mixed: !bySameArtist && !formData.artistName }">
@ -35,14 +35,14 @@
<typeahead
:items="artistState.artists"
:options="artistTypeaheadOptions"
v-model="formData.artistName"></typeahead>
v-model="formData.artistName"/>
</div>
<div class="form-row">
<label>Album</label>
<typeahead
:items="albumState.albums"
:options="albumTypeaheadOptions"
v-model="formData.albumName"></typeahead>
v-model="formData.albumName"/>
</div>
<div class="form-row">
<label class="small">
@ -60,7 +60,7 @@
</div>
<div v-show="currentView === 'lyrics' && editSingle">
<div class="form-row">
<textarea v-model="formData.lyrics"></textarea>
<textarea v-model="formData.lyrics"/>
</div>
</div>
</div>
@ -68,7 +68,7 @@
</div>
<footer>
<input type="submit" value="Update" />
<input type="submit" value="Update">
<a @click.prevent="close" class="btn btn-white">Cancel</a>
</footer>
</form>
@ -159,6 +159,15 @@
return every(this.songs, song => song.album.id === this.songs[0].album.id);
},
/**
* URL of the cover to display.
*
* @return {string}
*/
coverUrl() {
return this.inSameAlbum ? this.songs[0].album.cover : '/public/img/covers/unknown-album.png';
},
/**
* Determine the compilation state of the songs.
*

View file

@ -1,15 +1,15 @@
<template>
<article class="item" v-if="album.songs.length" draggable="true" @dragstart="dragStart">
<span class="cover" :style="{ backgroundImage: 'url(' + album.cover + ')' }">
<span class="cover" :style="{ backgroundImage: 'url('+album.cover+')' }">
<a class="control" @click.prevent="play">
<i class="fa fa-play"></i>
</a>
</span>
<footer>
<div class="info">
<a class="name" :href="'/#!/album/' + album.id">{{ album.name }}</a>
<a class="name" :href="'/#!/album/'+album.id">{{ album.name }}</a>
<span class="sep">by</span>
<a class="artist" v-if="isNormalArtist" :href="'/#!/artist/' + album.artist.id">{{ album.artist.name }}</a>
<a class="artist" v-if="isNormalArtist" :href="'/#!/artist/'+album.artist.id">{{ album.artist.name }}</a>
<span class="artist nope" v-else>{{ album.artist.name }}</span>
</div>
<p class="meta">
@ -21,10 +21,10 @@
{{ album.playCount | pluralize('play') }}
</span>
<span class="right">
<a href="#" @click.prevent="shuffle" title="Shuffle">
<a href @click.prevent="shuffle" title="Shuffle">
<i class="fa fa-random"></i>
</a>
<a href="#" @click.prevent="download" v-if="sharedState.allowDownload" title="Download all songs in album">
<a href @click.prevent="download" v-if="sharedState.allowDownload" title="Download all songs in album">
<i class="fa fa-download"></i>
</a>
</span>

View file

@ -1,13 +1,13 @@
<template>
<article class="item" v-if="showing" draggable="true" @dragstart="dragStart">
<span class="cover" :style="{ backgroundImage: 'url(' + artist.image + ')' }">
<span class="cover" :style="{ backgroundImage: 'url('+artist.image+')' }">
<a class="control" @click.prevent="play">
<i class="fa fa-play"></i>
</a>
</span>
<footer>
<div class="info">
<a class="name" :href="'/#!/artist/' + artist.id">{{ artist.name }}</a>
<a class="name" :href="'/#!/artist/'+artist.id">{{ artist.name }}</a>
</div>
<p class="meta">
<span class="left">
@ -18,7 +18,7 @@
{{ artist.playCount | pluralize('play') }}
</span>
<span class="right">
<a href="#" @click.prevent="download" v-if="sharedState.allowDownload" title="Download all songs by artist">
<a href @click.prevent="download" v-if="sharedState.allowDownload" title="Download all songs by artist">
<i class="fa fa-download"></i>
</a>
</span>

View file

@ -3,21 +3,18 @@
:class="{ playing: song.playbackState === 'playing' || song.playbackState === 'paused' }"
@dblclick.prevent="play"
>
<span class="cover" :style="{ backgroundImage: 'url(' + song.album.cover + ')' }">
<span class="cover" :style="{ backgroundImage: 'url('+song.album.cover+')' }">
<a class="control" @click.prevent="changeSongState">
<i class="fa fa-play" v-if="song.playbackState !== 'playing'"></i>
<i class="fa fa-pause" v-else></i>
</a>
</span>
<span class="details">
<span v-if="showPlayCount" :style="{ width: song.playCount * 100 / topPlayCount + '%' }"
class="play-count"></span>
<span v-if="showPlayCount" :style="{ width: song.playCount*100/topPlayCount+'%' }" class="play-count"/>
{{ song.title }}
<span class="by">
<a :href="'/#!/artist/' + song.artist.id">{{ song.artist.name }}</a>
<template v-if="showPlayCount">-
{{ song.playCount | pluralize('play') }}
</template>
<a :href="'/#!/artist/'+song.artist.id">{{ song.artist.name }}</a>
<template v-if="showPlayCount">- {{ song.playCount | pluralize('play') }}</template>
</span>
</span>
</li>

View file

@ -1,13 +1,13 @@
<template>
<div id="overlay" v-show="state.showing" :class="state.type">
<div class="display">
<sound-bar v-show="state.type === 'loading'"></sound-bar>
<i class="fa fa-exclamation-circle" v-show="state.type === 'error'"></i>
<i class="fa fa-exclamation-triangle" v-show="state.type === 'warning'"></i>
<i class="fa fa-info-circle" v-show="state.type === 'info'"></i>
<i class="fa fa-check-circle" v-show="state.type === 'success'"></i>
<sound-bar v-show="state.type === 'loading'"/>
<i class="fa fa-exclamation-circle" v-show="state.type === 'error'"/>
<i class="fa fa-exclamation-triangle" v-show="state.type === 'warning'"/>
<i class="fa fa-info-circle" v-show="state.type === 'info'"/>
<i class="fa fa-check-circle" v-show="state.type === 'success'"/>
<span v-html="state.message"></span>
<span v-html="state.message"/>
</div>
<button v-show="state.dismissable" @click.prevent="state.showing = false">Close</button>

View file

@ -19,8 +19,8 @@
<td class="album">{{ song.album.name }}</td>
<td class="time">{{ song.fmtLength }}</td>
<td class="play" @click.stop="doPlayback">
<i class="fa fa-pause-circle" v-if="song.playbackState === 'playing'"></i>
<i class="fa fa-play-circle" v-else></i>
<i class="fa fa-pause-circle" v-if="song.playbackState === 'playing'"/>
<i class="fa fa-play-circle" v-else/>
</td>
</tr>
</template>

View file

@ -11,36 +11,36 @@
<thead>
<tr>
<th @click="sort('track')" class="track-number">#
<i class="fa fa-angle-down" v-show="sortKey === 'track' && order > 0"></i>
<i class="fa fa-angle-up" v-show="sortKey === 'track' && order < 0"></i>
<i class="fa fa-angle-down" v-show="sortKey === 'track' && order > 0"/>
<i class="fa fa-angle-up" v-show="sortKey === 'track' && order < 0"/>
</th>
<th @click="sort('title')" class="title">Title
<i class="fa fa-angle-down" v-show="sortKey === 'title' && order > 0"></i>
<i class="fa fa-angle-up" v-show="sortKey === 'title' && order < 0"></i>
<i class="fa fa-angle-down" v-show="sortKey === 'title' && order > 0"/>
<i class="fa fa-angle-up" v-show="sortKey === 'title' && order < 0"/>
</th>
<th @click="sort(['album.artist.name', 'album.name', 'track'])" class="artist">Artist
<i class="fa fa-angle-down" v-show="sortingByArtist && order > 0"></i>
<i class="fa fa-angle-up" v-show="sortingByArtist && order < 0"></i>
<i class="fa fa-angle-down" v-show="sortingByArtist && order > 0"/>
<i class="fa fa-angle-up" v-show="sortingByArtist && order < 0"/>
</th>
<th @click="sort(['album.name', 'track'])" class="album">Album
<i class="fa fa-angle-down" v-show="sortingByAlbum && order > 0"></i>
<i class="fa fa-angle-up" v-show="sortingByAlbum && order < 0"></i>
<i class="fa fa-angle-down" v-show="sortingByAlbum && order > 0"/>
<i class="fa fa-angle-up" v-show="sortingByAlbum && order < 0"/>
</th>
<th @click="sort('fmtLength')" class="time">Time
<i class="fa fa-angle-down" v-show="sortKey === 'fmtLength' && order > 0"></i>
<i class="fa fa-angle-up" v-show="sortKey === 'fmtLength' && order < 0"></i>
<i class="fa fa-angle-down" v-show="sortKey === 'fmtLength' && order > 0"/>
<i class="fa fa-angle-up" v-show="sortKey === 'fmtLength' && order < 0"/>
</th>
<th class="play"></th>
</tr>
</thead>
<tbody>
<tr is="song-item" v-for="item in displayedItems" :song="item" ref="rows"></tr>
<tr is="song-item" v-for="item in displayedItems" :song="item" ref="rows"/>
</tbody>
</table>
<song-menu ref="contextMenu" :songs="selectedSongs"></song-menu>
<to-top-button :showing="showBackToTop"></to-top-button>
<song-menu ref="contextMenu" :songs="selectedSongs"/>
<to-top-button :showing="showBackToTop"/>
</div>
</template>

View file

@ -1,7 +1,7 @@
<template>
<ul ref="menu" class="menu song-menu" v-show="shown" tabindex="-1" @contextmenu.prevent
@blur="close"
:style="{ top: top + 'px', left: left + 'px' }"
:style="{ top: top+'px', left: left+'px' }"
>
<template v-show="onlyOneSongSelected">
<li @click="doPlayback">

View file

@ -1,6 +1,6 @@
<template>
<div id="bars">
<div class="bar" v-for="n in 5"></div>
<div class="bar" v-for="n in 5"/>
</div>
</template>

View file

@ -1,12 +1,12 @@
<template>
<article class="user-item" :class="{ editing: editing }">
<div class="info" v-if="!editing">
<img :src="user.avatar" width="128" height="128" alt="">
<img :src="user.avatar" width="128" height="128">
<div class="right">
<div>
<h1>{{ user.name }}
<i v-if="isCurrentUser" class="you fa fa-check-circle"></i>
<i v-if="isCurrentUser" class="you fa fa-check-circle"/>
</h1>
<p>{{ user.email }}</p>
</div>

View file

@ -80,7 +80,7 @@ export default {
*/
preferences.selectedPreset = val;
if (Number.parseInt(val, 10) !== -1) {
if (~~val !== -1) {
this.loadPreset(equalizerStore.getPresetById(val));
}
},

View file

@ -1,31 +1,27 @@
<template>
<footer id="mainFooter">
<div class="side player-controls" id="playerControls">
<i class="prev fa fa-step-backward control" @click.prevent="playPrev"></i>
<i class="prev fa fa-step-backward control" @click.prevent="playPrev"/>
<span class="play control"
v-if="song.playbackState === 'stopped' || song.playbackState === 'paused'"
@click.prevent="resume"
>
<span class="play control" v-if="song.playbackState !== 'playing'" @click.prevent="resume">
<i class="fa fa-play"></i>
</span>
<span class="pause control" v-else @click.prevent="pause">
<i class="fa fa-pause"></i>
</span>
<i class="next fa fa-step-forward control" @click.prevent="playNext"></i>
<i class="next fa fa-step-forward control" @click.prevent="playNext"/>
</div>
<div class="media-info-wrap">
<div class="middle-pane">
<span class="album-thumb" v-if="cover" :style="{ backgroundImage: 'url(' + cover + ')' }"></span>
<span class="album-thumb" v-if="cover" :style="{ backgroundImage: 'url('+cover+')' }"/>
<div class="progress" id="progressPane">
<h3 class="title">{{ song.title }}</h3>
<p class="meta">
<a class="artist" :href="'/#!/artist/' + song.artist.id">{{ song.artist.name }}</a>
<a class="album" :href="'/#!/album/' + song.album.id">{{ song.album.name }}</a>
<a class="artist" :href="'/#!/artist/'+song.artist.id">{{ song.artist.name }}</a>
<a class="album" :href="'/#!/album/'+song.album.id">{{ song.album.name }}</a>
</p>
<div class="plyr">
@ -36,17 +32,16 @@
<div class="other-controls" :class="{ 'with-gradient': prefs.showExtraPanel }">
<div class="wrapper" v-koel-clickaway="closeEqualizer">
<equalizer v-if="useEqualizer" v-show="showEqualizer"></equalizer>
<sound-bar v-show="song.playbackState === 'playing'"></sound-bar>
<i class="like control fa fa-heart" :class="{ liked: song.liked }"
@click.prevent="like"></i>
<equalizer v-if="useEqualizer" v-show="showEqualizer"/>
<sound-bar v-show="song.playbackState === 'playing'"/>
<i class="like control fa fa-heart" :class="{ liked: song.liked }" @click.prevent="like"/>
<span class="control"
@click.prevent="toggleExtraPanel"
:class="{ active: prefs.showExtraPanel }">Info</span>
<i class="fa fa-sliders control"
v-if="useEqualizer"
@click="showEqualizer = !showEqualizer"
:class="{ active: showEqualizer }"></i>
:class="{ active: showEqualizer }"/>
<a v-else
class="queue control"
:class="{ active: viewingQueue }"
@ -57,8 +52,8 @@
<i class="fa fa-repeat"></i>
</span>
<span class="volume control" id="volume">
<i class="fa fa-volume-up" @click.prevent="mute" v-show="!muted"></i>
<i class="fa fa-volume-off" @click.prevent="unmute" v-show="muted"></i>
<i class="fa fa-volume-up" @click.prevent="mute" v-show="!muted"/>
<i class="fa fa-volume-off" @click.prevent="unmute" v-show="muted"/>
<input type="range" id="volumeRange" max="10" step="0.1" class="plyr__volume">
</span>
</div>

View file

@ -7,8 +7,8 @@
<span class="magnifier" @click="toggleSearchForm">
<i class="fa fa-search"></i>
</span>
<search-form></search-form>
<user-badge></user-badge>
<search-form/>
<user-badge/>
</header>
</template>

View file

@ -1,7 +1,7 @@
<template>
<span class="profile" id="userBadge">
<a class="view-profile control" href="/#!/profile">
<img class="avatar" :src="state.current.avatar" alt="Avatar"></img>
<img class="avatar" :src="state.current.avatar" alt="Avatar"/>
<span class="name">{{ state.current.name }}</span>
</a>

View file

@ -23,7 +23,7 @@ export default {
},
'/album/(\\d+)'(id) {
const album = albumStore.byId(Number.parseInt(id, 10));
const album = albumStore.byId(~~id);
if (album) {
loadMainView('album', album);
}
@ -34,7 +34,7 @@ export default {
},
'/artist/(\\d+)'(id) {
const artist = artistStore.byId(Number.parseInt(id, 10));
const artist = artistStore.byId(~~id);
if (artist) {
loadMainView('artist', artist);
}
@ -45,7 +45,7 @@ export default {
},
'/playlist/(\\d+)'(id) {
const playlist = playlistStore.byId(Number.parseInt(id, 10));
const playlist = playlistStore.byId(~~id);
if (playlist) {
loadMainView('playlist', playlist);
}

View file

@ -3,7 +3,7 @@
* If H is 0, it will be ommited.
*/
export function secondsToHis(d) {
d = parseInt(d, 10);
d = ~~d;
let s = d % 60;

6565
yarn.lock

File diff suppressed because it is too large Load diff