Files
kolaytercih/src/components/site-top-banner.tsx
bilalgursen 65d630d754
All checks were successful
Deploy / deploy (push) Successful in 11m11s
Add @number-flow/react dependency and integrate SiteTopBanner component into layout
2026-07-30 12:24:37 +03:00

142 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useEffect, useState } from "react";
import NumberFlow, { NumberFlowGroup } from "@number-flow/react";
import { CalendarDays, Clock3 } from "lucide-react";
const TERCIH_BASLANGICI = new Date("2026-07-29T00:00:00+03:00").getTime();
const TERCIH_BITISI = new Date("2026-08-10T23:59:59+03:00").getTime();
type GeriSayim = {
asama: "baslamadi" | "devam-ediyor" | "sona-erdi";
gun: number;
saat: number;
dakika: number;
saniye: number;
};
function geriSayimiHesapla(simdi: number): GeriSayim {
const asama =
simdi < TERCIH_BASLANGICI
? "baslamadi"
: simdi <= TERCIH_BITISI
? "devam-ediyor"
: "sona-erdi";
const hedef =
asama === "baslamadi" ? TERCIH_BASLANGICI : TERCIH_BITISI;
const kalan = Math.max(0, hedef - simdi);
return {
asama,
gun: Math.floor(kalan / 86_400_000),
saat: Math.floor((kalan % 86_400_000) / 3_600_000),
dakika: Math.floor((kalan % 3_600_000) / 60_000),
saniye: Math.floor((kalan % 60_000) / 1_000),
};
}
const BIRIMLER = [
{ anahtar: "gun", etiket: "gün" },
{ anahtar: "saat", etiket: "sa" },
{ anahtar: "dakika", etiket: "dk" },
{ anahtar: "saniye", etiket: "sn" },
] as const;
export function SiteTopBanner() {
const [geriSayim, setGeriSayim] = useState<GeriSayim | null>(null);
useEffect(() => {
const guncelle = () => setGeriSayim(geriSayimiHesapla(Date.now()));
guncelle();
const zamanlayici = window.setInterval(guncelle, 1_000);
return () => window.clearInterval(zamanlayici);
}, []);
const asamaMetni =
geriSayim?.asama === "baslamadi"
? "Başlamasına"
: geriSayim?.asama === "sona-erdi"
? "Tercih dönemi sona erdi"
: "Sona ermesine";
return (
<section
aria-label="2026 YKS tercih dönemi"
className="relative z-50 border-b border-primary-foreground/15 bg-primary text-primary-foreground print:hidden"
>
<div className="mx-auto flex min-h-12 max-w-6xl flex-wrap items-center justify-center gap-x-5 gap-y-1.5 px-4 py-2 sm:justify-between">
<div className="flex min-w-0 items-center gap-2.5">
<CalendarDays className="size-4 shrink-0 opacity-80" aria-hidden />
<p className="truncate text-sm font-semibold tracking-[-0.01em]">
<span className="hidden sm:inline">2026 YKS tercih dönemi · </span>
<time dateTime="2026-07-29">29 Temmuz</time>
<span aria-hidden> – </span>
<time dateTime="2026-08-10">10 Ağustos 2026</time>
</p>
</div>
<div className="flex items-center gap-2.5" role="timer">
<div className="flex items-center gap-1.5 text-xs font-medium opacity-85">
<Clock3 className="size-3.5" aria-hidden />
<span>{asamaMetni}</span>
</div>
{geriSayim?.asama !== "sona-erdi" ? (
<dl
className="flex items-baseline gap-1 font-mono text-xs tabular-nums"
aria-label={
geriSayim
? `${geriSayim.gun} gün, ${geriSayim.saat} saat, ${geriSayim.dakika} dakika, ${geriSayim.saniye} saniye`
: "Geri sayım yükleniyor"
}
>
<NumberFlowGroup>
{BIRIMLER.map(({ anahtar, etiket }) => (
<div className="flex items-baseline gap-0.5" key={anahtar}>
<dt className="sr-only">{etiket}</dt>
<dd className="font-semibold">
{geriSayim ? (
<NumberFlow
value={geriSayim[anahtar]}
trend={-1}
format={{
minimumIntegerDigits: 2,
useGrouping: false,
}}
transformTiming={{
duration: 280,
easing: "cubic-bezier(0.23, 1, 0.32, 1)",
}}
spinTiming={{
duration: 280,
easing: "cubic-bezier(0.23, 1, 0.32, 1)",
}}
opacityTiming={{
duration: 180,
easing: "ease-out",
}}
willChange={anahtar === "saniye"}
className="inline-block min-w-[2ch] text-right"
aria-hidden
/>
) : (
"--"
)}
<span className="ml-0.5 text-[10px] font-medium opacity-70">
{etiket}
</span>
</dd>
</div>
))}
</NumberFlowGroup>
</dl>
) : null}
</div>
</div>
</section>
);
}