Add October Today route

This commit is contained in:
2026-09-10 13:43:18 -04:00
parent 8f1f361047
commit 523f36afbd
2 changed files with 153 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
import type { Metadata } from "next";
import { Suspense } from "react";
import { OctoberCounter } from "~/components/OctoberCounter";
export const metadata: Metadata = {
title: "October Today | Sean O'Connor",
description: "See what day of October 2019 it is today.",
};
export default function OctoberPage() {
return (
<div className="flex min-h-[calc(100vh-12rem)] items-center justify-center py-8">
<Suspense fallback={null}>
<OctoberCounter />
</Suspense>
</div>
);
}
+135
View File
@@ -0,0 +1,135 @@
"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import { useSearchParams } from "next/navigation";
import { CircleHelp, Share2 } from "lucide-react";
import { Button } from "~/components/ui/button";
import { Card, CardContent } from "~/components/ui/card";
const OCTOBER_FIRST_2019 = Date.UTC(2019, 9, 1);
const MILLISECONDS_PER_DAY = 1000 * 60 * 60 * 24;
function getOrdinalSuffix(number: number) {
if (number % 100 >= 11 && number % 100 <= 13) {
return "th";
}
switch (number % 10) {
case 1:
return "st";
case 2:
return "nd";
case 3:
return "rd";
default:
return "th";
}
}
function getOctoberDay(today: Date) {
const todayUtc = Date.UTC(
today.getFullYear(),
today.getMonth(),
today.getDate(),
);
return Math.floor((todayUtc - OCTOBER_FIRST_2019) / MILLISECONDS_PER_DAY) + 1;
}
export function OctoberCounter() {
const searchParams = useSearchParams();
const isJsonMode = searchParams.get("api") === "json";
const [targetDay] = useState(() => getOctoberDay(new Date()));
const [day, setDay] = useState(() =>
isJsonMode ? targetDay : Math.max(1, targetDay - 50),
);
const isAnimating = !isJsonMode && day < targetDay;
const ordinal = getOrdinalSuffix(targetDay);
useEffect(() => {
if (isJsonMode) return;
let currentNumber = Math.max(1, targetDay - 50);
const interval = window.setInterval(() => {
currentNumber += 1;
setDay(currentNumber);
if (currentNumber >= targetDay) {
window.clearInterval(interval);
document.title = `October ${targetDay}${ordinal}, 2019`;
}
}, 30);
return () => window.clearInterval(interval);
}, [isJsonMode, ordinal, targetDay]);
if (isJsonMode) {
const response = {
day,
ordinal,
formatted: `${day}${ordinal}`,
text: `happy october ${day}${ordinal}`,
};
return (
<pre className="w-full max-w-xl overflow-x-auto rounded-2xl bg-muted p-6 font-mono text-sm text-foreground ring-1 ring-foreground/10">
{JSON.stringify(response, null, 2)}
</pre>
);
}
const handleShare = () => {
const message = `happy october ${day}${ordinal}`;
window.open(`sms:?&body=${encodeURIComponent(message)}`, "_blank");
};
return (
<Card className="group relative z-10 mx-auto w-full max-w-[600px] overflow-hidden rounded-3xl border-none bg-background/80 py-0 shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-xl">
<div className="absolute inset-0 -z-10 bg-gradient-to-br from-transparent via-white/5 to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
<CardContent className="p-8 text-center sm:p-12">
<h1 className="mb-8 text-2xl font-medium tracking-tight sm:text-[2rem]">
Today is
</h1>
<div className="my-8" aria-live="polite" aria-busy={isAnimating}>
<h2 className="mb-1 font-heading text-[2.5rem] leading-none tracking-tight sm:text-[3.5rem]">
October{" "}
<span className="relative inline-block font-bold text-primary">
{day}
<span className="absolute -bottom-1 left-0 h-[3px] w-full origin-left scale-x-0 bg-primary transition-transform duration-300 ease-out group-hover:scale-x-100" />
</span>
<sup className="text-[0.6em]">{isAnimating ? "th" : ordinal}</sup>
</h2>
<p className="text-2xl tracking-tight text-muted-foreground">2019.</p>
</div>
<div className="mt-6 flex flex-col justify-center gap-3 sm:flex-row sm:gap-2">
<Button
onClick={handleShare}
className="rounded-xl transition-transform duration-200 hover:-translate-y-0.5"
>
<Share2 />
Share via SMS
</Button>
<Button
asChild
variant="outline"
className="rounded-xl transition-transform duration-200 hover:-translate-y-0.5"
>
<Link
href="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
target="_blank"
rel="noopener noreferrer"
>
<CircleHelp />
Why?
</Link>
</Button>
</div>
</CardContent>
</Card>
);
}