fix(sonuc): harita en üste çıkar, liste sayısı çerezi kaymayı sıfırlar
Manuel listenin haritası /sonuc'ta tablonun altından sayfanın en üstüne alındı: listesini kurmuş ziyaretçi ekranda önce kendi listesini görür. Liste boşken harita DOM'a hiç girmez — yer tutucu da çizilmez, tadımlık main'in ilk çocuğu kalır ve first:mt-0 çalışmayı sürdürür. Yani ürünü ilk kez gören ziyaretçide sayfa sırası hiç değişmiyor. Çerez neden gerekti: manuel liste localStorage'ta yaşıyor, store'un sunucu snapshot'ı her zaman boş liste dönüyor. Harita yukarıdayken kayıtlı liste ancak hidrasyondan sonra okunabildiği için harita sonradan belirip sayfayı itiyordu (mobilde ~146 px, masaüstünde ~368 px; CLS ~0,13 / ~0,35). Client artık listenin yalnızca UZUNLUĞUNU kolaytercih.liste-sayi çerezine aynalıyor (kişisel veri ya da program kimliği yok, öznitelikleri kolaytercih.profil ile birebir aynı); sunucu bunu okuyup haritaya ilk boyada tam ölçülü yer ayırıyor, chunk inince kutunun yalnızca içi doluyor. Çerez hidrasyona kadar geçerli: store okunduktan sonra tek doğru kaynak listenin kendisi, böylece bayat çerez ya da çekmeceden boşaltılan liste durumunda boş harita ekranda kalmıyor. Yanında: harita iskeletine motion-reduce:animate-none (artık katlamanın üstünde, durdurulamaz nabız gösterilmemeli), yurt dışı şeridine sabit yükseklikli loading yer tutucu (ssr:false + loading'siz dynamic, yoktan beliren ~104 px). Kararın tersini belgeleyen üç yorum bloğu da güncellendi. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
|||||||
SonucProgramTablosuSkeleton,
|
SonucProgramTablosuSkeleton,
|
||||||
} from "@/features/liste/components/sonuc-program-tablosu";
|
} from "@/features/liste/components/sonuc-program-tablosu";
|
||||||
import { ManuelHarita } from "@/features/liste/components/manuel-harita";
|
import { ManuelHarita } from "@/features/liste/components/manuel-harita";
|
||||||
|
import { LISTE_SAYI_CEREZ_ADI } from "@/features/liste/liste-dogrula";
|
||||||
import { TadimlikBolumu } from "@/features/rapor/components/tadimlik-bolumu";
|
import { TadimlikBolumu } from "@/features/rapor/components/tadimlik-bolumu";
|
||||||
import { SonucSihirbazi } from "@/features/sihirbaz/components/sihirbaz-bolumu";
|
import { SonucSihirbazi } from "@/features/sihirbaz/components/sihirbaz-bolumu";
|
||||||
import { SiraGerekli } from "@/features/sihirbaz/components/sira-gerekli";
|
import { SiraGerekli } from "@/features/sihirbaz/components/sira-gerekli";
|
||||||
@@ -85,6 +86,17 @@ export default function SonucPage({
|
|||||||
const uniturGrubu =
|
const uniturGrubu =
|
||||||
tipHam === "devlet" || tipHam === "vakif" ? tipHam : undefined;
|
tipHam === "devlet" || tipHam === "vakif" ? tipHam : undefined;
|
||||||
|
|
||||||
|
// Manuel liste localStorage'ta yaşar; store'un sunucu snapshot'ı her
|
||||||
|
// zaman boştur. Client, listenin yalnızca UZUNLUĞUNU çereze aynalar
|
||||||
|
// (liste-store.ts) — sunucunun "bu ziyaretçinin listesi var" bilgisini
|
||||||
|
// hidrasyondan ÖNCE alabildiği tek kanal bu. Sayı > 0 ise haritaya tam
|
||||||
|
// ölçülü yer ayrılır; çerez yoksa/0 ise harita hiç render edilmez.
|
||||||
|
const listeSayisi = Number.parseInt(
|
||||||
|
cerezler.get(LISTE_SAYI_CEREZ_ADI)?.value ?? "",
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
const haritayaYerAyir = Number.isFinite(listeSayisi) && listeSayisi > 0;
|
||||||
|
|
||||||
if (!Number.isFinite(sira) || sira < 1 || sira > 4_000_000) {
|
if (!Number.isFinite(sira) || sira < 1 || sira > 4_000_000) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -97,21 +109,26 @@ export default function SonucPage({
|
|||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-slate-50 text-slate-900">
|
<div className="min-h-screen bg-slate-50 text-slate-900">
|
||||||
<main className="mx-auto max-w-4xl px-4 py-12">
|
<main className="mx-auto max-w-4xl px-4 py-12">
|
||||||
{/* Sayfa hiyerarşisi: tadımlık → ham tablo → manuel listenin
|
{/* Sayfa hiyerarşisi: manuel listenin haritası → tadımlık → ham
|
||||||
haritası. Tadımlık, ödeme öncesi gösterebildiğimiz TEK gerçek
|
tablo. İki farklı ziyaretçi, iki farklı ilk ekran:
|
||||||
önizleme olduğu için ilk ekranda durur.
|
|
||||||
|
|
||||||
Harita neden TABLONUN ALTINDA: liste store'unun sunucu
|
• Listesi OLAN ziyaretçi ekranda önce kendi kurduğu listeyi
|
||||||
snapshot'ı her zaman boş liste döner (liste-store.ts), kayıtlı
|
görür — o kişi "bu ürün ne?" aşamasını geçmiştir.
|
||||||
liste ancak hidrasyondan sonra okunur. Harita yukarıda olsaydı
|
• Listesi OLMAYAN ziyaretçide harita DOM'a hiç girmez
|
||||||
dönüş ziyaretçisinde sayfa açıldıktan saniyeler sonra ~368 px
|
(manuel-harita.tsx), sıra bugünküyle birebir aynı kalır:
|
||||||
yüksekliğinde belirip tadımlığı ve tabloyu aşağı itecekti
|
tadımlık → tablo. Tadımlık, ödeme öncesi gösterebildiğimiz
|
||||||
(impact fraction ~1, CLS eşiğinin çok üstü). Aşağıda belirince
|
TEK gerçek önizleme olduğu için o kişide ilk ekranda durur
|
||||||
yalnızca sihirbaz ile dipnotu iter, ikisi de katlanın altında.
|
ve `first:mt-0` ile main'in py-12'sini kullanmayı sürdürür.
|
||||||
Bilgi mimarisi olarak da doğru sıra: harita, tablodan kurulan
|
|
||||||
listenin görselleştirmesidir. Liste boşken hiç render edilmez
|
Harita YUKARIDA nasıl CLS üretmiyor: kayıtlı liste ancak
|
||||||
(bkz. manuel-harita.tsx); store'a abone olduğu için tablodan
|
hidrasyondan sonra localStorage'tan okunabildiği için harita
|
||||||
"+" ile eklenenler buraya canlı yansır. */}
|
yukarıdayken sonradan belirip sayfayı iterdi (mobilde ~146 px,
|
||||||
|
masaüstünde ~368 px). Çözüm, listenin SAYISINI çerezle
|
||||||
|
sunucuya aynalamak (haritayaYerAyir, yukarısı): sunucu ilk
|
||||||
|
boyada haritanın tam ölçülü kutusunu çizer, chunk inince
|
||||||
|
kutunun yalnızca İÇİ dolar. Haritanın yerini bir daha
|
||||||
|
aşağı almadan önce bu mekanizmayı kontrol et. */}
|
||||||
|
<ManuelHarita yerAyir={haritayaYerAyir} />
|
||||||
|
|
||||||
{/* Girişsiz tadımlık: gerçek rapor satırı formatında tek örnek.
|
{/* Girişsiz tadımlık: gerçek rapor satırı formatında tek örnek.
|
||||||
Havuzda içerik yoksa bileşen hiç render edilmez. */}
|
Havuzda içerik yoksa bileşen hiç render edilmez. */}
|
||||||
@@ -128,8 +145,6 @@ export default function SonucPage({
|
|||||||
uniturGrubu={uniturGrubu}
|
uniturGrubu={uniturGrubu}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ManuelHarita />
|
|
||||||
|
|
||||||
{/* Sihirbaz akışı (CTA + modal) — üretim ve liste /listem'de
|
{/* Sihirbaz akışı (CTA + modal) — üretim ve liste /listem'de
|
||||||
yaşar, burada yalnızca funnel kartları render edilir */}
|
yaşar, burada yalnızca funnel kartları render edilir */}
|
||||||
<SonucSihirbazi
|
<SonucSihirbazi
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import type { HaritaPin } from "@/features/liste/components/tercih-haritasi";
|
|||||||
import { ilKonum, uniAdiNormalize, uniKonum } from "@/lib/harita";
|
import { ilKonum, uniAdiNormalize, uniKonum } from "@/lib/harita";
|
||||||
import { yurtdisiPinKaydet, type YurtdisiPin } from "@/lib/harita-pinler";
|
import { yurtdisiPinKaydet, type YurtdisiPin } from "@/lib/harita-pinler";
|
||||||
import type { RiskSeviyesi } from "@/lib/risk";
|
import type { RiskSeviyesi } from "@/lib/risk";
|
||||||
import { useManuelListe } from "../liste-store";
|
import { useListeHidreMi, useManuelListe } from "../liste-store";
|
||||||
|
|
||||||
// Aynı üniversitede birden çok tercih varsa pinde kötü risk baskın olsun
|
// Aynı üniversitede birden çok tercih varsa pinde kötü risk baskın olsun
|
||||||
const RISK_AGIRLIK: Record<RiskSeviyesi, number> = {
|
const RISK_AGIRLIK: Record<RiskSeviyesi, number> = {
|
||||||
@@ -20,8 +20,9 @@ const RISK_AGIRLIK: Record<RiskSeviyesi, number> = {
|
|||||||
riskli: 2,
|
riskli: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ManuelHarita() {
|
export function ManuelHarita({ yerAyir = false }: { yerAyir?: boolean }) {
|
||||||
const liste = useManuelListe();
|
const liste = useManuelListe();
|
||||||
|
const hidre = useListeHidreMi();
|
||||||
const [seciliIl, setSeciliIl] = useState<string | null>(null);
|
const [seciliIl, setSeciliIl] = useState<string | null>(null);
|
||||||
|
|
||||||
const { pinler, yurtdisiPinler, haritaDisi } = useMemo(() => {
|
const { pinler, yurtdisiPinler, haritaDisi } = useMemo(() => {
|
||||||
@@ -64,18 +65,30 @@ export function ManuelHarita() {
|
|||||||
};
|
};
|
||||||
}, [liste]);
|
}, [liste]);
|
||||||
|
|
||||||
// Liste boşken hiç yer tutulmaz: boş harita /sonuc'un ilk ekranını işgal
|
// Liste boşken hiç yer tutulmaz: hiç liste kurmamış ziyaretçide harita
|
||||||
// ediyordu, oysa ödeme öncesi ilk ekranda durması gereken şey tadımlık.
|
// DOM'a girmez, yer tutucu da çizilmez (Bilal'in açık şartı). İlk "+" ile
|
||||||
// İlk "+" ile liste dolunca harita kendiliğinden belirir; 197 KB'lık il
|
// liste dolunca harita kendiliğinden belirir.
|
||||||
// geometrisi yine ancak o anda iner (TercihHaritasiLazy zaten `dynamic`).
|
//
|
||||||
if (liste.length === 0) return null;
|
// yerAyir: sunucu, kullanıcının kayıtlı bir listesi OLDUĞUNU biliyorsa
|
||||||
|
// (LISTE_SAYI_CEREZ_ADI çerezi > 0) bu bayrağı verir. Liste ancak
|
||||||
|
// hidrasyondan sonra localStorage'tan okunduğu için ilk boyada `liste` hâlâ
|
||||||
|
// boştur; bayrak olmadan harita sonradan belirip sayfayı iterdi. Boş+yerAyir
|
||||||
|
// durumunda AYRI bir iskelet dalı yazmıyoruz: fonksiyon akar, `pinler` boş
|
||||||
|
// dizi olur ve TercihHaritasiLazy chunk inene kadar zaten HaritaIskeleti'ni
|
||||||
|
// gösterir — böylece yer tutucu ile gerçek harita aynı kutudan gelir
|
||||||
|
// (yükseklik ayrışamaz) ve 197 KB'lık chunk hidrasyonu beklemeden inmeye
|
||||||
|
// başlar.
|
||||||
|
//
|
||||||
|
// yerAyir yalnızca hidrasyona KADAR geçerlidir: store okunduktan sonra tek
|
||||||
|
// doğru kaynak listenin kendisidir. Böylece hem bayat çerez (localStorage
|
||||||
|
// silinmiş, çerez kalmış) hem de kullanıcının çekmeceden listeyi boşaltması
|
||||||
|
// durumunda boş harita ekranda kalmaz.
|
||||||
|
if (liste.length === 0 && (hidre || !yerAyir)) return null;
|
||||||
|
|
||||||
// mt-16: /sonuc'ta harita artık tablonun ALTINDA duruyor (bkz. sonuc/page.tsx)
|
// Margin yok: harita /sonuc'ta main'in İLK çocuğudur, üst boşluğunu
|
||||||
// ve sayfanın bölüm ritmini paylaşıyor — tablo <section>'ı ve sihirbaz
|
// main'in py-12'sinden alır (bkz. sonuc/page.tsx).
|
||||||
// kartları da mt-16 kullanır. Eskiden main'in ilk çocuğu olduğu için üst
|
|
||||||
// boşluğu main'in py-12'sinden alıyordu, kendi margin'i yoktu.
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-16">
|
<div>
|
||||||
<TercihHaritasiLazy
|
<TercihHaritasiLazy
|
||||||
pinler={pinler}
|
pinler={pinler}
|
||||||
seciliIl={seciliIl}
|
seciliIl={seciliIl}
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
// çizileceği zaman insin: dynamic + ssr'siz. İskelet, haritanın gerçek
|
// çizileceği zaman insin: dynamic + ssr'siz. İskelet, haritanın gerçek
|
||||||
// oranını (viewBox 1050 × 447, bkz. tercih-haritasi TAM_GORUNUM) rezerve
|
// oranını (viewBox 1050 × 447, bkz. tercih-haritasi TAM_GORUNUM) rezerve
|
||||||
// eder — chunk gelince yerleşim zıplamaz.
|
// eder — chunk gelince yerleşim zıplamaz.
|
||||||
|
//
|
||||||
|
// motion-reduce:animate-none: iskelet artık /sonuc'ta katlamanın üstünde
|
||||||
|
// duruyor; hareketi azaltılmış isteyen kullanıcıya sürekli, durdurulamaz
|
||||||
|
// nabız gösterilmez.
|
||||||
|
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
|
|
||||||
@@ -11,7 +15,7 @@ export function HaritaIskeleti() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
aria-hidden
|
aria-hidden
|
||||||
className="aspect-[1050/447] w-full animate-pulse rounded-xl bg-slate-100"
|
className="aspect-[1050/447] w-full animate-pulse rounded-xl bg-slate-100 motion-reduce:animate-none"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,14 @@
|
|||||||
|
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
|
|
||||||
|
// loading: chunk inene kadar şeridin yüksekliğini rezerve eder. Türkiye
|
||||||
|
// haritası /sonuc'un en üstüne çıktığı için bu şerit de katlamanın üstünde;
|
||||||
|
// yer tutucusuz hâlinde yoktan belirip altındaki her şeyi iterdi.
|
||||||
|
// h-26 (104 px) tek satırlık gerçek yüksekliktir: figür w-52 (208 px),
|
||||||
|
// svg oranı 1050×447 → 88,6 px, figcaption text-xs → 16 px. Kap mt-3'ü
|
||||||
|
// bileşenin kendi kökündekiyle aynı (yurtdisi-haritalar.tsx). Birden çok
|
||||||
|
// ülke alt satıra kayarsa fark kalır — sunucu ülke sayısını bilemez.
|
||||||
export const YurtdisiHaritalarLazy = dynamic(
|
export const YurtdisiHaritalarLazy = dynamic(
|
||||||
() => import("./yurtdisi-haritalar").then((m) => m.YurtdisiHaritalar),
|
() => import("./yurtdisi-haritalar").then((m) => m.YurtdisiHaritalar),
|
||||||
{ ssr: false },
|
{ ssr: false, loading: () => <div className="mt-3 h-26" aria-hidden /> },
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,6 +6,16 @@ import type { RiskSeviyesi } from "@/lib/risk";
|
|||||||
|
|
||||||
export const MANUEL_LISTE_MAX = 24;
|
export const MANUEL_LISTE_MAX = 24;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listenin sunucu aynası — yalnızca ELEMAN SAYISI taşır, hiçbir kişisel veri
|
||||||
|
* ya da program kimliği taşımaz. Liste localStorage'ta yaşadığı için sunucu
|
||||||
|
* snapshot'ı her zaman boştur; /sonuc bu çerezi okuyup haritaya hidrasyondan
|
||||||
|
* önce tam ölçülü yer ayırabilsin diye var (bkz. sonuc/page.tsx).
|
||||||
|
* Sabit burada durur çünkü bu dosya client store ile sunucu tarafının ortak
|
||||||
|
* zemini; store'un kendisi "use client".
|
||||||
|
*/
|
||||||
|
export const LISTE_SAYI_CEREZ_ADI = "kolaytercih.liste-sayi";
|
||||||
|
|
||||||
export type ManuelKaynak = "sonuc" | "bolum" | "universite";
|
export type ManuelKaynak = "sonuc" | "bolum" | "universite";
|
||||||
|
|
||||||
export type ManuelTercih = {
|
export type ManuelTercih = {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
} from "@/features/sihirbaz/sihirbaz-sabitler";
|
} from "@/features/sihirbaz/sihirbaz-sabitler";
|
||||||
import { tercihProfiliOku } from "@/features/sihirbaz/sihirbaz-profil";
|
import { tercihProfiliOku } from "@/features/sihirbaz/sihirbaz-profil";
|
||||||
import {
|
import {
|
||||||
|
LISTE_SAYI_CEREZ_ADI,
|
||||||
MANUEL_LISTE_MAX,
|
MANUEL_LISTE_MAX,
|
||||||
dogrula,
|
dogrula,
|
||||||
type ManuelKaynak,
|
type ManuelKaynak,
|
||||||
@@ -39,10 +40,23 @@ function yayinla() {
|
|||||||
for (const cb of dinleyiciler) cb();
|
for (const cb of dinleyiciler) cb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sunucu aynası: listenin yalnızca UZUNLUĞU çereze yazılır (kişisel veri yok).
|
||||||
|
* /sonuc bunu okuyup haritaya hidrasyondan önce tam ölçülü yer ayırır; yoksa
|
||||||
|
* kayıtlı listesi olan ziyaretçide harita sonradan belirip sayfayı iterdi.
|
||||||
|
* Öznitelikler profilCerezineYaz ile birebir aynı (sihirbaz-profil.ts).
|
||||||
|
*/
|
||||||
|
function sayiCereziniYaz(n: number) {
|
||||||
|
if (typeof document === "undefined") return;
|
||||||
|
const guvenli = window.location.protocol === "https:" ? "; secure" : "";
|
||||||
|
document.cookie = `${LISTE_SAYI_CEREZ_ADI}=${n}; path=/; max-age=31536000; samesite=lax${guvenli}`;
|
||||||
|
}
|
||||||
|
|
||||||
function kaydet() {
|
function kaydet() {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(liste));
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(liste));
|
||||||
} catch {}
|
} catch {}
|
||||||
|
sayiCereziniYaz(liste.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
function yukle() {
|
function yukle() {
|
||||||
@@ -52,6 +66,10 @@ function yukle() {
|
|||||||
const ham = localStorage.getItem(STORAGE_KEY);
|
const ham = localStorage.getItem(STORAGE_KEY);
|
||||||
if (ham) liste = dogrula(JSON.parse(ham));
|
if (ham) liste = dogrula(JSON.parse(ham));
|
||||||
} catch {}
|
} catch {}
|
||||||
|
// Çerezi her açılışta gerçek uzunlukla tazele: yeni dağıtımdan sonra ilk
|
||||||
|
// ziyarette çerezi doğurur, localStorage silinmiş ama çerez kalmış durumda
|
||||||
|
// da 0 yazıp /sonuc'un boşuna yer ayırmasını engeller.
|
||||||
|
sayiCereziniYaz(liste.length);
|
||||||
// Profilsiz + ile eklenenlerin riski null'dır. Profil sonradan hangi yoldan
|
// Profilsiz + ile eklenenlerin riski null'dır. Profil sonradan hangi yoldan
|
||||||
// yazılırsa yazılsın (kapı, hero/CTA formu, sihirbaz, giriş senkronu) riskler
|
// yazılırsa yazılsın (kapı, hero/CTA formu, sihirbaz, giriş senkronu) riskler
|
||||||
// dolsun: açılışta bir kez, sonra her profil değişiminde.
|
// dolsun: açılışta bir kez, sonra her profil değişiminde.
|
||||||
@@ -62,6 +80,7 @@ function yukle() {
|
|||||||
if (e.key !== STORAGE_KEY) return;
|
if (e.key !== STORAGE_KEY) return;
|
||||||
try {
|
try {
|
||||||
liste = e.newValue ? dogrula(JSON.parse(e.newValue)) : [];
|
liste = e.newValue ? dogrula(JSON.parse(e.newValue)) : [];
|
||||||
|
sayiCereziniYaz(liste.length);
|
||||||
yayinla();
|
yayinla();
|
||||||
} catch {}
|
} catch {}
|
||||||
});
|
});
|
||||||
@@ -87,6 +106,20 @@ export function useManuelListe(): ManuelTercih[] {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store'un client'ta hidre olup olmadığı: sunucu snapshot'ı false, hidrasyondan
|
||||||
|
* sonra true. `liste` ile aynı anda flip eder (ikisi de abone içindeki
|
||||||
|
* yukle()'den doğar), bu yüzden "boş liste" ile "henüz okunmadı" ayrımı
|
||||||
|
* gereken yerlerde tek render'da tutarlıdır — bkz. ManuelHarita.
|
||||||
|
*/
|
||||||
|
export function useListeHidreMi(): boolean {
|
||||||
|
return useSyncExternalStore(
|
||||||
|
abone,
|
||||||
|
() => yuklendi,
|
||||||
|
() => false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function useCekmeceAcik(): boolean {
|
export function useCekmeceAcik(): boolean {
|
||||||
return useSyncExternalStore(
|
return useSyncExternalStore(
|
||||||
abone,
|
abone,
|
||||||
|
|||||||
@@ -120,9 +120,11 @@ export function TadimlikSatiri({
|
|||||||
const girisUrl = `/giris?callback=${encodeURIComponent(listemUretHref("tadimlik"))}`;
|
const girisUrl = `/giris?callback=${encodeURIComponent(listemUretHref("tadimlik"))}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// first:mt-0 — /sonuc'ta bu <section> main'in ilk DOM çocuğudur (harita
|
// first:mt-0 — /sonuc'ta harita bu <section>'ın ÜSTÜNDE durur ama yalnızca
|
||||||
// artık tablonun altında, üstte hiçbir kardeş yok; JSX yorumları düğüm
|
// kayıtlı listesi olan ziyaretçide DOM'a girer (manuel-harita.tsx). Liste
|
||||||
// üretmez): main'in py-12'si tek başına yeterli üst boşluğu verir.
|
// yoksa tadımlık main'in ilk DOM çocuğudur (JSX yorumları düğüm üretmez) ve
|
||||||
|
// main'in py-12'si tek başına yeterli üst boşluğu verir; harita varsa
|
||||||
|
// tadımlık ikinci çocuk olur ve bölüm ritmini veren mt-16'yı alır.
|
||||||
// Tadımlığın render edilmediği durumlarda (girişli kullanıcı, boş havuz)
|
// Tadımlığın render edilmediği durumlarda (girişli kullanıcı, boş havuz)
|
||||||
// bu bileşen hiç dönmediği için kural ilk gerçek bölüme geçer.
|
// bu bileşen hiç dönmediği için kural ilk gerçek bölüme geçer.
|
||||||
<section ref={gorunumRef} className="mt-16 min-w-0 first:mt-0">
|
<section ref={gorunumRef} className="mt-16 min-w-0 first:mt-0">
|
||||||
|
|||||||
Reference in New Issue
Block a user