diff --git a/app/page.tsx b/app/page.tsx index 322c0b8..07ee759 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,25 +1,10 @@ -import EventCard from "@/components/EventCard"; -import dynamic from 'next/dynamic'; - -const Starfield = dynamic(() => import('@/components/Starfield'), { - ssr: false -}); +// app/page.tsx +import MissionControl from '@/components/MissionControl'; export default function Home() { return ( -
- - -

- Mission Control // Ground Station -

- -
- -
+
+
); -} +} \ No newline at end of file diff --git a/components/EventCard.tsx b/components/EventCard.tsx index de62a63..da86994 100644 --- a/components/EventCard.tsx +++ b/components/EventCard.tsx @@ -1,32 +1,67 @@ "use client"; -import { motion } from "framer-motion"; -import { Rocket } from "lucide-react"; -import { EventCardProps } from "@/types/space" - +import { useState, useEffect } from 'react'; +import { EventCardProps } from '@/types/space'; export default function EventCard({ title, targetDate, icon }: EventCardProps) { + // 1. Setup the state to hold our strings + const [timeLeft, setTimeLeft] = useState({ h: "00", m: "00", s: "00" }); + + useEffect(() => { + const updateTimer = () => { + const now = new Date().getTime(); + const distance = targetDate.getTime() - now; + + // If the time has passed, keep it at zero + if (distance < 0) { + setTimeLeft({ h: "00", m: "00", s: "00" }); + return; + } + + // Math to convert milliseconds to Hours, Minutes, and Seconds + const h = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + const m = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); + const s = Math.floor((distance % (1000 * 60)) / 1000); + + // 2. Update the state (padStart ensures we always see '05' instead of '5') + setTimeLeft({ + h: h.toString().padStart(2, '0'), + m: m.toString().padStart(2, '0'), + s: s.toString().padStart(2, '0') + }); + }; + + // Run the timer every 1000ms (1 second) + const interval = setInterval(updateTimer, 1000); + + // Call it once immediately so the user doesn't see 00:00:00 for the first second + updateTimer(); + + // Important: Clean up the timer if the component disappears + return () => clearInterval(interval); + }, [targetDate]); + return ( - -
- +
- {icon || } + {icon}
-

{title}

+

+ {title} +

- 02: - 14: - 55 + {timeLeft.h} + : + {timeLeft.m} + : + {timeLeft.s}
-

T-Minus to Horizon

- +

+ T-Minus to Horizon +

+
); } \ No newline at end of file diff --git a/components/MissionControl.tsx b/components/MissionControl.tsx new file mode 100644 index 0000000..b57e8bc --- /dev/null +++ b/components/MissionControl.tsx @@ -0,0 +1,65 @@ +"use client"; + +import { useMemo } from 'react'; +import dynamic from 'next/dynamic'; +import EventCard from '@/components/EventCard'; +import { Satellite, Rocket, Moon, Sparkles } from 'lucide-react'; + +// Now we can safely call dynamic with ssr:false here +const Starfield = dynamic(() => import('@/components/Starfield'), { + ssr: false +}); + +export default function MissionControl() { + // Use the BASE_TIME from your terminal (Jan 2026 value) + const BASE_TIME = 1769610273000; + + const events = useMemo(() => [ + { + title: "ISS Overhead: Home", + date: new Date(BASE_TIME + 1000 * 60 * 60 * 2), + icon: , + }, + { + title: "Next Lunar Phase: Full", + date: new Date(BASE_TIME + 1000 * 60 * 60 * 24 * 3), + icon: , + }, + { + title: "Starlink Train", + date: new Date(BASE_TIME + 1000 * 60 * 45), + icon: , + }, + { + title: "Meteor Shower", + date: new Date(BASE_TIME + 1000 * 60 * 60 * 24 * 10), + icon: , + } + ], []); + + return ( +
+ + +
+

+ MissionControl +

+

+ Ground Station // [55.6761° N, 12.5683° E] +

+
+ +
+ {events.map((event, index) => ( + + ))} +
+
+ ); +} \ No newline at end of file