diff --git a/app/page.tsx b/app/page.tsx index db0b55f..64a709d 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -4,7 +4,6 @@ import { Buffer } from 'buffer' import { Montserrat } from 'next/font/google' import { AppStoreBadge } from '@/components/AppStore' import { PlayStoreBadge } from '@/components/PlayStore' -import { ProductHunt } from '@/components/ProductHunt' const montserrat = Montserrat({ subsets: ['latin'] }) @@ -170,7 +169,6 @@ export default async function LandingPage({ - ) } diff --git a/src/components/ProductHunt.tsx b/src/components/ProductHunt.tsx deleted file mode 100644 index c5c3ca0..0000000 --- a/src/components/ProductHunt.tsx +++ /dev/null @@ -1,188 +0,0 @@ -'use client' - -import React from "react"; - -/** - * FloatingProductHuntBadge - * - Fixed bottom-right on desktop; stretches nicely on mobile - * - Live countdown to Sun Sep 28, 2025 12:01 AM America/Los_Angeles (PDT) - * - After expiry, shows a thank-you message - */ -export function ProductHunt() { - // Target instant: 2025-09-28 00:01:00 in America/Los_Angeles. - // PDT is UTC-7 on this date, so UTC = 07:01. - const TARGET_UTC_MS = Date.UTC(2025, 8, 28, 7, 1, 0); // months are 0-based - - const [remainingMs, setRemainingMs] = React.useState(() => { - return TARGET_UTC_MS - Date.now(); - }); - - // Update once per second without setTimeout (uses rAF; coalesces to 1Hz updates) - React.useEffect(() => { - let rafId = 0; - let lastShownSecond = Math.floor(remainingMs / 1000); - - const tick = () => { - const now = Date.now(); - const nextRemaining = TARGET_UTC_MS - now; - const nextSecond = Math.floor(nextRemaining / 1000); - if (nextSecond !== lastShownSecond) { - lastShownSecond = nextSecond; - setRemainingMs(nextRemaining); - } - rafId = requestAnimationFrame(tick); - }; - - rafId = requestAnimationFrame(tick); - return () => cancelAnimationFrame(rafId); - // We intentionally don't include remainingMs in deps to avoid resetting lastShownSecond each render. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const isOver = remainingMs <= 0; - - const formatRemaining = (ms: number) => { - if (ms <= 0) return "00:00:00"; - const totalSeconds = Math.floor(ms / 1000); - const days = Math.floor(totalSeconds / 86400); - const hours = Math.floor((totalSeconds % 86400) / 3600); - const minutes = Math.floor((totalSeconds % 3600) / 60); - const seconds = totalSeconds % 60; - - const two = (n: number) => n.toString().padStart(2, "0"); - // Show D:HH:MM:SS (omit days label if zero) - return days > 0 - ? `${days}d ${two(hours)}:${two(minutes)}:${two(seconds)}` - : `${two(hours)}:${two(minutes)}:${two(seconds)}`; - }; - - return ( - - - - - - - {isOver ? ( - thanks for voting for us on product hunt - ) : ( - <> - - - we’re live — time left to vote: - - {formatRemaining(remainingMs)} - > - )} - - - {/* Styles (scoped) */} - - - ); -}