move LoadingSpinner

This commit is contained in:
Brian Beck 2025-12-02 22:16:40 -08:00
parent 2f23934de0
commit 5d0a8a3fab
12 changed files with 55 additions and 34 deletions

View file

@ -1,5 +1,5 @@
"use client";
import { useState, useEffect, Suspense } from "react";
import { useState, useEffect, useCallback, Suspense } from "react";
import { useSearchParams, useRouter } from "next/navigation";
import { Canvas } from "@react-three/fiber";
import { EffectComposer, N8AO } from "@react-three/postprocessing";
@ -25,6 +25,7 @@ function MapInspector() {
const [missionName, setMissionName] = useState(
searchParams.get("mission") || "TWL2_WoodyMyrk",
);
const [isLoading, setIsLoading] = useState(true);
// Update query params when state changes
useEffect(() => {
@ -33,15 +34,24 @@ function MapInspector() {
router.replace(`?${params.toString()}`, { scroll: false });
}, [missionName, router]);
const handleLoadingChange = useCallback((loading: boolean) => {
setIsLoading(loading);
}, []);
return (
<QueryClientProvider client={queryClient}>
<main>
<SettingsProvider>
<div id="canvasContainer">
{isLoading && <div className="LoadingSpinner" />}
<Canvas shadows frameloop="always">
<CamerasProvider>
<AudioProvider>
<Mission key={missionName} name={missionName} />
<Mission
key={missionName}
name={missionName}
onLoadingChange={handleLoadingChange}
/>
<ObserverCamera />
<DebugElements />
<ObserverControls />

View file

@ -257,3 +257,24 @@ main {
color: rgba(255, 255, 255, 0.5);
text-align: center;
}
.LoadingSpinner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 48px;
height: 48px;
border: 4px solid rgba(255, 255, 255, 0.2);
border-top-color: white;
border-radius: 50%;
animation: LoadingSpinner-spin 1s linear infinite;
pointer-events: none;
z-index: 1;
}
@keyframes LoadingSpinner-spin {
to {
transform: translate(-50%, -50%) rotate(360deg);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
html{box-sizing:border-box;margin:0;padding:0;background:black}*,:after,:before{box-sizing:inherit}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;font-size:100%}body{margin:0;padding:0}main{width:100vw;height:100vh}#canvasContainer{position:absolute;top:0;left:0;right:0;bottom:0;z-index:0}#controls{display:flex;align-items:center;gap:20px;position:fixed;top:0;left:0;background:rgba(0,0,0,.5);color:#fff;padding:8px 12px 8px 8px;border-radius:0 0 4px 0;font-size:13px;z-index:1}.CheckboxField,.Field{display:flex;align-items:center;gap:6px}#fovInput,#speedInput{max-width:80px}.StaticShapeLabel{background:rgba(0,0,0,.5);color:#fff;font-size:11px;white-space:nowrap;padding:1px 3px;border-radius:1px}.StatsPanel{left:auto!important;right:0}.AxisLabel{font-size:12px;pointer-events:none}.AxisLabel[data-axis=x]{color:rgb(255,153,0)}.AxisLabel[data-axis=y]{color:rgb(153,255,0)}.AxisLabel[data-axis=z]{color:rgb(0,153,255)}.MissionSelect-inputWrapper{position:relative;display:flex;align-items:center}.MissionSelect-shortcut{position:absolute;right:7px;font-family:system-ui,sans-serif;font-size:11px;padding:1px 4px;border-radius:3px;background:rgba(255,255,255,.15);color:rgba(255,255,255,.6);pointer-events:none}.MissionSelect-input[aria-expanded=true]~.MissionSelect-shortcut{display:none}.MissionSelect-input{width:240px;padding:6px 36px 6px 8px;font-size:14px;border:1px solid rgba(255,255,255,.3);border-radius:3px;background:rgba(0,0,0,.6);color:#fff;outline:none}.MissionSelect-input[aria-expanded=true]{padding-right:8px}.MissionSelect-input:focus{border-color:rgba(255,255,255,.6)}.MissionSelect-input::placeholder{color:#fff;font-weight:600}.MissionSelect-popover{z-index:100;min-width:320px;max-height:var(--popover-available-height,90vh);overflow-y:auto;overscroll-behavior:contain;background:rgba(20,20,20,.95);border:1px solid rgba(255,255,255,.5);border-radius:3px;box-shadow:0 8px 24px rgba(0,0,0,.6)}.MissionSelect-list{padding:4px 0}.MissionSelect-list:has(>.MissionSelect-group:first-child){padding-top:0}.MissionSelect-group{padding-bottom:4px}.MissionSelect-groupLabel{position:-webkit-sticky;position:sticky;top:0;padding:6px 8px 6px 12px;font-size:13px;font-weight:600;color:rgb(198,202,202);background:rgba(58,69,72,.95);z-index:1}.MissionSelect-group:not(:last-child),.MissionSelect-groupLabel{border-bottom:1px solid rgba(255,255,255,.3)}.MissionSelect-item{display:flex;flex-direction:column;gap:1px;margin:4px 4px 0;padding:6px 8px;border-radius:4px;cursor:pointer;outline:none;scroll-margin-top:32px}.MissionSelect-list>.MissionSelect-item:first-child{margin-top:0}.MissionSelect-item[data-active-item]{background:rgba(255,255,255,.15)}.MissionSelect-item[aria-selected=true]{background:rgba(100,150,255,.3)}.MissionSelect-itemHeader{display:flex;align-items:center;gap:6px}.MissionSelect-itemName{font-size:14px;font-weight:600;color:#fff}.MissionSelect-itemTypes{display:flex;gap:3px}.MissionSelect-itemType{font-size:10px;font-weight:600;padding:2px 5px;border-radius:3px;background:rgba(255,157,0,.4);color:#fff}.MissionSelect-itemMissionName{font-size:12px;color:rgba(255,255,255,.5)}.MissionSelect-noResults{padding:12px 8px;font-size:13px;color:rgba(255,255,255,.5);text-align:center}
html{box-sizing:border-box;margin:0;padding:0;background:black}*,:after,:before{box-sizing:inherit}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;font-size:100%}body{margin:0;padding:0}main{width:100vw;height:100vh}#canvasContainer{position:absolute;top:0;left:0;right:0;bottom:0;z-index:0}#controls{display:flex;align-items:center;gap:20px;position:fixed;top:0;left:0;background:rgba(0,0,0,.5);color:#fff;padding:8px 12px 8px 8px;border-radius:0 0 4px 0;font-size:13px;z-index:1}.CheckboxField,.Field{display:flex;align-items:center;gap:6px}#fovInput,#speedInput{max-width:80px}.StaticShapeLabel{background:rgba(0,0,0,.5);color:#fff;font-size:11px;white-space:nowrap;padding:1px 3px;border-radius:1px}.StatsPanel{left:auto!important;right:0}.AxisLabel{font-size:12px;pointer-events:none}.AxisLabel[data-axis=x]{color:rgb(255,153,0)}.AxisLabel[data-axis=y]{color:rgb(153,255,0)}.AxisLabel[data-axis=z]{color:rgb(0,153,255)}.MissionSelect-inputWrapper{position:relative;display:flex;align-items:center}.MissionSelect-shortcut{position:absolute;right:7px;font-family:system-ui,sans-serif;font-size:11px;padding:1px 4px;border-radius:3px;background:rgba(255,255,255,.15);color:rgba(255,255,255,.6);pointer-events:none}.MissionSelect-input[aria-expanded=true]~.MissionSelect-shortcut{display:none}.MissionSelect-input{width:240px;padding:6px 36px 6px 8px;font-size:14px;border:1px solid rgba(255,255,255,.3);border-radius:3px;background:rgba(0,0,0,.6);color:#fff;outline:none}.MissionSelect-input[aria-expanded=true]{padding-right:8px}.MissionSelect-input:focus{border-color:rgba(255,255,255,.6)}.MissionSelect-input::placeholder{color:#fff;font-weight:600}.MissionSelect-popover{z-index:100;min-width:320px;max-height:var(--popover-available-height,90vh);overflow-y:auto;overscroll-behavior:contain;background:rgba(20,20,20,.95);border:1px solid rgba(255,255,255,.5);border-radius:3px;box-shadow:0 8px 24px rgba(0,0,0,.6)}.MissionSelect-list{padding:4px 0}.MissionSelect-list:has(>.MissionSelect-group:first-child){padding-top:0}.MissionSelect-group{padding-bottom:4px}.MissionSelect-groupLabel{position:-webkit-sticky;position:sticky;top:0;padding:6px 8px 6px 12px;font-size:13px;font-weight:600;color:rgb(198,202,202);background:rgba(58,69,72,.95);z-index:1}.MissionSelect-group:not(:last-child),.MissionSelect-groupLabel{border-bottom:1px solid rgba(255,255,255,.3)}.MissionSelect-item{display:flex;flex-direction:column;gap:1px;margin:4px 4px 0;padding:6px 8px;border-radius:4px;cursor:pointer;outline:none;scroll-margin-top:32px}.MissionSelect-list>.MissionSelect-item:first-child{margin-top:0}.MissionSelect-item[data-active-item]{background:rgba(255,255,255,.15)}.MissionSelect-item[aria-selected=true]{background:rgba(100,150,255,.3)}.MissionSelect-itemHeader{display:flex;align-items:center;gap:6px}.MissionSelect-itemName{font-size:14px;font-weight:600;color:#fff}.MissionSelect-itemTypes{display:flex;gap:3px}.MissionSelect-itemType{font-size:10px;font-weight:600;padding:2px 5px;border-radius:3px;background:rgba(255,157,0,.4);color:#fff}.MissionSelect-itemMissionName{font-size:12px;color:rgba(255,255,255,.5)}.MissionSelect-noResults{padding:12px 8px;font-size:13px;color:rgba(255,255,255,.5);text-align:center}.LoadingSpinner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:48px;height:48px;border:4px solid rgba(255,255,255,.2);border-top-color:white;border-radius:50%;animation:LoadingSpinner-spin 1s linear infinite;pointer-events:none;z-index:1}@keyframes LoadingSpinner-spin{to{transform:translate(-50%,-50%) rotate(1turn)}}

File diff suppressed because one or more lines are too long

View file

@ -2,15 +2,15 @@
2:I[9766,[],""]
3:I[8924,[],""]
4:I[1959,[],"ClientPageRoot"]
5:I[8283,["367","static/chunks/b536a0f1-05ee2c75df4a3b9d.js","831","static/chunks/bd904a5c-3aea2adebde6f067.js","664","static/chunks/a3cd4a83-5c5b758da206345b.js","794","static/chunks/f6211eb1-4f3105d2434536dc.js","413","static/chunks/1329d575-16915d95397758f8.js","331","static/chunks/331-37e8e553d8a20c21.js","974","static/chunks/app/page-992a02d96730d72d.js"],"default"]
5:I[8283,["367","static/chunks/b536a0f1-05ee2c75df4a3b9d.js","831","static/chunks/bd904a5c-3aea2adebde6f067.js","664","static/chunks/a3cd4a83-5c5b758da206345b.js","794","static/chunks/f6211eb1-4f3105d2434536dc.js","413","static/chunks/1329d575-16915d95397758f8.js","331","static/chunks/331-37e8e553d8a20c21.js","974","static/chunks/app/page-f60b39f483c86849.js"],"default"]
8:I[4431,[],"OutletBoundary"]
a:I[5278,[],"AsyncMetadataOutlet"]
c:I[4431,[],"ViewportBoundary"]
e:I[4431,[],"MetadataBoundary"]
f:"$Sreact.suspense"
11:I[7150,[],""]
:HL["/t2-mapper/_next/static/css/9e91738631ff0ad7.css","style"]
0:{"P":null,"b":"tafDAgWrdAOojPa0uDzEv","p":"/t2-mapper","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/t2-mapper/_next/static/css/9e91738631ff0ad7.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L4",null,{"Component":"$5","searchParams":{},"params":{},"promises":["$@6","$@7"]}],null,["$","$L8",null,{"children":["$L9",["$","$La",null,{"promise":"$@b"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Lc",null,{"children":"$Ld"}],null],["$","$Le",null,{"children":["$","div",null,{"hidden":true,"children":["$","$f",null,{"fallback":null,"children":"$L10"}]}]}]]}],false]],"m":"$undefined","G":["$11",[]],"s":false,"S":true}
:HL["/t2-mapper/_next/static/css/e7a9161e212d890f.css","style"]
0:{"P":null,"b":"1kiuXQr5AbGwVAE5IklXM","p":"/t2-mapper","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/t2-mapper/_next/static/css/e7a9161e212d890f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L4",null,{"Component":"$5","searchParams":{},"params":{},"promises":["$@6","$@7"]}],null,["$","$L8",null,{"children":["$L9",["$","$La",null,{"promise":"$@b"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Lc",null,{"children":"$Ld"}],null],["$","$Le",null,{"children":["$","div",null,{"hidden":true,"children":["$","$f",null,{"fallback":null,"children":"$L10"}]}]}]]}],false]],"m":"$undefined","G":["$11",[]],"s":false,"S":true}
6:{}
7:"$0:f:0:1:2:children:1:props:children:0:props:params"
d:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]

View file

@ -1,5 +1,4 @@
import { useQuery } from "@tanstack/react-query";
import { Html } from "@react-three/drei";
import picomatch from "picomatch";
import { loadMission } from "../loaders";
import { type ParsedMission } from "../mission";
@ -86,34 +85,25 @@ function useExecutedMission(
return missionGroup;
}
function LoadingSpinner() {
return (
<Html>
<div
style={{
position: "fixed",
top: "50%",
left: "50%",
width: 48,
height: 48,
border: "4px solid rgba(255, 255, 255, 0.2)",
borderTopColor: "white",
borderRadius: "50%",
animation: "spin 1s linear infinite",
pointerEvents: "none",
}}
/>
<style>{`@keyframes spin { to { transform: translate(-50%, -50%) rotate(360deg); } from { transform: translate(-50%, -50%) rotate(0deg); } }`}</style>
</Html>
);
interface MissionProps {
name: string;
onLoadingChange?: (isLoading: boolean) => void;
}
export const Mission = memo(function Mission({ name }: { name: string }) {
export const Mission = memo(function Mission({
name,
onLoadingChange,
}: MissionProps) {
const { data: parsedMission } = useParsedMission(name);
const missionGroup = useExecutedMission(name, parsedMission);
const isLoading = !missionGroup;
if (!missionGroup) {
return <LoadingSpinner />;
useEffect(() => {
onLoadingChange?.(isLoading);
}, [isLoading, onLoadingChange]);
if (isLoading) {
return null;
}
return <TickProvider>{renderObject(missionGroup)}</TickProvider>;