From 9a9e38d4a8ad6e474602851a40b80a44b06582c8 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 25 Sep 2025 19:58:07 +0200 Subject: [PATCH] Show loader when page is updating --- page/src/App.tsx | 36 ++++- page/src/animation.css | 311 +++++++++++++++++++++++++++++++++++++++++ page/src/main.tsx | 23 ++- 3 files changed, 362 insertions(+), 8 deletions(-) create mode 100644 page/src/animation.css diff --git a/page/src/App.tsx b/page/src/App.tsx index 2a12e2fd..82a7561b 100644 --- a/page/src/App.tsx +++ b/page/src/App.tsx @@ -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 ; } +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 ( +
+ ); +} + function App() { return ( @@ -28,6 +61,7 @@ function App() { } /> + ); diff --git a/page/src/animation.css b/page/src/animation.css new file mode 100644 index 00000000..204d33b0 --- /dev/null +++ b/page/src/animation.css @@ -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; +} diff --git a/page/src/main.tsx b/page/src/main.tsx index 794b4af8..e4c11801 100644 --- a/page/src/main.tsx +++ b/page/src/main.tsx @@ -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( , ); - -registerSW({ - onNeedRefresh() { - window.location.reload(); - }, - onOfflineReady() {}, -});