shadows
This commit is contained in:
parent
87a7c5680a
commit
1f5dd9d618
6 changed files with 33 additions and 22 deletions
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
CYP is a web-based frontend for [MPD](https://www.musicpd.org/), the Music Player Daemon. You can use it to control the playback without having to install native application(s). It works in modern web browsers, both desktop and mobile.
|
CYP is a web-based frontend for [MPD](https://www.musicpd.org/), the Music Player Daemon. You can use it to control the playback without having to install native application(s). It works in modern web browsers, both desktop and mobile.
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Control the playback, queue, volume
|
- Control the playback, queue, volume
|
||||||
- Save and load playlists
|
- Save and load playlists
|
||||||
|
@ -9,6 +10,7 @@ CYP is a web-based frontend for [MPD](https://www.musicpd.org/), the Music Playe
|
||||||
- Display album art via native MPD calls (no need to access the library; requires MPD >= 0.21)
|
- Display album art via native MPD calls (no need to access the library; requires MPD >= 0.21)
|
||||||
- [Youtube-dl](https://ytdl-org.github.io/youtube-dl/index.html) intergration
|
- [Youtube-dl](https://ytdl-org.github.io/youtube-dl/index.html) intergration
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Make sure you have a working MPD setup first.
|
Make sure you have a working MPD setup first.
|
||||||
|
@ -21,16 +23,21 @@ node .
|
||||||
|
|
||||||
Point your browser to http://localhost:8080 to open the interface.
|
Point your browser to http://localhost:8080 to open the interface.
|
||||||
|
|
||||||
|
|
||||||
## Technology
|
## Technology
|
||||||
- Connected to MPD via WebSockets (using the [ws2mpd](https://github.com/ondras/ws2mpd/) bridge)
|
- Connected to MPD via WebSockets (using the [ws2mpd](https://github.com/ondras/ws2mpd/) bridge)
|
||||||
|
- Token-based access to the WebSocket endpoint (better than an `Origin` check)
|
||||||
- Modern ES6+ (modules, async/await)
|
- Modern ES6+ (modules, async/await)
|
||||||
- Responsive layout via Flexbox
|
- Responsive layout via Flexbox
|
||||||
|
- CSS Custom Properties
|
||||||
- SVG icons (Material Design)
|
- SVG icons (Material Design)
|
||||||
- Dark/Light theme available
|
- Dark/Light theme available
|
||||||
- Album art downloaded directly from MPD (and cached via localStorage)
|
- Can spawn Youtube-dl to download audio files
|
||||||
|
- Album art retrieved directly from MPD (and cached via localStorage)
|
||||||
|
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- [ ] Bundling
|
- [ ] Bundling
|
||||||
- [ ] Range styling
|
- [ ] Range styling
|
||||||
|
- [ ] Browser testing
|
||||||
|
|
28
app/app.css
28
app/app.css
|
@ -14,15 +14,16 @@ body {
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
background-color: var(--bg);
|
background-color: var(--bg);
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
text-shadow: var(--shadow);
|
text-shadow: var(--text-shadow);
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
body > header,
|
header,
|
||||||
body > footer {
|
footer {
|
||||||
box-shadow: 0 0 3px #000;
|
z-index: 1;
|
||||||
|
box-shadow: var(--box-shadow);
|
||||||
}
|
}
|
||||||
input,
|
input,
|
||||||
select,
|
select,
|
||||||
|
@ -280,7 +281,7 @@ nav ul li.active {
|
||||||
.component li .info .icon {
|
.component li .info .icon {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
filter: drop-shadow(var(--shadow));
|
filter: drop-shadow(var(--text-shadow));
|
||||||
}
|
}
|
||||||
.component li .info h2 {
|
.component li .info h2 {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
|
@ -339,7 +340,7 @@ nav ul li.active {
|
||||||
#queue li .info .icon {
|
#queue li .info .icon {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
filter: drop-shadow(var(--shadow));
|
filter: drop-shadow(var(--text-shadow));
|
||||||
}
|
}
|
||||||
#queue li .info h2 {
|
#queue li .info h2 {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
|
@ -401,7 +402,7 @@ nav ul li.active {
|
||||||
#library li .info .icon {
|
#library li .info .icon {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
filter: drop-shadow(var(--shadow));
|
filter: drop-shadow(var(--text-shadow));
|
||||||
}
|
}
|
||||||
#library li .info h2 {
|
#library li .info h2 {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
|
@ -436,7 +437,7 @@ nav ul li.active {
|
||||||
width: 64px;
|
width: 64px;
|
||||||
}
|
}
|
||||||
#library .art .icon {
|
#library .art .icon {
|
||||||
filter: drop-shadow(var(--shadow));
|
filter: drop-shadow(var(--text-shadow));
|
||||||
}
|
}
|
||||||
#library .group {
|
#library .group {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -497,7 +498,7 @@ nav ul li.active {
|
||||||
#fs li .info .icon {
|
#fs li .info .icon {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
filter: drop-shadow(var(--shadow));
|
filter: drop-shadow(var(--text-shadow));
|
||||||
}
|
}
|
||||||
#fs li .info h2 {
|
#fs li .info h2 {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
|
@ -576,7 +577,7 @@ nav ul li.active {
|
||||||
#playlists li .info .icon {
|
#playlists li .info .icon {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
filter: drop-shadow(var(--shadow));
|
filter: drop-shadow(var(--text-shadow));
|
||||||
}
|
}
|
||||||
#playlists li .info h2 {
|
#playlists li .info h2 {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
|
@ -643,7 +644,7 @@ nav ul li.active {
|
||||||
#yt li .info .icon {
|
#yt li .info .icon {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
filter: drop-shadow(var(--shadow));
|
filter: drop-shadow(var(--text-shadow));
|
||||||
}
|
}
|
||||||
#yt li .info h2 {
|
#yt li .info h2 {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
|
@ -759,18 +760,19 @@ nav ul li.active {
|
||||||
--icon-spacing: 4px;
|
--icon-spacing: 4px;
|
||||||
--primary: rgb(var(--primary-raw));
|
--primary: rgb(var(--primary-raw));
|
||||||
--spacing: 8px;
|
--spacing: 8px;
|
||||||
|
--box-shadow: 0 0 3px #000;
|
||||||
}
|
}
|
||||||
:root[data-theme=light] {
|
:root[data-theme=light] {
|
||||||
--fg: #333;
|
--fg: #333;
|
||||||
--bg: #f0f0f0;
|
--bg: #f0f0f0;
|
||||||
--bg-alt: #e0e0e0;
|
--bg-alt: #e0e0e0;
|
||||||
--shadow: none;
|
--text-shadow: none;
|
||||||
}
|
}
|
||||||
:root[data-theme=dark] {
|
:root[data-theme=dark] {
|
||||||
--fg: #f0f0f0;
|
--fg: #f0f0f0;
|
||||||
--bg: #333;
|
--bg: #333;
|
||||||
--bg-alt: #555;
|
--bg-alt: #555;
|
||||||
--shadow: 0 1px 1px rgba(0, 0, 0, 0.8);
|
--text-shadow: 0 1px 1px rgba(0, 0, 0, 0.8);
|
||||||
}
|
}
|
||||||
:root[data-color=dodgerblue] {
|
:root[data-color=dodgerblue] {
|
||||||
--primary-raw: 30, 144, 255;
|
--primary-raw: 30, 144, 255;
|
||||||
|
|
|
@ -12,15 +12,16 @@ body {
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
background-color: var(--bg);
|
background-color: var(--bg);
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
text-shadow: var(--shadow);
|
text-shadow: var(--text-shadow);
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
> header, > footer {
|
header, footer {
|
||||||
box-shadow: 0 0 3px #000;
|
z-index: 1;
|
||||||
}
|
box-shadow: var(--box-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
input, select, button {
|
input, select, button {
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
.icon {
|
.icon {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
filter: drop-shadow(var(--shadow));
|
filter: drop-shadow(var(--text-shadow));
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.art .icon {
|
.art .icon {
|
||||||
filter: drop-shadow(var(--shadow));
|
filter: drop-shadow(var(--text-shadow));
|
||||||
}
|
}
|
||||||
|
|
||||||
.group {
|
.group {
|
||||||
|
|
|
@ -3,20 +3,21 @@
|
||||||
--icon-spacing: 4px;
|
--icon-spacing: 4px;
|
||||||
--primary: rgb(var(--primary-raw));
|
--primary: rgb(var(--primary-raw));
|
||||||
--spacing: 8px;
|
--spacing: 8px;
|
||||||
|
--box-shadow: 0 0 3px #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[data-theme=light] {
|
:root[data-theme=light] {
|
||||||
--fg: #333;
|
--fg: #333;
|
||||||
--bg: #f0f0f0;
|
--bg: #f0f0f0;
|
||||||
--bg-alt: #e0e0e0;
|
--bg-alt: #e0e0e0;
|
||||||
--shadow: none;
|
--text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[data-theme=dark] {
|
:root[data-theme=dark] {
|
||||||
--fg: #f0f0f0;
|
--fg: #f0f0f0;
|
||||||
--bg: #333;
|
--bg: #333;
|
||||||
--bg-alt: #555;
|
--bg-alt: #555;
|
||||||
--shadow: 0 1px 1px rgba(0, 0, 0, 0.8);
|
--text-shadow: 0 1px 1px rgba(0, 0, 0, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[data-color=dodgerblue] {
|
:root[data-color=dodgerblue] {
|
||||||
|
|
Loading…
Reference in a new issue