Enhance Admin and Profile UI: Update admin page to display user preferences with improved layout and visuals. Add password change functionality to profile page, including form handling and validation. Refactor ImageSelector for better image preview and upload experience.
This commit is contained in:
@@ -2,9 +2,94 @@
|
||||
|
||||
import { useBackgroundImage } from "@/hooks/usePreferences";
|
||||
import Link from "next/link";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
interface Particle {
|
||||
width: number;
|
||||
height: number;
|
||||
left: number;
|
||||
top: number;
|
||||
duration: number;
|
||||
delay: number;
|
||||
shadow: number;
|
||||
fadeIn: number;
|
||||
fadeOut: number;
|
||||
visibleDuration: number;
|
||||
moveY1: number;
|
||||
moveX1: number;
|
||||
moveY2: number;
|
||||
moveX2: number;
|
||||
moveY3: number;
|
||||
moveX3: number;
|
||||
moveY4: number;
|
||||
moveX4: number;
|
||||
moveY5: number;
|
||||
moveX5: number;
|
||||
moveY6: number;
|
||||
moveX6: number;
|
||||
}
|
||||
|
||||
interface Orb {
|
||||
width: number;
|
||||
height: number;
|
||||
left: number;
|
||||
top: number;
|
||||
duration: number;
|
||||
delay: number;
|
||||
}
|
||||
|
||||
export default function HeroSection() {
|
||||
const backgroundImage = useBackgroundImage("home", "/got-2.jpg");
|
||||
const [particles, setParticles] = useState<Particle[]>([]);
|
||||
const [orbs, setOrbs] = useState<Orb[]>([]);
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
// Generate particles - more visible and dynamic
|
||||
setParticles(
|
||||
Array.from({ length: 30 }, () => {
|
||||
const fadeIn = Math.random() * 5 + 2; // 2-7% of animation - faster fade in
|
||||
const visibleDuration = Math.random() * 30 + 20; // 20-50% of animation
|
||||
const fadeOut = Math.random() * 5 + 2; // 2-7% of animation - faster fade out
|
||||
return {
|
||||
width: Math.random() * 6 + 3,
|
||||
height: Math.random() * 6 + 3,
|
||||
left: Math.random() * 100,
|
||||
top: Math.random() * 100,
|
||||
duration: 10 + Math.random() * 15,
|
||||
delay: Math.random() * 8,
|
||||
shadow: Math.random() * 15 + 8,
|
||||
fadeIn: fadeIn,
|
||||
fadeOut: fadeOut,
|
||||
visibleDuration: visibleDuration,
|
||||
moveY1: 20 + Math.random() * 20,
|
||||
moveX1: Math.random() * 10 - 5,
|
||||
moveY2: 40 + Math.random() * 20,
|
||||
moveX2: Math.random() * 15 - 7,
|
||||
moveY3: 60 + Math.random() * 20,
|
||||
moveX3: Math.random() * 10 - 5,
|
||||
moveY4: 80 + Math.random() * 20,
|
||||
moveX4: Math.random() * 10 - 5,
|
||||
moveY5: 100 + Math.random() * 20,
|
||||
moveX5: Math.random() * 10 - 5,
|
||||
moveY6: 120 + Math.random() * 20,
|
||||
moveX6: Math.random() * 10 - 5,
|
||||
};
|
||||
})
|
||||
);
|
||||
// Generate orbs
|
||||
setOrbs(
|
||||
Array.from({ length: 4 }, () => ({
|
||||
width: 100 + Math.random() * 200,
|
||||
height: 100 + Math.random() * 200,
|
||||
left: Math.random() * 80,
|
||||
top: Math.random() * 80,
|
||||
duration: 20 + Math.random() * 15,
|
||||
delay: Math.random() * 10,
|
||||
}))
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section className="relative w-full min-h-screen flex flex-col items-center justify-center overflow-hidden pt-24">
|
||||
@@ -16,7 +101,89 @@ export default function HeroSection() {
|
||||
}}
|
||||
>
|
||||
{/* Dark overlay for readability */}
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-black/70 via-black/60 to-black/80"></div>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-black/70 via-black/60 to-black/80 z-[1]"></div>
|
||||
|
||||
{/* Animated particles */}
|
||||
{mounted && (
|
||||
<div className="absolute inset-0 overflow-hidden z-[2]">
|
||||
{particles.map((particle, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: `${particle.width}px`,
|
||||
height: `${particle.height}px`,
|
||||
left: `${particle.left}%`,
|
||||
top: `${particle.top}%`,
|
||||
background: `radial-gradient(circle, rgba(218, 165, 32, 0.9) 0%, rgba(218, 165, 32, 0.4) 50%, transparent 100%)`,
|
||||
animation: `float-particle-${i} ${particle.duration}s infinite ease-in-out`,
|
||||
animationDelay: `${particle.delay}s`,
|
||||
boxShadow: `0 0 ${
|
||||
particle.shadow
|
||||
}px rgba(218, 165, 32, 0.8), 0 0 ${
|
||||
particle.shadow * 2
|
||||
}px rgba(218, 165, 32, 0.4)`,
|
||||
filter: "blur(0.5px)",
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Animated light rays */}
|
||||
<div className="absolute inset-0 overflow-hidden opacity-30">
|
||||
{[...Array(3)].map((_, i) => {
|
||||
const rotation = -15 + i * 15;
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className="absolute w-1 bg-gradient-to-b from-transparent via-pixel-gold/20 to-transparent"
|
||||
style={{
|
||||
height: "100%",
|
||||
left: `${20 + i * 30}%`,
|
||||
transform: `rotate(${rotation}deg)`,
|
||||
animation: `light-ray-${i} ${
|
||||
8 + i * 2
|
||||
}s infinite ease-in-out`,
|
||||
animationDelay: `${i * 2}s`,
|
||||
transformOrigin: "top center",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Glowing orbs */}
|
||||
{mounted && (
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
{orbs.map((orb, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="absolute rounded-full blur-xl"
|
||||
style={{
|
||||
width: `${orb.width}px`,
|
||||
height: `${orb.height}px`,
|
||||
left: `${orb.left}%`,
|
||||
top: `${orb.top}%`,
|
||||
background: `radial-gradient(circle, rgba(218, 165, 32, 0.2) 0%, transparent 70%)`,
|
||||
animation: `orb-float ${orb.duration}s infinite ease-in-out`,
|
||||
animationDelay: `${orb.delay}s`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Shimmer effect */}
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<div
|
||||
className="absolute inset-0 bg-gradient-to-r from-transparent via-pixel-gold/10 to-transparent"
|
||||
style={{
|
||||
transform: "skewX(-20deg)",
|
||||
animation: "shimmer 8s infinite",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Hero Content */}
|
||||
@@ -77,6 +244,108 @@ export default function HeroSection() {
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
}
|
||||
|
||||
${particles
|
||||
.map((particle, i) => {
|
||||
const fadeInPercent = particle.fadeIn;
|
||||
const visibleStart = fadeInPercent;
|
||||
const visibleEnd = visibleStart + particle.visibleDuration;
|
||||
const fadeOutStart = visibleEnd;
|
||||
const fadeOutEnd = Math.min(100, fadeOutStart + particle.fadeOut);
|
||||
|
||||
return `
|
||||
@keyframes float-particle-${i} {
|
||||
0% {
|
||||
transform: translateY(0px) translateX(0px) scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
${fadeInPercent}% {
|
||||
transform: translateY(-${particle.moveY1}px) translateX(${particle.moveX1}px) scale(1);
|
||||
opacity: 0.9;
|
||||
}
|
||||
${visibleStart}% {
|
||||
transform: translateY(-${particle.moveY2}px) translateX(${particle.moveX2}px) scale(1.1);
|
||||
opacity: 1;
|
||||
}
|
||||
${visibleEnd}% {
|
||||
transform: translateY(-${particle.moveY3}px) translateX(${particle.moveX3}px) scale(1.05);
|
||||
opacity: 1;
|
||||
}
|
||||
${fadeOutStart}% {
|
||||
transform: translateY(-${particle.moveY4}px) translateX(${particle.moveX4}px) scale(0.9);
|
||||
opacity: 0.7;
|
||||
}
|
||||
${fadeOutEnd}% {
|
||||
transform: translateY(-${particle.moveY5}px) translateX(${particle.moveX5}px) scale(0.5);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-${particle.moveY6}px) translateX(${particle.moveX6}px) scale(0.3);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
})
|
||||
.join("")}
|
||||
|
||||
@keyframes light-ray-0 {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
transform: rotate(-15deg) scaleY(0.8);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
transform: rotate(-15deg) scaleY(1.2);
|
||||
}
|
||||
}
|
||||
@keyframes light-ray-1 {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
transform: rotate(0deg) scaleY(0.8);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
transform: rotate(0deg) scaleY(1.2);
|
||||
}
|
||||
}
|
||||
@keyframes light-ray-2 {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
transform: rotate(15deg) scaleY(0.8);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
transform: rotate(15deg) scaleY(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes orb-float {
|
||||
0%,
|
||||
100% {
|
||||
transform: translate(0, 0) scale(1);
|
||||
opacity: 0.2;
|
||||
}
|
||||
33% {
|
||||
transform: translate(30px, -30px) scale(1.1);
|
||||
opacity: 0.3;
|
||||
}
|
||||
66% {
|
||||
transform: translate(-20px, 20px) scale(0.9);
|
||||
opacity: 0.25;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
transform: translateX(-100%) skewX(-20deg);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(200%) skewX(-20deg);
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</section>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user