feat(ui): transform portal interface to enterprise dark purple sidebar navigation architecture with video playback dashboard
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
This commit is contained in:
135
src/components/Header/Header.tsx
Normal file
135
src/components/Header/Header.tsx
Normal file
@@ -0,0 +1,135 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Search, Bell, Menu, Sparkles, User, Calendar, ShieldCheck, LogIn } from 'lucide-react';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
|
||||
interface HeaderProps {
|
||||
onToggleSidebar: () => void;
|
||||
}
|
||||
|
||||
export default function Header({ onToggleSidebar }: HeaderProps) {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [currentDate, setCurrentDate] = useState('');
|
||||
const navigate = useNavigate();
|
||||
const { user, isAuthenticated, isVerifiedStudent, loginWithGoogle } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
const now = new Date();
|
||||
const formatted = now.toLocaleDateString('en-US', {
|
||||
weekday: 'short',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
});
|
||||
setCurrentDate(formatted);
|
||||
}, []);
|
||||
|
||||
const handleSearch = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!searchQuery.trim()) return;
|
||||
const q = searchQuery.toLowerCase();
|
||||
if (q.includes('note') || q.includes('pyq') || q.includes('syllabus')) {
|
||||
navigate('/notes');
|
||||
} else if (q.includes('bus') || q.includes('route')) {
|
||||
navigate('/bus-routes');
|
||||
} else if (q.includes('faculty') || q.includes('teacher') || q.includes('prof')) {
|
||||
navigate('/faculty');
|
||||
} else if (q.includes('club') || q.includes('event')) {
|
||||
navigate('/events');
|
||||
} else if (q.includes('ai') || q.includes('chat') || q.includes('bot')) {
|
||||
navigate('/ai-assistant');
|
||||
} else if (q.includes('community') || q.includes('qa') || q.includes('question')) {
|
||||
navigate('/community');
|
||||
} else if (q.includes('collab') || q.includes('dev')) {
|
||||
navigate('/collab');
|
||||
} else if (q.includes('raise') || q.includes('incubator') || q.includes('pitch')) {
|
||||
navigate('/raise');
|
||||
} else {
|
||||
navigate(`/notes?search=${encodeURIComponent(searchQuery)}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-30 w-full bg-white/80 backdrop-blur-md border-b border-slate-200/80 px-4 lg:px-8 py-3 flex items-center justify-between shadow-xs">
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Mobile Toggle */}
|
||||
<button
|
||||
onClick={onToggleSidebar}
|
||||
className="lg:hidden p-2 rounded-xl bg-slate-100 hover:bg-slate-200 text-slate-700 transition-colors cursor-pointer"
|
||||
title="Toggle Navigation Menu"
|
||||
>
|
||||
<Menu className="w-5 h-5" />
|
||||
</button>
|
||||
|
||||
{/* Global Search Bar */}
|
||||
<form onSubmit={handleSearch} className="relative w-64 sm:w-80 md:w-96">
|
||||
<Search className="absolute left-3.5 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
|
||||
<input
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder="Search notes, faculty, bus routes, clubs..."
|
||||
className="w-full pl-10 pr-12 py-2 text-xs font-medium bg-slate-100/90 hover:bg-slate-100 focus:bg-white border border-transparent focus:border-purple-500/40 rounded-xl text-slate-800 placeholder-slate-400 outline-none transition-all shadow-inner"
|
||||
style={{ fontFamily: 'Inter, sans-serif' }}
|
||||
/>
|
||||
<span className="hidden sm:inline-flex absolute right-3 top-1/2 -translate-y-1/2 text-[10px] font-semibold text-slate-400 bg-white border border-slate-200 px-1.5 py-0.5 rounded-md shadow-2xs">
|
||||
⌘K
|
||||
</span>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* Right Header Status Bar */}
|
||||
<div className="flex items-center gap-3">
|
||||
{/* Date Display Badge */}
|
||||
<div className="hidden md:flex items-center gap-1.5 px-3 py-1.5 rounded-xl bg-slate-100 text-slate-600 text-xs font-medium border border-slate-200/60">
|
||||
<Calendar className="w-3.5 h-3.5 text-purple-600" />
|
||||
<span>{currentDate}</span>
|
||||
</div>
|
||||
|
||||
{/* Notifications Icon */}
|
||||
<button
|
||||
className="relative p-2 rounded-xl bg-slate-100 hover:bg-purple-50 text-slate-600 hover:text-purple-600 transition-colors cursor-pointer border border-slate-200/60"
|
||||
title="Notifications"
|
||||
>
|
||||
<Bell className="w-4 h-4" />
|
||||
<span className="absolute top-1.5 right-1.5 w-2 h-2 rounded-full bg-purple-600 ring-2 ring-white" />
|
||||
</button>
|
||||
|
||||
{/* User Auth Quick Badge */}
|
||||
{isAuthenticated && user ? (
|
||||
<div className="flex items-center gap-2 pl-2 border-l border-slate-200">
|
||||
{user.pictureUrl ? (
|
||||
<img
|
||||
src={user.pictureUrl}
|
||||
alt={user.name}
|
||||
className="w-8 h-8 rounded-full border border-purple-300 object-cover"
|
||||
referrerPolicy="no-referrer"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-8 h-8 rounded-full bg-purple-600 text-white font-bold text-xs flex items-center justify-center">
|
||||
{user.name.charAt(0)}
|
||||
</div>
|
||||
)}
|
||||
<div className="hidden xl:flex flex-col text-left">
|
||||
<span className="text-xs font-bold text-slate-800 leading-tight" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
{user.name}
|
||||
</span>
|
||||
<span className="text-[10px] text-purple-600 font-semibold">
|
||||
{isVerifiedStudent ? 'Verified Student' : 'RIT Account'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
onClick={loginWithGoogle}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 rounded-xl bg-purple-600 hover:bg-purple-700 text-white text-xs font-bold shadow-sm transition-all cursor-pointer"
|
||||
style={{ fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
<LogIn className="w-3.5 h-3.5" />
|
||||
<span>Sign In</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
281
src/components/Sidebar/Sidebar.tsx
Normal file
281
src/components/Sidebar/Sidebar.tsx
Normal file
@@ -0,0 +1,281 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
LayoutDashboard,
|
||||
BookOpen,
|
||||
Wrench,
|
||||
Bot,
|
||||
MapPin,
|
||||
Bus,
|
||||
Users,
|
||||
Calendar,
|
||||
MessageSquare,
|
||||
Code2,
|
||||
Trophy,
|
||||
Rocket,
|
||||
ShieldAlert,
|
||||
LogOut,
|
||||
LogIn,
|
||||
ShieldCheck,
|
||||
ChevronRight,
|
||||
Sparkles,
|
||||
Menu,
|
||||
X
|
||||
} from 'lucide-react';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
|
||||
interface SidebarProps {
|
||||
isOpen: boolean;
|
||||
onToggle: () => void;
|
||||
}
|
||||
|
||||
interface NavItem {
|
||||
label: string;
|
||||
path: string;
|
||||
icon: any;
|
||||
badge?: string;
|
||||
highlight?: boolean;
|
||||
}
|
||||
|
||||
interface NavGroup {
|
||||
title: string;
|
||||
items: NavItem[];
|
||||
}
|
||||
|
||||
export default function Sidebar({ isOpen, onToggle }: SidebarProps) {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const { user, isAuthenticated, isVerifiedStudent, loginWithGoogle, logout } = useAuth();
|
||||
|
||||
const checkIsActive = (linkPath: string) => {
|
||||
const [pathName, searchString] = linkPath.split('?');
|
||||
if (location.pathname !== pathName) return false;
|
||||
|
||||
if (pathName === '/notes') {
|
||||
const params = new URLSearchParams(location.search);
|
||||
const hasToolkit = params.has('toolkit') || params.get('section') === 'toolkit';
|
||||
if (searchString) {
|
||||
return hasToolkit;
|
||||
} else {
|
||||
return !hasToolkit;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const navGroups: NavGroup[] = [
|
||||
{
|
||||
title: 'ACADEMICS & PORTAL',
|
||||
items: [
|
||||
{ label: 'Dashboard', path: '/', icon: LayoutDashboard },
|
||||
{ label: 'Notes & PYQs', path: '/notes', icon: BookOpen },
|
||||
{ label: 'Student Toolkit', path: '/notes?section=toolkit', icon: Wrench },
|
||||
{ label: 'RIT AI Chatbot', path: '/ai-assistant', icon: Bot, badge: 'AI' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'CAMPUS & UTILITIES',
|
||||
items: [
|
||||
{ label: 'Bus Tracker', path: '/bus-routes', icon: Bus },
|
||||
{ label: 'Campus Map', path: '/campus', icon: MapPin },
|
||||
{ label: 'Faculty Directory', path: '/faculty', icon: Users },
|
||||
{ label: 'Student Clubs', path: '/events', icon: Calendar },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'COMMUNITY & DEV',
|
||||
items: [
|
||||
{ label: 'Freshers Q&A', path: '/community', icon: MessageSquare },
|
||||
{ label: 'Dev Collab Hub', path: '/collab', icon: Code2 },
|
||||
{ label: 'LeetCode Board', path: '/leetcode', icon: Trophy },
|
||||
{ label: 'RAISE Incubator', path: '/raise', icon: Rocket, highlight: true },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Mobile Backdrop Overlay */}
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
onClick={onToggle}
|
||||
className="fixed inset-0 bg-black/60 backdrop-blur-xs z-40 lg:hidden"
|
||||
/>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Main Sidebar Container */}
|
||||
<aside
|
||||
className={`fixed top-0 left-0 z-50 h-screen w-64 xl:w-72 bg-gradient-to-b from-[#1E1B4B] via-[#2E1065] to-[#3B0764] text-white transition-transform duration-300 ease-in-out lg:translate-x-0 ${
|
||||
isOpen ? 'translate-x-0' : '-translate-x-full'
|
||||
} flex flex-col justify-between border-r border-white/10 shadow-[8px_0_32px_rgba(0,0,0,0.3)]`}
|
||||
>
|
||||
{/* Top Header & Branding */}
|
||||
<div className="p-6 flex flex-col gap-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<Link to="/" className="flex items-center gap-3 group">
|
||||
<div className="relative p-2 rounded-2xl bg-gradient-to-br from-purple-500/30 to-indigo-500/20 border border-white/20 shadow-lg group-hover:scale-105 transition-transform">
|
||||
<img
|
||||
src="/logo.png"
|
||||
alt="RIT Logo"
|
||||
className="w-8 h-8 object-contain rounded-full"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="font-extrabold text-white text-xl tracking-tight" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
RIT Portal
|
||||
</span>
|
||||
<span className="text-[10px] font-bold px-1.5 py-0.5 rounded-full bg-purple-500/30 text-purple-200 border border-purple-400/30">
|
||||
v2.0
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-[10px] font-medium text-purple-200/70 tracking-wider uppercase" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
Rajalakshmi Tech
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
<button
|
||||
onClick={onToggle}
|
||||
className="lg:hidden p-2 rounded-xl bg-white/10 hover:bg-white/20 text-purple-200 transition-colors"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Quick Pitch CTA inside Sidebar */}
|
||||
<Link
|
||||
to="/raise"
|
||||
className="w-full flex items-center justify-between p-3.5 rounded-2xl bg-gradient-to-r from-purple-600 via-indigo-600 to-purple-700 hover:from-purple-500 hover:to-indigo-500 border border-purple-400/30 shadow-md shadow-purple-900/40 text-white group transition-all duration-200"
|
||||
>
|
||||
<div className="flex items-center gap-2.5">
|
||||
<div className="w-7 h-7 rounded-xl bg-amber-400/20 border border-amber-300/40 flex items-center justify-center text-amber-300">
|
||||
<Sparkles className="w-4 h-4" />
|
||||
</div>
|
||||
<div className="flex flex-col text-left">
|
||||
<span className="text-xs font-bold leading-tight" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
RAISE Incubator
|
||||
</span>
|
||||
<span className="text-[10px] text-purple-200/80">Pitch Startup Idea</span>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRight className="w-4 h-4 text-purple-200 group-hover:translate-x-1 transition-transform" />
|
||||
</Link>
|
||||
|
||||
{/* Navigation Groups */}
|
||||
<nav className="flex flex-col gap-6 overflow-y-auto max-h-[calc(100vh-340px)] custom-scrollbar pr-1">
|
||||
{navGroups.map((group) => (
|
||||
<div key={group.title} className="flex flex-col gap-1">
|
||||
<span
|
||||
className="px-3 text-[10px] font-bold text-purple-300/60 tracking-widest uppercase mb-1"
|
||||
style={{ fontFamily: 'Inter, sans-serif' }}
|
||||
>
|
||||
{group.title}
|
||||
</span>
|
||||
|
||||
{group.items.map((item) => {
|
||||
const isActive = checkIsActive(item.path);
|
||||
const Icon = item.icon;
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
className={`relative flex items-center justify-between px-3.5 py-2.5 rounded-xl text-xs font-semibold transition-all duration-200 group ${
|
||||
isActive
|
||||
? 'bg-gradient-to-r from-purple-600/90 via-purple-700/80 to-indigo-800/90 text-white shadow-lg shadow-purple-950/50 border border-purple-400/30'
|
||||
: 'text-purple-200/80 hover:text-white hover:bg-white/10'
|
||||
}`}
|
||||
style={{ fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<Icon
|
||||
className={`w-4 h-4 transition-colors ${
|
||||
isActive
|
||||
? 'text-white'
|
||||
: 'text-purple-300/70 group-hover:text-purple-200'
|
||||
}`}
|
||||
/>
|
||||
<span>{item.label}</span>
|
||||
</div>
|
||||
|
||||
{item.badge && (
|
||||
<span className="text-[9px] font-bold px-1.5 py-0.5 rounded-md bg-amber-500/20 text-amber-300 border border-amber-400/30">
|
||||
{item.badge}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{item.highlight && !isActive && (
|
||||
<span className="w-2 h-2 rounded-full bg-rose-400 animate-pulse" />
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{/* Footer User Profile & Auth Section */}
|
||||
<div className="p-4 border-t border-white/10 bg-black/20 backdrop-blur-md">
|
||||
{isAuthenticated && user ? (
|
||||
<div className="flex items-center justify-between p-2.5 rounded-2xl bg-white/5 border border-white/10">
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
{user.pictureUrl ? (
|
||||
<img
|
||||
src={user.pictureUrl}
|
||||
alt={user.name}
|
||||
className="w-9 h-9 rounded-xl border border-purple-400/40 object-cover shrink-0"
|
||||
referrerPolicy="no-referrer"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-9 h-9 rounded-xl bg-gradient-to-br from-purple-500 to-indigo-600 flex items-center justify-center text-white font-bold text-sm shrink-0">
|
||||
{user.name.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col min-w-0">
|
||||
<span className="text-xs font-bold text-white truncate" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
{user.name}
|
||||
</span>
|
||||
<div className="flex items-center gap-1 text-[10px] text-purple-200/70 truncate">
|
||||
{isVerifiedStudent ? (
|
||||
<span className="text-emerald-400 font-semibold flex items-center gap-0.5">
|
||||
<ShieldCheck className="w-3 h-3" /> Verified Student
|
||||
</span>
|
||||
) : (
|
||||
<span>RIT Account</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={logout}
|
||||
title="Sign Out"
|
||||
className="p-2 rounded-xl hover:bg-white/10 text-purple-300 hover:text-white transition-colors cursor-pointer"
|
||||
>
|
||||
<LogOut className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
onClick={loginWithGoogle}
|
||||
className="w-full flex items-center justify-center gap-2 p-3 rounded-2xl bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-500 hover:to-indigo-500 text-white font-bold text-xs shadow-md border border-purple-400/30 transition-all cursor-pointer"
|
||||
style={{ fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
<LogIn className="w-4 h-4" />
|
||||
<span>Student Sign In</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</aside>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Outlet, useSearchParams, useLocation } from 'react-router-dom';
|
||||
import { useState } from 'react';
|
||||
import { Outlet, useLocation } from 'react-router-dom';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import Navbar from '@/components/Navbar/Navbar';
|
||||
import Sidebar from '@/components/Sidebar/Sidebar';
|
||||
import Header from '@/components/Header/Header';
|
||||
import Footer from '@/components/Footer/Footer';
|
||||
|
||||
const pageVariants = {
|
||||
@@ -10,26 +12,41 @@ const pageVariants = {
|
||||
};
|
||||
|
||||
export default function MainLayout() {
|
||||
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
||||
const location = useLocation();
|
||||
const [searchParams] = useSearchParams();
|
||||
const hideFooter = location.pathname === '/notes' && searchParams.has('toolkit');
|
||||
|
||||
const toggleSidebar = () => setIsSidebarOpen((prev) => !prev);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen" style={{ backgroundColor: '#FAFAFA' }}>
|
||||
<Navbar />
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.main
|
||||
key={location.pathname}
|
||||
variants={pageVariants}
|
||||
initial="initial"
|
||||
animate="enter"
|
||||
exit="exit"
|
||||
transition={{ duration: 0.3, ease: 'easeInOut' }}
|
||||
>
|
||||
<Outlet />
|
||||
</motion.main>
|
||||
</AnimatePresence>
|
||||
{!hideFooter && <Footer />}
|
||||
<div className="min-h-screen bg-[#F8FAFC] flex flex-col lg:flex-row font-sans selection:bg-purple-600 selection:text-white">
|
||||
{/* Left Sidebar Navigation */}
|
||||
<Sidebar isOpen={isSidebarOpen} onToggle={toggleSidebar} />
|
||||
|
||||
{/* Main Right Viewport Wrapper */}
|
||||
<div className="flex-1 flex flex-col min-w-0 lg:pl-64 xl:pl-72 transition-all duration-300">
|
||||
{/* Top Header */}
|
||||
<Header onToggleSidebar={toggleSidebar} />
|
||||
|
||||
{/* Dynamic Page Content */}
|
||||
<div className="flex-1 p-4 sm:p-6 lg:p-8">
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.main
|
||||
key={location.pathname}
|
||||
variants={pageVariants}
|
||||
initial="initial"
|
||||
animate="enter"
|
||||
exit="exit"
|
||||
transition={{ duration: 0.25, ease: 'easeInOut' }}
|
||||
className="max-w-7xl mx-auto"
|
||||
>
|
||||
<Outlet />
|
||||
</motion.main>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
{/* Global Footer */}
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,248 +1,400 @@
|
||||
import { motion, useScroll, useTransform } from 'framer-motion';
|
||||
import { useState, useRef } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { motion } from 'framer-motion';
|
||||
import {
|
||||
ArrowRight, BookOpen, Bot, GraduationCap,
|
||||
CheckCircle, Zap, Shield, Trophy, Award, Cpu, Users, MapPin, Sparkles
|
||||
BookOpen,
|
||||
Bot,
|
||||
Bus,
|
||||
Users,
|
||||
Trophy,
|
||||
Rocket,
|
||||
Code2,
|
||||
MapPin,
|
||||
Sparkles,
|
||||
ArrowRight,
|
||||
Play,
|
||||
Pause,
|
||||
Volume2,
|
||||
VolumeX,
|
||||
FileText,
|
||||
Clock,
|
||||
ShieldCheck,
|
||||
CheckCircle2,
|
||||
ExternalLink,
|
||||
ChevronRight,
|
||||
Bell,
|
||||
GraduationCap
|
||||
} from 'lucide-react';
|
||||
import SectionTitle from '@/components/SectionTitle/SectionTitle';
|
||||
import FeatureCard from '@/components/FeatureCard/FeatureCard';
|
||||
import { StaggerContainer, StaggerItem } from '@/components/AnimatedContainer/AnimatedContainer';
|
||||
import AnimatedContainer from '@/components/AnimatedContainer/AnimatedContainer';
|
||||
import { FEATURES, CAMPUS_LOCATIONS } from '@/constants';
|
||||
import * as LucideIcons from 'lucide-react';
|
||||
|
||||
import LazyVideoHero from '@/components/LazyVideoHero/LazyVideoHero';
|
||||
import { FEATURES, FACULTY_DATA, BUS_ROUTES } from '@/constants';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
|
||||
export default function Home() {
|
||||
const { scrollY } = useScroll();
|
||||
const heroOpacity = useTransform(scrollY, [0, 450], [1, 0]);
|
||||
const heroY = useTransform(scrollY, [0, 450], [0, -60]);
|
||||
const { user, isAuthenticated } = useAuth();
|
||||
const [isPlaying, setIsPlaying] = useState(true);
|
||||
const [isMuted, setIsMuted] = useState(true);
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
|
||||
const togglePlay = () => {
|
||||
if (videoRef.current) {
|
||||
if (isPlaying) {
|
||||
videoRef.current.pause();
|
||||
} else {
|
||||
videoRef.current.play();
|
||||
}
|
||||
setIsPlaying(!isPlaying);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleMute = () => {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.muted = !isMuted;
|
||||
setIsMuted(!isMuted);
|
||||
}
|
||||
};
|
||||
|
||||
const dailyNotices = [
|
||||
{
|
||||
id: '1',
|
||||
title: 'Official Moodle Notes & PYQs Updated',
|
||||
date: 'Aug 12, 2026',
|
||||
category: 'Academics',
|
||||
desc: '1st to 8th semester course notes and previous year question papers are live on Moodle portal.',
|
||||
color: '#8B5CF6',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'RAISE Incubator Pitching Registration Open',
|
||||
date: 'Aug 15, 2026',
|
||||
category: 'Innovation',
|
||||
desc: 'Submit your startup ideation proposals to win prototyping grants up to ₹2 Lakhs.',
|
||||
color: '#EC4899',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'RIT Code Fest 24-Hour Hackathon',
|
||||
date: 'Aug 20, 2026',
|
||||
category: 'Events',
|
||||
desc: 'Annual coding hackathon hosted by CSE Department. Cash prizes & internship opportunities.',
|
||||
color: '#F97316',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="relative bg-[#FAFAFA] min-h-screen overflow-hidden">
|
||||
{/* ─── Hero Section with IntersectionObserver Lazy Video ─────────────────── */}
|
||||
<LazyVideoHero>
|
||||
<section className="relative pt-20 pb-24 z-10">
|
||||
<motion.div
|
||||
className="container-custom relative z-20 flex flex-col items-center text-center px-4"
|
||||
style={{ opacity: heroOpacity, y: heroY }}
|
||||
>
|
||||
{/* Heading */}
|
||||
<motion.h1
|
||||
initial={{ opacity: 0, y: 15 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.1 }}
|
||||
className="text-3xl md:text-5xl font-medium tracking-wide mb-2"
|
||||
style={{ color: '#FFFFFF', fontFamily: 'Playfair Display, serif', textShadow: '0 2px 14px rgba(0,0,0,0.95)' }}
|
||||
>
|
||||
Welcome to
|
||||
</motion.h1>
|
||||
<div className="space-y-8">
|
||||
{/* ─── 1. Welcome Hero Banner with Video Playback ─────────────────── */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 16 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="relative overflow-hidden rounded-3xl bg-gradient-to-r from-[#1E1B4B] via-[#2E1065] to-[#3B0764] p-6 sm:p-8 lg:p-10 text-white shadow-xl shadow-purple-950/20 border border-purple-500/20"
|
||||
>
|
||||
{/* Subtle Decorative Background Glows */}
|
||||
<div className="absolute -right-20 -top-20 w-96 h-96 bg-purple-500/20 rounded-full blur-3xl pointer-events-none" />
|
||||
<div className="absolute -left-20 -bottom-20 w-96 h-96 bg-indigo-500/20 rounded-full blur-3xl pointer-events-none" />
|
||||
|
||||
<motion.h2
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.7, delay: 0.2 }}
|
||||
className="text-5xl md:text-7xl font-black leading-tight mb-6"
|
||||
style={{ color: '#FFFFFF', fontFamily: 'Playfair Display, serif', textShadow: '0 4px 24px rgba(0,0,0,0.95)' }}
|
||||
>
|
||||
RIT Freshers Hub
|
||||
</motion.h2>
|
||||
<div className="relative z-10 grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
|
||||
{/* Left Text & CTAs */}
|
||||
<div className="lg:col-span-7 space-y-5 text-left">
|
||||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/10 border border-white/20 text-xs font-semibold text-purple-200">
|
||||
<Clock className="w-3.5 h-3.5 text-purple-300" />
|
||||
<span>{new Date().toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })}</span>
|
||||
</div>
|
||||
|
||||
<motion.p
|
||||
initial={{ opacity: 0, y: 15 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.7, delay: 0.3 }}
|
||||
className="max-w-2xl text-slate-100 text-base md:text-lg font-medium leading-relaxed mb-8 drop-shadow-md"
|
||||
style={{ fontFamily: 'Inter, sans-serif' }}
|
||||
>
|
||||
Your centralized gateway to campus life at Rajalakshmi Institute of Technology — academic notes, AI assistant, bus routes, faculty directory, and campus navigation.
|
||||
</motion.p>
|
||||
<h1 className="text-3xl sm:text-4xl xl:text-5xl font-extrabold tracking-tight leading-tight" style={{ fontFamily: 'Playfair Display, serif' }}>
|
||||
Welcome back,{' '}
|
||||
<span className="bg-gradient-to-r from-purple-200 via-pink-200 to-amber-200 bg-clip-text text-transparent">
|
||||
{isAuthenticated && user ? user.name.split(' ')[0] : 'Student'}!
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
{/* Call to Actions */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 15 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.7, delay: 0.4 }}
|
||||
className="flex flex-wrap justify-center gap-4"
|
||||
>
|
||||
<a href="#built-for-freshers">
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.04, boxShadow: '0 10px 30px -5px rgba(249,115,22,0.4)' }}
|
||||
whileTap={{ scale: 0.96 }}
|
||||
className="flex items-center gap-2 px-8 py-3.5 rounded-xl text-white font-semibold text-sm cursor-pointer shadow-md"
|
||||
style={{
|
||||
fontFamily: 'Poppins, sans-serif',
|
||||
background: 'linear-gradient(135deg, #F97316, #FB923C)',
|
||||
}}
|
||||
>
|
||||
<BookOpen className="w-4 h-4" />
|
||||
Explore Hub
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</motion.button>
|
||||
</a>
|
||||
<p className="text-sm sm:text-base text-purple-200/90 leading-relaxed max-w-xl" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
Always stay updated with semester notes, live bus routes, AI chatbot assistant, community Q&A, and startup incubation pitching.
|
||||
</p>
|
||||
|
||||
<Link to="/ai-assistant">
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.04, borderColor: '#F97316', backgroundColor: 'rgba(255,255,255,0.2)' }}
|
||||
whileTap={{ scale: 0.96 }}
|
||||
className="flex items-center gap-2 px-8 py-3.5 rounded-xl font-semibold text-sm border-2 border-white/40 text-white bg-black/30 backdrop-blur-md transition-all cursor-pointer shadow-2xs"
|
||||
{/* Quick Action CTAs */}
|
||||
<div className="pt-2 flex flex-wrap items-center gap-3">
|
||||
<Link
|
||||
to="/notes"
|
||||
className="inline-flex items-center gap-2 px-5 py-2.5 rounded-xl bg-white hover:bg-purple-50 text-purple-950 font-bold text-xs shadow-lg transition-all cursor-pointer hover:scale-[1.02]"
|
||||
style={{ fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
<Bot className="w-4 h-4 text-[#F97316]" />
|
||||
Ask Assistant
|
||||
</motion.button>
|
||||
</Link>
|
||||
<BookOpen className="w-4 h-4 text-purple-700" />
|
||||
<span>Launch Moodle Notes</span>
|
||||
<ArrowRight className="w-3.5 h-3.5" />
|
||||
</Link>
|
||||
|
||||
<Link to="/raise">
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.04, boxShadow: '0 10px 30px -5px rgba(233,30,99,0.5)' }}
|
||||
whileTap={{ scale: 0.96 }}
|
||||
className="flex items-center gap-2 px-8 py-3.5 rounded-xl font-bold text-sm text-white bg-gradient-to-r from-rose-500 to-pink-600 border border-white/30 backdrop-blur-md transition-all cursor-pointer shadow-lg shadow-pink-500/20"
|
||||
<Link
|
||||
to="/ai-assistant"
|
||||
className="inline-flex items-center gap-2 px-5 py-2.5 rounded-xl bg-white/10 hover:bg-white/20 border border-white/20 text-white font-semibold text-xs transition-all cursor-pointer"
|
||||
style={{ fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
<Sparkles className="w-4 h-4 text-amber-200" />
|
||||
Pitch your Idea - RAISE
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</motion.button>
|
||||
</Link>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</section>
|
||||
</LazyVideoHero>
|
||||
<Bot className="w-4 h-4 text-amber-300" />
|
||||
<span>Ask AI Chatbot</span>
|
||||
</Link>
|
||||
|
||||
{/* Sleek Stats Card Section */}
|
||||
<section className="relative z-30 -mt-6 px-4">
|
||||
<div className="container-custom max-w-5xl">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, delay: 0.6 }}
|
||||
className="rounded-3xl border border-[#E5E7EB] p-6 md:p-8 bg-white shadow-[0_20px_50px_-15px_rgba(0,0,0,0.06)]"
|
||||
>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-6 text-center">
|
||||
{[
|
||||
{ value: '20+', label: 'SPORTS', icon: Trophy },
|
||||
{ value: '100+', label: 'FACULTY', icon: GraduationCap },
|
||||
{ value: '18', label: 'CLUBS', icon: Award },
|
||||
{ value: '24/7', label: 'ASSISTANT', icon: Cpu },
|
||||
{ value: '5000+', label: 'STUDENTS', icon: Users },
|
||||
].map((stat, i) => (
|
||||
<div key={i} className="flex flex-col items-center justify-center p-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-[#FFF7ED] flex items-center justify-center mb-2.5">
|
||||
<stat.icon className="w-5 h-5 text-[#F97316]" />
|
||||
<Link
|
||||
to="/raise"
|
||||
className="inline-flex items-center gap-2 px-4 py-2.5 rounded-xl bg-gradient-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white font-bold text-xs shadow-md border border-white/20 transition-all cursor-pointer"
|
||||
style={{ fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
<Rocket className="w-4 h-4 text-amber-200" />
|
||||
<span>RAISE Incubator</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Video Playback & Preview Showcase */}
|
||||
<div className="lg:col-span-5 relative">
|
||||
<div className="relative rounded-2xl overflow-hidden border border-white/20 shadow-2xl bg-black/40 group">
|
||||
<video
|
||||
ref={videoRef}
|
||||
src="/campus-video.mp4"
|
||||
autoPlay
|
||||
loop
|
||||
muted={isMuted}
|
||||
playsInline
|
||||
className="w-full h-48 sm:h-56 lg:h-64 object-cover"
|
||||
/>
|
||||
|
||||
{/* Video Overlay Controls */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-black/20 opacity-90 group-hover:opacity-100 transition-opacity p-4 flex flex-col justify-between">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-[10px] font-bold uppercase tracking-wider px-2 py-0.5 rounded-md bg-purple-600/80 text-white border border-purple-400/40">
|
||||
Campus Tour Video
|
||||
</span>
|
||||
<button
|
||||
onClick={toggleMute}
|
||||
className="p-1.5 rounded-lg bg-black/50 hover:bg-black/80 text-white transition-colors cursor-pointer"
|
||||
title={isMuted ? 'Unmute Sound' : 'Mute Sound'}
|
||||
>
|
||||
{isMuted ? <VolumeX className="w-4 h-4" /> : <Volume2 className="w-4 h-4" />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xs font-bold text-white" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
RIT Campus Infrastructure
|
||||
</span>
|
||||
<span className="text-[10px] text-slate-300">Official Rajalakshmi Institute of Technology Overview</span>
|
||||
</div>
|
||||
<div
|
||||
className="text-2xl md:text-3xl font-black text-[#1E293B] mb-0.5"
|
||||
|
||||
<button
|
||||
onClick={togglePlay}
|
||||
className="p-2.5 rounded-full bg-white/90 hover:bg-white text-purple-900 shadow-lg transition-transform hover:scale-110 cursor-pointer"
|
||||
>
|
||||
{isPlaying ? <Pause className="w-4 h-4" /> : <Play className="w-4 h-4 fill-current ml-0.5" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* ─── 2. Enterprise Quick Metrics Grid ────────────────────────────── */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5">
|
||||
<div className="p-5 rounded-2xl bg-white border border-slate-200/80 shadow-xs flex items-center justify-between hover:border-purple-300 transition-all">
|
||||
<div className="space-y-1 text-left">
|
||||
<span className="text-xs font-semibold text-slate-500 uppercase tracking-wider" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
Academic Notes
|
||||
</span>
|
||||
<div className="text-2xl font-extrabold text-slate-900" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
1st – 8th Sem
|
||||
</div>
|
||||
<span className="text-[11px] text-emerald-600 font-semibold flex items-center gap-1">
|
||||
<CheckCircle2 className="w-3.5 h-3.5" /> Moodle Verified
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-12 h-12 rounded-2xl bg-purple-50 text-purple-600 border border-purple-200/60 flex items-center justify-center font-bold">
|
||||
<BookOpen className="w-6 h-6" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-5 rounded-2xl bg-white border border-slate-200/80 shadow-xs flex items-center justify-between hover:border-purple-300 transition-all">
|
||||
<div className="space-y-1 text-left">
|
||||
<span className="text-xs font-semibold text-slate-500 uppercase tracking-wider" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
Bus Routes
|
||||
</span>
|
||||
<div className="text-2xl font-extrabold text-slate-900" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
{BUS_ROUTES.length} Active Routes
|
||||
</div>
|
||||
<span className="text-[11px] text-blue-600 font-semibold flex items-center gap-1">
|
||||
<Clock className="w-3.5 h-3.5" /> 7:00 AM Departures
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-12 h-12 rounded-2xl bg-blue-50 text-blue-600 border border-blue-200/60 flex items-center justify-center font-bold">
|
||||
<Bus className="w-6 h-6" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-5 rounded-2xl bg-white border border-slate-200/80 shadow-xs flex items-center justify-between hover:border-purple-300 transition-all">
|
||||
<div className="space-y-1 text-left">
|
||||
<span className="text-xs font-semibold text-slate-500 uppercase tracking-wider" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
AI Assistant
|
||||
</span>
|
||||
<div className="text-2xl font-extrabold text-slate-900" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
24/7 Live
|
||||
</div>
|
||||
<span className="text-[11px] text-purple-600 font-semibold flex items-center gap-1">
|
||||
<Sparkles className="w-3.5 h-3.5" /> Instant Answers
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-12 h-12 rounded-2xl bg-purple-50 text-purple-600 border border-purple-200/60 flex items-center justify-center font-bold">
|
||||
<Bot className="w-6 h-6" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-5 rounded-2xl bg-white border border-slate-200/80 shadow-xs flex items-center justify-between hover:border-purple-300 transition-all">
|
||||
<div className="space-y-1 text-left">
|
||||
<span className="text-xs font-semibold text-slate-500 uppercase tracking-wider" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
Community Q&A
|
||||
</span>
|
||||
<div className="text-2xl font-extrabold text-slate-900" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
Senior Helpers
|
||||
</div>
|
||||
<span className="text-[11px] text-rose-600 font-semibold flex items-center gap-1">
|
||||
<ShieldCheck className="w-3.5 h-3.5" /> Verified Answers
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-12 h-12 rounded-2xl bg-rose-50 text-rose-600 border border-rose-200/60 flex items-center justify-center font-bold">
|
||||
<Users className="w-6 h-6" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ─── 3. Main Dashboard Layout (Two Columns: Courses Grid + Right Widgets) ────── */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 text-left">
|
||||
{/* Left 8 Cols: Enrolled Modules / Quick Access */}
|
||||
<div className="lg:col-span-8 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-1">
|
||||
<h2 className="text-xl font-bold text-slate-900" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
Academic Modules & Tools
|
||||
</h2>
|
||||
<p className="text-xs text-slate-500">Quick access to all essential student portal tools</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
||||
{FEATURES.map((feature) => {
|
||||
return (
|
||||
<div
|
||||
key={feature.id}
|
||||
className="p-5 rounded-2xl bg-white border border-slate-200/80 hover:border-purple-400/60 shadow-xs hover:shadow-md transition-all flex flex-col justify-between gap-4 group"
|
||||
>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<div
|
||||
className="w-10 h-10 rounded-xl flex items-center justify-center font-bold"
|
||||
style={{ backgroundColor: feature.bgColor, color: feature.color }}
|
||||
>
|
||||
<BookOpen className="w-5 h-5" />
|
||||
</div>
|
||||
<span className="text-[10px] font-bold px-2 py-0.5 rounded-full bg-slate-100 text-slate-600">
|
||||
Official Module
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 className="text-base font-bold text-slate-900 group-hover:text-purple-700 transition-colors" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
{feature.title}
|
||||
</h3>
|
||||
|
||||
<p className="text-xs text-slate-600 leading-relaxed line-clamp-2" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Link
|
||||
to={feature.path}
|
||||
className="w-full inline-flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl bg-slate-100 group-hover:bg-purple-600 text-slate-700 group-hover:text-white text-xs font-bold transition-all cursor-pointer"
|
||||
style={{ fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
{stat.value}
|
||||
<span>Launch Module</span>
|
||||
<ChevronRight className="w-3.5 h-3.5 group-hover:translate-x-1 transition-transform" />
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right 4 Cols: Faculty Spotlight & Daily Notices Widget */}
|
||||
<div className="lg:col-span-4 space-y-6">
|
||||
{/* Featured Instructors / Faculty */}
|
||||
<div className="p-6 rounded-2xl bg-white border border-slate-200/80 shadow-xs space-y-4">
|
||||
<div className="flex items-center justify-between pb-3 border-b border-slate-100">
|
||||
<h3 className="text-sm font-bold text-slate-900" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
Course Instructors
|
||||
</h3>
|
||||
<Link to="/faculty" className="text-xs font-bold text-purple-600 hover:text-purple-700">
|
||||
See all
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{FACULTY_DATA.slice(0, 4).map((prof) => (
|
||||
<div key={prof.id} className="flex items-center gap-3 p-2.5 rounded-xl hover:bg-slate-50 transition-colors">
|
||||
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-purple-500 to-indigo-600 text-white font-bold text-xs flex items-center justify-center shrink-0">
|
||||
{prof.name.replace('Dr. ', '').replace('Prof. ', '').charAt(0)}
|
||||
</div>
|
||||
<div
|
||||
className="text-[11px] font-bold tracking-wider text-[#94A3B8] uppercase"
|
||||
style={{ fontFamily: 'Inter, sans-serif' }}
|
||||
<div className="flex-1 min-w-0">
|
||||
<h4 className="text-xs font-bold text-slate-900 truncate" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
{prof.name}
|
||||
</h4>
|
||||
<span className="text-[11px] text-slate-500 block truncate">{prof.department}</span>
|
||||
</div>
|
||||
<Link
|
||||
to="/faculty"
|
||||
className="p-1.5 rounded-lg bg-slate-100 text-slate-600 hover:bg-purple-100 hover:text-purple-700 transition-colors"
|
||||
>
|
||||
{stat.label}
|
||||
</div>
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
</Link>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{/* ─── Features Section ─────────────────────────────────────────────────── */}
|
||||
<section id="built-for-freshers" className="section-padding relative z-20">
|
||||
<div className="container-custom">
|
||||
<SectionTitle
|
||||
tag="Everything You Need"
|
||||
title="Built for"
|
||||
highlight="RIT Freshers"
|
||||
subtitle="From notes to AI assistance — we've got everything you need to navigate campus life with confidence."
|
||||
/>
|
||||
|
||||
<StaggerContainer className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{FEATURES.map((feature) => (
|
||||
<StaggerItem key={feature.id}>
|
||||
<FeatureCard feature={feature} />
|
||||
</StaggerItem>
|
||||
))}
|
||||
</StaggerContainer>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ─── Campus Quick Nav ─────────────────────────────────────────────────── */}
|
||||
<section className="section-padding relative z-20 bg-white border-y border-[#E5E7EB]">
|
||||
<div className="container-custom">
|
||||
<SectionTitle
|
||||
tag="Navigate Campus"
|
||||
title="Explore"
|
||||
highlight="RIT Campus"
|
||||
subtitle="Find your way around campus — departments, labs, library, and key locations."
|
||||
/>
|
||||
|
||||
<AnimatedContainer>
|
||||
<div className="bg-white rounded-3xl border border-[#E5E7EB] overflow-hidden shadow-sm">
|
||||
{/* Map Teaser Header */}
|
||||
<div
|
||||
className="h-52 flex items-center justify-center relative overflow-hidden"
|
||||
style={{ background: 'linear-gradient(135deg, #1E293B, #0F172A)' }}
|
||||
>
|
||||
<div
|
||||
className="absolute inset-0 opacity-15"
|
||||
style={{
|
||||
backgroundImage: 'linear-gradient(rgba(249,115,22,0.4) 1px, transparent 1px), linear-gradient(90deg, rgba(249,115,22,0.4) 1px, transparent 1px)',
|
||||
backgroundSize: '28px 28px',
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="relative z-10 text-center px-4">
|
||||
<div className="w-12 h-12 rounded-2xl bg-[#F97316]/20 border border-[#F97316]/30 flex items-center justify-center mx-auto mb-3">
|
||||
<MapPin className="w-6 h-6 text-[#F97316]" />
|
||||
</div>
|
||||
<h3 className="text-white text-lg font-bold mb-1" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
Interactive Campus Map
|
||||
</h3>
|
||||
<p className="text-slate-400 text-xs mb-3" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
Locate all major campus blocks, labs, library & amenities.
|
||||
</p>
|
||||
<Link to="/campus">
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className="px-5 py-2 rounded-xl text-white text-xs font-semibold shadow-sm cursor-pointer"
|
||||
style={{ background: 'linear-gradient(135deg, #F97316, #FB923C)', fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
Open Full Map
|
||||
</motion.button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Nav Grid */}
|
||||
<div className="p-5 grid grid-cols-3 sm:grid-cols-7 gap-3 bg-[#FAFAFA]">
|
||||
{CAMPUS_LOCATIONS.map((loc) => {
|
||||
const Icon = (LucideIcons as unknown as Record<string, React.ComponentType<{ className?: string }>>)[loc.icon];
|
||||
return (
|
||||
<Link to="/campus" key={loc.id}>
|
||||
<motion.div
|
||||
whileHover={{ y: -3, backgroundColor: '#FFF7ED' }}
|
||||
className="flex flex-col items-center gap-2 p-3 rounded-xl cursor-pointer transition-all border border-transparent hover:border-[#FED7AA] bg-white shadow-2xs"
|
||||
>
|
||||
<div className="w-9 h-9 rounded-xl bg-[#FFF7ED] flex items-center justify-center">
|
||||
{Icon && <Icon className="w-4.5 h-4.5 text-[#F97316]" />}
|
||||
</div>
|
||||
<span className="text-[11px] text-[#475569] text-center font-medium leading-tight" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
{loc.name}
|
||||
</span>
|
||||
</motion.div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
{/* Daily Notices & Announcements */}
|
||||
<div className="p-6 rounded-2xl bg-white border border-slate-200/80 shadow-xs space-y-4">
|
||||
<div className="flex items-center justify-between pb-3 border-b border-slate-100">
|
||||
<div className="flex items-center gap-2">
|
||||
<Bell className="w-4 h-4 text-purple-600" />
|
||||
<h3 className="text-sm font-bold text-slate-900" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
Daily Campus Notices
|
||||
</h3>
|
||||
</div>
|
||||
<span className="text-[10px] font-bold text-emerald-600 bg-emerald-50 border border-emerald-200/60 px-2 py-0.5 rounded-full">
|
||||
Live Feed
|
||||
</span>
|
||||
</div>
|
||||
</AnimatedContainer>
|
||||
|
||||
<div className="space-y-4">
|
||||
{dailyNotices.map((notice) => (
|
||||
<div key={notice.id} className="p-3.5 rounded-xl bg-slate-50/80 border border-slate-200/60 space-y-2 text-left">
|
||||
<div className="flex items-center justify-between">
|
||||
<span
|
||||
className="text-[10px] font-bold px-2 py-0.5 rounded-md text-white"
|
||||
style={{ backgroundColor: notice.color }}
|
||||
>
|
||||
{notice.category}
|
||||
</span>
|
||||
<span className="text-[10px] text-slate-400 font-medium">{notice.date}</span>
|
||||
</div>
|
||||
|
||||
<h4 className="text-xs font-bold text-slate-900 leading-snug" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
{notice.title}
|
||||
</h4>
|
||||
|
||||
<p className="text-[11px] text-slate-600 leading-relaxed" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
{notice.desc}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user