Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ body, html {
/* Body and Background Enhancements */
body {
font-family: 'Roboto', sans-serif; /* Modern font */
background: linear-gradient(135deg, #1e3c72, #2a5298); /* Futuristic gradient background */
/* Background is now handled by AnimatedGradientBackground component */
color: #e0e0e0; /* Light text for contrast */
overflow-x: hidden; /* Prevent horizontal scrolling */
line-height: 1.6;
Expand Down
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import DeleteUser from './components/DeleteUser';
import NotFound from './components/NotFound';
import UserContext from './context/UserContext';
import OrderHistory from './components/OrderHistory';
import AnimatedGradientBackground from './components/AnimatedGradientBackground';
import './App.css';

const queryClient = new QueryClient();
Expand All @@ -24,6 +25,7 @@ function App() {
return (
<QueryClientProvider client={queryClient}>
<UserContext.Provider value={{ user, setUser }}>
<AnimatedGradientBackground />
<BrowserRouter>
<Routes>
<Route path="/" element={<Login />} />
Expand Down
58 changes: 58 additions & 0 deletions src/components/AnimatedGradientBackground.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* Animated Gradient Background Styles */

.animated-gradient-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
transition: background 0.3s ease-out;
}

.ripples-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
pointer-events: none;
overflow: hidden;
}

.ripple {
position: absolute;
width: 0;
height: 0;
border-radius: 50%;
background: radial-gradient(
circle,
rgba(255, 255, 255, 0.3) 0%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0) 100%
);
transform: translate(-50%, -50%);
animation: ripple-animation 1.5s ease-out forwards;
}

@keyframes ripple-animation {
0% {
width: 0;
height: 0;
opacity: 1;
}
50% {
opacity: 0.6;
}
100% {
width: 500px;
height: 500px;
opacity: 0;
}
}

/* Ensure the background doesn't interfere with scrolling */
body {
position: relative;
}
110 changes: 110 additions & 0 deletions src/components/AnimatedGradientBackground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React, { useState, useEffect, useRef } from 'react';
import './AnimatedGradientBackground.css';

interface Ripple {
id: number;
x: number;
y: number;
}

const AnimatedGradientBackground: React.FC = () => {
const [mousePosition, setMousePosition] = useState({ x: 50, y: 50 });
const [ripples, setRipples] = useState<Ripple[]>([]);
const rippleIdRef = useRef(0);
const timeoutIdsRef = useRef<Set<NodeJS.Timeout>>(new Set());
const rafIdRef = useRef<number | null>(null);

useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
// Throttle mouse move updates using requestAnimationFrame
if (rafIdRef.current === null) {
rafIdRef.current = requestAnimationFrame(() => {
const x = (e.clientX / window.innerWidth) * 100;
const y = (e.clientY / window.innerHeight) * 100;
setMousePosition({ x, y });
rafIdRef.current = null;
});
}
};

const handleMouseClick = (e: MouseEvent) => {
const newRipple: Ripple = {
id: rippleIdRef.current++,
x: e.clientX,
y: e.clientY,
};

setRipples(prev => [...prev, newRipple]);

// Remove ripple after animation completes, track timeout for cleanup
const timeoutId = setTimeout(() => {
setRipples(prev => prev.filter(r => r.id !== newRipple.id));
timeoutIdsRef.current.delete(timeoutId);
}, 1500);
timeoutIdsRef.current.add(timeoutId);
};

window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('click', handleMouseClick);

return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('click', handleMouseClick);

// Clean up pending timeouts
timeoutIdsRef.current.forEach(id => clearTimeout(id));
timeoutIdsRef.current.clear();

// Clean up pending animation frame
if (rafIdRef.current !== null) {
cancelAnimationFrame(rafIdRef.current);
}
};
}, []);

// Calculate gradient colors based on mouse position
const calculateGradient = () => {
// Using a monochromatic blue palette
const baseHue = 220; // Blue hue
const saturation = 70;

// Vary lightness based on mouse position
const lightness1 = 15 + (mousePosition.x / 100) * 20; // 15-35%
const lightness2 = 25 + (mousePosition.y / 100) * 25; // 25-50%
const lightness3 = 20 + ((mousePosition.x + mousePosition.y) / 200) * 30; // 20-50%

return `
radial-gradient(
circle at ${mousePosition.x}% ${mousePosition.y}%,
hsl(${baseHue}, ${saturation}%, ${lightness1}%) 0%,
hsl(${baseHue}, ${saturation - 10}%, ${lightness2}%) 40%,
hsl(${baseHue}, ${saturation - 20}%, ${lightness3}%) 100%
)
`;
};

return (
<>
<div
className="animated-gradient-background"
style={{
background: calculateGradient(),
}}
/>
<div className="ripples-container">
{ripples.map(ripple => (
<div
key={ripple.id}
className="ripple"
style={{
left: `${ripple.x}px`,
top: `${ripple.y}px`,
}}
/>
))}
</div>
</>
);
};

export default AnimatedGradientBackground;