diff --git a/src/components/CatalogueContent.tsx b/src/components/CatalogueContent.tsx index 42a42cbe..2b26c66e 100644 --- a/src/components/CatalogueContent.tsx +++ b/src/components/CatalogueContent.tsx @@ -19,8 +19,6 @@ import { FilterProvider, useFilters } from "@/context/filterContext"; import EmptyState from "./ui/EmptyState"; import SidebarButton from "./SidebarButton"; import SortComponent from "./ui/sorting"; -import Announcement from "./ui/announcement/Announcement"; -import { getSubjectEvent, EVENTS, type EventData } from "@/config/events"; const CatalogueContentInner = ({ subject }: { subject: string | null }) => { const [isMounted, setIsMounted] = useState(false); @@ -237,60 +235,11 @@ const CatalogueContentInner = ({ subject }: { subject: string | null }) => { setAppliedFilters, ]); - const [activeEvent, setActiveEvent] = useState(null); - const [isGridEventsDismissed, setIsGridEventsDismissed] = useState(false); - - useEffect(() => { - try { - setIsGridEventsDismissed( - window.sessionStorage.getItem("announcement:global-grid-card:dismissed") === "true", - ); - } catch { - setIsGridEventsDismissed(false); - } - }, []); - - const handleDismissGridEvents = () => { - setIsGridEventsDismissed(true); - try { - window.sessionStorage.setItem( - "announcement:global-grid-card:dismissed", - "true", - ); - } catch {} - }; - - useEffect(() => { - setActiveEvent(getSubjectEvent(subject)); - }, [subject]); - const renderGridItems = (paperList: IPaper[]) => { if (paperList.length === 0) return null; - const currentEvent = activeEvent ?? EVENTS[0]!; const items: React.ReactNode[] = []; - paperList.forEach((paper, index) => { - if (index === 2 && !isGridEventsDismissed) { - items.push( - , - ); - } + paperList.forEach((paper) => { items.push( { ); }); - if (paperList.length > 0 && paperList.length < 2 && !isGridEventsDismissed) { - items.push( - , - ); - } - return items; }; diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 4be2b93b..e4e10cea 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -23,48 +23,58 @@ import { useCourses } from "@/context/courseContext"; import PinnedModal from "./ui/PinnedModal"; import RequestModal from "./ui/RequestModal"; import Announcement from "./ui/announcement/Announcement"; -import { EVENTS } from "@/config/events"; +import { getSubjectEvent, type EventData } from "@/config/events"; function Navbar() { const pathname: string = usePathname() ?? "/"; const [dropdownOpen, setDropdownOpen] = useState(false); - const [currentBannerIndex, setCurrentBannerIndex] = useState(0); - const [isPaused, setIsPaused] = useState(false); const [isTopBannerDismissed, setIsTopBannerDismissed] = useState(false); const { courses } = useCourses(); useEffect(() => { try { - setIsTopBannerDismissed( - window.sessionStorage.getItem("announcement:global-top-banner:dismissed") === "true", - ); + const storageKey = "announcement:global-top-banner:dismissed"; + const timestampKey = `${storageKey}:time`; + const isDismissed = window.localStorage.getItem(storageKey) === "true"; + const dismissedAt = window.localStorage.getItem(timestampKey); + const TWELVE_HOURS = 12 * 60 * 60 * 1000; + + if (isDismissed && dismissedAt) { + const timePassed = Date.now() - parseInt(dismissedAt, 10); + if (timePassed < TWELVE_HOURS) { + setIsTopBannerDismissed(true); + } else { + window.localStorage.removeItem(storageKey); + window.localStorage.removeItem(timestampKey); + setIsTopBannerDismissed(false); + } + } else if (isDismissed) { + setIsTopBannerDismissed(true); + } else { + setIsTopBannerDismissed(false); + } } catch { setIsTopBannerDismissed(false); } }, []); - useEffect(() => { - if (isPaused || EVENTS.length <= 1) return; - - const interval = setInterval(() => { - setCurrentBannerIndex((prevIndex) => (prevIndex + 1) % EVENTS.length); - }, 5000); - - return () => clearInterval(interval); - }, [isPaused]); - const handleDismissTopBanner = (e?: React.MouseEvent) => { e?.stopPropagation(); setIsTopBannerDismissed(true); try { - window.sessionStorage.setItem( - "announcement:global-top-banner:dismissed", - "true", - ); + const storageKey = "announcement:global-top-banner:dismissed"; + window.localStorage.setItem(storageKey, "true"); + window.localStorage.setItem(`${storageKey}:time`, Date.now().toString()); } catch {} }; + const [currentEvent, setCurrentEvent] = useState(null); + + useEffect(() => { + setCurrentEvent(getSubjectEvent()); + }, []); + const renderHomePageButtons = () => ( <> {/* @@ -90,38 +100,23 @@ function Navbar() { return (
- {EVENTS.length > 0 && !isTopBannerDismissed && ( -
setIsPaused(true)} - onMouseLeave={() => setIsPaused(false)} - > -
- {EVENTS.map((event) => ( -
- -
- ))} -
-
+ {currentEvent && !isTopBannerDismissed && ( + )}
diff --git a/src/components/ui/announcement/Announcement.tsx b/src/components/ui/announcement/Announcement.tsx index d2e36cbc..85f5fe70 100644 --- a/src/components/ui/announcement/Announcement.tsx +++ b/src/components/ui/announcement/Announcement.tsx @@ -59,16 +59,16 @@ const accentStyles: Record< badgeBg: "bg-[#EFEAFF] text-[#562EE7] dark:bg-[#2E1A47] dark:text-[#C4B5FD]", }, amber: { - cardBorder: "border-[#D97706] dark:border-[#B45309]", - cardSurface: "bg-white dark:bg-[#1C1305] hover:bg-[#FEF3C7] hover:dark:bg-[#2B1B07]", - bannerSurface: "bg-[#FEF3C7] dark:bg-[#2A1C07]", - chip: "bg-[#FDE8B8] dark:bg-[#3D290A]", - chipIcon: "text-[#92600B] dark:text-[#FCD34D]", - accentText: "text-[#92600B] dark:text-[#FBBF24]", - cta: "bg-[#D97706] text-white hover:bg-[#B8630A] dark:bg-[#D97706] dark:hover:bg-[#B45309]", - secondaryCta: "border border-[#D97706] text-[#92600B] hover:bg-[#FEF3C7] dark:border-[#F59E0B] dark:text-[#FCD34D] dark:hover:bg-[#3D290A]", - tagText: "text-[#92600B] dark:text-[#FCD34D]", - badgeBg: "bg-[#FEF3C7] text-[#92600B] dark:bg-[#3D290A] dark:text-[#FCD34D]", + cardBorder: "border-[#734DFF] dark:border-[#562EE7]", + cardSurface: "bg-white dark:bg-[#120B24] hover:bg-[#EFEAFF] hover:dark:bg-[#1D1438]", + bannerSurface: "bg-[#EFEAFF] dark:bg-[#1A1133]", + chip: "bg-[#EFEAFF] dark:bg-[#231845]", + chipIcon: "text-[#562EE7] dark:text-[#C4B5FD]", + accentText: "text-[#562EE7] dark:text-[#A78BFA]", + cta: "bg-[#734DFF] text-white hover:bg-[#5F3FE0] dark:bg-[#6D28D9] dark:hover:bg-[#5B21B6]", + secondaryCta: "border border-[#734DFF] text-[#562EE7] hover:bg-[#EFEAFF] dark:border-[#7C3AED] dark:text-[#C4B5FD] dark:hover:bg-[#2E1A47]", + tagText: "text-[#734DFF] dark:text-[#C4B5FD]", + badgeBg: "bg-[#EFEAFF] text-[#562EE7] dark:bg-[#2E1A47] dark:text-[#C4B5FD]", }, green: { cardBorder: "border-[#16A34A] dark:border-[#15803D]", @@ -167,7 +167,25 @@ export default function Announcement({ setMounted(true); if (dismissible) { try { - setDismissed(window.sessionStorage.getItem(storageKey) === "true"); + const timestampKey = `${storageKey}:time`; + const isDismissed = window.localStorage.getItem(storageKey) === "true"; + const dismissedAt = window.localStorage.getItem(timestampKey); + const TWELVE_HOURS = 12 * 60 * 60 * 1000; + + if (isDismissed && dismissedAt) { + const timePassed = Date.now() - parseInt(dismissedAt, 10); + if (timePassed < TWELVE_HOURS) { + setDismissed(true); + } else { + window.localStorage.removeItem(storageKey); + window.localStorage.removeItem(timestampKey); + setDismissed(false); + } + } else if (isDismissed) { + setDismissed(true); + } else { + setDismissed(false); + } } catch { setDismissed(false); } @@ -178,7 +196,8 @@ export default function Announcement({ e.stopPropagation(); setDismissed(true); try { - window.sessionStorage.setItem(storageKey, "true"); + window.localStorage.setItem(storageKey, "true"); + window.localStorage.setItem(`${storageKey}:time`, Date.now().toString()); } catch { // ignore quota / security error } @@ -214,7 +233,7 @@ export default function Announcement({ className, )} > -
+
{/* Info section - grouped neatly right next to the logo */}
{imageUrl ? ( diff --git a/src/components/ui/announcement/EventLogo.tsx b/src/components/ui/announcement/EventLogo.tsx index 1954aa8d..939045cc 100644 --- a/src/components/ui/announcement/EventLogo.tsx +++ b/src/components/ui/announcement/EventLogo.tsx @@ -66,7 +66,7 @@ export function EventLogo({ type = "default", className, size = "md" }: EventLog return (
- - - + + + @@ -95,7 +95,7 @@ export function EventLogo({ type = "default", className, size = "md" }: EventLog fill="url(#hatGrad)" /> {/* Hat Ribbon / Code Bar */} - + {/* Central Coding Flame */} @@ -105,8 +105,8 @@ export function EventLogo({ type = "default", className, size = "md" }: EventLog /> {/* Sparkles */} - - + +
); diff --git a/src/components/ui/banners/bannerDismiss.tsx b/src/components/ui/banners/bannerDismiss.tsx index f75808c4..244771b3 100644 --- a/src/components/ui/banners/bannerDismiss.tsx +++ b/src/components/ui/banners/bannerDismiss.tsx @@ -15,10 +15,10 @@ interface BannerProps { export default function Banner({ bannerId, - bgColor = "#fef3c7", - textColor = "#5a3000", - iconColor = "#d97706", - accentColor = "#78350f", + bgColor = "#EFEAFF", + textColor = "#120B24", + iconColor = "#562EE7", + accentColor = "#562EE7", message, title, }: BannerProps) { diff --git a/src/config/events.ts b/src/config/events.ts index 4172d9e8..6c29bab6 100644 --- a/src/config/events.ts +++ b/src/config/events.ts @@ -34,7 +34,7 @@ export const EVENTS: EventData[] = [ tagline: "Largest Competitive Coding Contest", description: "Test your algorithmic problem solving skills against top coders. Win prizes, certificates, and glory at Gravitas !", badge: "CookOff 11", - accent: "amber", + accent: "purple", registrationUrl: "https://gravitas.vit.ac.in/events/0629102b-cc5f-4992-8921-2e55df1cb2f8", landingPageUrl: "https://gravitas.codechefvit.com/", dates: "Gravitas '26",