diff --git a/apps/live/src/app/(landing)/CarnivalLanding/CarnivalScene.tsx b/apps/live/src/app/(landing)/CarnivalLanding/CarnivalScene.tsx new file mode 100644 index 00000000..d2202d5d --- /dev/null +++ b/apps/live/src/app/(landing)/CarnivalLanding/CarnivalScene.tsx @@ -0,0 +1,172 @@ +"use client"; + +import React from "react"; +import HeroBackground from "../../lib/Assets/SVG/CarnivalLanding/HeroBackground"; +import YellowFirework from "../../lib/Assets/SVG/CarnivalLanding/YellowFirework"; +import OrangeFirework from "../../lib/Assets/SVG/CarnivalLanding/OrangeFirework"; +import PurpleTent from "../../lib/Assets/SVG/CarnivalLanding/PurpleTent"; +import OrangeTent from "../../lib/Assets/SVG/CarnivalLanding/OrangeTent"; +import DartBoard from "../../lib/Assets/SVG/CarnivalLanding/DartBoard"; +import CabinRace from "./Components/CabinRace"; +import OpeningText from "./Components/OpeningText"; +import useDevice from "@util/hooks/useDevice"; + +const CarnivalScene: React.FC = () => { + const { isMobile, isTablet, isDesktop } = useDevice(); + + const getMinHeight = () => { + // Reduce overall scene height so the following section + // (SponsorFeature) appears closer without a large blank gap. + if (isDesktop) return "min-h-[1000px]"; + if (isTablet) return "min-h-[1300px]"; + return "min-h-[890px]"; + }; + + return ( +
+ {/* Background - Night Sky */} +
+ +
+ + {/* Cabin Race - Top Left */} +
+
+ +
+
+ + {/* Fireworks */} + {/* Yellow Firework - Left side behind purple tent */} +
+
+ +
+
+ + {/* Orange Firework - Right side behind orange tent */} +
+
+ +
+
+ + {/* Tents */} + {/* Purple Tent - Left side */} +
+
+ +
+
+ + {/* Orange Tent - Right side */} +
+
+ +
+
+ + {/* Opening Text - Above Dart Board */} +
+ +
+ + {/* Central Dart Board Booth */} +
+
+
+ +
+
+
+
+ ); +}; + +export default CarnivalScene; diff --git a/apps/live/src/app/(landing)/CarnivalLanding/Components/CabinRace.tsx b/apps/live/src/app/(landing)/CarnivalLanding/Components/CabinRace.tsx new file mode 100644 index 00000000..534b9869 --- /dev/null +++ b/apps/live/src/app/(landing)/CarnivalLanding/Components/CabinRace.tsx @@ -0,0 +1,199 @@ +"use client"; + +import React from "react"; +import Button from "@repo/ui/Button"; +import useDevice from "@util/hooks/useDevice"; + +interface CabinRaceProps { + text: string; +} + +const ArrowIcon = () => ( + + + + +); + +const CabinRace: React.FC = ({ text }) => { + const { isMobile } = useDevice(); + + const containerClassName = `relative w-[238px] h-[108px] ${isMobile ? "scale-75" : "scale-100"}`; + + return ( +
+ + + + + + + {text} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ ); +}; +export default CabinRace; diff --git a/apps/live/src/app/(landing)/CarnivalLanding/Components/CountdownTimer.tsx b/apps/live/src/app/(landing)/CarnivalLanding/Components/CountdownTimer.tsx new file mode 100644 index 00000000..db4d28b6 --- /dev/null +++ b/apps/live/src/app/(landing)/CarnivalLanding/Components/CountdownTimer.tsx @@ -0,0 +1,123 @@ +"use client"; + +import React, { useEffect, useState } from "react"; + +// Feb 13, 2026 8:00 PM EST — Opening ceremony (countdown begins) +const COUNTDOWN_START = new Date("2026-02-13T20:00:00-05:00"); +// Feb 15, 2026 9:00 AM EST — Countdown ends +const COUNTDOWN_END = new Date("2026-02-15T09:00:00-05:00"); + +const CountdownTimer = () => { + const [days, setDays] = useState(0); + const [hours, setHours] = useState(0); + const [minutes, setMinutes] = useState(0); + + useEffect(() => { + const update = () => { + const now = new Date(); + + if (now < COUNTDOWN_START) { + setDays(0); + setHours(0); + setMinutes(0); + return; + } + + if (now >= COUNTDOWN_END) { + setDays(0); + setHours(0); + setMinutes(0); + return; + } + + const difference = COUNTDOWN_END.getTime() - now.getTime(); + setDays(Math.floor(difference / (1000 * 60 * 60 * 24))); + setHours( + Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)), + ); + setMinutes(Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60))); + }; + + update(); + const interval = setInterval(update, 1000); + return () => clearInterval(interval); + }, []); + + // Format numbers to always show 2 digits + const formatNumber = (num: number) => String(num).padStart(2, "0"); + + return ( + + + + + + {/* Days */} + + {formatNumber(days)} + + + Days + + + {/* First Colon */} + + : + + + {/* Hours */} + + {formatNumber(hours)} + + + Hours + + + {/* Second Colon */} + + : + + + {/* Minutes */} + + {formatNumber(minutes)} + + + Minutes + + + ); +}; + +export default CountdownTimer; diff --git a/apps/live/src/app/(landing)/CarnivalLanding/Components/OpeningText.tsx b/apps/live/src/app/(landing)/CarnivalLanding/Components/OpeningText.tsx new file mode 100644 index 00000000..e0335ae4 --- /dev/null +++ b/apps/live/src/app/(landing)/CarnivalLanding/Components/OpeningText.tsx @@ -0,0 +1,24 @@ +"use client"; + +import React from "react"; +import HBPLogo from "main/src/app/lib/Assets/SVG/Hero/LandingAssets/HBPLogo.tsx"; +import CountdownTimer from "./CountdownTimer.tsx"; +import UntilSubmissionsClose from "../../../lib/Assets/SVG/CarnivalLanding/UntilSubmissionsClose.tsx"; + +const OpeningText: React.FC = () => { + return ( +
+
+ Step on stage, +
+ +
+ is in town!{" "} +
+ + +
+ ); +}; + +export default OpeningText; diff --git a/apps/live/src/app/(landing)/ComingUp/ComingUp.tsx b/apps/live/src/app/(landing)/ComingUp/ComingUp.tsx index dbfcd631..f70ddf11 100644 --- a/apps/live/src/app/(landing)/ComingUp/ComingUp.tsx +++ b/apps/live/src/app/(landing)/ComingUp/ComingUp.tsx @@ -1,183 +1,24 @@ "use client"; -// Imports -import React, { useEffect, useState, useRef, forwardRef } from "react"; - -// Components -import ComingUpEvent from "./ComingUpEvent"; +import React from "react"; import Section from "@repo/ui/Section"; -import Typography from "@repo/ui/Typography"; -import ComingUpBackground from "../../lib/Assets/SVG/ComingUpBackground"; - -// Utils -import removeHoursFromDate from "@util/functions/removeHoursfromDate"; - -// Hooks -import useWindowSize from "@repo/util/hooks/useWindowSize"; -import useContentHeight from "@repo/util/hooks/useContentHeight"; - -export type AirtableRecord = { - id: string; - createdTime: string; - fields: { - end_time: string; - eventLocation: string; - start_time: string; - tags: string; - difficulty: string; - description: string; - eventName: string; - }; -}; - -export type AirtableData = { - records: AirtableRecord[]; -}; - -type EventByDate = { - [date: string]: AirtableRecord[]; -}; - -const toTime = (time: string, showAmPm: boolean): string => { - const date = new Date(time); - - if (showAmPm) { - return date.toLocaleTimeString("en-us", { - hour: "numeric", - minute: "2-digit", - hour12: true, - }); - } - - let hours = date.getHours(); - const minutes = date.getMinutes().toString().padStart(2, "0"); - - // Convert to 12-hour format - hours = hours % 12; - hours = hours ? hours : 12; // the hour '0' should be '12' - - // Combine hours and minutes - const timeString = `${hours}:${minutes}`; - - return timeString; -}; +import CarnivalScene from "../CarnivalLanding/CarnivalScene"; -const getEventStatus = (startTime: string, endTime: string): string => { - const now = new Date(); - const startDate = new Date(startTime); - const endDate = new Date(endTime); - const timeDiff = startDate.getTime() - now.getTime(); //difference in milliseconds - - if (startDate <= now && now <= endDate) { - return "NOW!"; - } else if (timeDiff > 0 && timeDiff <= 60 * 60 * 1000) { - //60 min × 60 sec × 1000 ms - return "IN 1 HOUR!"; - } - return "COMING UP!"; -}; - -const ComingUpContent = forwardRef((_, ref) => { - const [data, setData] = useState(null); - - async function getScheduleData() { - const res = await fetch("/api/airtable"); - - const status = res.status; - - if (status == 200) { - setData(await res.json()); - } - } - - useEffect(() => { - getScheduleData(); - }, []); - - const eventsByDate = - data?.records.reduce((acc, record) => { - const eventDate = new Date(record.fields.start_time); - const uniqueEventDate = removeHoursFromDate(eventDate); - if (!acc[uniqueEventDate.toISOString()]) { - acc[uniqueEventDate.toISOString()] = []; - } - acc[uniqueEventDate.toISOString()].push(record); - return acc; - }, {} as EventByDate) || null; - - const datesSorted = Object.keys(eventsByDate || {}).sort((a, b) => { - const dateA = new Date(a); - const dateB = new Date(b); - return dateA.getTime() - dateB.getTime(); - }); - - const upcomingEvents = datesSorted - .flatMap((date) => eventsByDate?.[date] || []) - .filter((event) => { - const now = new Date(); - const startTime = new Date(event.fields.start_time); - const endTime = new Date(event.fields.end_time); - return startTime >= now || (startTime <= now && now <= endTime); - }) - .sort( - (a, b) => - new Date(a.fields.start_time).getTime() - - new Date(b.fields.start_time).getTime(), - ) // Sort by start time - .slice(0, 3); +const ComingUp = () => { + const background = null; // CarnivalScene includes its own background - return ( -
- - COMING UP! - -
- {/* if there are no upcoming events or if its null, show no events */} - {upcomingEvents.length == 0 || upcomingEvents == undefined ? ( -
- -
- ) : ( - upcomingEvents.map((event) => ( - - )) - )} -
+ const content = ( +
+
); -}); - -ComingUpContent.displayName = "ComingUpContent"; - -const ComingUp = () => { - const ref = useRef(null); - const { height: windowHeight } = useWindowSize(); - const [contentHeight] = useContentHeight(ref); - - const height = windowHeight ? (contentHeight / windowHeight) * 100 + 10 : 110; return (
} - content={} - height={height} + background={background} + content={content} + height={70} /> ); }; diff --git a/apps/live/src/app/(landing)/Judging/index.tsx b/apps/live/src/app/(landing)/Judging/index.tsx index 05813371..23f3317e 100644 --- a/apps/live/src/app/(landing)/Judging/index.tsx +++ b/apps/live/src/app/(landing)/Judging/index.tsx @@ -2,7 +2,7 @@ import React from "react"; import useDevice from "@util/hooks/useDevice.ts"; -import JudgingTicketBooth from "../../lib/Assets/SVG/Judging/JudgingTicketBooth.tsx" +import JudgingTicketBooth from "../../lib/Assets/SVG/Judging/JudgingTicketBooth.tsx"; import JudgingLiveBackground from "../../lib/Assets/SVG/Judging/JudgingLiveBackground.tsx"; import JudgingLiveFireworks from "../../lib/Assets/SVG/Judging/JudgingLiveFireworks.tsx"; import FrontGreenWave from "../../lib/Assets/SVG/Judging/FrontGreenWave.tsx"; @@ -12,55 +12,59 @@ import BackBush from "../../lib/Assets/SVG/Judging/BackBush.tsx"; import CarnivalTitle from "@repo/ui/CarnivalTitle"; export default function Judging(): React.ReactNode { - const { isMobile} = useDevice(); - - return ( -
- - -
+ const { isMobile } = useDevice(); + + return ( +
+ + +
+ - -

- Come back after submissions close
- to see where you will be demoing! + className="absolute left-1/2 -translate-x-1/2 font-NeulisNeue-Bold text-marigoldYellow flex flex-col items-center" + style={{ + fontSize: isMobile ? "2.8vw" : "1.7vw", + top: isMobile ? "40%" : "30%", + }} + > + Come back after submissions close +
+ to see where you will be demoing!

- -
- + +
+
-
- +
+
-
- +
+
-
- +
+
-
- +
+
- + - -
- ); - } - \ No newline at end of file +
+ ); +} diff --git a/apps/live/src/app/(landing)/Landing.tsx b/apps/live/src/app/(landing)/Landing.tsx index d9d4a51e..8e8545dc 100644 --- a/apps/live/src/app/(landing)/Landing.tsx +++ b/apps/live/src/app/(landing)/Landing.tsx @@ -1,88 +1,7 @@ "use client"; import React from "react"; -import Section from "@repo/ui/Section"; -import Typography from "@repo/ui/Typography"; -import Image from "next/image"; -import TimeRemainingSign from "../components/TimeRemainingSign"; -import useIsMobile from "@repo/util/hooks/useIsMobile"; -// import Placeholder from "@repo/ui/Placeholder"; -export default function Landing(): JSX.Element { - const isMobile = useIsMobile(); - - const background = ( -
- ProjectsBackground -
- ); - const content = ( -
-
-

- Buckle up! We're going on a... -

- - ROADTRIP! - -
-
- -
-
-
- Van -
-
- {!isMobile && ( -
-
- Fern -
-
- Fern -
-
- )} -
- ); - - return ( -
- // - ); +export default function Landing(): JSX.Element { + return <>; } diff --git a/apps/live/src/app/(landing)/OurTeam/OurTeamGrid.tsx b/apps/live/src/app/(landing)/OurTeam/OurTeamGrid.tsx index 2af23e25..4149f33b 100644 --- a/apps/live/src/app/(landing)/OurTeam/OurTeamGrid.tsx +++ b/apps/live/src/app/(landing)/OurTeam/OurTeamGrid.tsx @@ -211,7 +211,7 @@ const TeamTable = () => { const iconGridStyles = clsx( "flex flex-wrap justify-center items-center mx-auto gap-6", isDesktop && "w-3/4", - isMobile && "grid grid-cols-2" + isMobile && "grid grid-cols-2", ); return ( @@ -222,7 +222,9 @@ const TeamTable = () => { key={team.toString()} onClick={() => changeTeam(teamName as keyof typeof teams)} className={`py-2 px-3 transition-transform duration-300 transform scale-100 hover:scale-[102%] rounded-xl font-NeulisNeue-Bold text-[20px] ${ - currTeam === teamName ? "bg-firecrackerRed" : "border border-white" + currTeam === teamName + ? "bg-firecrackerRed" + : "border border-white" }`} > {teamName.toString()} @@ -236,7 +238,13 @@ const TeamTable = () => { href={member.url} className="transition-transform scale-100 hover:scale-105" > - + ))}
diff --git a/apps/live/src/app/(landing)/OurTeam/index.tsx b/apps/live/src/app/(landing)/OurTeam/index.tsx index af787a66..4eb72457 100644 --- a/apps/live/src/app/(landing)/OurTeam/index.tsx +++ b/apps/live/src/app/(landing)/OurTeam/index.tsx @@ -17,7 +17,7 @@ export default function OurTeam(): React.ReactNode { const ribbonStyles = clsx( isDesktop && "scale-100", isTablet && "scale-75", - isMobile && "scale-[60%]" + isMobile && "scale-[60%]", ); const blurbStyles = clsx( @@ -44,6 +44,5 @@ export default function OurTeam(): React.ReactNode {
- ); } diff --git a/apps/live/src/app/(landing)/page.tsx b/apps/live/src/app/(landing)/page.tsx index 9c70adfc..7a8182bd 100644 --- a/apps/live/src/app/(landing)/page.tsx +++ b/apps/live/src/app/(landing)/page.tsx @@ -12,7 +12,7 @@ import Footer from "@repo/ui/Footer"; import OurTeam from "./OurTeam"; import Keynote from "./Keynote"; import SponsorFeature from "./SponsorFeature.tsx"; - +import CarnivalScene from "./CarnivalLanding/CarnivalScene.tsx"; export default function Page(): JSX.Element { return (
@@ -20,6 +20,7 @@ export default function Page(): JSX.Element { {/**/} {/**/} + diff --git a/apps/live/src/app/providers.tsx b/apps/live/src/app/(landing)/providers.tsx similarity index 100% rename from apps/live/src/app/providers.tsx rename to apps/live/src/app/(landing)/providers.tsx diff --git a/apps/live/src/app/layout.tsx b/apps/live/src/app/layout.tsx index bbe5f4ac..ba4af90c 100644 --- a/apps/live/src/app/layout.tsx +++ b/apps/live/src/app/layout.tsx @@ -4,7 +4,7 @@ import "@repo/ui/styles.css"; import type { Metadata } from "next"; import { Inter } from "next/font/google"; import React from "react"; -import { Providers } from "./providers"; +import { Providers } from "./(landing)/providers"; const inter = Inter({ subsets: ["latin"] }); diff --git a/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/DartBoard.tsx b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/DartBoard.tsx new file mode 100644 index 00000000..c3f5c56b --- /dev/null +++ b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/DartBoard.tsx @@ -0,0 +1,2252 @@ +import React from "react"; +const DartBoard: React.FC = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; +export default DartBoard; diff --git a/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/HeroBackground.tsx b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/HeroBackground.tsx new file mode 100644 index 00000000..6d3daaee --- /dev/null +++ b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/HeroBackground.tsx @@ -0,0 +1,230 @@ +import React from "react"; +const HeroBackground: React.FC = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* Grass - Positioned at bottom */} + + + + + + + + + + + + + + + + + + ); +}; + +export default HeroBackground; diff --git a/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/OrangeFirework.tsx b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/OrangeFirework.tsx new file mode 100644 index 00000000..b79b716b --- /dev/null +++ b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/OrangeFirework.tsx @@ -0,0 +1,20 @@ +import React from "react"; +const OrangeFirework: React.FC = () => { + return ( + + + + ); +}; + +export default OrangeFirework; diff --git a/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/OrangeTent.tsx b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/OrangeTent.tsx new file mode 100644 index 00000000..75a483af --- /dev/null +++ b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/OrangeTent.tsx @@ -0,0 +1,227 @@ +import React from "react"; +const OrangeTent: React.FC = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; +export default OrangeTent; diff --git a/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/PurpleTent.tsx b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/PurpleTent.tsx new file mode 100644 index 00000000..7c11e91c --- /dev/null +++ b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/PurpleTent.tsx @@ -0,0 +1,182 @@ +import React from "react"; +const PurpleTent: React.FC = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; +export default PurpleTent; diff --git a/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/SubmissionsClose.tsx b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/SubmissionsClose.tsx new file mode 100644 index 00000000..602c8ebd --- /dev/null +++ b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/SubmissionsClose.tsx @@ -0,0 +1,24 @@ +import React from "react"; +const SubmissionsClose: React.FC = () => { + return ( + + + + + + ); +}; + +export default SubmissionsClose; diff --git a/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/UntilSubmissionsClose.tsx b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/UntilSubmissionsClose.tsx new file mode 100644 index 00000000..c682b217 --- /dev/null +++ b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/UntilSubmissionsClose.tsx @@ -0,0 +1,24 @@ +import React from "react"; +const UntilSubmissionsClose: React.FC = () => { + return ( + + + + + + ); +}; + +export default UntilSubmissionsClose; diff --git a/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/YellowFirework.tsx b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/YellowFirework.tsx new file mode 100644 index 00000000..0653845b --- /dev/null +++ b/apps/live/src/app/lib/Assets/SVG/CarnivalLanding/YellowFirework.tsx @@ -0,0 +1,19 @@ +import React from "react"; +const YellowFirework: React.FC = () => { + return ( + + + + ); +}; +export default YellowFirework; diff --git a/apps/main/src/app/sponsors/page.tsx b/apps/main/src/app/sponsors/page.tsx index a16c240b..4e186310 100644 --- a/apps/main/src/app/sponsors/page.tsx +++ b/apps/main/src/app/sponsors/page.tsx @@ -30,7 +30,12 @@ function makeSponsorRow( > {ticketSizes.map((width, i) => logos?.[i] === PureButton ? ( - + = ({ url, isLive = false, isActive = false, - textColor = "charcoalFog" + textColor = "charcoalFog", }) => { return (