diff --git a/.gitignore b/.gitignore index 6a63795..f4dac66 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,7 @@ cache bin ambiance/*.mp3 + +*.yml +public/ +node_modules/ diff --git a/css/style.css b/css/style.css index f657232..158c1cb 100644 --- a/css/style.css +++ b/css/style.css @@ -1,41 +1,69 @@ .container { - display: grid; - grid-template-columns: 1fr 1fr 1fr; - grid-template-rows: auto; - padding: 10px; - border-radius: 10px; + --grid-layout-gap: 8px; + --grid-column-count: 3; + --grid-item--min-width: 150px; + + --gap-count: calc(var(--grid-column-count) - 1); + --total-gap-width: calc(var(--gap-count) * var(--grid-layout-gap)); + --grid-item--max-width: calc((100% - var(--total-gap-width)) / var(--grid-column-count)); + + display: grid; + grid-template-columns: repeat(auto-fill, minmax(max(var(--grid-item--min-width), var(--grid-item--max-width)), 1fr)); + grid-auto-rows: 1fr; + grid-gap: var(--grid-layout-gap); } .playing { - background-color: burlywood; + background-color: burlywood; } h2.bot { - margin-top: 10px; - margin-bottom: 0px; - text-align: center; + margin-top: 0; + margin-bottom: .5rem; + text-align: center; } .item { - background-color: #80cbc4; - border: 1px solid black; - padding: 20px; - font-size: clamp(1rem, -0.8750rem + 8.3333vw, 2rem); - text-align: center; - cursor: pointer; - color: #073642 + display: flex; + justify-content: center; + align-items: center; + padding: 1rem; + background-color: #80cbc4; + border: 1px solid black; + font-size: clamp(1rem, -0.8750rem + 8.3333vw, 2rem); + text-align: center; + cursor: pointer; + color: #073642 } -.container2 { - display: block; - border-radius: 10px; - padding: 10px; +.item.stop { + background-color: #cb4b16; +} + +#info { + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; +} + +.controls { + display: flex; + align-items: center; + justify-content: space-around; + width: 100%; + margin: 0 auto; + max-width: 512px; +} + +.input-container { + max-width: 512px; } .box { -/* background-color: #fefefe;*/ + /* background-color: #fefefe;*/ margin: 15% auto; /* 15% from the top and centered */ - padding: 20px; + padding: 2rem; /*border: 1px solid #888;*/ width: 80%; /* Could be more or less, depending on screen size */ align-content: center; @@ -58,12 +86,72 @@ h2.bot { /* Modal Content/Box */ .modal-content { margin: 15% auto; /* 15% from the top and centered */ - padding: 20px; + padding: 2rem; width: 80%; /* Could be more or less, depending on screen size */ text-align: center; font-size: 32px; } -body > div.container2 > input[type=text]:nth-child(2) { - width: 512px; +body, html { + margin: 0; + padding: .5rem; +} + +input[type="button"], +input[type="submit"] { + display: inline-block; + height: 38px; + padding: 0 30px; + color: #555; + text-align: center; + font-size: 11px; + font-weight: 600; + line-height: 38px; + letter-spacing: .1rem; + text-transform: uppercase; + text-decoration: none; + white-space: nowrap; + border-radius: 4px; + border: 1px solid #bbb; + cursor: pointer; + box-sizing: border-box; +} + +input[type="button"]:focus, +input[type="submit"]:hover { + color: #333; + border-color: #888; + outline: 0; +} + +input[type="text"] { + height: 38px; + padding: 6px 10px; + background-color: #fff; + border: 1px solid #D1D1D1; + border-radius: 4px; + box-shadow: none; + box-sizing: border-box; + + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +input[type="text"]:focus { + border: 1px solid #33C3F0; + outline: 0; +} + +section { + margin-bottom: .5rem; +} + +.u-full-width { + width: 100%; + box-sizing: border-box; +} + +.u-hidden { + display: none; } diff --git a/js/script.js b/js/script.js index bc39407..2354ee3 100644 --- a/js/script.js +++ b/js/script.js @@ -1,4 +1,7 @@ -window.onload = function() { +import ReconnectingWebSocket from 'reconnecting-websocket'; +import Sortable from 'sortablejs'; + +window.onload = function () { const ws = new ReconnectingWebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/ws"); const items = document.querySelector("#items"); @@ -6,6 +9,8 @@ window.onload = function() { const submit = document.querySelector("#addplaylist") const output = document.querySelector(".container2 p#output") const info = document.querySelector("#info") + const link = document.querySelector("#link") + const time = document.querySelector("#time") const waiting = document.querySelector("#waiting") document.querySelector("input#next").addEventListener("click", (e) => { @@ -63,11 +68,11 @@ window.onload = function() { }) ws.onopen = (e) => { - waiting.style.display = "none"; + waiting.classList.add("u-hidden") } ws.onclose = (e) => { - waiting.style.display = "block"; + waiting.classList.remove("u-hidden") } ws.onmessage = (e) => { @@ -88,14 +93,14 @@ window.onload = function() { el.style.removeProperty("background-color") }) if (data.payload.pause) { - info.style.display = "none" + info.classList.add("u-hidden") } else { - info.style.display = "block" - info.children.link.children.channel.innerText = data.payload.channel - info.children.link.children.title.innerText = data.payload.current - info.children.link.href = "https://youtu.be/" + data.payload.song - info.children.link.target = "_blank" - info.children.time.innerText = `( ${msToTime(data.payload.position)} / ${msToTime(data.payload.len)} )` + info.classList.remove("u-hidden") + link.children.channel.innerText = data.payload.channel + link.children.title.innerText = data.payload.current + link.href = "https://youtu.be/" + data.payload.song + link.target = "_blank" + time.innerText = `${msToTime(data.payload.position)} / ${msToTime(data.payload.len)}` document.querySelector(`#items > div[data-id='${data.payload.playlist}']`).style.backgroundColor = "burlywood" } setTimeout(() => { @@ -103,15 +108,15 @@ window.onload = function() { }, 1000); break case "song_position": - info.children.time.innerText = `( ${msToTime(data.payload.position)} / ${msToTime(data.payload.len)} )` - info.style.display = "block" + time.innerText = `${msToTime(data.payload.position)} / ${msToTime(data.payload.len)}` + info.classList.remove("u-hidden") break case "stop": setTimeout(() => { items.style.pointerEvents = 'auto' }, 2000); - info.style.display = "none" + info.classList.add("u-hidden") break case "new_playlist": addPlaylist(data.payload); diff --git a/package.json b/package.json new file mode 100644 index 0000000..b509036 --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "scripts": { + "build": "esbuild js/script.js --bundle --outdir=public/" + }, + "dependencies": { + "esbuild": "^0.15.14", + "reconnecting-websocket": "^4.4.0", + "sortablejs": "^1.15.0" + } +} diff --git a/routes.go b/routes.go index 05539b1..4417393 100644 --- a/routes.go +++ b/routes.go @@ -22,7 +22,7 @@ func init() { app.router.GET("/play/:playlist", app.Play) app.router.GET("/reset", app.Reset) - app.router.ServeFiles("/js/*filepath", http.Dir("js")) + app.router.ServeFiles("/js/*filepath", http.Dir("public")) app.router.ServeFiles("/css/*filepath", http.Dir("css")) app.router.HandlerFunc("GET", "/ws", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/tmpl/index.tmpl b/tmpl/index.tmpl index 3312da4..f824cd5 100644 --- a/tmpl/index.tmpl +++ b/tmpl/index.tmpl @@ -5,47 +5,67 @@
Waiting for bot..