Files
GNX-WEB/gnx-react/components/shared/layout/Preloader.tsx
Iliyan Angelov 3f5bcfad68 update
2025-09-26 00:45:31 +03:00

388 lines
9.8 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import { usePathname } from "next/navigation";
import Image from "next/image";
interface PreloaderProps {
children: React.ReactNode;
}
const Preloader = ({ children }: PreloaderProps) => {
const [isLoading, setIsLoading] = useState(true);
const [progress, setProgress] = useState(0);
const [currentPath, setCurrentPath] = useState("");
const pathname = usePathname();
// Debug mode - set to true to see console logs
const DEBUG = false;
// Skip preloader for faster development/testing (set to true to disable preloader)
const SKIP_PRELOADER = false;
// Fast mode - set to true for even faster loading (200ms total)
const FAST_MODE = true;
useEffect(() => {
// Only show preloader if path has changed or it's initial load
if (currentPath !== pathname) {
if (DEBUG) console.log('Preloader: Starting transition from', currentPath, 'to', pathname);
setIsLoading(true);
setProgress(0);
// Simulate loading progress - faster and more responsive
const progressInterval = setInterval(() => {
setProgress((prev) => {
if (prev >= 85) {
clearInterval(progressInterval);
return 85;
}
return prev + Math.random() * 25 + 10; // Faster progress increments
});
}, 50); // Reduced interval from 100ms to 50ms for smoother animation
// Complete loading much faster - adjust timing based on FAST_MODE
const loadingDuration = FAST_MODE ? 200 : 400;
const fadeOutDuration = FAST_MODE ? 50 : 100;
const completeTimer = setTimeout(() => {
setProgress(100);
setTimeout(() => {
if (DEBUG) console.log('Preloader: Transition complete');
setIsLoading(false);
setCurrentPath(pathname);
}, fadeOutDuration);
}, loadingDuration);
// Fallback: Force complete after reasonable time
const fallbackDuration = FAST_MODE ? 800 : 1500;
const fallbackTimer = setTimeout(() => {
if (DEBUG) console.log('Preloader: Fallback triggered - force completing');
setIsLoading(false);
setCurrentPath(pathname);
setProgress(100);
}, fallbackDuration);
return () => {
clearInterval(progressInterval);
clearTimeout(completeTimer);
clearTimeout(fallbackTimer);
};
}
}, [pathname, currentPath, DEBUG, FAST_MODE]);
// Skip preloader entirely if SKIP_PRELOADER is true
if (SKIP_PRELOADER) {
return <>{children}</>;
}
// Don't show preloader if not loading
if (!isLoading) {
return <>{children}</>;
}
return (
<>
<div className="preloader-overlay">
<div className="preloader-container">
{/* Logo with shine effect */}
<div className="preloader-logo">
<div className="logo-wrapper">
<Image
src="/images/logo.png"
alt="GNX Logo"
width={80}
height={60}
className="logo-image"
priority
/>
<div className="shine-effect"></div>
</div>
</div>
{/* Progress bar */}
<div className="progress-container">
<div className="progress-bar">
<div
className="progress-fill"
style={{ width: `${progress}%` }}
></div>
</div>
<div className="progress-text">{Math.round(progress)}%</div>
</div>
{/* Loading text */}
<div className="loading-text">
<span className="loading-dots">
<span>.</span>
<span>.</span>
<span>.</span>
</span>
</div>
{/* Enterprise tagline */}
<div className="enterprise-tagline">
<span>Enterprise Solutions</span>
<span>Excellence in Every Project</span>
</div>
</div>
</div>
<style jsx>{`
.preloader-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 50%, #0f0f0f 100%);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
backdrop-filter: blur(10px);
}
.preloader-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 2rem;
text-align: center;
}
.preloader-logo {
position: relative;
animation: logoFloat 2s ease-in-out infinite;
}
.logo-wrapper {
position: relative;
display: inline-block;
padding: 1.5rem;
border-radius: 50%;
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
overflow: hidden;
transition: all 0.2s ease; /* Faster transitions */
}
.logo-image {
position: relative;
z-index: 2;
filter: brightness(1.1);
transition: all 0.2s ease; /* Faster transitions */
}
.shine-effect {
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.4),
transparent
);
animation: shine 2s infinite;
z-index: 3;
}
.progress-container {
width: 200px;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.progress-bar {
width: 100%;
height: 3px;
background: rgba(255, 255, 255, 0.1);
border-radius: 2px;
overflow: hidden;
position: relative;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #4f46e5, #7c3aed, #ec4899);
border-radius: 2px;
transition: width 0.2s ease; /* Faster progress bar animation */
position: relative;
overflow: hidden;
}
.progress-fill::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.6),
transparent
);
animation: progressShine 1.5s infinite;
}
.progress-text {
font-size: 0.875rem;
color: rgba(255, 255, 255, 0.7);
font-weight: 500;
letter-spacing: 0.05em;
}
.loading-text {
color: rgba(255, 255, 255, 0.6);
font-size: 0.875rem;
font-weight: 400;
letter-spacing: 0.1em;
}
.loading-dots {
display: inline-flex;
gap: 0.25rem;
}
.loading-dots span {
animation: dotPulse 1.4s infinite ease-in-out;
animation-fill-mode: both;
}
.loading-dots span:nth-child(1) {
animation-delay: -0.32s;
}
.loading-dots span:nth-child(2) {
animation-delay: -0.16s;
}
.loading-dots span:nth-child(3) {
animation-delay: 0s;
}
.enterprise-tagline {
display: flex;
flex-direction: column;
gap: 0.25rem;
margin-top: 1rem;
text-align: center;
}
.enterprise-tagline span {
font-size: 0.75rem;
color: rgba(255, 255, 255, 0.5);
font-weight: 300;
letter-spacing: 0.15em;
text-transform: uppercase;
animation: fadeInUp 0.8s ease-out 0.5s both;
}
.enterprise-tagline span:first-child {
animation-delay: 0.7s;
}
.enterprise-tagline span:last-child {
animation-delay: 0.9s;
}
@keyframes logoFloat {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
}
@keyframes shine {
0% {
left: -100%;
}
100% {
left: 100%;
}
}
@keyframes progressShine {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
@keyframes dotPulse {
0%, 80%, 100% {
opacity: 0.3;
transform: scale(0.8);
}
40% {
opacity: 1;
transform: scale(1);
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Responsive adjustments */
@media (max-width: 768px) {
.preloader-container {
gap: 1.5rem;
}
.logo-wrapper {
padding: 1rem;
}
.logo-image {
width: 60px;
height: 45px;
}
.progress-container {
width: 150px;
}
}
@media (max-width: 480px) {
.preloader-container {
gap: 1rem;
}
.logo-wrapper {
padding: 0.75rem;
}
.logo-image {
width: 50px;
height: 37px;
}
.progress-container {
width: 120px;
}
}
`}</style>
</>
);
};
export default Preloader;