mirror of
https://github.com/koel/koel
synced 2024-11-28 06:50:27 +00:00
Close menu with clickaway
This commit is contained in:
parent
eafa856b02
commit
640d8fc8dc
8 changed files with 64 additions and 61 deletions
|
@ -39,6 +39,7 @@
|
||||||
"rangeslider.js": "^2.1.1",
|
"rangeslider.js": "^2.1.1",
|
||||||
"sinon": "^1.17.2",
|
"sinon": "^1.17.2",
|
||||||
"vue": "^1.0.16",
|
"vue": "^1.0.16",
|
||||||
|
"vue-clickaway": "^1.1.1",
|
||||||
"vue-hot-reload-api": "^1.2.2",
|
"vue-hot-reload-api": "^1.2.2",
|
||||||
"vue-resource": "~0.5.1",
|
"vue-resource": "~0.5.1",
|
||||||
"vueify": "^7.0.2",
|
"vueify": "^7.0.2",
|
||||||
|
|
|
@ -4,18 +4,18 @@
|
||||||
<span class="overview">
|
<span class="overview">
|
||||||
<img :src="album.cover" width="64" height="64" class="cover">
|
<img :src="album.cover" width="64" height="64" class="cover">
|
||||||
{{ album.name }}
|
{{ album.name }}
|
||||||
<i class="fa fa-angle-down toggler"
|
<i class="fa fa-angle-down toggler"
|
||||||
v-show="isPhone && !showingControls"
|
v-show="isPhone && !showingControls"
|
||||||
@click="showingControls = true"></i>
|
@click="showingControls = true"></i>
|
||||||
<i class="fa fa-angle-up toggler"
|
<i class="fa fa-angle-up toggler"
|
||||||
v-show="isPhone && showingControls"
|
v-show="isPhone && showingControls"
|
||||||
@click.prevent="showingControls = false"></i>
|
@click.prevent="showingControls = false"></i>
|
||||||
|
|
||||||
<span class="meta" v-show="meta.songCount">
|
<span class="meta" v-show="meta.songCount">
|
||||||
by <a class="artist" @click.prevent="viewArtistDetails">{{ album.artist.name }}</a>
|
by <a class="artist" @click.prevent="viewArtistDetails">{{ album.artist.name }}</a>
|
||||||
•
|
•
|
||||||
{{ meta.songCount }} {{ meta.songCount | pluralize 'song' }}
|
{{ meta.songCount }} {{ meta.songCount | pluralize 'song' }}
|
||||||
•
|
•
|
||||||
{{ meta.totalLength }}
|
{{ meta.totalLength }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
||||||
<i class="fa fa-random"></i> Selected
|
<i class="fa fa-random"></i> Selected
|
||||||
</button>
|
</button>
|
||||||
<button class="add-to" @click.prevent="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
|
<button class="add-to" @click.prevent.stop="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
|
||||||
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,18 @@
|
||||||
<span class="overview">
|
<span class="overview">
|
||||||
<img :src="artist.image" width="64" height="64" class="cover">
|
<img :src="artist.image" width="64" height="64" class="cover">
|
||||||
{{ artist.name }}
|
{{ artist.name }}
|
||||||
<i class="fa fa-angle-down toggler"
|
<i class="fa fa-angle-down toggler"
|
||||||
v-show="isPhone && !showingControls"
|
v-show="isPhone && !showingControls"
|
||||||
@click="showingControls = true"></i>
|
@click="showingControls = true"></i>
|
||||||
<i class="fa fa-angle-up toggler"
|
<i class="fa fa-angle-up toggler"
|
||||||
v-show="isPhone && showingControls"
|
v-show="isPhone && showingControls"
|
||||||
@click.prevent="showingControls = false"></i>
|
@click.prevent="showingControls = false"></i>
|
||||||
|
|
||||||
<span class="meta" v-show="meta.songCount">
|
<span class="meta" v-show="meta.songCount">
|
||||||
{{ artist.albums.length }} {{ artist.albums.length | pluralize 'album' }}
|
{{ artist.albums.length }} {{ artist.albums.length | pluralize 'album' }}
|
||||||
•
|
•
|
||||||
{{ meta.songCount }} {{ meta.songCount | pluralize 'song' }}
|
{{ meta.songCount }} {{ meta.songCount | pluralize 'song' }}
|
||||||
•
|
•
|
||||||
{{ meta.totalLength }}
|
{{ meta.totalLength }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
||||||
<i class="fa fa-random"></i> Selected
|
<i class="fa fa-random"></i> Selected
|
||||||
</button>
|
</button>
|
||||||
<button class="add-to" @click.prevent="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
|
<button class="add-to" @click.prevent.stop="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
|
||||||
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,22 @@
|
||||||
<section id="favoritesWrapper">
|
<section id="favoritesWrapper">
|
||||||
<h1 class="heading">
|
<h1 class="heading">
|
||||||
<span>Songs You Love
|
<span>Songs You Love
|
||||||
<i class="fa fa-angle-down toggler"
|
<i class="fa fa-angle-down toggler"
|
||||||
v-show="isPhone && !showingControls"
|
v-show="isPhone && !showingControls"
|
||||||
@click="showingControls = true"></i>
|
@click="showingControls = true"></i>
|
||||||
<i class="fa fa-angle-up toggler"
|
<i class="fa fa-angle-up toggler"
|
||||||
v-show="isPhone && showingControls"
|
v-show="isPhone && showingControls"
|
||||||
@click.prevent="showingControls = false"></i>
|
@click.prevent="showingControls = false"></i>
|
||||||
|
|
||||||
<span class="meta" v-show="meta.songCount">
|
<span class="meta" v-show="meta.songCount">
|
||||||
{{ meta.songCount }} {{ meta.songCount | pluralize 'song' }}
|
{{ meta.songCount }} {{ meta.songCount | pluralize 'song' }}
|
||||||
•
|
•
|
||||||
{{ meta.totalLength }}
|
{{ meta.totalLength }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="buttons" v-show="!isPhone || showingControls">
|
<div class="buttons" v-show="!isPhone || showingControls">
|
||||||
<button class="play-shuffle"
|
<button class="play-shuffle"
|
||||||
@click.prevent="shuffle"
|
@click.prevent="shuffle"
|
||||||
v-if="state.songs.length && selectedSongs.length < 2"
|
v-if="state.songs.length && selectedSongs.length < 2"
|
||||||
>
|
>
|
||||||
|
@ -26,28 +26,28 @@
|
||||||
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
||||||
<i class="fa fa-random"></i> Selected
|
<i class="fa fa-random"></i> Selected
|
||||||
</button>
|
</button>
|
||||||
<button class="add-to" @click.prevent="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
|
<button class="add-to" @click.prevent.stop="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
|
||||||
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<add-to-menu
|
<add-to-menu
|
||||||
:songs="selectedSongs"
|
:songs="selectedSongs"
|
||||||
:showing="showingAddToMenu && state.songs.length"
|
:showing="showingAddToMenu && state.songs.length"
|
||||||
:settings="{ canLike: false }">
|
:settings="{ canLike: false }">
|
||||||
<add-to-menu>
|
<add-to-menu>
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<song-list
|
<song-list
|
||||||
v-show="state.songs.length"
|
v-show="state.songs.length"
|
||||||
:items="state.songs"
|
:items="state.songs"
|
||||||
:selected-songs.sync="selectedSongs"
|
:selected-songs.sync="selectedSongs"
|
||||||
type="favorites">
|
type="favorites">
|
||||||
</song-list>
|
</song-list>
|
||||||
|
|
||||||
<div v-show="!state.songs.length" class="none">
|
<div v-show="!state.songs.length" class="none">
|
||||||
Start loving!
|
Start loving!
|
||||||
Click the <i style="margin: 0 5px" class="fa fa-heart"></i> icon when a song is playing to add it
|
Click the <i style="margin: 0 5px" class="fa fa-heart"></i> icon when a song is playing to add it
|
||||||
to this list.
|
to this list.
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -55,11 +55,11 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import isMobile from 'ismobilejs';
|
import isMobile from 'ismobilejs';
|
||||||
|
|
||||||
import favoriteStore from '../../../stores/favorite';
|
import favoriteStore from '../../../stores/favorite';
|
||||||
import playback from '../../../services/playback';
|
import playback from '../../../services/playback';
|
||||||
import hasSongList from '../../../mixins/has-song-list';
|
import hasSongList from '../../../mixins/has-song-list';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [hasSongList],
|
mixins: [hasSongList],
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,22 @@
|
||||||
<section id="playlistWrapper">
|
<section id="playlistWrapper">
|
||||||
<h1 class="heading">
|
<h1 class="heading">
|
||||||
<span>{{ playlist.name }}
|
<span>{{ playlist.name }}
|
||||||
<i class="fa fa-angle-down toggler"
|
<i class="fa fa-angle-down toggler"
|
||||||
v-show="isPhone && !showingControls"
|
v-show="isPhone && !showingControls"
|
||||||
@click="showingControls = true"></i>
|
@click="showingControls = true"></i>
|
||||||
<i class="fa fa-angle-up toggler"
|
<i class="fa fa-angle-up toggler"
|
||||||
v-show="isPhone && showingControls"
|
v-show="isPhone && showingControls"
|
||||||
@click.prevent="showingControls = false"></i>
|
@click.prevent="showingControls = false"></i>
|
||||||
|
|
||||||
<span class="meta" v-show="meta.songCount">
|
<span class="meta" v-show="meta.songCount">
|
||||||
{{ meta.songCount }} {{ meta.songCount | pluralize 'song' }}
|
{{ meta.songCount }} {{ meta.songCount | pluralize 'song' }}
|
||||||
•
|
•
|
||||||
{{ meta.totalLength }}
|
{{ meta.totalLength }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="buttons" v-show="!isPhone || showingControls">
|
<div class="buttons" v-show="!isPhone || showingControls">
|
||||||
<button class="play-shuffle"
|
<button class="play-shuffle"
|
||||||
@click.prevent="shuffle"
|
@click.prevent="shuffle"
|
||||||
v-if="playlist.songs.length && selectedSongs.length < 2"
|
v-if="playlist.songs.length && selectedSongs.length < 2"
|
||||||
>
|
>
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
||||||
<i class="fa fa-random"></i> Selected
|
<i class="fa fa-random"></i> Selected
|
||||||
</button>
|
</button>
|
||||||
<button class="add-to" @click.prevent="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
|
<button class="add-to" @click.prevent.stop="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
|
||||||
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
||||||
</button>
|
</button>
|
||||||
<button class="del"
|
<button class="del"
|
||||||
|
@ -39,15 +39,15 @@
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<song-list v-show="playlist.songs.length"
|
<song-list v-show="playlist.songs.length"
|
||||||
:items="playlist.songs"
|
:items="playlist.songs"
|
||||||
:selected-songs.sync="selectedSongs"
|
:selected-songs.sync="selectedSongs"
|
||||||
:playlist="playlist"
|
:playlist="playlist"
|
||||||
type="playlist">
|
type="playlist">
|
||||||
</song-list>
|
</song-list>
|
||||||
|
|
||||||
<div v-show="!playlist.songs.length" class="none">
|
<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,
|
The playlist is currently empty. You can fill it up by dragging songs into its name in the sidebar,
|
||||||
or use the "Add To…" button.
|
or use the "Add To…" button.
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
||||||
<i class="fa fa-random"></i> Selected
|
<i class="fa fa-random"></i> Selected
|
||||||
</button>
|
</button>
|
||||||
<button class="add-to" @click.prevent="showingAddToMenu = !showingAddToMenu" v-if="state.songs.length > 1">
|
<button class="add-to" @click.prevent.stop="showingAddToMenu = !showingAddToMenu" v-if="state.songs.length > 1">
|
||||||
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
||||||
</button>
|
</button>
|
||||||
<button class="clear" @click.prevent="clear" v-if="state.songs.length">Clear</button>
|
<button class="clear" @click.prevent="clear" v-if="state.songs.length">Clear</button>
|
||||||
|
|
|
@ -2,24 +2,24 @@
|
||||||
<section id="songsWrapper">
|
<section id="songsWrapper">
|
||||||
<h1 class="heading">
|
<h1 class="heading">
|
||||||
<span>All Songs
|
<span>All Songs
|
||||||
<i class="fa fa-angle-down toggler"
|
<i class="fa fa-angle-down toggler"
|
||||||
v-show="isPhone && !showingControls"
|
v-show="isPhone && !showingControls"
|
||||||
@click="showingControls = true"></i>
|
@click="showingControls = true"></i>
|
||||||
<i class="fa fa-angle-up toggler"
|
<i class="fa fa-angle-up toggler"
|
||||||
v-show="isPhone && showingControls"
|
v-show="isPhone && showingControls"
|
||||||
@click.prevent="showingControls = false"></i>
|
@click.prevent="showingControls = false"></i>
|
||||||
|
|
||||||
<span class="meta" v-show="meta.songCount">
|
<span class="meta" v-show="meta.songCount">
|
||||||
{{ meta.songCount }} {{ meta.songCount | pluralize 'song' }}
|
{{ meta.songCount }} {{ meta.songCount | pluralize 'song' }}
|
||||||
•
|
•
|
||||||
{{ meta.totalLength }}
|
{{ meta.totalLength }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="buttons" v-show="!isPhone || showingControls">
|
<div class="buttons" v-show="!isPhone || showingControls">
|
||||||
<button
|
<button
|
||||||
class="play-shuffle"
|
class="play-shuffle"
|
||||||
@click.prevent="shuffle"
|
@click.prevent="shuffle"
|
||||||
v-if="state.songs.length && selectedSongs.length < 2"
|
v-if="state.songs.length && selectedSongs.length < 2"
|
||||||
>
|
>
|
||||||
<i class="fa fa-random"></i> All
|
<i class="fa fa-random"></i> All
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
<i class="fa fa-random"></i> Selected
|
<i class="fa fa-random"></i> Selected
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="add-to" @click.prevent="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
|
<button class="add-to" @click.prevent.stop="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
|
||||||
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="add-to-playlist" v-show="showing">
|
<div class="add-to-playlist" v-show="showing" v-on-clickaway="hideMenu">
|
||||||
<p>Add {{ songs.length }} {{ songs.length | pluralize 'song' }} to</p>
|
<p>Add {{ songs.length }} {{ songs.length | pluralize 'song' }} to</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -10,11 +10,11 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>or create a new playlist</p>
|
<p>or create a new playlist</p>
|
||||||
|
|
||||||
<form class="form-save form-simple" @submit.prevent="createNewPlaylistFromSongs">
|
<form class="form-save form-simple" @submit.prevent="createNewPlaylistFromSongs">
|
||||||
<input type="text"
|
<input type="text"
|
||||||
@keyup.esc.prevent="hideMenu"
|
@keyup.esc.prevent="hideMenu"
|
||||||
v-model="newPlaylistName"
|
v-model="newPlaylistName"
|
||||||
placeholder="Playlist name"
|
placeholder="Playlist name"
|
||||||
required>
|
required>
|
||||||
<button type="submit">
|
<button type="submit">
|
||||||
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import VueClickaway from 'vue-clickaway';
|
||||||
|
|
||||||
import playlistStore from '../../stores/playlist';
|
import playlistStore from '../../stores/playlist';
|
||||||
import favoriteStore from '../../stores/favorite';
|
import favoriteStore from '../../stores/favorite';
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['songs', 'showing', 'settings'],
|
props: ['songs', 'showing', 'settings'],
|
||||||
|
mixins: [ VueClickaway.mixin ],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -106,14 +108,14 @@
|
||||||
*/
|
*/
|
||||||
createNewPlaylistFromSongs() {
|
createNewPlaylistFromSongs() {
|
||||||
this.newPlaylistName = this.newPlaylistName.trim();
|
this.newPlaylistName = this.newPlaylistName.trim();
|
||||||
|
|
||||||
if (!this.newPlaylistName) {
|
if (!this.newPlaylistName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlistStore.store(this.newPlaylistName, this.songs, () => {
|
playlistStore.store(this.newPlaylistName, this.songs, () => {
|
||||||
this.newPlaylistName = '';
|
this.newPlaylistName = '';
|
||||||
|
|
||||||
// Activate the new playlist right away
|
// Activate the new playlist right away
|
||||||
this.$root.loadPlaylist(_.last(this.playlistState.playlists));
|
this.$root.loadPlaylist(_.last(this.playlistState.playlists));
|
||||||
});
|
});
|
||||||
|
@ -127,8 +129,8 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
clearSelection() {
|
clearSelection() {
|
||||||
this.$parent.$broadcast('song:selection-clear');
|
this.$parent.$broadcast('song:selection-clear');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -144,7 +146,7 @@
|
||||||
top: 36px;
|
top: 36px;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
|
@ -159,7 +161,7 @@
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
max-height: 5 * ($itemHeight + $itemMargin);
|
max-height: 5 * ($itemHeight + $itemMargin);
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue