All checks were successful
Deploy / deploy (push) Successful in 18m31s
- Updated AGENTS.md with new guidelines for UI consistency, including badge and modal styles. - Refactored layout.tsx to improve the placement of the progressive blur effect. - Enhanced NotFound component text for better user guidance. - Replaced HeroFocusButton with HeroBaslik and KapanisCta in the Home component for improved clarity. - Added SiteFooter to multiple pages for consistent footer display. - Removed ListemSekmeleri component and adjusted ListemPage to streamline functionality. - Updated various components to ensure consistent styling and user experience.
146 lines
5.2 KiB
TypeScript
146 lines
5.2 KiB
TypeScript
"use client";
|
||
|
||
import { useState } from "react";
|
||
import { usePathname, useRouter } from "next/navigation";
|
||
import {
|
||
ArrowRight,
|
||
ChartNoAxesCombined,
|
||
Database,
|
||
ListChecks,
|
||
} from "lucide-react";
|
||
import { Button } from "@/components/ui/button";
|
||
import { TypingAnimation } from "@/components/ui/typing-animation";
|
||
import { SIHIRBAZ_AC_EVENT, sonucHref } from "@/lib/sihirbaz";
|
||
import {
|
||
profilToplamaAc,
|
||
useTercihProfili,
|
||
} from "@/components/manuel-liste/profil-kapisi-store";
|
||
|
||
const FUNNEL_METINLERI = [
|
||
"Sıralamana en uygun listeyi birlikte kuralım.",
|
||
"Geleceğin 24 satırlık bir plana sığar.",
|
||
"Gerçek YÖK Atlas verisiyle güvenle seç.",
|
||
"Her tercihinin bir nedeni olsun.",
|
||
"Riskleri biz hesaplayalım, kararı sen ver.",
|
||
"Sana uygun bölümler bir adım uzağında.",
|
||
"Dengeli bir liste, rahat bir tercih dönemi.",
|
||
"Tercihlerini şansa bırakma.",
|
||
"Doğru strateji, doğru yerleşme.",
|
||
"Hayalindeki bölüm için doğru plan.",
|
||
"Verilerle konuşan bir tercih listesi.",
|
||
"Üç adımda sana özel 24 tercih.",
|
||
"Tercih dönemini stressiz geçir.",
|
||
"Geçen yılın verisi, senin avantajın.",
|
||
"Güvenli ve iddialı tercihleri dengele.",
|
||
"Sıralaman ne söylüyor? Birlikte bakalım.",
|
||
"Her satırı senin için hesaplıyoruz.",
|
||
"Akıllı tercih, içi rahat bir bekleyiş.",
|
||
"Yerleşme ihtimalini görerek seç.",
|
||
"Sana özel liste birkaç dakikada hazır.",
|
||
"İlgi alanların ve şehrin, tek listede.",
|
||
"Boş kalan tercih, kaçan fırsattır.",
|
||
"Uzman işi bir liste, senin onayınla.",
|
||
"Kararını veriye dayandır.",
|
||
"Doğru tercih, doğru bilgiyle başlar.",
|
||
"Listeni bugün kur, için rahat olsun.",
|
||
"Yerleşme riskin renklerle önünde.",
|
||
"En önemli 24 kararını birlikte verelim.",
|
||
"Senin sıralaman, sana özel plan.",
|
||
"İyi bir liste, iyi bir başlangıçtır.",
|
||
];
|
||
|
||
/** Fisher-Yates ile kopya üzerinde karıştırır; her açılışta farklı sıra. */
|
||
function karistir<T>(dizi: readonly T[]): T[] {
|
||
const kopya = [...dizi];
|
||
for (let i = kopya.length - 1; i > 0; i--) {
|
||
const j = Math.floor(Math.random() * (i + 1));
|
||
[kopya[i], kopya[j]] = [kopya[j], kopya[i]];
|
||
}
|
||
return kopya;
|
||
}
|
||
|
||
const KANITLAR = [
|
||
{ ikon: ListChecks, etiket: "24 tercih" },
|
||
{ ikon: ChartNoAxesCombined, etiket: "Risk analizi" },
|
||
{ ikon: Database, etiket: "YÖK Atlas verisi" },
|
||
];
|
||
|
||
/**
|
||
* Arama modalının açılış ekranında yaşayan satın alım funnel kartı.
|
||
* Rastgele sırayla yazılıp silinen funnel metinleriyle adayı sihirbaza
|
||
* iter: /sonuc üzerindeyse oradaki orkestratörü olayla açar, başka
|
||
* sayfadaysa profile göre /sonuc'a (sihirbaz açık) yönlendirir ya da
|
||
* sıralama kapısını açar. Modal yalnızca açıkken mount olduğundan
|
||
* karıştırma her açılışta yenilenir ve hydration sorunu yaratmaz.
|
||
*/
|
||
export function AramaFunnelKarti({ onSec }: { onSec: () => void }) {
|
||
const router = useRouter();
|
||
const pathname = usePathname();
|
||
const profil = useTercihProfili();
|
||
const [metinler] = useState(() => karistir(FUNNEL_METINLERI));
|
||
|
||
function sihirbazaGit() {
|
||
onSec();
|
||
if (pathname === "/sonuc") {
|
||
window.dispatchEvent(new Event(SIHIRBAZ_AC_EVENT));
|
||
return;
|
||
}
|
||
if (profil) {
|
||
router.push(sonucHref(profil, { sihirbaz: "1" }));
|
||
return;
|
||
}
|
||
profilToplamaAc("sonuc");
|
||
}
|
||
|
||
return (
|
||
<section
|
||
aria-label="Tercih listeni kur"
|
||
className="relative mt-5 overflow-hidden rounded-2xl border border-blue-400/20 bg-[#0b1f3a] px-4 py-5 text-white shadow-[0_20px_50px_-28px_rgba(15,71,150,0.65)] sm:px-5"
|
||
>
|
||
<div
|
||
aria-hidden
|
||
className="pointer-events-none absolute -right-12 -top-16 size-44 rounded-full bg-blue-500/25 blur-3xl"
|
||
/>
|
||
<div
|
||
aria-hidden
|
||
className="pointer-events-none absolute -bottom-14 left-1/3 size-36 rounded-full bg-cyan-400/10 blur-3xl"
|
||
/>
|
||
|
||
<div className="relative grid items-center gap-4 sm:grid-cols-[minmax(0,1fr)_auto] sm:gap-5">
|
||
<div className="min-w-0">
|
||
<TypingAnimation
|
||
as="h3"
|
||
words={metinler}
|
||
loop
|
||
typeSpeed={38}
|
||
deleteSpeed={18}
|
||
pauseDelay={2600}
|
||
className="min-h-[2.75em] font-heading text-base font-bold leading-snug tracking-[-0.02em] sm:min-h-[1.4em] sm:text-lg"
|
||
/>
|
||
|
||
<div className="mt-3 flex flex-wrap gap-x-4 gap-y-2">
|
||
{KANITLAR.map(({ ikon: Ikon, etiket }) => (
|
||
<span
|
||
key={etiket}
|
||
className="inline-flex items-center gap-1.5 text-xs font-medium text-slate-200"
|
||
>
|
||
<Ikon className="size-3.5 text-cyan-300" aria-hidden />
|
||
{etiket}
|
||
</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<Button
|
||
size="lg"
|
||
onClick={sihirbazaGit}
|
||
className="h-11 w-full shrink-0 cursor-pointer rounded-xl bg-orange-500 px-5 font-semibold text-white shadow-[0_8px_24px_rgba(249,115,22,0.28)] transition-[background-color,transform,box-shadow] duration-200 hover:bg-orange-400 hover:shadow-[0_10px_28px_rgba(249,115,22,0.36)] active:scale-[0.98] focus-visible:ring-white/70 sm:w-auto"
|
||
>
|
||
AI listemi kur
|
||
<ArrowRight className="size-4" aria-hidden />
|
||
</Button>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|