/** * LoadingScreen Component * * A beautiful loading screen with a circular progress meter that stays still * while the progress arc fills. Replaces the spinning loader animation. * * © 2025 Netwerk Digitaal Erfgoed & TextPast. All rights reserved. */ import React, { useState, useEffect } from 'react'; import './LoadingScreen.css'; interface LoadingScreenProps { /** Loading message to display */ message?: string; /** Optional: show determinate progress (0-100). If not provided, shows indeterminate animation */ progress?: number; /** Size of the circular meter: 'small' (40px), 'medium' (80px), 'large' (120px) */ size?: 'small' | 'medium' | 'large'; /** Whether to show fullscreen overlay */ fullscreen?: boolean; } export const LoadingScreen: React.FC = ({ message = 'Loading...', progress, size = 'medium', fullscreen = true, }) => { // For indeterminate mode, animate progress from 0 to 100 smoothly const [animatedProgress, setAnimatedProgress] = useState(0); useEffect(() => { if (progress !== undefined) { // Use the provided progress value setAnimatedProgress(progress); } else { // Indeterminate mode: smoothly animate progress const interval = setInterval(() => { setAnimatedProgress((prev) => { // Slow start, speed up in middle, slow at end (ease-in-out feel) const increment = prev < 30 ? 0.8 : prev < 70 ? 1.2 : prev < 90 ? 0.6 : 0.2; const next = prev + increment; return next >= 95 ? 0 : next; // Reset at 95% for smooth loop }); }, 50); return () => clearInterval(interval); } }, [progress]); // SVG circle properties const sizeMap = { small: 40, medium: 80, large: 120 }; const strokeWidthMap = { small: 3, medium: 5, large: 7 }; const diameter = sizeMap[size]; const strokeWidth = strokeWidthMap[size]; const radius = (diameter - strokeWidth) / 2; const circumference = 2 * Math.PI * radius; const strokeDashoffset = circumference - (animatedProgress / 100) * circumference; const containerClass = fullscreen ? 'loading-screen loading-screen--fullscreen' : 'loading-screen loading-screen--inline'; return (
{/* Circular progress meter - stationary circle with filling arc */}
{/* Background circle (track) */} {/* Progress arc - fills up clockwise from top */} {/* Center icon or percentage */}
{progress !== undefined ? ( {Math.round(animatedProgress)}% ) : ( )}
{/* Message text */}

{message}

{/* Optional linear progress bar below */} {progress !== undefined && (
)}
); }; export default LoadingScreen;