diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeek/CalendarItem.tsx b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/CalendarItem.tsx new file mode 100644 index 0000000..5140c25 --- /dev/null +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/CalendarItem.tsx @@ -0,0 +1,126 @@ +import Image from 'next/image'; +import Event, { EventTag, EventType } from '@data/event'; +import { SCHEDULE_EVENT_STYLES } from './scheduleEventStyles'; +import { formatScheduleTimeRange } from './scheduleTime'; + +import locationIcon from '@public/schedule/location.svg'; +import attendeeIcon from '@public/schedule/attendee.svg'; + +interface CalendarItemProps { + event: Event; + attendeeCount?: number; +} + +const isEventType = (value: string): value is EventType => { + return value in SCHEDULE_EVENT_STYLES; +}; + +const normalizeTag = (tag: EventTag) => tag.toUpperCase().replace('_', ' '); + +const toHostLines = (host?: string) => + host + ? host + .split(/,|\n/) + .map((line) => line.trim()) + .filter(Boolean) + .slice(0, 3) + : []; + +export function CalendarItem({ event, attendeeCount }: CalendarItemProps) { + const { name, type, location, start_time, end_time, tags, host } = event; + const rawType = type ?? ''; + const normalizedType = rawType.toUpperCase(); + const displayType: EventType = isEventType(normalizedType) + ? normalizedType + : 'GENERAL'; + const eventStyle = SCHEDULE_EVENT_STYLES[displayType]; + const hostLines = toHostLines(host); + const showAttendees = displayType === 'WORKSHOPS' && (attendeeCount ?? 0) > 0; + const hasMeta = + hostLines.length > 0 || (tags?.length ?? 0) > 0 || showAttendees; + + const timeDisplay = formatScheduleTimeRange( + new Date(start_time), + end_time ? new Date(end_time) : undefined + ); + + return ( +
+
+
+
+

+ {name} +

+
+ {timeDisplay} + {location && ( + + + {location} + + )} +
+
+ {hostLines.length > 0 && ( +
+ {hostLines.map((line) => ( +

{line}

+ ))} +
+ )} +
+ + {hasMeta && ( +
+ {(tags?.length ?? 0) > 0 && ( +
+ {tags?.map((tag) => ( + + {normalizeTag(tag)} + + ))} +
+ )} + + {showAttendees && ( +
+ + + {attendeeCount} Hacker{attendeeCount === 1 ? ' is' : 's are'}{' '} + attending this event + +
+ )} +
+ )} +
+
+ ); +} + +export default CalendarItem; diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeek/ScheduleSneakPeek.tsx b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/ScheduleSneakPeek.tsx new file mode 100644 index 0000000..d765ad7 --- /dev/null +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/ScheduleSneakPeek.tsx @@ -0,0 +1,241 @@ +'use client'; + +import { useEffect, useMemo, useState } from 'react'; +import Image from 'next/image'; +import type { ComponentProps } from 'react'; +import rawScheduleEvents from '@data/hub-2026-staging.events.json'; +import Event, { EventTag, EventType } from '@data/event'; +import CalendarItem from './CalendarItem'; +import { + formatCountdown, + getScheduleEventEndTime, + isScheduleEventLive, +} from './scheduleTime'; + +import duckBunny from '@public/schedule/duck+bunny.svg'; +import duckFrog from '@public/schedule/duck+frog.svg'; + +interface ScheduleSneakPeekProps { + className?: string; +} + +interface RawScheduleEvent { + name: string; + host?: string; + type: string; + location?: string; + start_time: { $date: string }; + end_time?: { $date: string }; + tags?: string[]; +} + +const VALID_EVENT_TYPES: EventType[] = [ + 'GENERAL', + 'ACTIVITIES', + 'WORKSHOPS', + 'MEALS', + 'RECOMMENDED', +]; +const DISPLAY_TYPES = new Set(['ACTIVITIES', 'WORKSHOPS', 'MEALS']); +const VALID_TAGS: EventTag[] = [ + 'developer', + 'designer', + 'pm', + 'other', + 'beginner', +]; + +const isEventType = (value: string): value is EventType => + VALID_EVENT_TYPES.includes(value as EventType); + +const isEventTag = (value: string): value is EventTag => + VALID_TAGS.includes(value as EventTag); + +const normalizeScheduleEvent = ( + event: RawScheduleEvent, + index: number +): Event => { + const start = new Date(event.start_time.$date); + const end = event.end_time ? new Date(event.end_time.$date) : undefined; + const normalizedType = (event.type || 'GENERAL').toUpperCase(); + const type = isEventType(normalizedType) ? normalizedType : 'GENERAL'; + const tags = event.tags?.filter(isEventTag); + const eventId = `${index}-${event.name}-${start.getTime()}`; + + return { + _id: eventId, + name: event.name, + host: event.host, + type, + location: event.location, + start_time: start, + end_time: end, + tags, + }; +}; + +const normalizedEvents = (rawScheduleEvents as RawScheduleEvent[]) + .map((event, index) => normalizeScheduleEvent(event, index)) + .sort( + (a, b) => + new Date(a.start_time).getTime() - new Date(b.start_time).getTime() + ); + +const displayableEvents = normalizedEvents.filter((event) => + DISPLAY_TYPES.has(event.type) +); + +const estimateAttendeeCount = (event: Event): number | undefined => { + if (event.type !== 'WORKSHOPS') return undefined; + const seedSource = event._id ?? event.name; + const hash = Array.from(seedSource).reduce( + (total, character) => total + character.charCodeAt(0), + 0 + ); + return 8 + (hash % 19); +}; + +function EmptyState({ + title, + description, + imageSrc, + imageAlt, +}: { + title: string; + description: string; + imageSrc: ComponentProps['src']; + imageAlt: string; +}) { + return ( +
+ {imageAlt} +

+ {title} +

+

+ {description} +

+
+ ); +} + +export default function ScheduleSneakPeek({ + className, +}: ScheduleSneakPeekProps) { + const [nowMs, setNowMs] = useState(() => Date.now()); + + useEffect(() => { + const interval = window.setInterval(() => { + setNowMs(Date.now()); + }, 1000); + return () => window.clearInterval(interval); + }, []); + + const displayNowMs = nowMs; + const displayNow = useMemo(() => new Date(displayNowMs), [displayNowMs]); + + const liveEvents = useMemo( + () => + displayableEvents + .filter((event) => isScheduleEventLive(event, displayNow)) + .sort( + (a, b) => + getScheduleEventEndTime(a).getTime() - + getScheduleEventEndTime(b).getTime() + ) + .slice(0, 3), + [displayNow] + ); + + const upcomingEvents = useMemo( + () => + displayableEvents + .filter((event) => new Date(event.start_time).getTime() > displayNowMs) + .slice(0, 3), + [displayNowMs] + ); + + const liveLabel = + liveEvents.length > 0 + ? `UNTIL ${formatCountdown( + Math.min( + ...liveEvents.map((event) => + getScheduleEventEndTime(event).getTime() + ) + ) - displayNowMs + )}` + : 'NO LIVE EVENTS'; + const upcomingLabel = + upcomingEvents.length > 0 + ? `IN ${formatCountdown( + new Date(upcomingEvents[0].start_time).getTime() - displayNowMs + )}` + : 'NO UPCOMING EVENTS'; + + return ( +
+
+
+
+
+

+ {liveLabel} +

+

+ Happening now +

+
+
+ {liveEvents.length > 0 ? ( + liveEvents.map((event) => ( + + )) + ) : ( + + )} +
+
+
+ +
+
+

+ {upcomingLabel} +

+

+ Upcoming Events +

+
+
+ {upcomingEvents.length > 0 ? ( + upcomingEvents.map((event) => ( + + )) + ) : ( + + )} +
+
+
+
+
+
+ ); +} diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleEventStyles.ts b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleEventStyles.ts new file mode 100644 index 0000000..66042fb --- /dev/null +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleEventStyles.ts @@ -0,0 +1,40 @@ +import { EventType } from '@data/event'; + +export interface ScheduleEventStyle { + bgColor: string; + textColor: string; + mutedTextColor: string; + chipBorderColor?: string; +} + +export const SCHEDULE_EVENT_STYLES: Record = { + GENERAL: { + bgColor: '#D9F2F4', + textColor: '#2B3A3B', + mutedTextColor: '#5F686A', + }, + ACTIVITIES: { + bgColor: '#FFE2D5', + textColor: '#3F3F46', + mutedTextColor: '#65656E', + chipBorderColor: 'rgba(63, 63, 70, 0.35)', + }, + WORKSHOPS: { + bgColor: '#D7E8AB', + textColor: '#202020', + mutedTextColor: '#606060', + chipBorderColor: 'rgba(32, 32, 32, 0.35)', + }, + MEALS: { + bgColor: '#CFF3F2', + textColor: '#2E3D3F', + mutedTextColor: '#5F6C6E', + chipBorderColor: 'rgba(46, 61, 63, 0.35)', + }, + RECOMMENDED: { + bgColor: '#D6C8E8', + textColor: '#2B3A3B', + mutedTextColor: '#596A6C', + chipBorderColor: 'rgba(43, 58, 59, 0.35)', + }, +}; diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleTime.ts b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleTime.ts new file mode 100644 index 0000000..49140ed --- /dev/null +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleTime.ts @@ -0,0 +1,55 @@ +import Event from '@data/event'; + +export const formatScheduleTime = (date: Date): string => + date.toLocaleString('en-US', { + hour: 'numeric', + minute: '2-digit', + hour12: true, + }); + +export const formatScheduleTimeRange = (start: Date, end?: Date): string => { + if (!end || start.getTime() === end.getTime()) { + return formatScheduleTime(start); + } + + const startTimeStr = formatScheduleTime(start); + const endTimeStr = formatScheduleTime(end); + + const startAMPM = startTimeStr.slice(-2); + const endAMPM = endTimeStr.slice(-2); + + if (startAMPM === endAMPM) { + const startWithoutDayPeriod = startTimeStr + .replace(/\s?(AM|PM)$/i, '') + .trimEnd(); + return `${startWithoutDayPeriod} - ${endTimeStr}`; + } + + return `${startTimeStr} - ${endTimeStr}`; +}; + +export const getScheduleEventEndTime = (event: Event): Date => { + if (event.end_time) return new Date(event.end_time); + const fallback = new Date(event.start_time); + fallback.setMinutes(fallback.getMinutes() + 60); + return fallback; +}; + +export const isScheduleEventLive = ( + event: Event, + now: Date = new Date() +): boolean => { + const start = new Date(event.start_time); + const end = getScheduleEventEndTime(event); + return start <= now && now < end; +}; + +export const formatCountdown = (milliseconds: number): string => { + const clamped = Math.max(0, milliseconds); + const hours = Math.floor(clamped / 3600000); + const minutes = Math.floor((clamped % 3600000) / 60000); + const seconds = Math.floor((clamped % 60000) / 1000); + return `${hours.toString().padStart(2, '0')}:${minutes + .toString() + .padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; +}; diff --git a/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx b/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx new file mode 100644 index 0000000..10ca664 --- /dev/null +++ b/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx @@ -0,0 +1,162 @@ +'use client'; + +import { useEffect, useMemo, useState } from 'react'; +import Image from 'next/image'; +import rawEvents from '@data/hub-2026-staging.events.json'; + +import bunny from '@public/Images/upcoming/bunny.svg'; +import cow from '@public/Images/upcoming/cow.svg'; +import froggie from '@public/Images/upcoming/froggie.svg'; +import yellowStar from '@public/Images/upcoming/yellow_star.svg'; +import scissors from '@public/Images/upcoming/scissors.svg'; +import mochinut from '@public/Images/upcoming/mochinut.svg'; +import ditto from '@public/Images/upcoming/ditto.svg'; +import greenFlower from '@public/Images/upcoming/green_flower.svg'; + +interface UpcomingTimelineProps { + className?: string; +} + +interface RawUpcomingEvent { + name: string; + type: string; + start_time: { $date: string }; +} + +interface UpcomingEvent { + id: string; + name: string; + startTime: Date; +} + +const DISPLAY_LIMIT = 3; + +const formatEventTime = (date: Date) => + new Intl.DateTimeFormat('en-US', { + hour: 'numeric', + minute: '2-digit', + hour12: true, + }).format(date); + +const allEvents = (rawEvents as RawUpcomingEvent[]).map((event, index) => ({ + id: `${index}-${event.name}-${event.start_time.$date}`, + name: event.name, + type: (event.type || '').toUpperCase(), + startTime: new Date(event.start_time.$date), +})); + +export default function UpcomingTimeline({ className }: UpcomingTimelineProps) { + const [nowMs, setNowMs] = useState(() => Date.now()); + + useEffect(() => { + const intervalId = window.setInterval(() => { + setNowMs(Date.now()); + }, 60_000); + + return () => window.clearInterval(intervalId); + }, []); + + const upcomingGeneralEvents = useMemo( + () => + allEvents + .filter( + (event) => + event.type === 'GENERAL' && event.startTime.getTime() > nowMs + ) + .sort((a, b) => a.startTime.getTime() - b.startTime.getTime()) + .slice(0, DISPLAY_LIMIT), + [nowMs] + ); + + return ( +
+ + + + + +
+
+
+

+ Upcoming Timeline +

+ +
+ {upcomingGeneralEvents.length > 0 ? ( + upcomingGeneralEvents.map((event) => ( +
+

+ {formatEventTime(event.startTime)} +

+

+ {event.name} +

+
+ )) + ) : ( +
+

+ No upcoming general events yet +

+
+ )} +
+
+
+ +
+
+ Bunny tile artwork + Yellow star tile artwork +
+ +
+ Cow tile artwork + Frog tile artwork +
+
+
+
+ ); +} diff --git a/app/(pages)/(index-page)/page.tsx b/app/(pages)/(index-page)/page.tsx index 73a3142..59547dd 100644 --- a/app/(pages)/(index-page)/page.tsx +++ b/app/(pages)/(index-page)/page.tsx @@ -5,11 +5,15 @@ import AccordionFAQ from './_components/FAQ/faq'; import Create from './_components/Create/create'; import DonorScroll from './_components/DonorScroll/DonorScroll'; import Sponsers from './_components/Sponsers/Sponsers'; +import UpcomingTimeline from './_components/UpcomingTimeline/UpcomingTimeline'; +import ScheduleSneakPeek from './_components/ScheduleSneakPeek/ScheduleSneakPeek'; export default function Home() { return (
+ + diff --git a/app/(pages)/_data/event.ts b/app/(pages)/_data/event.ts new file mode 100644 index 0000000..27b32f5 --- /dev/null +++ b/app/(pages)/_data/event.ts @@ -0,0 +1,21 @@ +type EventType = + | 'GENERAL' + | 'ACTIVITIES' + | 'WORKSHOPS' + | 'MEALS' + | 'RECOMMENDED'; +type EventTag = 'developer' | 'designer' | 'pm' | 'other' | 'beginner'; + +interface Event { + _id?: string; + name: string; + host?: string; + type: EventType; + location?: string; + start_time: Date; + end_time?: Date; + tags?: EventTag[]; +} + +export default Event; +export type { EventType, EventTag }; diff --git a/app/(pages)/_data/hub-2026-staging.events.json b/app/(pages)/_data/hub-2026-staging.events.json new file mode 100644 index 0000000..f86694e --- /dev/null +++ b/app/(pages)/_data/hub-2026-staging.events.json @@ -0,0 +1,404 @@ +[{ + "_id": { + "$oid": "67f7a4153eaf1040a69ac6a7" + }, + "name": "Lunch Starts", + "type": "MEALS", + "start_time": { + "$date": "2026-05-09T20:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a60f3eaf1040a69ac6ae" + }, + "name": "Therapy Dogs", + "type": "ACTIVITIES", + "start_time": { + "$date": "2026-05-09T22:30:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T00:00:00.000Z" + }, + "location": "South Wing" +}, +{ + "_id": { + "$oid": "680027589d521a51759d7e86" + }, + "name": "Tech Together Meetup", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T23:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T00:00:00.000Z" + }, + "host": "Major League Hacking", + "tags": [ + "beginner", + "developer", + "pm", + "designer", + "other" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "680076779d521a51759d7e8c" + }, + "name": "Break", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-10T18:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T19:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "680026b09d521a51759d7e83" + }, + "name": "GitHub Copilot Workshop", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T22:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T23:00:00.000Z" + }, + "host": "Major League Hacking", + "tags": [ + "beginner", + "developer", + "pm" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "67e62cf95f285b9f3db580f1" + }, + "name": "Check-in Starts", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-09T14:30:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a5de3eaf1040a69ac6ad" + }, + "name": "Bracelet Making", + "type": "ACTIVITIES", + "start_time": { + "$date": "2026-05-09T22:30:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T00:30:00.000Z" + }, + "location": "North Wing" +}, +{ + "_id": { + "$oid": "67f7ab113eaf1040a69ac6b2" + }, + "name": "Getting Started with Git & GitHub", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T20:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T22:00:00.000Z" + }, + "host": "UC Davis DataLab", + "tags": [ + "beginner", + "developer" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "680027f49d521a51759d7e89" + }, + "name": "Intro to Freepik AI Suite", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-10T00:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T01:00:00.000Z" + }, + "host": "Freepik", + "tags": [ + "developer", + "pm", + "designer", + "other" + ], + "location": "ARC Ballroom B" +}, +{ + "_id": { + "$oid": "67eb840248055efb36b62324" + }, + "name": "Closing Ceremony", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-10T22:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T23:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7ad173eaf1040a69ac6b3" + }, + "name": "Software Development", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T20:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T21:00:00.000Z" + }, + "host": "CodeLab", + "tags": [ + "beginner", + "developer", + "pm" + ], + "location": "ARC Ballroom B" +}, +{ + "_id": { + "$oid": "67f7a43f3eaf1040a69ac6a8" + }, + "name": "Dinner Starts", + "type": "MEALS", + "start_time": { + "$date": "2026-05-10T02:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a5a93eaf1040a69ac6ac" + }, + "name": "Spaghetti & Marshmallow", + "type": "ACTIVITIES", + "start_time": { + "$date": "2026-05-09T21:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T22:00:00.000Z" + }, + "location": "North Wing" +}, +{ + "_id": { + "$oid": "67f7aa013eaf1040a69ac6b0" + }, + "name": "Hackathons 101", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T18:30:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T20:00:00.000Z" + }, + "host": "HackDavis", + "tags": [ + "beginner" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "6800265c9d521a51759d7e82" + }, + "name": "Hacking with LLMs", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T21:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T22:00:00.000Z" + }, + "host": "Miguel Avecedo, Founder @ Marble", + "tags": [ + "beginner", + "developer", + "pm" + ], + "location": "ARC Ballroom B" +}, +{ + "_id": { + "$oid": "67eb83a648055efb36b62323" + }, + "name": "Check-in closes", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-09T23:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a4ef3eaf1040a69ac6ab" + }, + "name": "Panel Judging", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-10T21:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T22:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a9773eaf1040a69ac6af" + }, + "name": "Jeopardy/Kahoot", + "type": "ACTIVITIES", + "start_time": { + "$date": "2026-05-10T04:30:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T05:30:00.000Z" + }, + "location": "ARC Ballroom B" +}, +{ + "_id": { + "$oid": "680027d19d521a51759d7e88" + }, + "name": "Intro to Letta AI Agents Framework", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-10T00:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T01:00:00.000Z" + }, + "host": "Letta", + "tags": [ + "developer" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "67eb834a48055efb36b62320" + }, + "name": "Team Mixer", + "type": "ACTIVITIES", + "start_time": { + "$date": "2026-05-09T15:30:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T17:00:00.000Z" + }, + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "67eb837948055efb36b62321" + }, + "name": "Opening Ceremony", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-09T17:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T18:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f21f0a3c0ba318b4930cfc" + }, + "name": "Hacking Ends", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-10T18:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "6800279a9d521a51759d7e87" + }, + "name": "Surprise Mini-Event!", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-10T03:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T04:00:00.000Z" + }, + "host": "Major League Hacking", + "tags": [ + "beginner", + "developer", + "pm", + "designer", + "other" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "67eb839548055efb36b62322" + }, + "name": "Hacking Begins", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-09T18:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a46d3eaf1040a69ac6a9" + }, + "name": "Brunch Starts", + "type": "MEALS", + "start_time": { + "$date": "2026-05-10T16:30:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a4db3eaf1040a69ac6aa" + }, + "name": "Demos", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-10T19:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T21:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "680028219d521a51759d7e8a" + }, + "name": "Intro to UI/UX", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T23:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T00:00:00.000Z" + }, + "host": "Design Interactive", + "tags": [ + "beginner", + "designer" + ], + "location": "ARC Ballroom B" +}] \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 710373f..d194a64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@szhsin/react-accordion": "^1.4.1", "@vercel/analytics": "^1.6.1", "autoprefixer": "^10.4.20", - "framer-motion": "^12.34.0", + "framer-motion": "^12.38.0", "next": "14.2.4", "react": "^18", "react-dom": "^18", @@ -4208,13 +4208,13 @@ } }, "node_modules/framer-motion": { - "version": "12.34.0", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.34.0.tgz", - "integrity": "sha512-+/H49owhzkzQyxtn7nZeF4kdH++I2FWrESQ184Zbcw5cEqNHYkE5yxWxcTLSj5lNx3NWdbIRy5FHqUvetD8FWg==", + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz", + "integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==", "license": "MIT", "dependencies": { - "motion-dom": "^12.34.0", - "motion-utils": "^12.29.2", + "motion-dom": "^12.38.0", + "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { @@ -5501,18 +5501,18 @@ } }, "node_modules/motion-dom": { - "version": "12.34.0", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.34.0.tgz", - "integrity": "sha512-Lql3NuEcScRDxTAO6GgUsRHBZOWI/3fnMlkMcH5NftzcN37zJta+bpbMAV9px4Nj057TuvRooMK7QrzMCgtz6Q==", + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz", + "integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==", "license": "MIT", "dependencies": { - "motion-utils": "^12.29.2" + "motion-utils": "^12.36.0" } }, "node_modules/motion-utils": { - "version": "12.29.2", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.29.2.tgz", - "integrity": "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==", + "version": "12.36.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.36.0.tgz", + "integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==", "license": "MIT" }, "node_modules/ms": { diff --git a/package.json b/package.json index 5f2c60f..b116284 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,10 @@ "@fortawesome/free-brands-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0", "@fortawesome/react-fontawesome": "^3.1.1", - "@vercel/analytics": "^1.6.1", "@szhsin/react-accordion": "^1.4.1", + "@vercel/analytics": "^1.6.1", "autoprefixer": "^10.4.20", - "framer-motion": "^12.34.0", + "framer-motion": "^12.38.0", "next": "14.2.4", "react": "^18", "react-dom": "^18", @@ -30,8 +30,8 @@ "@types/react": "^18", "@types/react-dom": "^18", "@types/react-transition-group": "^4.4.12", - "autoprefixer": "^10.4.24", "@typescript-eslint/eslint-plugin": "^6.16.0", + "autoprefixer": "^10.4.24", "eslint": "^8.57.1", "eslint-config-next": "14.2.4", "eslint-config-prettier": "^9.1.0", diff --git a/public/Images/upcoming/bunny.svg b/public/Images/upcoming/bunny.svg new file mode 100644 index 0000000..915791d --- /dev/null +++ b/public/Images/upcoming/bunny.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/Images/upcoming/cow.svg b/public/Images/upcoming/cow.svg new file mode 100644 index 0000000..efcae78 --- /dev/null +++ b/public/Images/upcoming/cow.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/Images/upcoming/ditto.svg b/public/Images/upcoming/ditto.svg new file mode 100644 index 0000000..4c35082 --- /dev/null +++ b/public/Images/upcoming/ditto.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/public/Images/upcoming/froggie.svg b/public/Images/upcoming/froggie.svg new file mode 100644 index 0000000..d65e263 --- /dev/null +++ b/public/Images/upcoming/froggie.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/Images/upcoming/green_flower.svg b/public/Images/upcoming/green_flower.svg new file mode 100644 index 0000000..e67d734 --- /dev/null +++ b/public/Images/upcoming/green_flower.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/Images/upcoming/mochinut.svg b/public/Images/upcoming/mochinut.svg new file mode 100644 index 0000000..bd80b4c --- /dev/null +++ b/public/Images/upcoming/mochinut.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/Images/upcoming/scissors.svg b/public/Images/upcoming/scissors.svg new file mode 100644 index 0000000..7ec828a --- /dev/null +++ b/public/Images/upcoming/scissors.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/Images/upcoming/yellow_star.svg b/public/Images/upcoming/yellow_star.svg new file mode 100644 index 0000000..325c425 --- /dev/null +++ b/public/Images/upcoming/yellow_star.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/public/schedule/arrow-right.svg b/public/schedule/arrow-right.svg new file mode 100644 index 0000000..6a58aac --- /dev/null +++ b/public/schedule/arrow-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/schedule/attendee.svg b/public/schedule/attendee.svg new file mode 100644 index 0000000..6f7ea58 --- /dev/null +++ b/public/schedule/attendee.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/public/schedule/check.svg b/public/schedule/check.svg new file mode 100644 index 0000000..0aee042 --- /dev/null +++ b/public/schedule/check.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/schedule/cucumber_cow.svg b/public/schedule/cucumber_cow.svg new file mode 100644 index 0000000..745e361 --- /dev/null +++ b/public/schedule/cucumber_cow.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/schedule/duck+bunny.svg b/public/schedule/duck+bunny.svg new file mode 100644 index 0000000..7e0fd50 --- /dev/null +++ b/public/schedule/duck+bunny.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/schedule/duck+frog.svg b/public/schedule/duck+frog.svg new file mode 100644 index 0000000..1c21b20 --- /dev/null +++ b/public/schedule/duck+frog.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/schedule/header_grass.svg b/public/schedule/header_grass.svg new file mode 100644 index 0000000..872fd44 --- /dev/null +++ b/public/schedule/header_grass.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/public/schedule/location.svg b/public/schedule/location.svg new file mode 100644 index 0000000..e0d0ccc --- /dev/null +++ b/public/schedule/location.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/schedule/plus.svg b/public/schedule/plus.svg new file mode 100644 index 0000000..c1c8b66 --- /dev/null +++ b/public/schedule/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/schedule/sleeping_cow.svg b/public/schedule/sleeping_cow.svg new file mode 100644 index 0000000..069da7b --- /dev/null +++ b/public/schedule/sleeping_cow.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/schedule/vocal_angel_cow.svg b/public/schedule/vocal_angel_cow.svg new file mode 100644 index 0000000..4144e92 --- /dev/null +++ b/public/schedule/vocal_angel_cow.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +