diff --git a/package.json b/package.json index 9848947..30a33ee 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@anthropic-ai/sdk": "^0.112.4", "@cds/city": "^1.1.0", "@libsql/client": "^0.17.4", + "@number-flow/react": "^0.6.2", "@react-pdf/renderer": "^4.5.1", "better-auth": "^1.6.23", "better-sqlite3": "^12.11.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4313df..4089a0d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@libsql/client': specifier: ^0.17.4 version: 0.17.4 + '@number-flow/react': + specifier: ^0.6.2 + version: 0.6.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-pdf/renderer': specifier: ^4.5.1 version: 4.5.1(react@19.2.4) @@ -1240,6 +1243,12 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} + '@number-flow/react@0.6.2': + resolution: {integrity: sha512-WjZuV4aA+vhRCgCF+adGLgFVVAJ8vdvq6EchRT2FiBIgElTXtDOA3YgkcMr9UHpvpS9v4H70AB5wZv0D9jc3QA==} + peerDependencies: + react: ^18 || ^19 + react-dom: ^18 || ^19 + '@opentelemetry/semantic-conventions@1.43.0': resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} engines: {node: '>=14'} @@ -3258,6 +3267,9 @@ packages: jiti: optional: true + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4414,6 +4426,9 @@ packages: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} + number-flow@0.6.2: + resolution: {integrity: sha512-MCnImG4Q5vPwhSXnov56nOuyyKn6LC+Qd7II1UiKc+ACRtug5iAtn0+CwXNxM38AC5lSowEY+oYEtZX2qMnUyw==} + oauth-sign@0.9.0: resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} @@ -6320,6 +6335,13 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} + '@number-flow/react@0.6.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + esm-env: 1.2.2 + number-flow: 0.6.2 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + '@opentelemetry/semantic-conventions@1.43.0': {} '@postman/form-data@3.1.1': @@ -8511,6 +8533,8 @@ snapshots: transitivePeerDependencies: - supports-color + esm-env@1.2.2: {} + espree@10.4.0: dependencies: acorn: 8.17.0 @@ -9837,6 +9861,10 @@ snapshots: path-key: 4.0.0 unicorn-magic: 0.3.0 + number-flow@0.6.2: + dependencies: + esm-env: 1.2.2 + oauth-sign@0.9.0: {} object-assign@4.1.1: {} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 0dcae62..038f64a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,7 @@ import { Cal_Sans, Geist_Mono, Bricolage_Grotesque } from "next/font/google"; import localFont from "next/font/local"; import { Toaster } from "@/components/ui/sonner"; import { SiteHeader } from "@/components/site-header"; +import { SiteTopBanner } from "@/components/site-top-banner"; import { ListeCekmecesi } from "@/components/manuel-liste/liste-cekmecesi"; import { HeaderGate } from "@/components/header-gate"; import { ProgressiveBlur } from "@/components/ui/skiper-ui/skiper41"; @@ -73,6 +74,7 @@ export default function RootLayout({ /> + diff --git a/src/components/site-top-banner.tsx b/src/components/site-top-banner.tsx new file mode 100644 index 0000000..c0ce99f --- /dev/null +++ b/src/components/site-top-banner.tsx @@ -0,0 +1,141 @@ +"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(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 ( + + + + + + 2026 YKS tercih dönemi · + 29 Temmuz + – + 10 Ağustos 2026 + + + + + + + {asamaMetni} + + + {geriSayim?.asama !== "sona-erdi" ? ( + + + {BIRIMLER.map(({ anahtar, etiket }) => ( + + {etiket} + + {geriSayim ? ( + + ) : ( + "--" + )} + + {etiket} + + + + ))} + + + ) : null} + + + + ); +}
+ 2026 YKS tercih dönemi · + 29 Temmuz + – + 10 Ağustos 2026 +