feat(App): replace PageLoader with LazyLoader for improved loading experience
This commit is contained in:
parent
fc2ed1c321
commit
f1f4c6dc16
|
|
@ -13,6 +13,7 @@ import MediaManager from './components/MediaManager';
|
||||||
import logoSvg from '../imports/logo.svg';
|
import logoSvg from '../imports/logo.svg';
|
||||||
import { useSettings } from './settings';
|
import { useSettings } from './settings';
|
||||||
import { WsProvider } from './ws';
|
import { WsProvider } from './ws';
|
||||||
|
import { LazyLoader } from './components/ui/lazy-loader';
|
||||||
|
|
||||||
// Three.js lives only in RealityOverridePage — keep lazy so it doesn't load on startup.
|
// Three.js lives only in RealityOverridePage — keep lazy so it doesn't load on startup.
|
||||||
// CodeMirror/syntax-highlighter/ReactMarkdown live in MediaViewerEditor — lazy-loaded
|
// CodeMirror/syntax-highlighter/ReactMarkdown live in MediaViewerEditor — lazy-loaded
|
||||||
|
|
@ -47,13 +48,6 @@ type AppId =
|
||||||
| 'reality-override'
|
| 'reality-override'
|
||||||
| 'reality-override-admin';
|
| 'reality-override-admin';
|
||||||
|
|
||||||
function PageLoader() {
|
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-center h-full text-neutral-400">
|
|
||||||
<Loader2 className="w-6 h-6 animate-spin" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [currentPage, setCurrentPage] = useState<Page>('status');
|
const [currentPage, setCurrentPage] = useState<Page>('status');
|
||||||
|
|
@ -314,7 +308,7 @@ function AppPage({ title, onBack }: { title: string; onBack: () => void }) {
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main className="flex-1 overflow-y-auto">
|
<main className="flex-1 overflow-y-auto">
|
||||||
<Suspense fallback={<PageLoader />}>
|
<Suspense fallback={<LazyLoader />}>
|
||||||
{pages[currentPage]}
|
{pages[currentPage]}
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
38
src/app/components/ui/lazy-loader.tsx
Normal file
38
src/app/components/ui/lazy-loader.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { Loader2 } from 'lucide-react';
|
||||||
|
|
||||||
|
export function LazyLoader() {
|
||||||
|
const [pct, setPct] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const steps: [number, number][] = [
|
||||||
|
[80, 30],
|
||||||
|
[400, 60],
|
||||||
|
[1200, 80],
|
||||||
|
[2500, 92],
|
||||||
|
];
|
||||||
|
const timers = steps.map(([delay, val]) => setTimeout(() => setPct(val), delay));
|
||||||
|
return () => timers.forEach(clearTimeout);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const duration =
|
||||||
|
pct <= 30 ? '150ms' :
|
||||||
|
pct <= 60 ? '500ms' :
|
||||||
|
pct <= 80 ? '1000ms' : '1500ms';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 bg-neutral-950 z-40 flex flex-col items-center justify-center">
|
||||||
|
<div className="absolute top-0 left-0 right-0 h-[2px] bg-neutral-800 overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="h-full bg-blue-500 transition-[width] ease-out"
|
||||||
|
style={{ width: `${pct}%`, transitionDuration: duration }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-center gap-3 text-neutral-600">
|
||||||
|
<Loader2 className="w-5 h-5 animate-spin" />
|
||||||
|
<span className="text-xs tracking-wide">Loading…</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user