refactor: pazarlama feature'ı — landing + meraklısına taşındı (Faz 5)

- landing/{sosyal-kanit,sosyal-kanit-govde,reveal} + hero-baslik +
  hero-focus-button + turkey-pixel-map features/pazarlama/components/ altına
- app/page.tsx'teki inline ComparisonCell landing-parcalari.tsx'e çıkarıldı
- /meraklisina içeriği MeraklisinaIcerik'e (okumayı pazarlama-queries'in
  meraklisinaDemoVerisi'nden alıyor); sayfa senkron + Suspense; demo.tsx →
  meraklisina-demo.tsx, huni-semasi.tsx feature'a taşındı
- AGENTS.md'deki huni-semasi ve anlatım metni yol referansları aynı commit'te
  güncellendi; SEMA içeriği değişmedi
- Davranış değişikliği yok

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-08-08 01:27:53 +03:00
parent 8b5aa8c8a6
commit baebc1fc80
15 changed files with 228 additions and 185 deletions

View File

@@ -2,7 +2,7 @@ import { NextResponse } from "next/server";
import { sosyalKanitVerisi } from "@/lib/sosyal-kanit";
// Fiyat bölümündeki şeridin canlı sayıyı tazelemek için yokladığı uç.
// İlk değer sunucudan HTML ile geliyor (bkz. components/landing/sosyal-kanit.tsx);
// İlk değer sunucudan HTML ile geliyor (bkz. features/pazarlama/components/sosyal-kanit.tsx);
// burası yalnızca sayfa açık kaldıkça gelen güncellemeler için.
// Sayılar sosyal kanıt, gizli veri değil — kimlik doğrulaması yok.
// Yük: sosyalKanitVerisi kendi içinde TTL önbelleğine sahip, yoklama

View File

@@ -1,251 +0,0 @@
"use client";
// /meraklisina'nın canlı anlatım katmanı: kullanıcının kayıtlı tercih
// profilindeki sıralama + puan türü okunur, dilim şeridi o sıralamanın GERÇEK
// sayılarıyla güncellenir. Profil yoksa sayfa SSR'daki örnek sıralamayla kalır.
// Provider sayfadaki metin bölümlerini (RSC children) sarar; görseller
// context'ten okur. (Sihirbaz hunisi statik bir şemayla anlatılır — bkz.
// huni-semasi.tsx.)
import {
createContext,
useContext,
useEffect,
useState,
type ReactNode,
} from "react";
import Link from "next/link";
import { ArrowRight } from "lucide-react";
import { useTercihProfili } from "@/components/manuel-liste/profil-kapisi-store";
import { PUAN_TURU_ETIKET, sonucHref } from "@/lib/sihirbaz";
import type { DilimKey, SihirbazFacetleri } from "@/types/yokatlas";
export type DemoVeri = {
facetler: SihirbazFacetleri;
dilimToplam: Record<DilimKey, number>;
};
type DemoDurum = {
sira: number;
tur: string;
veri: DemoVeri;
yukleniyor: boolean;
profilVar: boolean;
};
const DemoContext = createContext<DemoDurum | null>(null);
function useDemo(): DemoDurum {
const ctx = useContext(DemoContext);
if (!ctx) throw new Error("Demo bileşenleri SiralamaDemo içinde kullanılmalı");
return ctx;
}
async function facetGetir(
sira: number,
tur: string,
signal: AbortSignal,
): Promise<{ facetler: SihirbazFacetleri; dilimToplam?: Record<DilimKey, number> } | null> {
const params = new URLSearchParams({ sira: String(sira), tur, dilimler: "1" });
try {
const res = await fetch(`/api/facetler?${params}`, { signal });
if (!res.ok) return null;
return (await res.json()) as {
facetler: SihirbazFacetleri;
dilimToplam?: Record<DilimKey, number>;
};
} catch {
return null;
}
}
export function SiralamaDemo({
baslangicSira,
baslangicVeri,
children,
}: {
baslangicSira: number;
baslangicVeri: DemoVeri;
children: ReactNode;
}) {
const profil = useTercihProfili();
const sira = profil?.sira ?? baslangicSira;
const tur = profil?.tur ?? "say";
const [veri, setVeri] = useState(baslangicVeri);
const [yukleniyor, setYukleniyor] = useState(false);
// Profil yüklendi ve SSR örneğinden farklı → ana veriyi tazele
useEffect(() => {
if (sira === baslangicSira && tur === "say") return;
const ctrl = new AbortController();
// eslint-disable-next-line react-hooks/set-state-in-effect -- fetch başlangıç işareti
setYukleniyor(true);
facetGetir(sira, tur, ctrl.signal)
.then((cevap) => {
if (!cevap?.dilimToplam) return;
setVeri({ facetler: cevap.facetler, dilimToplam: cevap.dilimToplam });
})
.finally(() => setYukleniyor(false));
return () => ctrl.abort();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sira, tur]);
const durum: DemoDurum = {
sira,
tur,
veri,
yukleniyor,
profilVar: profil !== null,
};
return <DemoContext.Provider value={durum}>{children}</DemoContext.Provider>;
}
/** Görsellerin hangi sıralamayla hesaplandığını söyleyen bilgi kartı. */
export function DemoKumanda() {
const { sira, tur, yukleniyor, profilVar } = useDemo();
const turEtiket = PUAN_TURU_ETIKET[tur] ?? tur;
return (
<div className="rounded-2xl border border-primary/20 bg-primary/5 p-5">
<p className="font-heading text-sm font-bold text-slate-900">
{profilVar
? "Görseller senin sıralamana göre hesaplandı"
: "Görseller örnek bir sıralamayla gösteriliyor"}
</p>
<p
className={`mt-2 text-sm text-slate-600 ${yukleniyor ? "animate-pulse" : ""}`}
aria-live="polite"
>
{yukleniyor ? (
"Hesaplanıyor…"
) : (
<>
<span className="font-semibold tabular-nums text-slate-900">
{sira.toLocaleString("tr-TR")}.
</span>{" "}
sıra · {turEtiket} aşağıdaki tüm sayılar bu aday için gerçek YÖK
Atlas verisidir.
{!profilVar &&
" Ana sayfadan kendi sıralamanı girersen bu sayfa sana göre güncellenir."}
</>
)}
</p>
</div>
);
}
/** Sıralama ekseni: adayın sırasına göre dilim sınırları ve gerçek adetler. */
export function DilimSeridiCanli() {
const { sira, veri, yukleniyor } = useDemo();
const t = veri.dilimToplam;
const dengeliUst = Math.round(sira * 1.4);
const fmt = (n: number) => n.toLocaleString("tr-TR");
return (
<figure className={`mt-6 ${yukleniyor ? "animate-pulse opacity-60" : ""}`}>
<svg
viewBox="0 0 640 168"
role="img"
aria-label={`Sıralama ekseni: ${fmt(sira)}. sıradaki aday için Hayal diliminde ${fmt(t.hayal)}, Dengeli diliminde ${fmt(t.dengeli)}, Garanti diliminde ${fmt(t.garanti)} program var.`}
className="w-full"
>
{/* eksen */}
<line
x1="20"
y1="86"
x2="620"
y2="86"
stroke="currentColor"
className="text-slate-300"
strokeWidth="2"
/>
<text x="20" y="150" className="fill-slate-400 text-[11px]">
1. sıra (en iyi)
</text>
<text
x="620"
y="150"
textAnchor="end"
className="fill-slate-400 text-[11px]"
>
taban sıralaması büyüdükçe
</text>
{/* hayal */}
<rect x="20" y="70" width="150" height="32" rx="4" className="fill-red-100" />
<text x="95" y="40" textAnchor="middle" className="fill-red-600 text-[12px] font-semibold">
Hayal
</text>
<text x="95" y="56" textAnchor="middle" className="fill-slate-600 text-[11px] font-medium tabular-nums">
{fmt(t.hayal)} program
</text>
<text x="95" y="123" textAnchor="middle" className="fill-slate-500 text-[10px]">
tabanı senden iyi
</text>
{/* aday işareti */}
<line x1="172" y1="24" x2="172" y2="112" stroke="currentColor" className="text-slate-900" strokeWidth="2" strokeDasharray="4 3" />
<text x="172" y="16" textAnchor="middle" className="fill-slate-900 text-[12px] font-bold">
SEN · {fmt(sira)}.
</text>
{/* dengeli */}
<rect x="174" y="70" width="120" height="32" rx="4" className="fill-amber-100" />
<text x="234" y="40" textAnchor="middle" className="fill-amber-600 text-[12px] font-semibold">
Dengeli
</text>
<text x="234" y="56" textAnchor="middle" className="fill-slate-600 text-[11px] font-medium tabular-nums">
{fmt(t.dengeli)} program
</text>
<text x="234" y="123" textAnchor="middle" className="fill-slate-500 text-[10px]">
{fmt(sira)}. {fmt(dengeliUst)}. arası taban
</text>
{/* garanti */}
<rect x="296" y="70" width="324" height="32" rx="4" className="fill-emerald-100" />
<text x="458" y="40" textAnchor="middle" className="fill-emerald-700 text-[12px] font-semibold">
Garanti
</text>
<text x="458" y="56" textAnchor="middle" className="fill-slate-600 text-[11px] font-medium tabular-nums">
{fmt(t.garanti)} program
</text>
<text x="458" y="123" textAnchor="middle" className="fill-slate-500 text-[10px]">
{fmt(dengeliUst + 1)}. sonrası sonu yok, sayfaladıkça uzar
</text>
</svg>
<figcaption className="mt-2 text-xs text-slate-500">
Liste her dilimde{" "}
<span className="font-medium text-slate-700">
sana en yakın tabandan uzağa doğru
</span>{" "}
sıralanır; &ldquo;Daha fazla göster&rdquo; dedikçe uzaktakiler gelir.
</figcaption>
</figure>
);
}
/**
* Sayfanın kapanış kartı: profili olmayan ziyaretçiyi ana sayfadaki sıralama
* formuna, sıralamasını zaten girmiş adayı ise doğrudan sonuç sayfasına
* gönderir — "sıralamanı gir" CTA'sı profil varken gösterilmez.
*/
export function DemoKapanisCta() {
const profil = useTercihProfili();
return (
<div className="rounded-2xl border border-slate-200 bg-white p-6 text-center">
<p className="font-heading text-base font-bold text-slate-900">
{profil
? "Kuralları öğrendin — sayılar zaten senin sıralamanla hesaplandı."
: "Kuralları öğrendin — şimdi kendi sıralamanla dene."}
</p>
<Link
href={profil ? sonucHref(profil) : "/"}
className="mt-3 inline-flex items-center gap-1.5 rounded-full bg-orange-500 px-5 py-2.5 text-sm font-medium text-white transition-colors duration-200 hover:bg-orange-600"
>
{profil ? "Sıralamana uygun programları gör" : "Sıralamanı gir"}
<ArrowRight className="size-4" aria-hidden />
</Link>
</div>
);
}

View File

@@ -1,58 +0,0 @@
// Sihirbaz hunisinin statik anlatımı: interaktif demo yerine akışın tamamını
// tek bakışta gösteren bir mermaid şeması. Çizim, ürün genelindeki ortak
// "el çizimi" bileşeniyle yapılır (bkz. features/rehber/components/el-cizimi-sema.tsx).
import { ElCizimiSema } from "@/features/rehber/components/el-cizimi-sema";
// Renkler ürünün risk dilinden (kırmızı/sarı/yeşil) ve slate paletinden;
// renk tek başına anlam taşımaz, her düğüm metinle etiketlidir.
const SEMA = `---
config:
look: handDrawn
---
flowchart TD
T("Sıralamanla açılan tüm programlar") --> A("1. adım · Alan seçimi<br/>yalnızca ulaşabildiğin alanlar listelenir")
A --> B("2. adım · İl seçimi<br/>iller, seçtiğin alanlardaki program sayısına göre yeniden sayılır")
B --> C("3. adım · Devlet / Vakıf<br/>sayılar hem alanı hem ili hesaba katar")
C --> H("Aday havuzu<br/>elde kalan gerçek programlar")
H --> S{"Havuzda 24'ten az program mı kaldı?"}
S -- "evet" --> G("Filtreler adım adım gevşetilir<br/>önce il, sonra alan — listede açıkça belirtilir")
G --> H
H --> U("Havuz yine de dar kalırsa<br/>liste eldeki programlarla kurulur, dağılım havuza uyarlanır ve sana açıkça söylenir")
S -- "hayır" --> Y("Yapay zekâ havuzdan en fazla 24 tercih seçer<br/>havuzda olmayan bölümü yazamaz, her satıra gerekçe yazar")
U --> Y
Y --> R("Risk notu ve trend özeti<br/>gerçek sıralama geçmişinden hesaplanır, yapay zekâ yorumu değildir")
R --> L("En fazla 24 tercihlik liste")
L --> L1("üstte hayal — hedef 5, havuz elverdiğince")
L --> L2("ortada dengeli — hedef 13, havuz elverdiğince")
L --> L3("sonda garanti — hedef 6, havuz elverdiğince")
classDef havuz fill:#eff6ff,stroke:#3b82f6,color:#1e3a8a
classDef uyari fill:#fffbeb,stroke:#f59e0b,color:#92400e
classDef hayal fill:#fee2e2,stroke:#ef4444,color:#991b1b
classDef dengeli fill:#fef3c7,stroke:#f59e0b,color:#92400e
classDef garanti fill:#d1fae5,stroke:#10b981,color:#065f46
class H,Y havuz
class G,U uyari
class L1 hayal
class L2 dengeli
class L3 garanti`;
export function HuniSemasi() {
return (
<ElCizimiSema
tanim={SEMA}
ariaLabel="Sihirbaz akış şeması: sıralamanla açılan programlar alan, il ve devlet/vakıf adımlarıyla aday havuzuna daraltılır; havuz 24'ün altına düşerse filtreler gevşetilir, yine de dar kalırsa liste eldeki programlarla kurulur ve dağılım havuza uyarlanır; yapay zekâ havuzdan üstte hayal, ortada dengeli, sonda garanti olacak şekilde en fazla 24 tercih seçip her satıra gerekçe yazar; risk notu ve trend özeti gerçek sıralama geçmişinden hesaplanır."
figcaption={
<>
Her adım havuzu biraz daha daraltır; yapay zekâ listeyi bu havuzun{" "}
<span className="font-medium text-slate-700">
dışına asla çıkmadan
</span>{" "}
kurar havuz dar kalırsa liste eldeki programlarla kurulur ve bunu
listende ıkça görürsün.
</>
}
/>
);
}

View File

@@ -1,17 +1,12 @@
import { Suspense } from "react";
import type { Metadata } from "next";
import { Parallax } from "@/components/parallax";
import { PagePixelDivider, SectionEyebrow } from "@/components/pixel-decor";
import { SiteFooter } from "@/components/site-footer";
import { dilimAra, rankWindowFacets } from "@/lib/db";
import type { DilimKey } from "@/types/yokatlas";
import {
DemoKapanisCta,
DemoKumanda,
DilimSeridiCanli,
SiralamaDemo,
type DemoVeri,
} from "./demo";
import { HuniSemasi } from "./huni-semasi";
MeraklisinaIcerik,
MeraklisinaIcerikSkeleton,
} from "@/features/pazarlama/components/meraklisina-icerik";
export const metadata: Metadata = {
title: "Meraklısına: KolayTercih nasıl çalışır?",
@@ -20,164 +15,30 @@ export const metadata: Metadata = {
"Sıralamanı girdiğinde arka planda ne oluyor? Dilimler, risk renkleri ve sihirbazın adım adım daralan filtreleri — öğrenci diliyle, sıralamana göre hesaplanan canlı görsellerle.",
};
/**
* Algoritmanın öğrenci diline çevrilmiş anlatımı. Teknik detay (SQL, çarpan
* mutfağı) bilerek verilmez; amaç güven: veri gerçek, kurallar şeffaf.
* Dilim şeridi canlıdır: kullanıcının kayıtlı tercih profilindeki sıralama
* okunur, şerit o sıralamanın gerçek sayılarıyla güncellenir (bkz. demo.tsx);
* profil yoksa örnek sıralama gösterilir. Sihirbaz hunisi ise statik
* bir mermaid şemasıyla anlatılır (bkz. huni-semasi.tsx).
* Diyagramlar ürünün risk renk dilini kullanır (yeşil/sarı/kırmızı) ve her
* bölge metinle de etiketlenir — renk tek başına anlam taşımaz.
*/
// Profili olmayan ziyaretçi bu örnek sıralamayı görür; SSR'da gerçek veriyle
// render edilir ki profil olmadan da sayfa anlamlı olsun.
const VARSAYILAN_SIRA = 100_000;
export default function MeraklisinaPage() {
const dilimToplam = Object.fromEntries(
(["hayal", "dengeli", "garanti"] as DilimKey[]).map((d) => [
d,
dilimAra(VARSAYILAN_SIRA, "say", d, { limit: 0 }).toplam,
]),
) as Record<DilimKey, number>;
const baslangicVeri: DemoVeri = {
facetler: rankWindowFacets(VARSAYILAN_SIRA, "say"),
dilimToplam,
};
return (
<>
<main className="mx-auto w-full max-w-2xl px-4 py-16">
<Parallax fromStart strength={10}>
<SectionEyebrow>Meraklısına</SectionEyebrow>
<h1 className="mt-3 font-heading text-3xl font-bold">
Sıralamanı girince arka planda ne oluyor?
</h1>
<p className="mt-3 text-slate-600">
Sihir yok, kara kutu yok: KolayTercih&apos;in önerdiği her satır resmî
YÖK Atlas verisinden gelir ve hangi kurala göre önüne geldiği bellidir.
Bu sayfa o kuralları öğrenci diliyle anlatır üstelik görseller
canlı: sıralamanı girdiysen sayılar sana göre hesaplanır.
</p>
</Parallax>
<PagePixelDivider seed={73} className="mt-6" />
<SiralamaDemo
baslangicSira={VARSAYILAN_SIRA}
baslangicVeri={baslangicVeri}
>
<Parallax
fromStart
strength={4}
className="mt-8 space-y-10 text-sm leading-7 text-slate-700"
>
<section>
<h2 className="font-heading text-lg font-bold text-slate-900">
1. Her şey taban sıralamasıyla başlar
</h2>
<p className="mt-2">
Bir bölümün <strong>taban sıralaması</strong>, geçen yıl o bölüme
yerleşen <em>son</em>{" "}
öğrencinin Türkiye sıralamasıdır. Senin sıralaman bu sayıdan
küçükse (yani daha iyiysen), geçen yılın koşullarında o bölüme
yerleşebilirdin demektir. Sistemde her programın en güncel taban
sıralaması kayıtlıdır; bir bölümün 2025 verisi henüz oluşmamışsa
bir önceki yılınki kullanılır.
</p>
</section>
<DemoKumanda />
<section>
<h2 className="font-heading text-lg font-bold text-slate-900">
2. Programlar üç dilime ayrılır
</h2>
<p className="mt-2">
Sıralamanı girdiğinde tüm programlar senin konumuna göre üç kümeye
ayrılır: tabanı senden <strong>daha iyi</strong> olanlar{" "}
<span className="font-semibold text-red-600">Hayal</span> (şansını
denediğin satırlar), tabanı sıralamana{" "}
<strong>yakın</strong> olanlar{" "}
<span className="font-semibold text-amber-600">Dengeli</span>{" "}
(listenin bel kemiği sıralamanın yaklaşık yüzde kırk fazlasına
kadar pay bırakılır), tabanı{" "}
<strong>belirgin şekilde altında</strong> kalan her şey ise{" "}
<span className="font-semibold text-emerald-600">Garanti</span>{" "}
dilimidir.
</p>
<DilimSeridiCanli />
<p className="mt-4">
Garanti diliminin bir sonu yok: 87. sıradaki bir adayın da 500
bininci sıradaki bir adayın da ulaşabildiği <em>bütün</em>{" "}
programlar listededir. Liste sana en yakın tabandan başlar; aşağı
indikçe ve &ldquo;Daha fazla göster&rdquo;e bastıkça senden
uzaklaşan seçenekler gelir. Böylece ilk gördüklerin her zaman en
isabetli adaylardır ama hiçbir seçenek senden saklanmaz.
</p>
</section>
<section>
<h2 className="font-heading text-lg font-bold text-slate-900">
3. Risk renkleri her yerde aynı dili konuşur
</h2>
<p className="mt-2">
Tabloda, haritada ve yapay zekâ listesinde gördüğün nokta ve
renkler tek bir kurala bağlıdır:{" "}
<span className="font-semibold text-emerald-600">yeşil</span>{" "}
tabanı sıralamanın belirgin altında (güvenli),{" "}
<span className="font-semibold text-amber-600">sarı</span>{" "}
sıralamana yakın (az riskli),{" "}
<span className="font-semibold text-red-600">kırmızı</span>{" "}
tabanı senden iyi (riskli). Renk hangi sayfada olursa olsun aynı
hesaptan çıkar; bir satır sekme değiştirdi diye renk değiştirmez.
</p>
</section>
<section>
<h2 className="font-heading text-lg font-bold text-slate-900">
4. Sihirbaz süzer, yapay zekâ kurar
</h2>
<p className="mt-2">
&ldquo;Yapay Zeka listemi kur&rdquo; sihirbazındaki üç adım birbirinden
bağımsız değildir. İlk adımda yalnızca{" "}
<strong>sıralamanla ulaşabildiğin</strong>{" "}
alanlar listelenir; ikinci adımdaki iller, seçtiğin alanlardaki
program sayısına göre yeniden hesaplanır; üçüncü adımdaki
devlet/vakıf sayıları da hem alan hem il seçimini hesaba katar.
Adımlar bitince elde kalan gerçek programlar bir{" "}
<strong>aday havuzu</strong>{" "}
olur ve yapay zekâya öyle gider: ona boş bir sayfa değil, bu havuz
verilir. Aşağıdaki şema akışın tamamını gösterir havuz
24&apos;ün altına düşerse filtrelerin nasıl gevşetildiği, yine de
yetmezse listenin eldeki programlarla, sana ıkça belirtilerek
nasıl kurulduğu da dahil.
</p>
<HuniSemasi />
</section>
<section>
<h2 className="font-heading text-lg font-bold text-slate-900">
5. Dürüst olalım: bu bir tahmin aracıdır
</h2>
<p className="mt-2">
Tüm bu hesaplar <strong>geçen yılların</strong>{" "}
yerleştirme sonuçlarına dayanır. Kontenjanlar, tercih davranışları
ve puanlar her yıl değişir; geçen yıl &ldquo;garanti&rdquo;
görünen bir bölüm bu yıl dolabilir. Bu yüzden satırlarda son beş
yılın taban seyrini de gösteririz çizgi yukarı tırmanıyorsa
bölüm zorlaşıyor demektir. KolayTercih karar <em>destek</em>{" "}
aracıdır; listenin son hâli ve sorumluluğu her zaman sana aittir.
</p>
</section>
<DemoKapanisCta />
<main className="mx-auto w-full max-w-2xl px-4 py-16">
<Parallax fromStart strength={10}>
<SectionEyebrow>Meraklısına</SectionEyebrow>
<h1 className="mt-3 font-heading text-3xl font-bold">
Sıralamanı girince arka planda ne oluyor?
</h1>
<p className="mt-3 text-slate-600">
Sihir yok, kara kutu yok: KolayTercih&apos;in önerdiği her satır resmî
YÖK Atlas verisinden gelir ve hangi kurala göre önüne geldiği bellidir.
Bu sayfa o kuralları öğrenci diliyle anlatır üstelik görseller
canlı: sıralamanı girdiysen sayılar sana göre hesaplanır.
</p>
</Parallax>
</SiralamaDemo>
</main>
<SiteFooter />
<PagePixelDivider seed={73} className="mt-6" />
<Suspense fallback={<MeraklisinaIcerikSkeleton />}>
<MeraklisinaIcerik />
</Suspense>
</main>
<SiteFooter />
</>
);
}

View File

@@ -2,7 +2,6 @@ import {
ArrowRight,
ArrowUpRight,
BarChart3,
CheckCircle2,
Coins,
Compass,
FileText,
@@ -12,18 +11,18 @@ import {
ShieldCheck,
TrendingUp,
Wallet,
X,
} from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { Suspense } from "react";
import { HeroBaslik } from "@/components/hero-baslik";
import { KapanisCta } from "@/components/hero-focus-button";
import { ComparisonCell } from "@/features/pazarlama/components/landing-parcalari";
import { HeroBaslik } from "@/features/pazarlama/components/hero-baslik";
import { KapanisCta } from "@/features/pazarlama/components/hero-focus-button";
import { HeroForm } from "@/components/hero-form";
import { Parallax } from "@/components/parallax";
import { Reveal } from "@/components/landing/reveal";
import { SosyalKanitBandi } from "@/components/landing/sosyal-kanit";
import { TurkeyPixelMap } from "@/components/turkey-pixel-map";
import { Reveal } from "@/features/pazarlama/components/reveal";
import { SosyalKanitBandi } from "@/features/pazarlama/components/sosyal-kanit";
import { TurkeyPixelMap } from "@/features/pazarlama/components/turkey-pixel-map";
import {
PixelCorner,
PixelDivider,
@@ -188,17 +187,6 @@ const paketOzellikleri = [
},
] as const;
function ComparisonCell({ value }: { value: boolean | string }) {
if (typeof value === "string") {
return <span className="text-sm font-medium">{value}</span>;
}
return value ? (
<CheckCircle2 className="mx-auto size-5 text-primary" aria-label="Var" />
) : (
<X className="mx-auto size-5 text-muted-foreground/50" aria-label="Yok" />
);
}
export default function Home() {
return (
<div