Show loader when page is updating

This commit is contained in:
momo5502
2025-09-25 19:58:07 +02:00
parent afdae4aa8e
commit 9a9e38d4a8
3 changed files with 362 additions and 8 deletions

View File

@@ -3,12 +3,13 @@ import { TooltipProvider } from "@/components/ui/tooltip";
import { HashRouter, Route, Routes, Navigate } from "react-router-dom";
import { Playground, storeEmulateData } from "./playground";
import { LandingPage } from "./landing-page";
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import "@fontsource/inter/latin.css";
import "./App.css";
import "./animation.css";
function EmulateFile() {
const { encodedData } = useParams();
@@ -16,6 +17,38 @@ function EmulateFile() {
return <Navigate to="/playground" replace />;
}
function isWindowLoading() {
return !!(window as any).loading;
}
function useLoader() {
const [isLoading, setIsLoading] = useState(isWindowLoading());
useEffect(() => {
const id = setInterval(() => {
setIsLoading(isWindowLoading());
}, 60);
return () => {
clearInterval(id);
};
});
return isLoading;
}
function Loader() {
const loading = useLoader();
if (!loading) {
return <></>;
}
return (
<div className="fixed z-9999 top-10 right-10 p-8 rounded-2xl ring-of-dots bg-[#00000081]"></div>
);
}
function App() {
return (
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
@@ -28,6 +61,7 @@ function App() {
<Route path="/emulate/:encodedData?" element={<EmulateFile />} />
</Routes>
</HashRouter>
<Loader />
</TooltipProvider>
</ThemeProvider>
);

311
page/src/animation.css Normal file
View File

@@ -0,0 +1,311 @@
:root {
--ring-full-color: #ffffff00;
--ring-half-color: #ffffff75;
}
/**
* Ring of dots
*
* @author jh3y
*/
@-webkit-keyframes ring-of-dots {
0% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 var(--ring-half-color),
12.4698px -15.63663px 0 0 var(--ring-full-color);
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 var(--ring-half-color),
12.4698px -15.63663px 0 0 var(--ring-full-color);
}
14.28571% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 var(--ring-half-color),
-4.45042px -19.49856px 0 0 var(--ring-full-color),
12.4698px -15.63663px 0 0 white;
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 var(--ring-half-color),
-4.45042px -19.49856px 0 0 var(--ring-full-color),
12.4698px -15.63663px 0 0 white;
}
28.57143% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 var(--ring-half-color),
-18.01938px -8.67767px 0 0 var(--ring-full-color),
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 var(--ring-half-color),
-18.01938px -8.67767px 0 0 var(--ring-full-color),
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
}
42.85714% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 var(--ring-half-color),
-18.01938px 8.67767px 0 0 var(--ring-full-color),
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 var(--ring-half-color),
-18.01938px 8.67767px 0 0 var(--ring-full-color),
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
}
57.14286% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 var(--ring-half-color),
-4.45042px 19.49856px 0 0 var(--ring-full-color),
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 var(--ring-half-color),
-4.45042px 19.49856px 0 0 var(--ring-full-color),
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
}
71.42857% {
-webkit-box-shadow:
20px 0px 0 0 var(--ring-half-color),
12.4698px 15.63663px 0 0 var(--ring-full-color),
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
box-shadow:
20px 0px 0 0 var(--ring-half-color),
12.4698px 15.63663px 0 0 var(--ring-full-color),
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
}
85.71429% {
-webkit-box-shadow:
20px 0px 0 0 var(--ring-full-color),
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 var(--ring-half-color);
box-shadow:
20px 0px 0 0 var(--ring-full-color),
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 var(--ring-half-color);
}
100% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 var(--ring-half-color),
12.4698px -15.63663px 0 0 var(--ring-full-color);
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 var(--ring-half-color),
12.4698px -15.63663px 0 0 var(--ring-full-color);
}
}
@keyframes ring-of-dots {
0% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 var(--ring-half-color),
12.4698px -15.63663px 0 0 var(--ring-full-color);
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 var(--ring-half-color),
12.4698px -15.63663px 0 0 var(--ring-full-color);
}
14.28571% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 var(--ring-half-color),
-4.45042px -19.49856px 0 0 var(--ring-full-color),
12.4698px -15.63663px 0 0 white;
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 var(--ring-half-color),
-4.45042px -19.49856px 0 0 var(--ring-full-color),
12.4698px -15.63663px 0 0 white;
}
28.57143% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 var(--ring-half-color),
-18.01938px -8.67767px 0 0 var(--ring-full-color),
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 var(--ring-half-color),
-18.01938px -8.67767px 0 0 var(--ring-full-color),
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
}
42.85714% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 var(--ring-half-color),
-18.01938px 8.67767px 0 0 var(--ring-full-color),
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 var(--ring-half-color),
-18.01938px 8.67767px 0 0 var(--ring-full-color),
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
}
57.14286% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 var(--ring-half-color),
-4.45042px 19.49856px 0 0 var(--ring-full-color),
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 var(--ring-half-color),
-4.45042px 19.49856px 0 0 var(--ring-full-color),
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
}
71.42857% {
-webkit-box-shadow:
20px 0px 0 0 var(--ring-half-color),
12.4698px 15.63663px 0 0 var(--ring-full-color),
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
box-shadow:
20px 0px 0 0 var(--ring-half-color),
12.4698px 15.63663px 0 0 var(--ring-full-color),
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 white;
}
85.71429% {
-webkit-box-shadow:
20px 0px 0 0 var(--ring-full-color),
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 var(--ring-half-color);
box-shadow:
20px 0px 0 0 var(--ring-full-color),
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 white,
12.4698px -15.63663px 0 0 var(--ring-half-color);
}
100% {
-webkit-box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 var(--ring-half-color),
12.4698px -15.63663px 0 0 var(--ring-full-color);
box-shadow:
20px 0px 0 0 white,
12.4698px 15.63663px 0 0 white,
-4.45042px 19.49856px 0 0 white,
-18.01938px 8.67767px 0 0 white,
-18.01938px -8.67767px 0 0 white,
-4.45042px -19.49856px 0 0 var(--ring-half-color),
12.4698px -15.63663px 0 0 var(--ring-full-color);
}
}
.ring-of-dots:before {
animation: ring-of-dots 1s infinite linear reverse;
border-radius: 10px;
content: "";
display: block;
height: 10px;
width: 10px;
}

View File

@@ -4,15 +4,24 @@ import "./index.css";
import App from "./App.tsx";
import { registerSW } from "virtual:pwa-register";
(window as any).loading = false;
registerSW({
onNeedRefresh() {
setTimeout(() => {
window.location.reload();
}, 5000);
},
onOfflineReady() {},
onRegisteredSW(_, registration) {
registration?.addEventListener("updatefound", () => {
(window as any).loading = true;
});
},
});
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);
registerSW({
onNeedRefresh() {
window.location.reload();
},
onOfflineReady() {},
});