tag/path queueing
This commit is contained in:
parent
aca1f44a60
commit
c3871fa486
16 changed files with 62 additions and 161 deletions
|
@ -1,6 +1,4 @@
|
||||||
.art {
|
.art {
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
.icon, img {
|
.icon, img { display: block; }
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
.component {
|
|
||||||
header {
|
|
||||||
.flex-row;
|
|
||||||
padding: var(--spacing);
|
|
||||||
|
|
||||||
button {
|
|
||||||
font-size: var(--font-size-large);
|
|
||||||
font-weight: bold;
|
|
||||||
.icon { margin-right: var(--icon-spacing); }
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: auto;
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
.flex-row;
|
|
||||||
|
|
||||||
.info {
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: var(--primary);
|
|
||||||
margin-right: var(--icon-spacing);
|
|
||||||
filter: drop-shadow(var(--text-shadow));
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: var(--font-size-large);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// h2, div { .long-line; }
|
|
||||||
}
|
|
||||||
|
|
||||||
&.has-art {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.has-art) {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button .icon { width: 32px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
li:nth-child(odd) {
|
|
||||||
background-color: var(--bg-alt);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -65,9 +65,6 @@ select {
|
||||||
@import "font.less";
|
@import "font.less";
|
||||||
@import "icons.less";
|
@import "icons.less";
|
||||||
@import "mixins.less";
|
@import "mixins.less";
|
||||||
@import "component.less";
|
|
||||||
@import "library.less";
|
|
||||||
@import "fs.less";
|
|
||||||
@import "search.less";
|
@import "search.less";
|
||||||
@import "art.less";
|
@import "art.less";
|
||||||
@import "variables.less";
|
@import "variables.less";
|
||||||
|
|
|
@ -1,3 +1,16 @@
|
||||||
cyp-tag {
|
cyp-tag {
|
||||||
.item;
|
.item;
|
||||||
|
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.art {
|
||||||
|
img, .icon {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
filter: drop-shadow(var(--text-shadow));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
cyp-yt {
|
cyp-yt {
|
||||||
.component;
|
|
||||||
|
|
||||||
header {
|
header {
|
||||||
border-bottom: 1px solid var(--fg);
|
border-bottom: 1px solid var(--fg);
|
||||||
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
#fs {
|
|
||||||
.component;
|
|
||||||
|
|
||||||
header {
|
|
||||||
white-space: pre; // separator
|
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
|
||||||
order: 1;
|
|
||||||
&.open ~ * { display: none; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.group {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info {
|
|
||||||
// .multiline; FIXME
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
.icon {
|
.icon {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
// flex-shrink: 0;
|
flex: none;
|
||||||
|
|
||||||
path, polygon, circle {
|
path, polygon, circle {
|
||||||
&:not([fill]) {
|
&:not([fill]) {
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
#library {
|
|
||||||
.component;
|
|
||||||
|
|
||||||
header {
|
|
||||||
white-space: pre; // separator
|
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
|
||||||
order: 1;
|
|
||||||
&.open ~ * { display: none; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.art img, .art .icon {
|
|
||||||
width: 64px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.art .icon {
|
|
||||||
filter: drop-shadow(var(--text-shadow));
|
|
||||||
}
|
|
||||||
|
|
||||||
.group {
|
|
||||||
cursor: pointer;
|
|
||||||
h2 { font-weight: normal; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.tiles {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
||||||
grid-gap: 2px;
|
|
||||||
|
|
||||||
li {
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: rgba(255, 255, 255, 0.08);
|
|
||||||
height: 200px;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 150%;
|
|
||||||
margin: 4px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,21 +14,32 @@
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
.multiline {
|
|
||||||
.flex-row;
|
|
||||||
|
|
||||||
h2 { font-weight: normal; }
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
.selectable {
|
.selectable {
|
||||||
border-left: var(--border-width) solid transparent;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
position: relative; // kotva pro selected::before
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
border-left-color: var(--primary);
|
xbackground-color: var(--primary-tint); // FIXME jak zvyraznovat?
|
||||||
background-color: var(--primary-tint);
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: var(--border-width);
|
||||||
|
background-color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: var(--primary-tint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,14 +48,12 @@
|
||||||
.selectable;
|
.selectable;
|
||||||
|
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
padding-left: calc(8px - var(--border-width));
|
|
||||||
|
|
||||||
&:nth-child(odd) { // FIXME nutno poresit lepe s ohledem na search
|
&:nth-child(odd) {
|
||||||
background-color: var(--bg-alt);
|
background-color: var(--bg-alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
> .icon {
|
> .icon {
|
||||||
flex: none;
|
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
filter: drop-shadow(var(--text-shadow));
|
filter: drop-shadow(var(--text-shadow));
|
||||||
}
|
}
|
||||||
|
@ -61,5 +70,4 @@
|
||||||
&:first-of-type { margin-left: auto; }
|
&:first-of-type { margin-left: auto; }
|
||||||
.icon { width: 32px; }
|
.icon { width: 32px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -14,7 +14,7 @@ export default class Component extends HasApp {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this._app.addEventListener("load", _ => this._onAppLoad());
|
this._app.addEventListener("load", _ => this._onAppLoad());
|
||||||
this._app.addEventListener("component-change", _ => {
|
this._app.addEventListener("component-change", _ => {
|
||||||
const component = this._app.getAttribute("component");
|
const component = this._app.component;
|
||||||
const isThis = (this.nodeName.toLowerCase() == `cyp-${component}`);
|
const isThis = (this.nodeName.toLowerCase() == `cyp-${component}`);
|
||||||
this._onComponentChange(component, isThis);
|
this._onComponentChange(component, isThis);
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,8 +42,8 @@ class App extends HTMLElement {
|
||||||
this.dispatchEvent(new CustomEvent("load"));
|
this.dispatchEvent(new CustomEvent("load"));
|
||||||
|
|
||||||
const onHashChange = () => {
|
const onHashChange = () => {
|
||||||
const hash = location.hash.substring(1);
|
const component = location.hash.substring(1) || "queue";
|
||||||
this.setAttribute("component", hash || "queue");
|
if (component != this.component) { this.component = component; }
|
||||||
}
|
}
|
||||||
window.addEventListener("hashchange", onHashChange);
|
window.addEventListener("hashchange", onHashChange);
|
||||||
onHashChange();
|
onHashChange();
|
||||||
|
@ -58,6 +58,9 @@ class App extends HTMLElement {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get component() { return this.getAttribute("component"); }
|
||||||
|
set component(component) { return this.setAttribute("component", component); }
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("cyp-app", App);
|
customElements.define("cyp-app", App);
|
||||||
|
|
|
@ -9,14 +9,18 @@ import { escape, serializeFilter } from "../mpd.js";
|
||||||
|
|
||||||
const SORT = "-Track";
|
const SORT = "-Track";
|
||||||
|
|
||||||
|
function nonempty(str) { return (str.length > 0); }
|
||||||
|
|
||||||
function createEnqueueCommand(node) {
|
function createEnqueueCommand(node) {
|
||||||
if (node instanceof Song) {
|
if (node instanceof Song) {
|
||||||
return `add "${escape(node.data["file"])}"`;
|
return `add "${escape(node.data["file"])}"`;
|
||||||
|
} else if (node instanceof Path) {
|
||||||
|
return `add "${escape(node.file)}"`;
|
||||||
} else if (node instanceof Tag) {
|
} else if (node instanceof Tag) {
|
||||||
return [
|
return [
|
||||||
"findadd",
|
"findadd",
|
||||||
serializeFilter(node.createChildFilter()),
|
serializeFilter(node.createChildFilter()),
|
||||||
`sort ${SORT}`
|
// `sort ${SORT}` // MPD >= 0.22, not yet released
|
||||||
].join(" ");
|
].join(" ");
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Cannot create enqueue command for "${node.nodeName}"`);
|
throw new Error(`Cannot create enqueue command for "${node.nodeName}"`);
|
||||||
|
@ -37,7 +41,7 @@ class Library extends Component {
|
||||||
const wasHidden = this.hidden;
|
const wasHidden = this.hidden;
|
||||||
this.hidden = !isThis;
|
this.hidden = !isThis;
|
||||||
|
|
||||||
if (!wasHidden) { this._showRoot(); }
|
if (!wasHidden && isThis) { this._showRoot(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
_showRoot() {
|
_showRoot() {
|
||||||
|
@ -58,7 +62,7 @@ class Library extends Component {
|
||||||
html.clear(this);
|
html.clear(this);
|
||||||
|
|
||||||
if ("AlbumArtist" in filter) { this._buildBack(filter); }
|
if ("AlbumArtist" in filter) { this._buildBack(filter); }
|
||||||
values.forEach(value => this._buildTag(tag, value, filter));
|
values.filter(nonempty).forEach(value => this._buildTag(tag, value, filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _listPath(path) {
|
async _listPath(path) {
|
||||||
|
|
|
@ -9,19 +9,21 @@ function baseName(path) {
|
||||||
export default class Path extends Item {
|
export default class Path extends Item {
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
super();
|
super();
|
||||||
this.data = data;
|
this._data = data;
|
||||||
// FIXME spis ._data a .url
|
|
||||||
|
if ("directory" in this._data) {
|
||||||
|
this.file = data["directory"];
|
||||||
|
} else {
|
||||||
|
this.file = data["file"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
let path;
|
if ("directory" in this._data) {
|
||||||
if ("directory" in this.data) {
|
|
||||||
this.appendChild(html.icon("folder"));
|
this.appendChild(html.icon("folder"));
|
||||||
path = this.data["directory"];
|
|
||||||
} else {
|
} else {
|
||||||
this.appendChild(html.icon("music"));
|
this.appendChild(html.icon("music"));
|
||||||
path = this.data["file"];
|
|
||||||
}
|
}
|
||||||
this._buildTitle(baseName(path));
|
this._buildTitle(baseName(this.file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ class Player extends Component {
|
||||||
let artistOld = this._current["AlbumArtist"] || this._current["Artist"];
|
let artistOld = this._current["AlbumArtist"] || this._current["Artist"];
|
||||||
if (artistNew != artistOld || data["Album"] != this._current["Album"]) { // changed album (art)
|
if (artistNew != artistOld || data["Album"] != this._current["Album"]) { // changed album (art)
|
||||||
html.clear(DOM.art);
|
html.clear(DOM.art);
|
||||||
art.get(artistNew, data["Album"], data["file"]).then(src => {
|
art.get(this._mpd, artistNew, data["Album"], data["file"]).then(src => {
|
||||||
if (src) {
|
if (src) {
|
||||||
html.node("img", {src}, "", DOM.art);
|
html.node("img", {src}, "", DOM.art);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,7 +8,6 @@ const ICONS = {
|
||||||
"Album": "album"
|
"Album": "album"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default class Tag extends Item {
|
export default class Tag extends Item {
|
||||||
constructor(type, value, filter) {
|
constructor(type, value, filter) {
|
||||||
super();
|
super();
|
||||||
|
|
Loading…
Reference in a new issue