index.tsx
⎇
Raw
1/* @refresh reload */
2import { createSignal } from "solid-js";
3import { render } from "solid-js/web";
4import "./style.css";
5import "./components/Dialog.css";
6
7import { registerSW } from "virtual:pwa-register";
8import App from "./App";
9import { initCapabilities } from "./capabilities";
10import { clearLocalData, loadDataFromDB } from "./offline";
11import { toast } from "./utils";
12
13const root = document.getElementById("root");
14if (!(root instanceof HTMLElement)) {
15 throw new Error(
16 "Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?",
17 );
18}
19
20navigator?.storage?.persist()?.catch(() => {});
21
22function ResetDialog() {
23 const [error, setError] = createSignal<string>();
24 const [resetting, setResetting] = createSignal(false);
25
26 async function reset() {
27 setResetting(true);
28 setError(undefined);
29 const failure = await clearLocalData().catch((e) => e?.toString() ?? "Unknown error");
30 if (failure) {
31 setError(failure);
32 setResetting(false);
33 return;
34 }
35 location.hash = "";
36 location.reload();
37 }
38
39 return (
40 <div style={{ display: "flex", height: "100%", "align-items": "center" }}>
41 <dialog open>
42 <div>
43 Your local version of this application is not compatible with the newly loaded one, click "Reset" to delete
44 all stored settings, files and cached and refresh the page.
45 {error() && <div style={{ color: "rgb(255, 24, 24)" }}>{error()}</div>}
46 <button style={{ margin: "auto" }} disabled={resetting()} onClick={reset}>
47 {resetting() ? "Resetting..." : "Reset"}
48 </button>
49 </div>
50 </dialog>
51 </div>
52 );
53}
54
55const currentVersion = "1";
56const version = localStorage.getItem("app-version");
57if (version && version !== currentVersion) {
58 //TODO: add a way to at least export playlists before resetting
59 root.innerHTML = "";
60 render(() => <ResetDialog />, root);
61} else {
62 if (!version) {
63 try {
64 localStorage.setItem("app-version", currentVersion);
65 } catch {}
66 }
67
68 //the auto-injected registration only ever checks on a cold navigation, which for an installed
69 //player that stays open for days means new deploys are never picked up
70 const updateCheckInterval = 60 * 60 * 1000;
71 registerSW({
72 immediate: true,
73 onRegisteredSW: (_swScriptUrl, registration) => {
74 if (!registration) return;
75 setInterval(() => {
76 if (navigator.onLine) registration.update().catch(() => {});
77 }, updateCheckInterval);
78 },
79 //replaces the default automatic reload, which would cut off playback mid-track
80 onNeedReload: () => toast("A new version was installed, reload the page to use it", "info"),
81 });
82
83 Promise.all([loadDataFromDB(), initCapabilities()])
84 .then(() => {
85 root.innerHTML = "";
86 render(() => <App />, root);
87 })
88 .catch((e) => {
89 root.innerHTML = e.toString();
90 console.error(e);
91 });
92}
93