styling, readme
This commit is contained in:
parent
0dacf6cf54
commit
87a7c5680a
9 changed files with 73 additions and 17 deletions
36
README.md
Normal file
36
README.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# CYP: Control Your Player
|
||||||
|
|
||||||
|
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
|
||||||
|
- Control the playback, queue, volume
|
||||||
|
- Save and load playlists
|
||||||
|
- Browse the library by artists/albums/directories
|
||||||
|
- 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
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Make sure you have a working MPD setup first.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/ondras/cyp.git && cd cyp
|
||||||
|
npm i
|
||||||
|
node .
|
||||||
|
```
|
||||||
|
|
||||||
|
Point your browser to http://localhost:8080 to open the interface.
|
||||||
|
|
||||||
|
## Technology
|
||||||
|
- Connected to MPD via WebSockets (using the [ws2mpd](https://github.com/ondras/ws2mpd/) bridge)
|
||||||
|
- Modern ES6+ (modules, async/await)
|
||||||
|
- Responsive layout via Flexbox
|
||||||
|
- SVG icons (Material Design)
|
||||||
|
- Dark/Light theme available
|
||||||
|
- Album art downloaded directly from MPD (and cached via localStorage)
|
||||||
|
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- [ ] Bundling
|
||||||
|
- [ ] Range styling
|
34
app/app.css
34
app/app.css
|
@ -44,7 +44,6 @@ button {
|
||||||
border: none;
|
border: none;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -66,6 +65,7 @@ select {
|
||||||
}
|
}
|
||||||
.icon {
|
.icon {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.icon path:not([fill]),
|
.icon path:not([fill]),
|
||||||
.icon polygon:not([fill]),
|
.icon polygon:not([fill]),
|
||||||
|
@ -116,7 +116,7 @@ nav ul li {
|
||||||
border-top: 4px solid transparent;
|
border-top: 4px solid transparent;
|
||||||
}
|
}
|
||||||
nav ul li .icon {
|
nav ul li .icon {
|
||||||
margin-right: 4px;
|
margin-right: var(--icon-spacing);
|
||||||
}
|
}
|
||||||
nav ul li.active {
|
nav ul li.active {
|
||||||
border-top-color: var(--primary);
|
border-top-color: var(--primary);
|
||||||
|
@ -167,7 +167,7 @@ nav ul li.active {
|
||||||
#player .info {
|
#player .info {
|
||||||
flex-grow: 2;
|
flex-grow: 2;
|
||||||
flex-basis: 0;
|
flex-basis: 0;
|
||||||
padding-left: var(--icon-spacing);
|
padding: 0 var(--icon-spacing);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -251,11 +251,12 @@ nav ul li.active {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px;
|
padding: var(--spacing);
|
||||||
}
|
}
|
||||||
.component header button {
|
.component header button {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.component header button .icon {
|
.component header button .icon {
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
|
@ -309,11 +310,12 @@ nav ul li.active {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px;
|
padding: var(--spacing);
|
||||||
}
|
}
|
||||||
#queue header button {
|
#queue header button {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
#queue header button .icon {
|
#queue header button .icon {
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
|
@ -370,11 +372,12 @@ nav ul li.active {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px;
|
padding: var(--spacing);
|
||||||
}
|
}
|
||||||
#library header button {
|
#library header button {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
#library header button .icon {
|
#library header button .icon {
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
|
@ -465,11 +468,12 @@ nav ul li.active {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px;
|
padding: var(--spacing);
|
||||||
}
|
}
|
||||||
#fs header button {
|
#fs header button {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
#fs header button .icon {
|
#fs header button .icon {
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
|
@ -543,11 +547,12 @@ nav ul li.active {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px;
|
padding: var(--spacing);
|
||||||
}
|
}
|
||||||
#playlists header button {
|
#playlists header button {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
#playlists header button .icon {
|
#playlists header button .icon {
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
|
@ -609,11 +614,12 @@ nav ul li.active {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px;
|
padding: var(--spacing);
|
||||||
}
|
}
|
||||||
#yt header button {
|
#yt header button {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
#yt header button .icon {
|
#yt header button .icon {
|
||||||
margin-right: var(--icon-spacing);
|
margin-right: var(--icon-spacing);
|
||||||
|
@ -691,11 +697,11 @@ nav ul li.active {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
}
|
}
|
||||||
#settings dl {
|
#settings dl {
|
||||||
margin: 8px;
|
margin: var(--spacing);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: max-content 1fr;
|
grid-template-columns: max-content 1fr;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
grid-gap: 8px;
|
grid-gap: var(--spacing);
|
||||||
}
|
}
|
||||||
#settings dt {
|
#settings dt {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -752,6 +758,7 @@ nav ul li.active {
|
||||||
--font-size-large: 112.5%;
|
--font-size-large: 112.5%;
|
||||||
--icon-spacing: 4px;
|
--icon-spacing: 4px;
|
||||||
--primary: rgb(var(--primary-raw));
|
--primary: rgb(var(--primary-raw));
|
||||||
|
--spacing: 8px;
|
||||||
}
|
}
|
||||||
:root[data-theme=light] {
|
:root[data-theme=light] {
|
||||||
--fg: #333;
|
--fg: #333;
|
||||||
|
@ -774,3 +781,8 @@ nav ul li.active {
|
||||||
:root[data-color=limegreen] {
|
:root[data-color=limegreen] {
|
||||||
--primary-raw: 50, 205, 50;
|
--primary-raw: 50, 205, 50;
|
||||||
}
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
:root {
|
||||||
|
--spacing: var(--icon-spacing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -42,7 +42,6 @@ button {
|
||||||
border: none;
|
border: none;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|
|
@ -4,12 +4,13 @@
|
||||||
|
|
||||||
header {
|
header {
|
||||||
.flex-row;
|
.flex-row;
|
||||||
padding: 8px;
|
padding: var(--spacing);
|
||||||
|
|
||||||
button {
|
button {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
.icon { margin-right: var(--icon-spacing); }
|
.icon { margin-right: var(--icon-spacing); }
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
.icon {
|
.icon {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
path, polygon, circle {
|
path, polygon, circle {
|
||||||
&:not([fill]) {
|
&:not([fill]) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ nav ul {
|
||||||
border-top: 4px solid transparent;
|
border-top: 4px solid transparent;
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
margin-right: 4px;
|
margin-right: var(--icon-spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
.info {
|
.info {
|
||||||
flex-grow: 2;
|
flex-grow: 2;
|
||||||
flex-basis: 0;
|
flex-basis: 0;
|
||||||
padding-left: var(--icon-spacing);
|
padding: 0 var(--icon-spacing);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.flex-column;
|
.flex-column;
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
|
|
||||||
dl {
|
dl {
|
||||||
margin: 8px;
|
margin: var(--spacing);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: max-content 1fr;
|
grid-template-columns: max-content 1fr;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
grid-gap: 8px;
|
grid-gap: var(--spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
dt {
|
dt {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
--font-size-large: 112.5%;
|
--font-size-large: 112.5%;
|
||||||
--icon-spacing: 4px;
|
--icon-spacing: 4px;
|
||||||
--primary: rgb(var(--primary-raw));
|
--primary: rgb(var(--primary-raw));
|
||||||
|
--spacing: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[data-theme=light] {
|
:root[data-theme=light] {
|
||||||
|
@ -29,3 +30,9 @@
|
||||||
:root[data-color=limegreen] {
|
:root[data-color=limegreen] {
|
||||||
--primary-raw: 50, 205, 50;
|
--primary-raw: 50, 205, 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
:root {
|
||||||
|
--spacing: var(--icon-spacing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue