Time for React!

Stein Ivar Berghei 2023-10-26 22:51:54 +02:00
parent 605bd7f29e
commit 8a019c0817
7 changed files with 206 additions and 4 deletions

23
src/app/events.tsx Normal file
View File

@ -0,0 +1,23 @@
function on(eventType: any, listener: { (event: any): void; (this: Document, ev: any): any; }) {
document.addEventListener(eventType, listener);
}
function off(eventType: any, listener: { (event: any): void; (this: Document, ev: any): any; }) {
document.removeEventListener(eventType, listener);
}
function once(eventType: any, listener: (arg0: any) => void) {
on(eventType, handleEventOnce);
function handleEventOnce(event) {
listener(event);
off(eventType, handleEventOnce);
}
}
function trigger(eventType: string, data: any) {
const event = new CustomEvent(eventType, { detail: data });
document.dispatchEvent(event);
}
export { on, once, off, trigger };

77
src/app/playlist.tsx Normal file
View File

@ -0,0 +1,77 @@
import React, { useEffect, useState, useCallback } from "react";
import CSS from "csstype";
import { on } from "./events";
import ws from "./ws";
export default function Playlists() {
interface Playlist {
Id: string;
Title: string;
}
const [playlists, setPlaylists] = useState<Playlist[]>([]);
const [active, setActive] = useState("");
const activeStyle: CSS.Properties = {
backgroundColor: "burlywood",
};
const fetchPlaylists = () => {
fetch("/playlists")
.then((response) => {
return response.json();
})
.then((data) => {
setPlaylists(data);
});
};
useEffect(() => {
fetchPlaylists();
}, []);
const Play = (e: any) => {
console.log(e.target.dataset);
ws.send(
JSON.stringify({
event: "load_playlist",
payload: e.target.dataset.id,
})
);
};
const Stop = () => {
ws.send(
JSON.stringify({
event: "stop",
})
);
};
on("dnd:song_info", (e: any) => {
setActive(e.detail.playlist);
});
return (
<section>
<div id="items" className="item-container">
{playlists.map((playlist) => {
return (
<div
key={playlist.Id}
onClick={Play}
className="item"
data-id={playlist.Id}
style={playlist.Id == active ? activeStyle : {}}
>
{playlist.Title}
</div>
);
})}
<div className="item locked stop" onClick={Stop} data-id="reset">
Stop
</div>
</div>
</section>
);
}

23
src/app/root.tsx Normal file
View File

@ -0,0 +1,23 @@
import React, { createContext } from "react";
import { createRoot } from "react-dom/client";
import { trigger, on } from "./events";
import Playlists from "./playlist";
import ws from "./ws";
function Content() {
ws.onmessage = (e) => {
const data = JSON.parse(e.data);
trigger("dnd:" + data.event, data.payload);
};
return (
<>
<h2 className="bot">Playlists</h2>
<Playlists />
</>
);
}
const domNode = document.getElementById("content");
const root = createRoot(domNode!);
root.render(<Content />);

9
src/app/ws.tsx Normal file
View File

@ -0,0 +1,9 @@
import ReconnectingWebSocket from "reconnecting-websocket";
const ws = new ReconnectingWebSocket(
(window.location.protocol === "https:" ? "wss://" : "ws://") +
window.location.host +
"/ws"
);
export default ws;

View File

@ -1,9 +1,14 @@
{
"scripts": {
"build": "esbuild script.js --bundle --outdir=/public/"
"build": "esbuild script.js --bundle --outdir=/public/",
"build_test": "esbuild app/*.tsx --bundle --outfile=../public_test/script.js"
},
"dependencies": {
"@types/react": "^18.2.33",
"@types/react-dom": "^18.2.14",
"esbuild": "^0.15.14",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"reconnecting-websocket": "^4.4.0",
"sortablejs": "^1.15.0"
}

View File

@ -147,19 +147,19 @@ window.onload = function () {
avol.value = data.payload.ambiance
avol.nextElementSibling.value = data.payload.ambiance
break
case "ambiance_download_start":
case "ambiance_encode_start":
var progress = document.querySelector("#progressambiance progress")
progress.style.display = "initial"
progress.style.width = "100%"
progress.value = 0
break
case "ambiance_download_progress":
case "ambiance_encode_progress":
var progress = document.querySelector("#progressambiance progress")
progress.style.display = "initial"
progress.value = data.payload.percent
console.log(data)
break
case "ambiance_download_complete":
case "ambiance_encode_complete":
var progress = document.querySelector("#progressambiance progress")
progress.style.display = "initial"
progress.value = 100

View File

@ -12,6 +12,37 @@
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.14.tgz#1221684955c44385f8af34f7240088b7dc08d19d"
integrity sha512-eQi9rosGNVQFJyJWV0HCA5WZae/qWIQME7s8/j8DMvnylfBv62Pbu+zJ2eUDqNf2O4u3WB+OEXyfkpBoe194sg==
"@types/prop-types@*":
version "15.7.9"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.9.tgz#b6f785caa7ea1fe4414d9df42ee0ab67f23d8a6d"
integrity sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==
"@types/react-dom@^18.2.14":
version "18.2.14"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.14.tgz#c01ba40e5bb57fc1dc41569bb3ccdb19eab1c539"
integrity sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18.2.33":
version "18.2.33"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.33.tgz#055356243dc4350a9ee6c6a2c07c5cae12e38877"
integrity sha512-v+I7S+hu3PIBoVkKGpSYYpiBT1ijqEzWpzQD62/jm4K74hPpSP7FF9BnKG6+fg2+62weJYkkBWDJlZt5JO/9hg==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/scheduler@*":
version "0.16.5"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.5.tgz#4751153abbf8d6199babb345a52e1eb4167d64af"
integrity sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==
csstype@^3.0.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
esbuild-android-64@0.15.14:
version "0.15.14"
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.14.tgz#114e55b0d58fb7b45d7fa3d93516bd13fc8869cc"
@ -140,11 +171,45 @@ esbuild@^0.15.14:
esbuild-windows-64 "0.15.14"
esbuild-windows-arm64 "0.15.14"
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
react-dom@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
dependencies:
loose-envify "^1.1.0"
reconnecting-websocket@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783"
integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==
scheduler@^0.23.0:
version "0.23.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
dependencies:
loose-envify "^1.1.0"
sortablejs@^1.15.0:
version "1.15.0"
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.0.tgz#53230b8aa3502bb77a29e2005808ffdb4a5f7e2a"