diff --git a/app/live/page.tsx b/app/live/page.tsx new file mode 100644 index 0000000..2bdf97a --- /dev/null +++ b/app/live/page.tsx @@ -0,0 +1,250 @@ +"use client"; + +import Image from "next/image"; +import { useState, useEffect } from "react"; +import FadeInView from "@/components/FadeInView"; + +interface EventData { + time: string; + endTime?: string; + title: string; + venue: string; + type: "Internal" | "Public" | "Everyone"; + dateObj: Date; +} + +// Fixed timeline data mapped to actual Date objects for accurate tracking +const flattenedEvents: EventData[] = [ + { time: "2:30 PM", endTime: "5:00 PM", title: "Entry Begins", venue: "Main Gate", type: "Public" as const, dateObj: new Date("2026-04-03T14:30:00") }, + { time: "2:30 PM", endTime: "5:30 PM", title: "Registration and Reporting", venue: "Front of LHTC", type: "Public" as const, dateObj: new Date("2026-04-03T14:30:00") }, + { time: "5:00 PM", endTime: "6:45 PM", title: "Inauguration Ceremony", venue: "Auditorium, LHTC", type: "Everyone" as const, dateObj: new Date("2026-04-03T17:00:00") }, + { time: "6:45 PM", endTime: "7:00 PM", title: "Participants Move to Venue", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-03T18:45:00") }, + { time: "7:00 PM", title: "Hacking Begins", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-03T19:00:00") }, + { time: "9:00 PM", endTime: "10:00 PM", title: "Dinner", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-03T21:00:00") }, + + { time: "12:00 AM", endTime: "1:30 AM", title: "Mentorship Round 1", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T00:00:00") }, + { time: "1:45 AM", endTime: "2:30 AM", title: "Fun Event with Prizes!", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T01:45:00") }, + { time: "2:45 AM", title: "Midnight Snack", venue: "LHTC", type: "Public" as const, dateObj: new Date("2026-04-04T02:45:00") }, + { time: "4:30 AM", title: "Checkpoint 1 / 3", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T04:30:00") }, + { time: "7:30 AM", endTime: "8:30 AM", title: "Breakfast Break", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-04T07:30:00") }, + { time: "10:30 AM", endTime: "11:30 AM", title: "Fireside Chat", venue: "L104/L105", type: "Everyone" as const, dateObj: new Date("2026-04-04T10:30:00") }, + { time: "12:00 PM", endTime: "1:00 PM", title: "Lunch Break", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-04T12:00:00") }, + { time: "2:00 PM", title: "Checkpoint 2 / 3", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T14:00:00") }, + { time: "2:00 PM", endTime: "4:00 PM", title: "Judging Round 1", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T14:00:00") }, + { time: "4:45 PM", title: "Evening Snacks", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T16:45:00") }, + { time: "6:00 PM", endTime: "8:00 PM", title: "GitHub + MLH Workshop", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T18:00:00") }, + { time: "9:00 PM", endTime: "10:00 PM", title: "Dinner Break", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-04T21:00:00") }, + + { time: "12:00 AM", endTime: "1:30 AM", title: "Mentorship Round 2", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-05T00:00:00") }, + { time: "1:45 AM", endTime: "2:30 AM", title: "Fun Event with Prizes!", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-05T01:45:00") }, + { time: "2:45 AM", title: "Midnight Snack", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-05T02:45:00") }, + { time: "4:00 AM", title: "Checkpoint 3 / 3", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-05T04:00:00") }, + { time: "6:00 AM", title: "Soft Deadline", venue: "Online", type: "Public" as const, dateObj: new Date("2026-04-05T06:00:00") }, + { time: "7:00 AM", title: "Hard Deadline — Coding Ends", venue: "Online", type: "Public" as const, dateObj: new Date("2026-04-05T07:00:00") }, + { time: "7:30 AM", endTime: "8:30 AM", title: "Breakfast Break", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-05T07:30:00") }, + { time: "9:30 AM", title: "Judging Round 2", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-05T09:30:00") }, + { time: "12:00 PM", endTime: "1:00 PM", title: "Lunch Break", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-05T12:00:00") }, + { time: "2:30 PM", endTime: "4:00 PM", title: "Closing Ceremony", venue: "Auditorium, LHTC", type: "Everyone" as const, dateObj: new Date("2026-04-05T14:30:00") }, +]; // sorted chronologically + +const HACKATHON_START = new Date("2026-04-03T19:00:00"); +const HACKATHON_END = new Date("2026-04-05T07:00:00"); + +// --- TIME MACHINE FOR TESTING --- +// Change this value to simulate jumping forward in time (in milliseconds) +// e.g., To jump ahead to April 3rd at 7:00 PM: new Date("2026-04-03T19:00:00").getTime() - Date.now() +const TEST_OFFSET_MS = 0; +// -------------------------------- + +function formatTimeLeft(ms: number) { + if (ms <= 0) return "00 : 00 : 00"; + const hours = Math.floor(ms / (1000 * 60 * 60)); + const mins = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60)); + const secs = Math.floor((ms % (1000 * 60)) / 1000); + return `${hours.toString().padStart(2, "0")} : ${mins.toString().padStart(2, "0")} : ${secs.toString().padStart(2, "0")}`; +} + +export default function LiveProjectorPage() { + const [now, setNow] = useState(new Date(Date.now() + TEST_OFFSET_MS)); + + useEffect(() => { + const interval = setInterval(() => setNow(new Date(Date.now() + TEST_OFFSET_MS)), 1000); + return () => clearInterval(interval); + }, []); + + const timeLeftToHack = HACKATHON_END.getTime() - now.getTime(); + const hackIsOver = timeLeftToHack <= 0; + + const timeElapsed = now.getTime() - HACKATHON_START.getTime(); + const hasHackingStarted = timeElapsed > 0; + + // Find next event + const nextEventIndex = flattenedEvents.findIndex(e => e.dateObj.getTime() > now.getTime()); + const nextEvent = nextEventIndex !== -1 ? flattenedEvents[nextEventIndex] : null; + const timeToNextEvent = nextEvent ? nextEvent.dateObj.getTime() - now.getTime() : 0; + + // Find current event + // Automatically gets the event right before the 'next' event, or the last event if all are passed + const currentEvent = nextEventIndex > 0 + ? flattenedEvents[nextEventIndex - 1] + : nextEventIndex === -1 + ? flattenedEvents[flattenedEvents.length - 1] + : null; + + return ( +
+ + {/* Corner decorations */} +
+ +
+
+ +
+ + {/* Main Page Assets */} +
+ MLH badge +
+ +
+ Broken effect background hover +
+ +
+
+ TPC and IIITDM Jabalpur logos +
+
+ + + + {/* Top: Branding or Title */} +
+

HackByte 4.0 // Live

+
+
+ +
+ + {/* Main Countdown (Time left) - Spans 2 columns horizontally */} +
+

+ {hackIsOver ? "Hacking Concluded" : "Time Remaining"} +

+
+
+ {!hackIsOver ? formatTimeLeft(timeLeftToHack) : "00 : 00 : 00"} +
+
+
+ + {/* Next Event - Spans 2 rows vertically on large screens */} +
+ {nextEvent ? ( + <> +
+
+

+ Up Next +

+
+ {nextEvent.title} +
+
+
+ + + + {nextEvent.time} + + {timeToNextEvent > 0 && `(in ${Math.max(1, Math.round(timeToNextEvent / 3600000))} hours)`} + +
+ {nextEvent.venue && ( +
+ + + + + {nextEvent.venue} +
+ )} +
+
+ + ) : ( +
+

+ All Events Concluded +

+
+ )} +
+ + {/* Time Elapsed Box */} +
+ + Time Elapsed + + + {hasHackingStarted && !hackIsOver ? formatTimeLeft(timeElapsed) : "00 : 00 : 00"} + + {!hasHackingStarted && !hackIsOver && ( + + Starts at Hacking Period + + )} +
+ + {/* Current Event Box */} +
+
+ + Current Event + + {currentEvent ? ( +
+ + {currentEvent.title} + + {currentEvent.venue && ( +
+ + + + + {currentEvent.venue} +
+ )} +
+ ) : ( + + {nextEventIndex === 0 ? "Hackathon Starting Soon" : "All Events Concluded"} + + )} +
+ +
+
+
+ ); +} diff --git a/components/sections/hero-section.tsx b/components/sections/hero-section.tsx index ea52017..28abc35 100644 --- a/components/sections/hero-section.tsx +++ b/components/sections/hero-section.tsx @@ -25,7 +25,7 @@ const INITIAL_COUNTDOWN: CountdownState = { isOver: false, }; -const EVENT_START = new Date("2026-04-03T00:00:00+05:30").getTime(); +const EVENT_START = new Date("2026-04-03T17:00:00+05:30").getTime(); const EVENT_END = new Date("2026-04-05T23:59:59+05:30").getTime(); const getCountdownState = (): CountdownState => {