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;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
select {
|
||||
background-color: transparent;
|
||||
|
@ -66,6 +65,7 @@ select {
|
|||
}
|
||||
.icon {
|
||||
width: 24px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.icon path:not([fill]),
|
||||
.icon polygon:not([fill]),
|
||||
|
@ -116,7 +116,7 @@ nav ul li {
|
|||
border-top: 4px solid transparent;
|
||||
}
|
||||
nav ul li .icon {
|
||||
margin-right: 4px;
|
||||
margin-right: var(--icon-spacing);
|
||||
}
|
||||
nav ul li.active {
|
||||
border-top-color: var(--primary);
|
||||
|
@ -167,7 +167,7 @@ nav ul li.active {
|
|||
#player .info {
|
||||
flex-grow: 2;
|
||||
flex-basis: 0;
|
||||
padding-left: var(--icon-spacing);
|
||||
padding: 0 var(--icon-spacing);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -251,11 +251,12 @@ nav ul li.active {
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
.component header button {
|
||||
font-size: var(--font-size-large);
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
}
|
||||
.component header button .icon {
|
||||
margin-right: var(--icon-spacing);
|
||||
|
@ -309,11 +310,12 @@ nav ul li.active {
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
#queue header button {
|
||||
font-size: var(--font-size-large);
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
}
|
||||
#queue header button .icon {
|
||||
margin-right: var(--icon-spacing);
|
||||
|
@ -370,11 +372,12 @@ nav ul li.active {
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
#library header button {
|
||||
font-size: var(--font-size-large);
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
}
|
||||
#library header button .icon {
|
||||
margin-right: var(--icon-spacing);
|
||||
|
@ -465,11 +468,12 @@ nav ul li.active {
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
#fs header button {
|
||||
font-size: var(--font-size-large);
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
}
|
||||
#fs header button .icon {
|
||||
margin-right: var(--icon-spacing);
|
||||
|
@ -543,11 +547,12 @@ nav ul li.active {
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
#playlists header button {
|
||||
font-size: var(--font-size-large);
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
}
|
||||
#playlists header button .icon {
|
||||
margin-right: var(--icon-spacing);
|
||||
|
@ -609,11 +614,12 @@ nav ul li.active {
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
#yt header button {
|
||||
font-size: var(--font-size-large);
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
}
|
||||
#yt header button .icon {
|
||||
margin-right: var(--icon-spacing);
|
||||
|
@ -691,11 +697,11 @@ nav ul li.active {
|
|||
font-size: var(--font-size-large);
|
||||
}
|
||||
#settings dl {
|
||||
margin: 8px;
|
||||
margin: var(--spacing);
|
||||
display: grid;
|
||||
grid-template-columns: max-content 1fr;
|
||||
align-items: center;
|
||||
grid-gap: 8px;
|
||||
grid-gap: var(--spacing);
|
||||
}
|
||||
#settings dt {
|
||||
font-weight: bold;
|
||||
|
@ -752,6 +758,7 @@ nav ul li.active {
|
|||
--font-size-large: 112.5%;
|
||||
--icon-spacing: 4px;
|
||||
--primary: rgb(var(--primary-raw));
|
||||
--spacing: 8px;
|
||||
}
|
||||
:root[data-theme=light] {
|
||||
--fg: #333;
|
||||
|
@ -774,3 +781,8 @@ nav ul li.active {
|
|||
:root[data-color=limegreen] {
|
||||
--primary-raw: 50, 205, 50;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
:root {
|
||||
--spacing: var(--icon-spacing);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,6 @@ button {
|
|||
border: none;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
select {
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
|
||||
header {
|
||||
.flex-row;
|
||||
padding: 8px;
|
||||
padding: var(--spacing);
|
||||
|
||||
button {
|
||||
font-size: var(--font-size-large);
|
||||
font-weight: bold;
|
||||
.icon { margin-right: var(--icon-spacing); }
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
.icon {
|
||||
width: 24px;
|
||||
flex-shrink: 0;
|
||||
|
||||
path, polygon, circle {
|
||||
&:not([fill]) {
|
||||
|
|
|
@ -16,7 +16,7 @@ nav ul {
|
|||
border-top: 4px solid transparent;
|
||||
|
||||
.icon {
|
||||
margin-right: 4px;
|
||||
margin-right: var(--icon-spacing);
|
||||
}
|
||||
|
||||
&.active {
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
.info {
|
||||
flex-grow: 2;
|
||||
flex-basis: 0;
|
||||
padding-left: var(--icon-spacing);
|
||||
padding: 0 var(--icon-spacing);
|
||||
overflow: hidden;
|
||||
|
||||
.flex-column;
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
font-size: var(--font-size-large);
|
||||
|
||||
dl {
|
||||
margin: 8px;
|
||||
margin: var(--spacing);
|
||||
display: grid;
|
||||
grid-template-columns: max-content 1fr;
|
||||
align-items: center;
|
||||
grid-gap: 8px;
|
||||
grid-gap: var(--spacing);
|
||||
}
|
||||
|
||||
dt {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
--font-size-large: 112.5%;
|
||||
--icon-spacing: 4px;
|
||||
--primary: rgb(var(--primary-raw));
|
||||
--spacing: 8px;
|
||||
}
|
||||
|
||||
:root[data-theme=light] {
|
||||
|
@ -29,3 +30,9 @@
|
|||
:root[data-color=limegreen] {
|
||||
--primary-raw: 50, 205, 50;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
:root {
|
||||
--spacing: var(--icon-spacing);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue