Live location tracking and playback for the game "manhunt"

Smoother view transitions and loading screen

bwc9876.dev 291b733a 7d4959da

verified
+26 -12
+2 -1
frontend/src/components/App.tsx
··· 5 5 import MenuScreen from "./MenuScreen"; 6 6 import LobbyScreen from "./LobbyScreen"; 7 7 import GameScreen from "./GameScreen"; 8 + import { flushSync } from "react-dom"; 8 9 9 10 function ScreenRouter({ screen }: { screen: AppScreen }) { 10 11 switch (screen) { ··· 30 31 }; 31 32 32 33 if (document.startViewTransition) { 33 - document.startViewTransition(update); 34 + document.startViewTransition(() => flushSync(update)); 34 35 } else { 35 36 update(); 36 37 }
+10 -7
frontend/src/components/LobbyScreen.tsx
··· 69 69 70 70 export default function LobbyScreen() { 71 71 const [lobbyState, setLobbyState] = useState(initLobbyState); 72 - const [loadingCover, setLoadingCover] = useState(false); 72 + const [loadingCover, setLoadingCover] = useState(true); 73 73 74 74 useEffect(() => { 75 75 let cancel = false; 76 - commands.getLobbyState().then((state) => { 77 - if (!cancel) { 78 - setLobbyState(state); 79 - setLoadingCover(false); 80 - } 81 - }); 76 + const clear = setTimeout(() => { 77 + commands.getLobbyState().then((state) => { 78 + if (!cancel) { 79 + setLobbyState(state); 80 + setLoadingCover(false); 81 + } 82 + }); 83 + }, 300); 82 84 return () => { 83 85 cancel = true; 86 + clearTimeout(clear); 84 87 }; 85 88 }, [setLobbyState]); 86 89
+6 -4
frontend/src/components/MenuScreen.tsx
··· 44 44 45 45 const startLobby = () => { 46 46 setLoadingCover(true); 47 - commands.startLobby(null, defaultSettings()).finally(() => { 48 - setLoadingCover(false); 49 - }); 47 + setTimeout(() => { 48 + commands.startLobby(null, defaultSettings()).catch(() => { 49 + setLoadingCover(false); 50 + }); 51 + }, 100); 50 52 }; 51 53 52 54 const joinLobby = () => { ··· 61 63 .checkRoomCode(cleanedCode) 62 64 .then((valid) => { 63 65 if (valid) { 64 - commands.startLobby(cleanedCode, defaultSettings()).finally(() => { 66 + commands.startLobby(cleanedCode, defaultSettings()).catch(() => { 65 67 setLoadingCover(false); 66 68 }); 67 69 } else {
+8
frontend/src/style.css
··· 183 183 justify-content: center; 184 184 z-index: 500; 185 185 flex-direction: column; 186 + backdrop-filter: blur(1px); 186 187 gap: var(--2); 187 188 188 189 strong { ··· 192 193 193 194 .spinner { 194 195 font-size: 48pt; 196 + view-transition-name: spinner; 197 + opacity: 0.85; 195 198 } 199 + } 200 + 201 + :root::view-transition-group(spinner) { 202 + animation-duration: 0s; 203 + animation-delay: 0s; 196 204 } 197 205 198 206 @keyframes rotation {