diff --git a/Makefile b/Makefile
index 1109956..fb6d038 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
LESS := $(shell npm bin)/lessc
APP := app
CSS := $(APP)/cyp.css
-ICONS := $(APP)/js/lib/icons.js
+ICONS := $(APP)/js/icons.js
SYSD_USER := ~/.config/systemd/user
SERVICE := cyp.service
diff --git a/app/css/component.less b/app/css/component.less
index fc81fa5..bf9d6ab 100644
--- a/app/css/component.less
+++ b/app/css/component.less
@@ -38,7 +38,7 @@
margin: 0;
}
- h2, div { .long-line; }
+// h2, div { .long-line; }
}
&.has-art {
diff --git a/app/css/cyp.less b/app/css/cyp.less
index 2c2f3d4..32d1d4a 100644
--- a/app/css/cyp.less
+++ b/app/css/cyp.less
@@ -22,7 +22,7 @@ header, footer {
footer {
position: relative;
height: 56px;
- @media (max-width: 480px) {
+ @media (max-width: @breakpoint-menu) {
height: 40px;
}
}
diff --git a/app/css/elements/menu.less b/app/css/elements/menu.less
index 147aedf..318df05 100644
--- a/app/css/elements/menu.less
+++ b/app/css/elements/menu.less
@@ -9,7 +9,7 @@ cyp-menu, cyp-commands {
align-items: center;
justify-content: center;
- @media (max-width: 480px) {
+ @media (max-width: @breakpoint-menu) {
flex-direction: row;
span:not([id]) { display: none; }
}
@@ -47,7 +47,7 @@ cyp-commands {
}
button {
- flex: 0 0 80px;
+ flex: 0 0 @breakpoint-menu/6;
&.last {
order: 1;
margin-left: auto;
diff --git a/app/css/elements/player.less b/app/css/elements/player.less
index 8cee6fa..f506b66 100644
--- a/app/css/elements/player.less
+++ b/app/css/elements/player.less
@@ -34,7 +34,7 @@ cyp-player {
margin: 0;
}
- .title, .subtitle { .long-line; }
+ .title, .subtitle { .no-wrap; }
}
.timeline {
diff --git a/app/css/elements/playlist.less b/app/css/elements/playlist.less
index 6cc20df..bb82ead 100644
--- a/app/css/elements/playlist.less
+++ b/app/css/elements/playlist.less
@@ -1,7 +1,5 @@
cyp-playlist {
- .flex-row;
-
- padding: 8px;
+ .item;
&:nth-child(odd) {
background-color: var(--bg-alt);
diff --git a/app/css/elements/playlists.less b/app/css/elements/playlists.less
index fe50244..ffb438f 100644
--- a/app/css/elements/playlists.less
+++ b/app/css/elements/playlists.less
@@ -1,7 +1,2 @@
cyp-playlists {
- .component;
-
- .info {
- .multiline;
- }
-}
\ No newline at end of file
+}
diff --git a/app/css/elements/song.less b/app/css/elements/song.less
index a187253..570a86a 100644
--- a/app/css/elements/song.less
+++ b/app/css/elements/song.less
@@ -1,6 +1,5 @@
cyp-song {
- .selectable;
- .flex-row;
+ .item;
.info { // FIXME zrevidovat
flex-grow: 1;
@@ -17,14 +16,6 @@ cyp-song {
margin: 0;
}
- h2, div { .long-line; }
- }
-
- &:nth-child(odd) {
- background-color: var(--bg-alt);
- }
-
- &:not(.has-art) {
- padding: 8px;
+// h2, div { .long-line; } FIXME vyresit zalamovani/vypustku
}
}
diff --git a/app/css/fs.less b/app/css/fs.less
index 1584d2a..493ade7 100644
--- a/app/css/fs.less
+++ b/app/css/fs.less
@@ -15,6 +15,6 @@
}
.info {
- .multiline;
+// .multiline; FIXME
}
}
diff --git a/app/css/mixins.less b/app/css/mixins.less
index 676cac4..53ebfbe 100644
--- a/app/css/mixins.less
+++ b/app/css/mixins.less
@@ -9,17 +9,19 @@
flex-direction: column;
}
-.long-line {
+.no-wrap {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
+/*
.multiline {
.flex-row;
h2 { font-weight: normal; }
}
+*/
.selectable {
border-left: 4px solid transparent;
@@ -28,3 +30,13 @@
border-left-color: var(--primary);
}
}
+
+.item {
+ .flex-row;
+ .selectable;
+ padding: 8px;
+
+ &:nth-child(odd) {
+ background-color: var(--bg-alt);
+ }
+}
\ No newline at end of file
diff --git a/app/css/variables.less b/app/css/variables.less
index 4f97008..8ad3c9e 100644
--- a/app/css/variables.less
+++ b/app/css/variables.less
@@ -1,3 +1,5 @@
+@breakpoint-menu: 480px;
+
cyp-app {
--font-size-large: 112.5%;
--icon-spacing: 4px;
@@ -43,7 +45,7 @@ cyp-app[color=limegreen] {
--primary-raw: 50, 205, 50;
}
-@media (max-width: 480px) {
+@media (max-width: @breakpoint-menu) {
:root {
--spacing: var(--icon-spacing);
}
diff --git a/app/cyp.css b/app/cyp.css
index 7eea054..995133b 100644
--- a/app/cyp.css
+++ b/app/cyp.css
@@ -91,27 +91,39 @@ select {
.flex-column:not([hidden]) {
display: flex;
}
-.long-line {
+.no-wrap {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
+/*
.multiline {
- flex-direction: row;
- align-items: center;
-}
-.multiline:not([hidden]) {
- display: flex;
-}
-.multiline h2 {
- font-weight: normal;
+ .flex-row;
+
+ h2 { font-weight: normal; }
}
+*/
.selectable {
border-left: 4px solid transparent;
}
.selectable.selected {
border-left-color: var(--primary);
}
+.item {
+ flex-direction: row;
+ align-items: center;
+ border-left: 4px solid transparent;
+ padding: 8px;
+}
+.item:not([hidden]) {
+ display: flex;
+}
+.item.selected {
+ border-left-color: var(--primary);
+}
+.item:nth-child(odd) {
+ background-color: var(--bg-alt);
+}
.component header {
flex-direction: row;
align-items: center;
@@ -155,12 +167,6 @@ select {
font-size: var(--font-size-large);
margin: 0;
}
-.component li .info h2,
-.component li .info div {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
.component li:not(.has-art) {
padding: 8px;
}
@@ -213,12 +219,6 @@ select {
font-size: var(--font-size-large);
margin: 0;
}
-#library li .info h2,
-#library li .info div {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
#library li:not(.has-art) {
padding: 8px;
}
@@ -308,12 +308,6 @@ select {
font-size: var(--font-size-large);
margin: 0;
}
-#fs li .info h2,
-#fs li .info div {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
#fs li:not(.has-art) {
padding: 8px;
}
@@ -335,16 +329,6 @@ select {
#fs .group {
cursor: pointer;
}
-#fs .info {
- flex-direction: row;
- align-items: center;
-}
-#fs .info:not([hidden]) {
- display: flex;
-}
-#fs .info h2 {
- font-weight: normal;
-}
.search {
flex-direction: row;
align-items: center;
@@ -509,15 +493,19 @@ cyp-commands button.last {
margin-left: auto;
}
cyp-song {
- border-left: 4px solid transparent;
flex-direction: row;
align-items: center;
+ border-left: 4px solid transparent;
+ padding: 8px;
+}
+cyp-song:not([hidden]) {
+ display: flex;
}
cyp-song.selected {
border-left-color: var(--primary);
}
-cyp-song:not([hidden]) {
- display: flex;
+cyp-song:nth-child(odd) {
+ background-color: var(--bg-alt);
}
cyp-song .info {
flex-grow: 1;
@@ -532,18 +520,6 @@ cyp-song .info h2 {
font-size: var(--font-size-large);
margin: 0;
}
-cyp-song .info h2,
-cyp-song .info div {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-cyp-song:nth-child(odd) {
- background-color: var(--bg-alt);
-}
-cyp-song:not(.has-art) {
- padding: 8px;
-}
cyp-player {
flex-direction: row;
align-items: center;
@@ -662,74 +638,6 @@ cyp-player .misc .icon {
height: 96px;
}
}
-cyp-playlists header {
- flex-direction: row;
- align-items: center;
- padding: var(--spacing);
-}
-cyp-playlists header:not([hidden]) {
- display: flex;
-}
-cyp-playlists header button {
- font-size: var(--font-size-large);
- font-weight: bold;
- overflow: hidden;
-}
-cyp-playlists header button .icon {
- margin-right: var(--icon-spacing);
-}
-cyp-playlists ul {
- flex-grow: 1;
- overflow: auto;
- list-style: none;
- margin: 0;
- padding: 0;
-}
-cyp-playlists li {
- flex-direction: row;
- align-items: center;
-}
-cyp-playlists li:not([hidden]) {
- display: flex;
-}
-cyp-playlists li .info {
- flex-grow: 1;
- overflow: hidden;
-}
-cyp-playlists li .info .icon {
- color: var(--primary);
- margin-right: var(--icon-spacing);
- filter: drop-shadow(var(--text-shadow));
-}
-cyp-playlists li .info h2 {
- font-size: var(--font-size-large);
- margin: 0;
-}
-cyp-playlists li .info h2,
-cyp-playlists li .info div {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-cyp-playlists li:not(.has-art) {
- padding: 8px;
-}
-cyp-playlists li button .icon {
- width: 32px;
-}
-cyp-playlists li:nth-child(odd) {
- background-color: var(--bg-alt);
-}
-cyp-playlists .info {
- flex-direction: row;
- align-items: center;
-}
-cyp-playlists .info:not([hidden]) {
- display: flex;
-}
-cyp-playlists .info h2 {
- font-weight: normal;
-}
cyp-queue .current {
color: var(--primary);
}
@@ -808,12 +716,6 @@ cyp-yt li .info h2 {
font-size: var(--font-size-large);
margin: 0;
}
-cyp-yt li .info h2,
-cyp-yt li .info div {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
cyp-yt li:not(.has-art) {
padding: 8px;
}
@@ -917,11 +819,18 @@ x-range:not([disabled]) .-thumb:hover {
cyp-playlist {
flex-direction: row;
align-items: center;
+ border-left: 4px solid transparent;
padding: 8px;
}
cyp-playlist:not([hidden]) {
display: flex;
}
+cyp-playlist.selected {
+ border-left-color: var(--primary);
+}
+cyp-playlist:nth-child(odd) {
+ background-color: var(--bg-alt);
+}
cyp-playlist:nth-child(odd) {
background-color: var(--bg-alt);
}
diff --git a/app/icons/cancel.svg b/app/icons/cancel.svg
new file mode 100644
index 0000000..f798721
--- /dev/null
+++ b/app/icons/cancel.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/js/component.js b/app/js/component.js
index 27c2471..02b0fbe 100644
--- a/app/js/component.js
+++ b/app/js/component.js
@@ -13,9 +13,9 @@ export class Item extends HasApp {
}
export default class Component extends HasApp {
- constructor() {
+ constructor(options) {
super();
- this.selection = new Selection(this);
+ if (options.selection) { this.selection = new Selection(this, options.selection); }
}
connectedCallback() {
diff --git a/app/js/elements/menu.js b/app/js/elements/menu.js
index 42340b5..3dc55f9 100644
--- a/app/js/elements/menu.js
+++ b/app/js/elements/menu.js
@@ -2,7 +2,7 @@ import Component from "../component.js";
class Menu extends Component {
constructor() {
- super();
+ super({selection:null});
this._tabs = Array.from(this.querySelectorAll("[data-for]"));
this._tabs.forEach(tab => {
@@ -10,19 +10,13 @@ class Menu extends Component {
});
}
- async _listen() {
- const app = await this._app;
- let mo = new MutationObserver(_ => this._sync())
- mo.observe(app, {attributes:true});
- }
-
async _activate(component) {
const app = await this._app;
app.setAttribute("component", component);
}
_onComponentChange(component) {
- this._tabs.forEach(tab => {
+ this._tabs.forEach(/** @param {HTMLElement} tab */ tab => {
tab.classList.toggle("active", tab.dataset.for == component);
});
}
diff --git a/app/js/elements/player.js b/app/js/elements/player.js
index f0a3fe2..dcb56be 100644
--- a/app/js/elements/player.js
+++ b/app/js/elements/player.js
@@ -8,7 +8,7 @@ const DELAY = 1000;
class Player extends Component {
constructor() {
- super();
+ super({selection:null});
this._current = {};
this._toggledVolume = 0;
this._idleTimeout = null;
diff --git a/app/js/elements/playlist.js b/app/js/elements/playlist.js
index c5ec335..3054ca7 100644
--- a/app/js/elements/playlist.js
+++ b/app/js/elements/playlist.js
@@ -10,12 +10,6 @@ export default class Playlist extends Item {
connectedCallback() {
html.icon("playlist-music", this)
html.node("h2", {}, this.name, this);
-
-/*
- playButton(TYPE_PLAYLIST, name, node);
- addButton(TYPE_PLAYLIST, name, node);
- deleteButton(TYPE_PLAYLIST, name, node);
-*/
}
}
diff --git a/app/js/elements/playlists.js b/app/js/elements/playlists.js
index 8477db9..b8ceb0b 100644
--- a/app/js/elements/playlists.js
+++ b/app/js/elements/playlists.js
@@ -1,11 +1,14 @@
import * as html from "../html.js";
-import * as ui from "../ui.js";
-
import Component from "../component.js";
import Playlist from "./playlist.js";
class Playlists extends Component {
+ constructor() {
+ super({selection:"single"});
+ this._initCommands();
+ }
+
handleEvent(e) {
switch (e.type) {
case "playlists-change":
@@ -30,9 +33,25 @@ class Playlists extends Component {
_buildLists(lists) {
html.clear(this);
+ this.selection.clear();
lists.forEach(name => this.appendChild(new Playlist(name)));
}
+
+ _initCommands() {
+ const sel = this.selection;
+
+ sel.addCommand(async items => {
+ }, {label:"Play", icon:"play"});
+
+ sel.addCommand(async items => {
+ }, {label:"Enqueue", icon:"plus"});
+
+ sel.addCommand(async items => {
+ }, {label:"Delete", icon:"delete"});
+
+ sel.addCommandCancel();
+ }
}
customElements.define("cyp-playlists", Playlists);
diff --git a/app/js/elements/queue.js b/app/js/elements/queue.js
index 0822236..5dad233 100644
--- a/app/js/elements/queue.js
+++ b/app/js/elements/queue.js
@@ -2,9 +2,10 @@ import * as html from "../html.js";
import Component from "../component.js";
import Song from "./song.js";
+
class Queue extends Component {
constructor() {
- super();
+ super({selection:"multi"});
this._currentId = null;
this._initCommands();
}
@@ -35,7 +36,6 @@ class Queue extends Component {
}
async _sync() {
- this.selection.clear();
let songs = await this._mpd.listQueue();
this._buildSongs(songs);
@@ -51,6 +51,7 @@ class Queue extends Component {
_buildSongs(songs) {
html.clear(this);
+ this.selection.clear();
songs.forEach(song => this.appendChild(new Song(song)));
@@ -84,7 +85,7 @@ class Queue extends Component {
this._sync();
}, {label:"Remove", icon:"delete"});
- sel.addCommandClear();
+ sel.addCommandCancel();
}
}
diff --git a/app/js/elements/settings.js b/app/js/elements/settings.js
index 79d533d..65f9791 100644
--- a/app/js/elements/settings.js
+++ b/app/js/elements/settings.js
@@ -12,7 +12,7 @@ function saveToStorage(key, value) {
class Settings extends Component {
constructor() {
- super();
+ super({selection:null});
this._inputs = {
theme: this.querySelector("[name=theme]"),
color: Array.from(this.querySelectorAll("[name=color]"))
diff --git a/app/js/icons.js b/app/js/icons.js
index 34d24eb..811ef25 100644
--- a/app/js/icons.js
+++ b/app/js/icons.js
@@ -1,15 +1,33 @@
let ICONS={};
-ICONS["library-music"] = ``;
-ICONS["plus"] = `