Removed old frontend
This commit is contained in:
parent
a94967ab3f
commit
ff519ec1fc
1 changed files with 0 additions and 352 deletions
352
static/old.html
352
static/old.html
|
|
@ -1,352 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Spotify Queue</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<style>
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-family: system-ui, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background: #121212;
|
|
||||||
color: #fff;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
background: #1f1f1f;
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
header h1 {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
background: #1f1f1f;
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=text],
|
|
||||||
button {
|
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=text] {
|
|
||||||
flex: 1;
|
|
||||||
background: #2a2a2a;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
background: #1db954;
|
|
||||||
color: #000;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:disabled {
|
|
||||||
background: #555;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.song {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.75rem;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border-radius: 6px;
|
|
||||||
background: #1a1a1a;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
cursor: grab;
|
|
||||||
touch-action: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.song.dragging {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.song img {
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
border-radius: 4px;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.song div {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.song .title {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.song .artist {
|
|
||||||
font-size: 0.85rem;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.song .user {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
opacity: 0.6;
|
|
||||||
margin-top: 0.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabs {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabs button {
|
|
||||||
background: #2a2a2a;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabs button.active {
|
|
||||||
background: #1db954;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
|
||||||
max-width: 300px;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="loginScreen" class="login">
|
|
||||||
<h2>Enter your name</h2>
|
|
||||||
<input id="usernameInput" type="text" placeholder="Username" />
|
|
||||||
<button onclick="login()">Join</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="app" class="hidden">
|
|
||||||
<header>
|
|
||||||
<h1>Spotify Queue</h1>
|
|
||||||
<button onclick="logout()">Logout</button>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="tabs">
|
|
||||||
<button id="tabMy" class="active" onclick="switchTab('my')">My Queue</button>
|
|
||||||
<button id="tabMerged" onclick="switchTab('merged')">Merged Queue</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div id="myView">
|
|
||||||
<div style="display:flex; gap:0.5rem; margin-bottom:1rem;">
|
|
||||||
<input id="searchInput" type="text" placeholder="Search for songs…" />
|
|
||||||
<button onclick="search()">Search</button>
|
|
||||||
</div>
|
|
||||||
<div id="searchResults"></div>
|
|
||||||
<h3 style="margin-top:1rem;">My Queue</h3>
|
|
||||||
<div id="myQueue"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="mergedView" class="hidden">
|
|
||||||
<h3>Merged Queue</h3>
|
|
||||||
<div id="mergedQueue"></div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<!-- <footer> -->
|
|
||||||
<!-- <input id="searchFooter" type="text" placeholder="Search…" /> -->
|
|
||||||
<!-- <button onclick="searchFooter()">Search</button> -->
|
|
||||||
<!-- </footer> -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
let ws;
|
|
||||||
let username = '';
|
|
||||||
let myQueue = [];
|
|
||||||
let mergedQueue = [];
|
|
||||||
let searchResults = [];
|
|
||||||
let dragged = null;
|
|
||||||
|
|
||||||
function connect() {
|
|
||||||
ws = new WebSocket(`ws://${location.host}/ws/user`);
|
|
||||||
|
|
||||||
ws.onopen = () => {
|
|
||||||
ws.send(JSON.stringify({c: 'login', d: {name: username}}));
|
|
||||||
ws.send(JSON.stringify({c: 'getqueue'}));
|
|
||||||
};
|
|
||||||
|
|
||||||
ws.onmessage = (e) => {
|
|
||||||
const msg = JSON.parse(e.data);
|
|
||||||
if (msg.c === 'ping') {ws.send(JSON.stringify({c: 'pong'})); return;}
|
|
||||||
if (msg.c === 'search') {
|
|
||||||
searchResults = msg.d.songs || [];
|
|
||||||
renderSearch();
|
|
||||||
}
|
|
||||||
if (msg.c === 'getqueue') {
|
|
||||||
myQueue = msg.d.queue || [];
|
|
||||||
renderMyQueue();
|
|
||||||
}
|
|
||||||
if (msg.c === 'updatemergedqueue') {
|
|
||||||
console.log(msg)
|
|
||||||
mergedQueue = msg.d.queue || [];
|
|
||||||
if (document.getElementById('tabMerged').classList.contains('active')) renderMerged();
|
|
||||||
}
|
|
||||||
if (msg.c === "logout") {
|
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ws.onclose = () => setTimeout(connect, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function login() {
|
|
||||||
const name = document.getElementById('usernameInput').value.trim();
|
|
||||||
if (!name) return;
|
|
||||||
|
|
||||||
username = name;
|
|
||||||
document.getElementById('loginScreen').style.display = 'none';
|
|
||||||
document.getElementById('app').classList.remove('hidden');
|
|
||||||
|
|
||||||
connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
function logout() {
|
|
||||||
username = '';
|
|
||||||
if (ws) ws.close();
|
|
||||||
document.getElementById('app').classList.add('hidden');
|
|
||||||
document.getElementById('loginScreen').style.display = 'flex';
|
|
||||||
}
|
|
||||||
|
|
||||||
function switchTab(tab) {
|
|
||||||
document.getElementById('tabMy').classList.toggle('active', tab === 'my');
|
|
||||||
document.getElementById('tabMerged').classList.toggle('active', tab === 'merged');
|
|
||||||
document.getElementById('myView').classList.toggle('hidden', tab !== 'my');
|
|
||||||
document.getElementById('mergedView').classList.toggle('hidden', tab !== 'merged');
|
|
||||||
if (tab === 'merged') renderMerged();
|
|
||||||
}
|
|
||||||
|
|
||||||
function search() {
|
|
||||||
const q = document.getElementById('searchInput').value.trim();
|
|
||||||
if (!q) return;
|
|
||||||
ws.send(JSON.stringify({c: 'search', d: {query: q}}));
|
|
||||||
}
|
|
||||||
function searchFooter() {
|
|
||||||
const q = document.getElementById('searchFooter').value.trim();
|
|
||||||
if (!q) return;
|
|
||||||
document.getElementById('searchInput').value = q;
|
|
||||||
search();
|
|
||||||
switchTab('my');
|
|
||||||
}
|
|
||||||
|
|
||||||
function addSong(song) {
|
|
||||||
myQueue.push(song);
|
|
||||||
ws.send(JSON.stringify({c: 'queuesong', d: {song}}));
|
|
||||||
ws.send(JSON.stringify({c: 'getqueue'}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeSong(idx) {
|
|
||||||
myQueue.splice(idx, 1);
|
|
||||||
ws.send(JSON.stringify({c: 'setqueue', d: {queue: myQueue}}));
|
|
||||||
renderMyQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderSearch() {
|
|
||||||
const el = document.getElementById('searchResults');
|
|
||||||
el.innerHTML = '';
|
|
||||||
searchResults.forEach(s => {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.className = 'song';
|
|
||||||
div.innerHTML = `
|
|
||||||
<img src="${s.album.coverUrl || 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'}" alt="">
|
|
||||||
<div>
|
|
||||||
<div class="title">${s.name}</div>
|
|
||||||
<div class="artist">${s.artists.join(', ')}</div>
|
|
||||||
</div>
|
|
||||||
<button onclick='addSong(${JSON.stringify(s)})'>+</button>
|
|
||||||
`;
|
|
||||||
el.appendChild(div);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderMyQueue() {
|
|
||||||
const el = document.getElementById('myQueue');
|
|
||||||
el.innerHTML = '';
|
|
||||||
myQueue.forEach((s, i) => {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.className = 'song';
|
|
||||||
div.draggable = true;
|
|
||||||
div.dataset.idx = i;
|
|
||||||
div.innerHTML = `
|
|
||||||
<img src="${s.album.coverUrl || 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'}" alt="">
|
|
||||||
<div>
|
|
||||||
<div class="title">${s.name}</div>
|
|
||||||
<div class="artist">${s.artists.join(', ')}</div>
|
|
||||||
</div>
|
|
||||||
<button onclick="removeSong(${i})">✕</button>
|
|
||||||
`;
|
|
||||||
div.ondragstart = e => {dragged = +e.target.dataset.idx; e.target.classList.add('dragging');};
|
|
||||||
div.ondragend = e => e.target.classList.remove('dragging');
|
|
||||||
div.ondragover = e => e.preventDefault();
|
|
||||||
div.ondrop = e => {
|
|
||||||
e.preventDefault();
|
|
||||||
const to = +e.currentTarget.dataset.idx;
|
|
||||||
if (dragged === to) return;
|
|
||||||
const temp = myQueue[dragged];
|
|
||||||
myQueue.splice(dragged, 1);
|
|
||||||
myQueue.splice(to, 0, temp);
|
|
||||||
ws.send(JSON.stringify({c: 'setqueue', d: {queue: myQueue}}));
|
|
||||||
renderMyQueue();
|
|
||||||
};
|
|
||||||
el.appendChild(div);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderMerged() {
|
|
||||||
const el = document.getElementById('mergedQueue');
|
|
||||||
el.innerHTML = '';
|
|
||||||
mergedQueue.forEach(item => {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.className = 'song';
|
|
||||||
div.innerHTML = `
|
|
||||||
<img src="${item.song.album.coverUrl || 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'}" alt="">
|
|
||||||
<div>
|
|
||||||
<div class="title">${item.song.name}</div>
|
|
||||||
<div class="artist">${item.song.artists.join(', ')}</div>
|
|
||||||
<div class="user">Added by ${item.user}</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
el.appendChild(div);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function escSong(s) {
|
|
||||||
return encodeURIComponent(JSON.stringify(s).replace(/'/g, "\\'"));
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue