playlists

This commit is contained in:
Ondrej Zara 2019-03-28 15:23:28 +01:00
parent a2b6c45125
commit 5c9be9ceac
15 changed files with 235 additions and 73 deletions

View file

@ -39,14 +39,6 @@ button {
line-height: 1; line-height: 1;
cursor: pointer; cursor: pointer;
} }
.icon {
width: 24px;
}
.icon path:not([fill]),
.icon polygon:not([fill]),
.icon circle:not([fill]) {
fill: currentColor;
}
@font-face { @font-face {
font-family: 'Lato'; font-family: 'Lato';
src: url('font/LatoLatin-Regular.woff2') format('woff2'); src: url('font/LatoLatin-Regular.woff2') format('woff2');
@ -59,6 +51,15 @@ button {
font-style: bold; font-style: bold;
font-weight: normal; font-weight: normal;
} }
.icon {
vertical-align: middle;
width: 24px;
}
.icon path:not([fill]),
.icon polygon:not([fill]),
.icon circle:not([fill]) {
fill: currentColor;
}
main { main {
flex-grow: 1; flex-grow: 1;
overflow: hidden; overflow: hidden;
@ -90,6 +91,9 @@ nav ul li.active {
} }
#player .info { #player .info {
flex-grow: 1; flex-grow: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
#player:not([data-state=play]) .pause { #player:not([data-state=play]) .pause {
display: none; display: none;
@ -128,6 +132,7 @@ nav ul li.active {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 4px;
} }
.component .grid li h2 { .component .grid li h2 {
flex-grow: 1; flex-grow: 1;
@ -138,12 +143,17 @@ nav ul li.active {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.component .grid li button {
flex-shrink: 0;
}
@media (pointer: coarse) {
.component .grid li button .icon {
width: 32px;
}
}
.component .grid li:nth-child(odd) { .component .grid li:nth-child(odd) {
background-color: #555; background-color: #555;
} }
.component .grid button {
flex-shrink: 0;
}
#queue { #queue {
height: 100%; height: 100%;
display: flex; display: flex;
@ -160,6 +170,7 @@ nav ul li.active {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 4px;
} }
#queue .grid li h2 { #queue .grid li h2 {
flex-grow: 1; flex-grow: 1;
@ -170,12 +181,17 @@ nav ul li.active {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#queue .grid li button {
flex-shrink: 0;
}
@media (pointer: coarse) {
#queue .grid li button .icon {
width: 32px;
}
}
#queue .grid li:nth-child(odd) { #queue .grid li:nth-child(odd) {
background-color: #555; background-color: #555;
} }
#queue .grid button {
flex-shrink: 0;
}
#queue .current { #queue .current {
font-weight: bold; font-weight: bold;
} }
@ -195,6 +211,7 @@ nav ul li.active {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 4px;
} }
#library .grid li h2 { #library .grid li h2 {
flex-grow: 1; flex-grow: 1;
@ -205,12 +222,17 @@ nav ul li.active {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#library .grid li button {
flex-shrink: 0;
}
@media (pointer: coarse) {
#library .grid li button .icon {
width: 32px;
}
}
#library .grid li:nth-child(odd) { #library .grid li:nth-child(odd) {
background-color: #555; background-color: #555;
} }
#library .grid button {
flex-shrink: 0;
}
#fs { #fs {
height: 100%; height: 100%;
display: flex; display: flex;
@ -227,6 +249,7 @@ nav ul li.active {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 4px;
} }
#fs .grid li h2 { #fs .grid li h2 {
flex-grow: 1; flex-grow: 1;
@ -237,9 +260,52 @@ nav ul li.active {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#fs .grid li button {
flex-shrink: 0;
}
@media (pointer: coarse) {
#fs .grid li button .icon {
width: 32px;
}
}
#fs .grid li:nth-child(odd) { #fs .grid li:nth-child(odd) {
background-color: #555; background-color: #555;
} }
#fs .grid button { #playlists {
height: 100%;
display: flex;
flex-direction: column;
}
#playlists ul {
flex-grow: 1;
overflow: auto;
list-style: none;
margin: 0;
padding: 0;
}
#playlists .grid li {
display: flex;
flex-direction: row;
align-items: center;
padding: 0 4px;
}
#playlists .grid li h2 {
flex-grow: 1;
font-size: 100%;
font-weight: normal;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#playlists .grid li button {
flex-shrink: 0; flex-shrink: 0;
} }
@media (pointer: coarse) {
#playlists .grid li button .icon {
width: 32px;
}
}
#playlists .grid li:nth-child(odd) {
background-color: #555;
}

View file

@ -39,18 +39,9 @@ button {
cursor: pointer; cursor: pointer;
} }
.icon {
width: 24px;
path, polygon, circle {
&:not([fill]) {
fill: currentColor;
}
}
}
@import "font.less"; @import "font.less";
@import "icons.less";
@import "main.less"; @import "main.less";
@import "nav.less"; @import "nav.less";
@import "player.less"; @import "player.less";
@ -58,3 +49,4 @@ button {
@import "queue.less"; @import "queue.less";
@import "library.less"; @import "library.less";
@import "fs.less"; @import "fs.less";
@import "playlists.less";

View file

@ -16,6 +16,7 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 4px;
h2 { h2 {
flex-grow: 1; flex-grow: 1;
@ -26,14 +27,18 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
button {
flex-shrink: 0;
@media (pointer: coarse) {
.icon { width: 32px; }
}
}
} }
li:nth-child(odd) { li:nth-child(odd) {
background-color: #555; background-color: #555;
} }
button {
flex-shrink: 0;
}
} }
} }

10
app/css/icons.less Normal file
View file

@ -0,0 +1,10 @@
.icon {
vertical-align: middle;
width: 24px;
path, polygon, circle {
&:not([fill]) {
fill: currentColor;
}
}
}

View file

@ -3,7 +3,12 @@
flex-direction: row; flex-direction: row;
.art img { vertical-align: top; } .art img { vertical-align: top; }
.info { flex-grow: 1; } .info {
flex-grow: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&:not([data-state=play]) .pause { display: none; } &:not([data-state=play]) .pause { display: none; }
&[data-state=play] .play { display: none; } &[data-state=play] .play { display: none; }

3
app/css/playlists.less Normal file
View file

@ -0,0 +1,3 @@
#playlists {
.component;
}

View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M15,9H5V5H15M12,19A3,3 0 0,1 9,16A3,3 0 0,1 12,13A3,3 0 0,1 15,16A3,3 0 0,1 12,19M17,3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V7L17,3Z" /></svg>

After

Width:  |  Height:  |  Size: 445 B

View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M15,6H3V8H15V6M15,10H3V12H15V10M3,16H11V14H3V16M17,6V14.18C16.69,14.07 16.35,14 16,14A3,3 0 0,0 13,17A3,3 0 0,0 16,20A3,3 0 0,0 19,17V8H22V6H17Z" /></svg>

After

Width:  |  Height:  |  Size: 439 B

View file

@ -27,10 +27,15 @@
</header> </header>
<main> <main>
<section id="queue"> <section id="queue">
<header></header> <header>
<button class="clear"></button>
<button class="save"></button>
</header>
<ul class="grid"></ul>
</section>
<section id="playlists">
<ul class="grid"></ul> <ul class="grid"></ul>
</section> </section>
<section id="playlists"></section>
<section id="library"> <section id="library">
<header></header> <header></header>
<ul></ul> <ul></ul>

View file

@ -5,8 +5,9 @@ import * as player from "./player.js";
import * as queue from "./queue.js"; import * as queue from "./queue.js";
import * as library from "./library.js"; import * as library from "./library.js";
import * as fs from "./fs.js"; import * as fs from "./fs.js";
import * as playlists from "./playlists.js";
const components = { queue, library, fs }; const components = { queue, library, fs, playlists };
export function activate(what) { export function activate(what) {
for (let id in components) { for (let id in components) {

View file

@ -1,58 +1,64 @@
let ICONS={}; let ICONS={};
ICONS["play-circle-outline"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24"> ICONS["pause"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M10,16.5L16,12L10,7.5V16.5Z"/> <path d="M14,19H18V5H14M6,19H10V5H6V19Z"/>
</svg>`;
ICONS["shuffle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M14.83,13.41L13.42,14.82L16.55,17.95L14.5,20H20V14.5L17.96,16.54L14.83,13.41M14.5,4L16.54,6.04L4,18.59L5.41,20L17.96,7.46L20,9.5V4M10.59,9.17L5.41,4L4,5.41L9.17,10.58L10.59,9.17Z"/>
</svg>`;
ICONS["minus-circle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M17,13H7V11H17M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/>
</svg>`; </svg>`;
ICONS["rewind"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24"> ICONS["rewind"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M11.5,12L20,18V6M11,18V6L2.5,12L11,18Z"/> <path d="M11.5,12L20,18V6M11,18V6L2.5,12L11,18Z"/>
</svg>`; </svg>`;
ICONS["pause"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M14,19H18V5H14M6,19H10V5H6V19Z"/>
</svg>`;
ICONS["pause-circle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M15,16H13V8H15M11,16H9V8H11M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/>
</svg>`;
ICONS["close-circle-outline"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22C17.53,22 22,17.53 22,12C22,6.47 17.53,2 12,2M14.59,8L12,10.59L9.41,8L8,9.41L10.59,12L8,14.59L9.41,16L12,13.41L14.59,16L16,14.59L13.41,12L16,9.41L14.59,8Z"/>
</svg>`;
ICONS["close"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"/>
</svg>`;
ICONS["minus"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M19,13H5V11H19V13Z"/>
</svg>`;
ICONS["close-circle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z"/>
</svg>`;
ICONS["repeat"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M17,17H7V14L3,18L7,22V19H19V13H17M7,7H17V10L21,6L17,2V5H5V11H7V7Z"/>
</svg>`;
ICONS["play"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24"> ICONS["play"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M8,5.14V19.14L19,12.14L8,5.14Z"/> <path d="M8,5.14V19.14L19,12.14L8,5.14Z"/>
</svg>`; </svg>`;
ICONS["pause-circle-outline"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24"> ICONS["play-circle-outline"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M13,16V8H15V16H13M9,16V8H11V16H9M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z"/> <path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M10,16.5L16,12L10,7.5V16.5Z"/>
</svg>`; </svg>`;
ICONS["plus"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24"> ICONS["plus"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z"/> <path d="M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z"/>
</svg>`; </svg>`;
ICONS["close-circle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z"/>
</svg>`;
ICONS["minus"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M19,13H5V11H19V13Z"/>
</svg>`;
ICONS["shuffle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M14.83,13.41L13.42,14.82L16.55,17.95L14.5,20H20V14.5L17.96,16.54L14.83,13.41M14.5,4L16.54,6.04L4,18.59L5.41,20L17.96,7.46L20,9.5V4M10.59,9.17L5.41,4L4,5.41L9.17,10.58L10.59,9.17Z"/>
</svg>`;
ICONS["content-save"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M15,9H5V5H15M12,19A3,3 0 0,1 9,16A3,3 0 0,1 12,13A3,3 0 0,1 15,16A3,3 0 0,1 12,19M17,3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V7L17,3Z"/>
</svg>`;
ICONS["fast-forward"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24"> ICONS["fast-forward"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M13,6V18L21.5,12M4,18L12.5,12L4,6V18Z"/> <path d="M13,6V18L21.5,12M4,18L12.5,12L4,6V18Z"/>
</svg>`; </svg>`;
ICONS["close"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"/>
</svg>`;
ICONS["pause-circle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M15,16H13V8H15M11,16H9V8H11M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/>
</svg>`;
ICONS["minus-circle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M17,13H7V11H17M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/>
</svg>`;
ICONS["plus-circle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M17,13H13V17H11V13H7V11H11V7H13V11H17M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/>
</svg>`;
ICONS["minus-circle-outline"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24"> ICONS["minus-circle-outline"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M7,13H17V11H7"/> <path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M7,13H17V11H7"/>
</svg>`; </svg>`;
ICONS["playlist-music"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M15,6H3V8H15V6M15,10H3V12H15V10M3,16H11V14H3V16M17,6V14.18C16.69,14.07 16.35,14 16,14A3,3 0 0,0 13,17A3,3 0 0,0 16,20A3,3 0 0,0 19,17V8H22V6H17Z"/>
</svg>`;
ICONS["repeat"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M17,17H7V14L3,18L7,22V19H19V13H17M7,7H17V10L21,6L17,2V5H5V11H7V7Z"/>
</svg>`;
ICONS["close-circle-outline"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22C17.53,22 22,17.53 22,12C22,6.47 17.53,2 12,2M14.59,8L12,10.59L9.41,8L8,9.41L10.59,12L8,14.59L9.41,16L12,13.41L14.59,16L16,14.59L13.41,12L16,9.41L14.59,8Z"/>
</svg>`;
ICONS["pause-circle-outline"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M13,16V8H15V16H13M9,16V8H11V16H9M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z"/>
</svg>`;
ICONS["plus-circle-outline"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24"> ICONS["plus-circle-outline"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,7H11V11H7V13H11V17H13V13H17V11H13V7Z"/> <path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,7H11V11H7V13H11V17H13V13H17V11H13V7Z"/>
</svg>`; </svg>`;
ICONS["plus-circle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M17,13H13V17H11V13H7V11H11V7H13V11H17M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/>
</svg>`;
ICONS["play-circle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24"> ICONS["play-circle"] = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
<path d="M10,16.5V7.5L16,12M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/> <path d="M10,16.5V7.5L16,12M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/>
</svg>`; </svg>`;

View file

@ -77,6 +77,15 @@ export async function listQueue() {
return parser.songList(lines); return parser.songList(lines);
} }
export async function listPlaylists() {
let lines = await command("listplaylists");
let parsed = parser.linesToStruct(lines);
let list = parsed["playlist"];
if (!list) { return []; }
return (list instanceof Array ? list : [list]);
}
export async function enqueue(urlOrFilter, sort = null) { export async function enqueue(urlOrFilter, sort = null) {
if (typeof(urlOrFilter) == "string") { if (typeof(urlOrFilter) == "string") {
return command(`add "${escape(urlOrFilter)}"`); return command(`add "${escape(urlOrFilter)}"`);
@ -126,6 +135,10 @@ export async function albumArt(songUrl) {
} }
} }
export async function save(name) {
return command(`save "${escape(name)}"`);
}
export async function init() { export async function init() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {

View file

@ -45,7 +45,7 @@ function playButton(id, parent) {
} }
function deleteButton(id, parent) { function deleteButton(id, parent) {
let button = html.button({icon:"close"}, "", parent); let button = html.button({icon:"close", title:"Delete from queue"}, "", parent);
button.addEventListener("click", async e => { button.addEventListener("click", async e => {
await mpd.command(`deleteid ${id}`); await mpd.command(`deleteid ${id}`);
pubsub.publish("queue-change"); pubsub.publish("queue-change");
@ -67,7 +67,7 @@ function addAndPlayButton(urlOrFilter, parent) {
} }
function addButton(urlOrFilter, parent) { function addButton(urlOrFilter, parent) {
let button = html.button({icon:"plus"}, "", parent); let button = html.button({icon:"plus", title:"Add to queue"}, "", parent);
button.addEventListener("click", async e => { button.addEventListener("click", async e => {
e.stopPropagation(); e.stopPropagation();
await mpd.enqueue(urlOrFilter, SORT); await mpd.enqueue(urlOrFilter, SORT);
@ -109,4 +109,17 @@ export function group(type, label, urlOrFilter, parent) {
addButton(urlOrFilter, node); addButton(urlOrFilter, node);
return node; return node;
} }
export function playlist(name, parent) {
let node = html.node("li", {}, "", parent);
html.icon("playlist-music", node)
html.node("h2", {}, name, node);
// addAndPlayButton(url, node);
// addButton(url, node);
// deleteButton(id, node);
return node;
}

26
app/js/playlists.js Normal file
View file

@ -0,0 +1,26 @@
import * as mpd from "./lib/mpd.js";
import * as html from "./lib/html.js";
import * as pubsub from "./lib/pubsub.js";
import * as ui from "./lib/ui.js";
let node;
function buildLists(lists) {
let ul = node.querySelector("ul");
html.clear(ul);
lists.map(list => ui.playlist(list, ul));
}
async function syncLists() {
let lists = await mpd.listPlaylists();
buildLists(lists);
}
export async function activate() {
syncLists();
}
export function init(n) {
node = n;
}

View file

@ -46,4 +46,19 @@ export function init(n) {
syncQueue(); syncQueue();
pubsub.subscribe("song-change", onSongChange); pubsub.subscribe("song-change", onSongChange);
pubsub.subscribe("queue-change", onQueueChange); pubsub.subscribe("queue-change", onQueueChange);
let clear = node.querySelector(".clear");
clear.appendChild(html.icon("close"));
clear.addEventListener("click", async e => {
await mpd.command("clear");
syncQueue();
});
let save = node.querySelector(".save");
save.appendChild(html.icon("content-save"));
save.addEventListener("click", e => {
let name = prompt("Save current queue as a playlist?", "name");
if (name === null) { return; }
mpd.save(name);
});
} }