diff --git a/app/Makefile b/app/Makefile
index 725e23a..819f958 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -1,10 +1,18 @@
LESS := $(shell npm bin)/lessc
APP := app.css
+ICONS := js/lib/icons.js
all: $(APP)
+icons: $(ICONS)
+
+$(ICONS): icons/*
+ ./svg2js.sh icons > $@
+
$(APP): css/*
$(LESS) css/app.less > $@
watch: all
while inotifywait -e MODIFY -r css js ; do make $^ ; done
+
+.PHONY: all watch icons
diff --git a/app/app.css b/app/app.css
index b20cd3b..1424fe8 100644
--- a/app/app.css
+++ b/app/app.css
@@ -1,9 +1,10 @@
html {
background-color: #fff;
- font-family: lato, sans-serif;
}
body {
- background-color: #888;
+ font-family: lato, sans-serif;
+ line-height: 1.3;
+ background-color: #333;
color: #fff;
text-shadow: 0 1px 1px #000;
max-width: 800px;
@@ -17,6 +18,29 @@ body > header,
body > footer {
box-shadow: 0 0 3px #000;
}
+input,
+select,
+button {
+ color: inherit;
+}
+button {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background-color: transparent;
+ padding: 0;
+ border: none;
+ line-height: 1;
+ cursor: pointer;
+}
+.icon {
+ width: 24px;
+}
+.icon path:not([fill]),
+.icon polygon:not([fill]),
+.icon circle:not([fill]) {
+ fill: currentColor;
+}
@font-face {
font-family: 'Lato';
src: url('font/LatoLatin-Regular.woff2') format('woff2');
@@ -71,6 +95,10 @@ nav ul li.active {
#player:not([data-flags~=repeat]) .repeat {
opacity: 0.5;
}
+#player button {
+ width: 64px;
+ height: 64px;
+}
.component {
height: 100%;
display: flex;
@@ -86,16 +114,25 @@ nav ul li.active {
.component .grid li {
display: flex;
flex-direction: row;
+ align-items: center;
}
.component .grid li h2 {
flex-grow: 1;
+ font-size: 100%;
+ font-weight: normal;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.component .grid li:nth-child(odd) {
- background-color: #666;
+ background-color: #555;
+}
+.component .grid button {
+ flex-shrink: 0;
+ width: 32px;
+ height: 32px;
+ font-size: 32px;
}
#queue {
height: 100%;
@@ -112,16 +149,25 @@ nav ul li.active {
#queue .grid li {
display: flex;
flex-direction: row;
+ align-items: center;
}
#queue .grid li h2 {
flex-grow: 1;
+ font-size: 100%;
+ font-weight: normal;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#queue .grid li:nth-child(odd) {
- background-color: #666;
+ background-color: #555;
+}
+#queue .grid button {
+ flex-shrink: 0;
+ width: 32px;
+ height: 32px;
+ font-size: 32px;
}
#queue li {
display: flex;
@@ -148,16 +194,25 @@ nav ul li.active {
#library .grid li {
display: flex;
flex-direction: row;
+ align-items: center;
}
#library .grid li h2 {
flex-grow: 1;
+ font-size: 100%;
+ font-weight: normal;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#library .grid li:nth-child(odd) {
- background-color: #666;
+ background-color: #555;
+}
+#library .grid button {
+ flex-shrink: 0;
+ width: 32px;
+ height: 32px;
+ font-size: 32px;
}
#fs {
height: 100%;
@@ -174,14 +229,23 @@ nav ul li.active {
#fs .grid li {
display: flex;
flex-direction: row;
+ align-items: center;
}
#fs .grid li h2 {
flex-grow: 1;
+ font-size: 100%;
+ font-weight: normal;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#fs .grid li:nth-child(odd) {
- background-color: #666;
+ background-color: #555;
+}
+#fs .grid button {
+ flex-shrink: 0;
+ width: 32px;
+ height: 32px;
+ font-size: 32px;
}
diff --git a/app/css/app.less b/app/css/app.less
index ae00589..a1ffb8d 100644
--- a/app/css/app.less
+++ b/app/css/app.less
@@ -1,10 +1,11 @@
html {
background-color: #fff;
- font-family: lato, sans-serif;
}
body {
- background-color: #888;
+ font-family: lato, sans-serif;
+ line-height: 1.3;
+ background-color: #333;
color: #fff;
text-shadow: 0 1px 1px #000;
max-width: 800px;
@@ -19,6 +20,32 @@ body {
}
}
+input, select, button {
+ color: inherit;
+}
+
+button {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+
+ background-color: transparent;
+ padding: 0;
+ border: none;
+ line-height: 1;
+ cursor: pointer;
+}
+
+.icon {
+ width: 24px;
+
+ path, polygon, circle {
+ &:not([fill]) {
+ fill: currentColor;
+ }
+ }
+}
+
@import "font.less";
@import "main.less";
diff --git a/app/css/component.less b/app/css/component.less
index 0beea7e..dce52f9 100644
--- a/app/css/component.less
+++ b/app/css/component.less
@@ -15,9 +15,12 @@
li {
display: flex;
flex-direction: row;
+ align-items: center;
h2 {
flex-grow: 1;
+ font-size: 100%;
+ font-weight: normal;
margin: 0;
white-space: nowrap;
overflow: hidden;
@@ -26,7 +29,14 @@
}
li:nth-child(odd) {
- background-color: #666;
+ background-color: #555;
+ }
+
+ button {
+ flex-shrink: 0;
+ width: 32px;
+ height: 32px;
+ font-size: 32px;
}
}
}
diff --git a/app/css/player.less b/app/css/player.less
index af59629..285183d 100644
--- a/app/css/player.less
+++ b/app/css/player.less
@@ -8,4 +8,9 @@
&:not([data-state=play]) .pause { display: none; }
&[data-state=play] .play { display: none; }
&:not([data-flags~=random]) .random, &:not([data-flags~=repeat]) .repeat { opacity: 0.5; }
+
+ button {
+ width: 64px;
+ height: 64px;
+ }
}
\ No newline at end of file
diff --git a/app/icons/close-circle-outline.svg b/app/icons/close-circle-outline.svg
new file mode 100644
index 0000000..dad58cf
--- /dev/null
+++ b/app/icons/close-circle-outline.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/close-circle.svg b/app/icons/close-circle.svg
new file mode 100644
index 0000000..5a37396
--- /dev/null
+++ b/app/icons/close-circle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/close.svg b/app/icons/close.svg
new file mode 100644
index 0000000..18691d7
--- /dev/null
+++ b/app/icons/close.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/fast-forward.svg b/app/icons/fast-forward.svg
new file mode 100644
index 0000000..bfe744f
--- /dev/null
+++ b/app/icons/fast-forward.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/minus-circle-outline.svg b/app/icons/minus-circle-outline.svg
new file mode 100644
index 0000000..889d629
--- /dev/null
+++ b/app/icons/minus-circle-outline.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/minus-circle.svg b/app/icons/minus-circle.svg
new file mode 100644
index 0000000..445910b
--- /dev/null
+++ b/app/icons/minus-circle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/minus.svg b/app/icons/minus.svg
new file mode 100644
index 0000000..4cee9d4
--- /dev/null
+++ b/app/icons/minus.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/pause-circle-outline.svg b/app/icons/pause-circle-outline.svg
new file mode 100644
index 0000000..f9825b5
--- /dev/null
+++ b/app/icons/pause-circle-outline.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/pause-circle.svg b/app/icons/pause-circle.svg
new file mode 100644
index 0000000..9f33cb7
--- /dev/null
+++ b/app/icons/pause-circle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/pause.svg b/app/icons/pause.svg
new file mode 100644
index 0000000..37ed32d
--- /dev/null
+++ b/app/icons/pause.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/play-circle-outline.svg b/app/icons/play-circle-outline.svg
new file mode 100644
index 0000000..792051f
--- /dev/null
+++ b/app/icons/play-circle-outline.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/play-circle.svg b/app/icons/play-circle.svg
new file mode 100644
index 0000000..9835bb8
--- /dev/null
+++ b/app/icons/play-circle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/play.svg b/app/icons/play.svg
new file mode 100644
index 0000000..87a70f2
--- /dev/null
+++ b/app/icons/play.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/plus-circle-outline.svg b/app/icons/plus-circle-outline.svg
new file mode 100644
index 0000000..3fe6bec
--- /dev/null
+++ b/app/icons/plus-circle-outline.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/plus-circle.svg b/app/icons/plus-circle.svg
new file mode 100644
index 0000000..64b5a32
--- /dev/null
+++ b/app/icons/plus-circle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/plus.svg b/app/icons/plus.svg
new file mode 100644
index 0000000..2c21839
--- /dev/null
+++ b/app/icons/plus.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/repeat.svg b/app/icons/repeat.svg
new file mode 100644
index 0000000..8086726
--- /dev/null
+++ b/app/icons/repeat.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/rewind.svg b/app/icons/rewind.svg
new file mode 100644
index 0000000..ee45c02
--- /dev/null
+++ b/app/icons/rewind.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/shuffle.svg b/app/icons/shuffle.svg
new file mode 100644
index 0000000..dcd9763
--- /dev/null
+++ b/app/icons/shuffle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/index.html b/app/index.html
index 2d8f4ac..a22234e 100644
--- a/app/index.html
+++ b/app/index.html
@@ -15,12 +15,12 @@
/
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/app/js/lib/html.js b/app/js/lib/html.js
index 50bd354..ee109c7 100644
--- a/app/js/lib/html.js
+++ b/app/js/lib/html.js
@@ -1,3 +1,5 @@
+import icons from "./icons.js";
+
export function node(name, attrs, content, parent) {
let n = document.createElement(name);
Object.assign(n, attrs);
@@ -9,8 +11,32 @@ export function node(name, attrs, content, parent) {
return n;
}
+export function icon(type, parent) {
+ let str = icons[type];
+ if (!str) {
+ console.error("Bad icon type '%s'", type);
+ return node("span", {}, "‽");
+ }
+
+ let tmp = node("div");
+ tmp.innerHTML = str;
+ let s = tmp.querySelector("svg");
+ if (!s) { throw new Error(`Bad icon source for type '${type}'`); }
+
+ s.classList.add("icon");
+ s.classList.add(`icon-${type}`);
+
+ parent && parent.appendChild(s);
+ return s;
+}
+
export function button(attrs, content, parent) {
- return node("button", attrs, content, parent);
+ let result = node("button", attrs, content, parent);
+ if (attrs && attrs.icon) {
+ let i = icon(attrs.icon);
+ result.insertBefore(i, result.firstChild);
+ }
+ return result;
}
export function clear(node) {
diff --git a/app/js/lib/icons.js b/app/js/lib/icons.js
new file mode 100644
index 0000000..f09a849
--- /dev/null
+++ b/app/js/lib/icons.js
@@ -0,0 +1,59 @@
+let ICONS={};
+ICONS["play-circle-outline"] = ``;
+ICONS["shuffle"] = ``;
+ICONS["minus-circle"] = ``;
+ICONS["rewind"] = ``;
+ICONS["pause"] = ``;
+ICONS["pause-circle"] = ``;
+ICONS["close-circle-outline"] = ``;
+ICONS["close"] = ``;
+ICONS["minus"] = ``;
+ICONS["close-circle"] = ``;
+ICONS["repeat"] = ``;
+ICONS["play"] = ``;
+ICONS["pause-circle-outline"] = ``;
+ICONS["plus"] = ``;
+ICONS["fast-forward"] = ``;
+ICONS["minus-circle-outline"] = ``;
+ICONS["plus-circle-outline"] = ``;
+ICONS["plus-circle"] = ``;
+ICONS["play-circle"] = ``;
+export default ICONS;
diff --git a/app/js/lib/ui.js b/app/js/lib/ui.js
index 3d04bec..75488b8 100644
--- a/app/js/lib/ui.js
+++ b/app/js/lib/ui.js
@@ -37,7 +37,7 @@ function formatTitle(type, data) {
}
function playButton(id, parent) {
- let button = html.button({className:"play"}, "▶", parent);
+ let button = html.button({icon:"play", title:"Play"}, "", parent);
button.addEventListener("click", async e => {
await mpd.command(`playid ${id}`);
player.update();
@@ -45,7 +45,7 @@ function playButton(id, parent) {
}
function deleteButton(id, parent) {
- let button = html.button({className:"delete"}, "🗙", parent);
+ let button = html.button({icon:"close"}, "", parent);
button.addEventListener("click", async e => {
await mpd.command(`deleteid ${id}`);
pubsub.publish("queue-change");
@@ -54,7 +54,7 @@ function deleteButton(id, parent) {
}
function addAndPlayButton(urlOrFilter, parent) {
- let button = html.button({}, "▶", parent);
+ let button = html.button({icon:"play", title:"Play"}, "", parent);
button.addEventListener("click", async e => {
e.stopPropagation();
await mpd.command("clear");
@@ -67,7 +67,7 @@ function addAndPlayButton(urlOrFilter, parent) {
}
function addButton(urlOrFilter, parent) {
- let button = html.button({}, "+", parent);
+ let button = html.button({icon:"plus"}, "", parent);
button.addEventListener("click", async e => {
e.stopPropagation();
await mpd.enqueue(urlOrFilter, SORT);
diff --git a/app/js/player.js b/app/js/player.js
index d5b3ef5..dfd1088 100644
--- a/app/js/player.js
+++ b/app/js/player.js
@@ -76,5 +76,12 @@ export function init(n) {
DOM.random.addEventListener("click", e => command(`random ${current["random"] == "1" ? "0" : "1"}`));
DOM.repeat.addEventListener("click", e => command(`repeat ${current["repeat"] == "1" ? "0" : "1"}`));
+ DOM.play.appendChild(html.icon("play"));
+ DOM.pause.appendChild(html.icon("pause"));
+ DOM.prev.appendChild(html.icon("rewind"));
+ DOM.next.appendChild(html.icon("fast-forward"));
+ DOM.random.appendChild(html.icon("shuffle"));
+ DOM.repeat.appendChild(html.icon("repeat"));
+
update();
}
diff --git a/app/svg2js.sh b/app/svg2js.sh
new file mode 100755
index 0000000..bd3d9d2
--- /dev/null
+++ b/app/svg2js.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+ARGS="ed -O -N svg=http://www.w3.org/2000/svg"
+DELETE="-d //comment() -d //svg:defs -d //svg:title -d //svg:desc -d //@fill -d //@stroke -d //@stroke-width -d //@fill-rule -d //@width -d //@height"
+
+process_svg () {
+ NAME=$1
+ ID=$(basename $NAME | sed -e 's/.svg//')
+
+ DATA=$(cat $NAME | xmlstarlet fo -D -N | xmlstarlet $ARGS $DELETE)
+ printf "ICONS[\"$ID\"] = \`$DATA\`;\n"
+}
+
+if [ "$#" -ne 1 ]; then
+ echo "Usage: $0 svg_directory"
+ exit 1
+fi
+
+IMAGES=$(find "$1" -name "*.svg")
+
+printf "let ICONS={};\n"
+for i in $IMAGES; do
+ process_svg $i
+done
+printf "export default ICONS;\n"