styling
This commit is contained in:
parent
76802bc630
commit
37fdd5413c
10 changed files with 87 additions and 14 deletions
29
app/app.css
29
app/app.css
|
@ -4,6 +4,10 @@ body {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
header,
|
||||||
|
footer {
|
||||||
|
box-shadow: 0 0 3px #000;
|
||||||
|
}
|
||||||
main {
|
main {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
@ -27,6 +31,16 @@ nav ul li:hover {
|
||||||
nav ul li.active {
|
nav ul li.active {
|
||||||
background-color: green;
|
background-color: green;
|
||||||
}
|
}
|
||||||
|
#player {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
#player .art img {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
#player .info {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
#player:not([data-state=play]) .pause {
|
#player:not([data-state=play]) .pause {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +51,21 @@ nav ul li.active {
|
||||||
#player:not([data-flags~=repeat]) .repeat {
|
#player:not([data-flags~=repeat]) .repeat {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
#queue ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#queue li {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
#queue li + li {
|
||||||
|
border-top: 1px solid #888;
|
||||||
|
}
|
||||||
|
#queue .info {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
#queue .current {
|
#queue .current {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,10 @@ body {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header, footer {
|
||||||
|
box-shadow: 0 0 3px #000;
|
||||||
|
}
|
||||||
|
|
||||||
@import "main.less";
|
@import "main.less";
|
||||||
@import "nav.less";
|
@import "nav.less";
|
||||||
@import "player.less";
|
@import "player.less";
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
#player {
|
#player {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.art img { vertical-align: top; }
|
||||||
|
.info { flex-grow: 1; }
|
||||||
|
|
||||||
&: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; }
|
||||||
|
|
||||||
|
|
||||||
&:not([data-flags~=random]) .random, &:not([data-flags~=repeat]) .repeat { opacity: 0.5; }
|
&:not([data-flags~=random]) .random, &:not([data-flags~=repeat]) .repeat { opacity: 0.5; }
|
||||||
}
|
}
|
|
@ -1,3 +1,19 @@
|
||||||
#queue {
|
#queue {
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
+ li {
|
||||||
|
border-top: 1px solid #888;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info { flex-grow: 1; }
|
||||||
.current { font-weight: bold; }
|
.current { font-weight: bold; }
|
||||||
}
|
}
|
|
@ -10,9 +10,10 @@
|
||||||
<header>
|
<header>
|
||||||
<section id="player">
|
<section id="player">
|
||||||
<span class="art"></span>
|
<span class="art"></span>
|
||||||
<span class="title"></span>
|
<div class="info">
|
||||||
<span class="artist"></span>
|
<h2 class="title"></h2>
|
||||||
<span class="album"></span>
|
<span class="artist-album"></span>
|
||||||
|
</div>
|
||||||
<span class="elapsed"></span>/<span class="duration"></span>
|
<span class="elapsed"></span>/<span class="duration"></span>
|
||||||
<button class="play">⏯️▶</button>
|
<button class="play">⏯️▶</button>
|
||||||
<button class="pause">⏸️</button>
|
<button class="pause">⏸️</button>
|
||||||
|
|
1
app/js/conf.js
Normal file
1
app/js/conf.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const artSize = 96;
|
|
@ -1,11 +1,11 @@
|
||||||
import * as mpd from "./mpd.js";
|
import * as mpd from "./mpd.js";
|
||||||
import * as parser from "./parser.js";
|
import * as parser from "./parser.js";
|
||||||
import * as html from "./html.js";
|
import * as html from "./html.js";
|
||||||
|
import * as conf from "../conf.js";
|
||||||
|
|
||||||
let cache = {};
|
let cache = {};
|
||||||
const SIZE = 64;
|
|
||||||
const MIME = "image/jpeg";
|
const MIME = "image/jpeg";
|
||||||
const STORAGE_PREFIX = `art-${SIZE}` ;
|
const STORAGE_PREFIX = `art-${conf.artSize}` ;
|
||||||
|
|
||||||
function store(key, data) {
|
function store(key, data) {
|
||||||
localStorage.setItem(`${STORAGE_PREFIX}-${key}`, data);
|
localStorage.setItem(`${STORAGE_PREFIX}-${key}`, data);
|
||||||
|
@ -38,9 +38,9 @@ async function bytesToImage(bytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function resize(image) {
|
function resize(image) {
|
||||||
let canvas = html.node("canvas", {width:SIZE, height:SIZE});
|
let canvas = html.node("canvas", {width:conf.artSize, height:conf.artSize});
|
||||||
let ctx = canvas.getContext("2d");
|
let ctx = canvas.getContext("2d");
|
||||||
ctx.drawImage(image, 0, 0, SIZE, SIZE);
|
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,3 +4,10 @@ export function time(sec) {
|
||||||
let s = sec % 60;
|
let s = sec % 60;
|
||||||
return `${m}:${s.toString().padStart(2, "0")}`;
|
return `${m}:${s.toString().padStart(2, "0")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function artistAlbum(artist, album) {
|
||||||
|
let tokens = [];
|
||||||
|
artist && tokens.push(artist);
|
||||||
|
album && tokens.push(album);
|
||||||
|
return tokens.join(" – ");
|
||||||
|
}
|
|
@ -17,8 +17,7 @@ function sync(data) {
|
||||||
if (data["file"] != current["file"]) { // changed song
|
if (data["file"] != current["file"]) { // changed song
|
||||||
DOM.duration.textContent = format.time(Number(data["duration"] || 0));
|
DOM.duration.textContent = format.time(Number(data["duration"] || 0));
|
||||||
DOM.title.textContent = data["Title"] || "";
|
DOM.title.textContent = data["Title"] || "";
|
||||||
DOM.album.textContent = data["Album"] || "";
|
DOM["artist-album"].textContent = format.artistAlbum(data["Artist"], data["Album"]);
|
||||||
DOM.artist.textContent = data["Artist"] || "";
|
|
||||||
pubsub.publish("song-change", null, data);
|
pubsub.publish("song-change", null, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import * as mpd from "./lib/mpd.js";
|
||||||
import * as html from "./lib/html.js";
|
import * as html from "./lib/html.js";
|
||||||
import * as player from "./player.js";
|
import * as player from "./player.js";
|
||||||
import * as pubsub from "./lib/pubsub.js";
|
import * as pubsub from "./lib/pubsub.js";
|
||||||
|
import * as format from "./lib/format.js";
|
||||||
|
|
||||||
let node;
|
let node;
|
||||||
let currentId;
|
let currentId;
|
||||||
|
@ -18,15 +19,26 @@ async function playSong(id) {
|
||||||
player.update();
|
player.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function deleteSong(id) {
|
||||||
|
await mpd.command(`deleteid ${id}`);
|
||||||
|
activate();
|
||||||
|
}
|
||||||
|
|
||||||
function buildSong(song) {
|
function buildSong(song) {
|
||||||
let id = Number(song["Id"]);
|
let id = Number(song["Id"]);
|
||||||
|
|
||||||
let node = html.node("li");
|
let node = html.node("li");
|
||||||
node.dataset.songId = id;
|
node.dataset.songId = id;
|
||||||
|
|
||||||
node.textContent = song["file"];
|
html.button({className:"play"}, "▶", node).addEventListener("click", e => playSong(id));
|
||||||
let play = html.button({}, "▶", node);
|
|
||||||
play.addEventListener("click", e => playSong(id));
|
let info = html.node("div", {className:"info"}, "", node);
|
||||||
|
|
||||||
|
html.node("h2", {className:"title"}, song["Title"], info);
|
||||||
|
html.node("span", {className:"artist-album"}, format.artistAlbum(song["Artist"], song["Album"]), info);
|
||||||
|
html.node("span", {className:"duration"}, format.time(Number(song["duration"])), info);
|
||||||
|
|
||||||
|
html.button({className:"delete"}, "🗙", node).addEventListener("click", e => deleteSong(id));
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue