Updated Frontend
This commit is contained in:
75
app/components/CTA.tsx
Normal file
75
app/components/CTA.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { ArrowRight, Sparkles } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function CTA() {
|
||||
return (
|
||||
<section className="py-24 bg-white relative overflow-hidden">
|
||||
{/* Background Elements */}
|
||||
<div className="absolute inset-0">
|
||||
<div className="absolute top-0 left-1/4 w-96 h-96 bg-lime-100 rounded-full blur-3xl opacity-50" />
|
||||
<div className="absolute bottom-0 right-1/4 w-96 h-96 bg-sky-100 rounded-full blur-3xl opacity-50" />
|
||||
</div>
|
||||
|
||||
<div className="relative max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
<div className="inline-flex items-center gap-2 bg-black text-white px-4 py-2 text-xs font-medium tracking-wider rounded-full mb-8">
|
||||
<Sparkles className="w-4 h-4 text-lime-400" />
|
||||
LIMITED TIME
|
||||
</div>
|
||||
|
||||
<h2 className="text-4xl sm:text-5xl lg:text-6xl font-black tracking-tight text-black mb-6 leading-tight">
|
||||
Ready to Showcase
|
||||
<br />
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-lime-400 to-lime-600">
|
||||
Your Masterpiece?
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<p className="text-zinc-600 text-lg sm:text-xl max-w-2xl mx-auto mb-10">
|
||||
Join hundreds of talented artists from SJEC in this creative
|
||||
celebration. Submit your artwork and let the world vote for your
|
||||
talent.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<Link
|
||||
href="/register"
|
||||
className="inline-flex items-center justify-center gap-2 bg-lime-400 text-black px-10 py-5 text-base font-bold tracking-wide hover:bg-lime-300 transition-all hover:scale-105 rounded-full shadow-xl shadow-lime-400/25"
|
||||
>
|
||||
REGISTER NOW
|
||||
<ArrowRight className="w-5 h-5" />
|
||||
</Link>
|
||||
<Link
|
||||
href="/rules"
|
||||
className="inline-flex items-center justify-center gap-2 bg-white text-black px-10 py-5 text-base font-bold tracking-wide border-2 border-black hover:bg-black hover:text-white transition-all rounded-full"
|
||||
>
|
||||
VIEW RULES
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Deadline Notice */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
whileInView={{ opacity: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="mt-12 inline-flex items-center gap-3 bg-zinc-100 px-6 py-3 rounded-full"
|
||||
>
|
||||
<span className="w-3 h-3 bg-red-500 rounded-full animate-pulse" />
|
||||
<span className="text-zinc-700 font-medium">
|
||||
Submissions close on <span className="text-black font-bold">February 28, 2026</span>
|
||||
</span>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
131
app/components/Categories.tsx
Normal file
131
app/components/Categories.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { Palette, Monitor, FileImage, ArrowRight } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
const categories = [
|
||||
{
|
||||
icon: Monitor,
|
||||
title: "Digital Art",
|
||||
description:
|
||||
"Create stunning digital masterpieces using any software of your choice. From illustrations to photo manipulations.",
|
||||
color: "from-violet-500 to-purple-600",
|
||||
bgColor: "bg-violet-50",
|
||||
},
|
||||
{
|
||||
icon: Palette,
|
||||
title: "Paintings",
|
||||
description:
|
||||
"Traditional paintings in any medium - oil, acrylic, watercolor. Capture the essence of classic artistry.",
|
||||
color: "from-orange-500 to-red-500",
|
||||
bgColor: "bg-orange-50",
|
||||
},
|
||||
{
|
||||
icon: FileImage,
|
||||
title: "Poster Making",
|
||||
description:
|
||||
"Design impactful posters that communicate powerful messages. Blend creativity with purpose.",
|
||||
color: "from-lime-500 to-green-500",
|
||||
bgColor: "bg-lime-50",
|
||||
},
|
||||
];
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.2,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { opacity: 0, y: 30 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
duration: 0.6,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default function Categories() {
|
||||
return (
|
||||
<section className="py-24 bg-white">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{/* Section Header */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<span className="inline-block bg-lime-400 text-black px-4 py-1.5 text-xs font-bold tracking-wider rounded-full mb-4">
|
||||
CATEGORIES
|
||||
</span>
|
||||
<h2 className="text-4xl sm:text-5xl font-black tracking-tight text-black mb-4">
|
||||
Three Ways to
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-lime-400 to-lime-600">
|
||||
{" "}
|
||||
Express
|
||||
</span>
|
||||
</h2>
|
||||
<p className="text-zinc-600 text-lg max-w-2xl mx-auto">
|
||||
Choose your canvas, unleash your creativity. Each category offers a
|
||||
unique way to showcase your artistic vision.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Categories Grid */}
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true }}
|
||||
className="grid md:grid-cols-3 gap-8"
|
||||
>
|
||||
{categories.map((category) => (
|
||||
<motion.div
|
||||
key={category.title}
|
||||
variants={itemVariants}
|
||||
className={`group relative ${category.bgColor} rounded-3xl p-8 hover:shadow-2xl transition-all duration-500 overflow-hidden`}
|
||||
>
|
||||
{/* Background Gradient on Hover */}
|
||||
<div
|
||||
className={`absolute inset-0 bg-gradient-to-br ${category.color} opacity-0 group-hover:opacity-10 transition-opacity duration-500`}
|
||||
/>
|
||||
|
||||
{/* Icon */}
|
||||
<div
|
||||
className={`w-16 h-16 rounded-2xl bg-gradient-to-br ${category.color} flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-300`}
|
||||
>
|
||||
<category.icon className="w-8 h-8 text-white" />
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<h3 className="text-2xl font-bold text-black mb-3">
|
||||
{category.title}
|
||||
</h3>
|
||||
<p className="text-zinc-600 mb-6 leading-relaxed">
|
||||
{category.description}
|
||||
</p>
|
||||
|
||||
{/* Link */}
|
||||
<Link
|
||||
href="/submit"
|
||||
className="inline-flex items-center gap-2 text-black font-semibold group-hover:gap-4 transition-all"
|
||||
>
|
||||
Submit Now
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</Link>
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
111
app/components/Footer.tsx
Normal file
111
app/components/Footer.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { Diamond, Mail, Instagram, Twitter } from "lucide-react";
|
||||
|
||||
const footerLinks = {
|
||||
competition: [
|
||||
{ href: "/register", label: "Register" },
|
||||
{ href: "/submit", label: "Submit Art" },
|
||||
{ href: "/gallery", label: "Gallery" },
|
||||
{ href: "/rules", label: "Rules" },
|
||||
],
|
||||
information: [
|
||||
{ href: "/about", label: "About" },
|
||||
{ href: "/faq", label: "FAQ" },
|
||||
{ href: "/contact", label: "Contact" },
|
||||
],
|
||||
};
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="bg-black text-white">
|
||||
{/* Main Footer */}
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-12">
|
||||
{/* Brand */}
|
||||
<div className="lg:col-span-2">
|
||||
<Link href="/" className="flex items-center gap-2 mb-6">
|
||||
<Diamond className="w-8 h-8 text-lime-400" />
|
||||
<span className="text-2xl font-black tracking-tight">ARTSPLASH</span>
|
||||
</Link>
|
||||
<p className="text-zinc-400 max-w-md mb-6 leading-relaxed">
|
||||
ArtSplash is SJEC's premier art competition celebrating creativity
|
||||
across Digital Art, Paintings, and Poster Making. Join us in this
|
||||
vibrant celebration of artistic expression.
|
||||
</p>
|
||||
<div className="flex gap-4">
|
||||
<a
|
||||
href="#"
|
||||
className="w-10 h-10 rounded-full bg-zinc-800 flex items-center justify-center hover:bg-lime-400 hover:text-black transition-colors"
|
||||
>
|
||||
<Instagram className="w-5 h-5" />
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
className="w-10 h-10 rounded-full bg-zinc-800 flex items-center justify-center hover:bg-lime-400 hover:text-black transition-colors"
|
||||
>
|
||||
<Twitter className="w-5 h-5" />
|
||||
</a>
|
||||
<a
|
||||
href="mailto:artsplash@sjec.ac.in"
|
||||
className="w-10 h-10 rounded-full bg-zinc-800 flex items-center justify-center hover:bg-lime-400 hover:text-black transition-colors"
|
||||
>
|
||||
<Mail className="w-5 h-5" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Competition Links */}
|
||||
<div>
|
||||
<h3 className="text-lg font-bold mb-4">Competition</h3>
|
||||
<ul className="space-y-3">
|
||||
{footerLinks.competition.map((link) => (
|
||||
<li key={link.href}>
|
||||
<Link
|
||||
href={link.href}
|
||||
className="text-zinc-400 hover:text-lime-400 transition-colors"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Information Links */}
|
||||
<div>
|
||||
<h3 className="text-lg font-bold mb-4">Information</h3>
|
||||
<ul className="space-y-3">
|
||||
{footerLinks.information.map((link) => (
|
||||
<li key={link.href}>
|
||||
<Link
|
||||
href={link.href}
|
||||
className="text-zinc-400 hover:text-lime-400 transition-colors"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Bar */}
|
||||
<div className="border-t border-zinc-800">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
<div className="flex flex-col sm:flex-row items-center justify-between gap-4">
|
||||
<p className="text-zinc-500 text-sm">
|
||||
© 2026 ArtSplash. All rights reserved.
|
||||
</p>
|
||||
<div className="flex items-center gap-2 text-zinc-500 text-sm">
|
||||
<span>Powered by</span>
|
||||
<span className="text-lime-400 font-bold">Sceptix</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
191
app/components/Hero.tsx
Normal file
191
app/components/Hero.tsx
Normal file
@@ -0,0 +1,191 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useCallback } from "react";
|
||||
import Link from "next/link";
|
||||
import gsap from "gsap";
|
||||
|
||||
const GRID_COLS = 20;
|
||||
const GRID_ROWS = 12;
|
||||
|
||||
function TileGrid() {
|
||||
const gridRef = useRef<HTMLDivElement>(null);
|
||||
const tilesRef = useRef<(HTMLDivElement | null)[]>([]);
|
||||
|
||||
const handleMouseEnter = useCallback((index: number) => {
|
||||
const tile = tilesRef.current[index];
|
||||
if (tile) {
|
||||
gsap.to(tile, {
|
||||
rotateY: 180,
|
||||
duration: 0.4,
|
||||
ease: "power2.out",
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleMouseLeave = useCallback((index: number) => {
|
||||
const tile = tilesRef.current[index];
|
||||
if (tile) {
|
||||
gsap.to(tile, {
|
||||
rotateY: 0,
|
||||
duration: 0.4,
|
||||
ease: "power2.out",
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={gridRef}
|
||||
className="absolute inset-0 grid z-0"
|
||||
style={{
|
||||
gridTemplateColumns: `repeat(${GRID_COLS}, 1fr)`,
|
||||
gridTemplateRows: `repeat(${GRID_ROWS}, 1fr)`,
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: GRID_COLS * GRID_ROWS }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
onMouseEnter={() => handleMouseEnter(index)}
|
||||
onMouseLeave={() => handleMouseLeave(index)}
|
||||
className="cursor-pointer"
|
||||
style={{ perspective: "500px" }}
|
||||
>
|
||||
<div
|
||||
ref={(el) => { tilesRef.current[index] = el; }}
|
||||
className="w-full h-full relative"
|
||||
style={{ transformStyle: "preserve-3d" }}
|
||||
>
|
||||
{/* Front - Black */}
|
||||
<div
|
||||
className="absolute inset-0 bg-black border border-zinc-900"
|
||||
style={{ backfaceVisibility: "hidden" }}
|
||||
/>
|
||||
{/* Back - White */}
|
||||
<div
|
||||
className="absolute inset-0 bg-white"
|
||||
style={{
|
||||
backfaceVisibility: "hidden",
|
||||
transform: "rotateY(180deg)",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Hero() {
|
||||
const headingRef = useRef<HTMLHeadingElement>(null);
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Animate heading on mount
|
||||
if (headingRef.current) {
|
||||
gsap.fromTo(
|
||||
headingRef.current,
|
||||
{ opacity: 0, y: 50 },
|
||||
{ opacity: 1, y: 0, duration: 1, ease: "power3.out", delay: 0.3 }
|
||||
);
|
||||
}
|
||||
|
||||
if (contentRef.current) {
|
||||
gsap.fromTo(
|
||||
contentRef.current.children,
|
||||
{ opacity: 0, y: 30 },
|
||||
{ opacity: 1, y: 0, duration: 0.8, stagger: 0.15, ease: "power3.out", delay: 0.5 }
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section className="relative min-h-screen bg-black overflow-hidden pt-28">
|
||||
{/* Tile Grid Background */}
|
||||
<TileGrid />
|
||||
|
||||
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-full pointer-events-none">
|
||||
<div className="flex items-center justify-center min-h-[calc(100vh-12rem)] pb-20">
|
||||
{/* Center Content */}
|
||||
<div className="text-center relative z-10">
|
||||
<div className="inline-flex items-center gap-2 bg-lime-400 text-black px-5 py-2.5 text-xs font-bold tracking-widest rounded-full mb-10 pointer-events-auto">
|
||||
<span className="w-2 h-2 bg-black rounded-full animate-pulse" />
|
||||
FEBRUARY 2026
|
||||
</div>
|
||||
|
||||
<h1
|
||||
ref={headingRef}
|
||||
className="text-6xl sm:text-7xl lg:text-8xl xl:text-9xl font-black tracking-tighter text-white leading-[0.85] mb-8"
|
||||
style={{
|
||||
WebkitTextStroke: "2px black",
|
||||
paintOrder: "stroke fill",
|
||||
}}
|
||||
>
|
||||
<span className="block">UNLEASH</span>
|
||||
<span
|
||||
className="block text-lime-400 drop-shadow-[0_0_30px_rgba(163,230,53,0.5)]"
|
||||
style={{
|
||||
WebkitTextStroke: "2px black",
|
||||
paintOrder: "stroke fill",
|
||||
}}
|
||||
>
|
||||
YOUR ART
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<div ref={contentRef}>
|
||||
<p className="text-zinc-400 text-base sm:text-lg max-w-lg mx-auto mb-10 leading-relaxed font-light">
|
||||
From canvas to screen, showcase your creativity and let your
|
||||
artwork speak to the world.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center pointer-events-auto">
|
||||
<Link
|
||||
href="/register"
|
||||
className="inline-flex items-center justify-center gap-2 bg-lime-400 text-black px-10 py-4 text-sm font-bold tracking-wider hover:bg-lime-300 transition-all hover:scale-105 rounded-full shadow-[0_0_30px_rgba(163,230,53,0.3)]"
|
||||
>
|
||||
JOIN COMPETITION
|
||||
</Link>
|
||||
<Link
|
||||
href="/gallery"
|
||||
className="inline-flex items-center justify-center gap-2 bg-transparent text-white px-10 py-4 text-sm font-bold tracking-wider hover:bg-white/10 transition-all rounded-full border border-zinc-700 hover:border-zinc-500"
|
||||
>
|
||||
EXPLORE GALLERY
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scroll Indicator - positioned above the marquee */}
|
||||
<div className="absolute bottom-28 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2 text-zinc-500 z-10">
|
||||
<span className="text-[10px] tracking-[0.3em] uppercase">Scroll</span>
|
||||
<div className="w-px h-8 bg-gradient-to-b from-zinc-500 to-transparent" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Marquee */}
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-lime-400 text-black py-3 overflow-hidden z-10">
|
||||
<div className="animate-marquee-slow whitespace-nowrap flex items-center">
|
||||
{Array(8)
|
||||
.fill(null)
|
||||
.map((_, i) => (
|
||||
<div key={i} className="flex items-center">
|
||||
<span className="text-xl sm:text-2xl font-black tracking-tight mx-6 uppercase">
|
||||
ArtSplash
|
||||
</span>
|
||||
<span className="text-black/40 mx-4">✦</span>
|
||||
<span className="text-xl sm:text-2xl font-black tracking-tight mx-6 uppercase text-black/60">
|
||||
SJEC
|
||||
</span>
|
||||
<span className="text-black/40 mx-4">✦</span>
|
||||
<span className="text-xl sm:text-2xl font-black tracking-tight mx-6 uppercase">
|
||||
2026
|
||||
</span>
|
||||
<span className="text-black/40 mx-4">✦</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
101
app/components/HowItWorks.tsx
Normal file
101
app/components/HowItWorks.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { UserPlus, Upload, Shield, Vote, Trophy } from "lucide-react";
|
||||
|
||||
const steps = [
|
||||
{
|
||||
icon: UserPlus,
|
||||
step: "01",
|
||||
title: "Register",
|
||||
description: "Sign up with your SJEC email to participate in the competition.",
|
||||
},
|
||||
{
|
||||
icon: Upload,
|
||||
step: "02",
|
||||
title: "Submit",
|
||||
description: "Upload your artwork with title, description, and category details.",
|
||||
},
|
||||
{
|
||||
icon: Shield,
|
||||
step: "03",
|
||||
title: "Review",
|
||||
description: "Moderators review submissions to ensure guidelines are met.",
|
||||
},
|
||||
{
|
||||
icon: Vote,
|
||||
step: "04",
|
||||
title: "Public Voting",
|
||||
description: "The public votes for their favorite artworks in each category.",
|
||||
},
|
||||
{
|
||||
icon: Trophy,
|
||||
step: "05",
|
||||
title: "Results",
|
||||
description: "Winners are announced and celebrated across all categories.",
|
||||
},
|
||||
];
|
||||
|
||||
export default function HowItWorks() {
|
||||
return (
|
||||
<section className="py-24 bg-black text-white overflow-hidden">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{/* Section Header */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<span className="inline-block bg-lime-400 text-black px-4 py-1.5 text-xs font-bold tracking-wider rounded-full mb-4">
|
||||
HOW IT WORKS
|
||||
</span>
|
||||
<h2 className="text-4xl sm:text-5xl font-black tracking-tight mb-4">
|
||||
Your Journey to
|
||||
<span className="text-lime-400"> Victory</span>
|
||||
</h2>
|
||||
<p className="text-zinc-400 text-lg max-w-2xl mx-auto">
|
||||
From registration to winning, here's how ArtSplash works.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Steps Timeline */}
|
||||
<div className="relative">
|
||||
{/* Connection Line */}
|
||||
<div className="absolute top-1/2 left-0 right-0 h-0.5 bg-zinc-800 hidden lg:block" />
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-8 lg:gap-4">
|
||||
{steps.map((step, index) => (
|
||||
<motion.div
|
||||
key={step.step}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: index * 0.1 }}
|
||||
className="relative"
|
||||
>
|
||||
{/* Card */}
|
||||
<div className="bg-zinc-900 rounded-2xl p-6 h-full border border-zinc-800 hover:border-lime-400/50 transition-colors group">
|
||||
{/* Step Number */}
|
||||
<div className="relative z-10 w-12 h-12 rounded-full bg-lime-400 text-black font-black text-sm flex items-center justify-center mb-4 group-hover:scale-110 transition-transform">
|
||||
{step.step}
|
||||
</div>
|
||||
|
||||
{/* Icon */}
|
||||
<step.icon className="w-8 h-8 text-lime-400 mb-4" />
|
||||
|
||||
{/* Content */}
|
||||
<h3 className="text-xl font-bold mb-2">{step.title}</h3>
|
||||
<p className="text-zinc-400 text-sm leading-relaxed">
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
112
app/components/Navbar.tsx
Normal file
112
app/components/Navbar.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { Menu, X, Diamond } from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
const navLinks = [
|
||||
{ href: "/gallery", label: "GALLERY" },
|
||||
{ href: "/submit", label: "SUBMIT ART" },
|
||||
{ href: "/about", label: "ABOUT" },
|
||||
{ href: "/rules", label: "RULES" },
|
||||
{ href: "/faq", label: "FAQ" },
|
||||
{ href: "/contact", label: "CONTACT" },
|
||||
];
|
||||
|
||||
export default function Navbar() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<nav className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-zinc-200">
|
||||
{/* Announcement Bar */}
|
||||
<div className="bg-black text-white overflow-hidden">
|
||||
<div className="animate-marquee whitespace-nowrap py-2 text-xs tracking-widest">
|
||||
{Array(10)
|
||||
.fill("✦ OPEN FOR SUBMISSIONS")
|
||||
.map((text, i) => (
|
||||
<span key={i} className="mx-8">
|
||||
{text}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Navbar */}
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex items-center justify-between h-16">
|
||||
{/* Logo */}
|
||||
<Link href="/" className="flex items-center gap-2 group">
|
||||
<Diamond className="w-6 h-6 text-lime-400 group-hover:rotate-12 transition-transform" />
|
||||
<span className="text-xl font-bold tracking-tight">ARTSPLASH</span>
|
||||
</Link>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<div className="hidden lg:flex items-center gap-8">
|
||||
{navLinks.map((link) => (
|
||||
<Link
|
||||
key={link.href}
|
||||
href={link.href}
|
||||
className="text-sm font-medium tracking-wide text-zinc-700 hover:text-black transition-colors relative group"
|
||||
>
|
||||
{link.label}
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-lime-400 group-hover:w-full transition-all duration-300" />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* CTA Button */}
|
||||
<div className="hidden lg:block">
|
||||
<Link
|
||||
href="/register"
|
||||
className="bg-lime-400 text-black px-6 py-2.5 text-sm font-bold tracking-wide hover:bg-lime-300 transition-colors rounded-full"
|
||||
>
|
||||
REGISTER NOW
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="lg:hidden p-2 hover:bg-zinc-100 rounded-lg transition-colors"
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
{isOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu */}
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: "auto" }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
className="lg:hidden bg-white border-t border-zinc-200"
|
||||
>
|
||||
<div className="px-4 py-6 space-y-4">
|
||||
{navLinks.map((link) => (
|
||||
<Link
|
||||
key={link.href}
|
||||
href={link.href}
|
||||
onClick={() => setIsOpen(false)}
|
||||
className="block text-lg font-medium text-zinc-700 hover:text-black hover:pl-2 transition-all"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
))}
|
||||
<Link
|
||||
href="/register"
|
||||
onClick={() => setIsOpen(false)}
|
||||
className="block w-full text-center bg-lime-400 text-black px-6 py-3 text-sm font-bold tracking-wide hover:bg-lime-300 transition-colors rounded-full mt-6"
|
||||
>
|
||||
REGISTER NOW
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
38
app/components/Stats.tsx
Normal file
38
app/components/Stats.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
const stats = [
|
||||
{ value: "3", label: "Categories" },
|
||||
{ value: "∞", label: "Possibilities" },
|
||||
{ value: "1", label: "Winner Per Category" },
|
||||
{ value: "100%", label: "Free Entry" },
|
||||
];
|
||||
|
||||
export default function Stats() {
|
||||
return (
|
||||
<section className="py-16 bg-lime-400">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{stats.map((stat, index) => (
|
||||
<motion.div
|
||||
key={stat.label}
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||
className="text-center"
|
||||
>
|
||||
<div className="text-5xl sm:text-6xl font-black text-black mb-2">
|
||||
{stat.value}
|
||||
</div>
|
||||
<div className="text-black/70 font-medium tracking-wide uppercase text-sm">
|
||||
{stat.label}
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user