fix(tasarim): piksel zemin yalnız CTA yüzeylerinde, kabın ölçüsüne göre, küçük kare yok
Bilal (24 Eyl 2026): ana sayfa CTA'sında doku hiç görünmüyordu, bazı kartlarda çok azdı; sonra "çok fazla piksel, küçük olanlar hiç olmasın" ve "/sonuc'taki kartın arkasına da piksel koymuşsun; pikseller CTA'larda olacak sadece". - Kök neden: PixelMasonry sabit 420×120 çizimi kaplayacak şekilde ölçekleniyordu; yüksek kartlarda görünen kısım boş banda düşüyordu. Artık kabın gerçek ölçüsüne göre üretiliyor (ResizeObserver), yalnız kenar çerçevesinde, orta boş; `haric` verilen öğenin (24'lük piksel tablosu) çevresi her genişlikte boş. Sunucuda boş, ölçülünce belirir. - Küçük (tek hücre) kare yok: 4×4 makro hücrede 2–4 hücrelik kareler, iri olan seyrek ve silik. Ölçüm: kapanış kartı 1280 px'te 58 kare (tabloya binen 0), 375 px'te 27 kare. - Beyaz içerik kartlarından zemin geri alındı (tadımlık, /listem üretim ve kilit kartları, boş durum, sıralama-yok, meraklısına, paket kartları, kaydet bandı, katalog üstü kompakt satır, /sonuc "listen hazır"). Kalanlar: CtaBandi, PikselCtaYuzeyi, arama penceresi kartı. PikselZemin'in açık tonu kaldırıldı. DESIGN.md §10.8 güncellendi. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -677,9 +677,11 @@ karar.
|
|||||||
|
|
||||||
- Zemin `bg-primary` (sitenin mavisi), köşe `rounded-2xl`, yazı beyaz; alt satır da beyaz
|
- Zemin `bg-primary` (sitenin mavisi), köşe `rounded-2xl`, yazı beyaz; alt satır da beyaz
|
||||||
(`text-white`, `slate-300` değil). Piksel dokusu `PixelMasonry` (Bilal, 24 Eyl 2026: "arka
|
(`text-white`, `slate-300` değil). Piksel dokusu `PixelMasonry` (Bilal, 24 Eyl 2026: "arka
|
||||||
planda büyüklü küçüklü, masonry şeklinde"): 1–3 hücrelik kareler 3×3'lük makro hücrelere
|
planda büyüklü küçüklü, masonry şeklinde"): 2–4 hücrelik kareler 4×4'lük makro hücrelere
|
||||||
kaymış düşer, çakışmaz ama hizaya girmez; orta bant (%22–78) boş, kenarlara doğru yoğun; iri
|
kaymış düşer, çakışmaz ama hizaya girmez. Doku **kabın gerçek ölçüsüne göre** üretilir
|
||||||
kare daha silik; **durağan** — imleç ısı fırçasına katılmaz, üzerine gelince hiçbir şey
|
(ResizeObserver; sabit çizimi ölçeklemek yüksek kartlarda görünen kısmı boş banda düşürüyordu,
|
||||||
|
24 Eyl 2026'da yaşandı): kısa kenarın %30'u kadar kenar çerçevesi kenara doğru yoğunlaşır,
|
||||||
|
orta tamamen boş; küçük kare yok (2–4 hücre), iri kare daha silik; **durağan** — imleç ısı fırçasına katılmaz, üzerine gelince hiçbir şey
|
||||||
olmaz (Bilal, 24 Eyl 2026); yalnız seyrek turuncu vurgu kareleri kendi kendine yavaşça nefes
|
olmaz (Bilal, 24 Eyl 2026); yalnız seyrek turuncu vurgu kareleri kendi kendine yavaşça nefes
|
||||||
alır. Kap `relative isolate
|
alır. Kap `relative isolate
|
||||||
overflow-hidden`, doku `-inset-y-6 -z-10`. Eşit ızgaralı eski `PixelField` kaldırıldı.
|
overflow-hidden`, doku `-inset-y-6 -z-10`. Eşit ızgaralı eski `PixelField` kaldırıldı.
|
||||||
@@ -691,19 +693,16 @@ karar.
|
|||||||
kart varyantı, "Kendi Listem" çekmecesinin altı (kompakt). Aynı sayfadaki iki band farklı
|
kart varyantı, "Kendi Listem" çekmecesinin altı (kompakt). Aynı sayfadaki iki band farklı
|
||||||
`seed` alır.
|
`seed` alır.
|
||||||
|
|
||||||
**Her CTA benzeri yüzeyin arkasında piksel zemin — `PikselZemin`, `src/components/piksel-zemin.tsx`**
|
**Piksel zemin yalnız CTA yüzeylerinde — `PikselZemin`, `src/components/piksel-zemin.tsx`**
|
||||||
(Bilal, 24 Eyl 2026: "piksel arka planları her CTA benzeri kısmın arkasında olmalı, masonry gibi
|
(Bilal, 24 Eyl 2026: önce "her CTA benzeri kısmın arkasında olmalı", sonra "/sonuc'taki kartın
|
||||||
büyüklü küçüklü"). CTA benzeri yüzey = tek bir aksiyona çağıran kart, bant, boş durum ya da
|
arkasına da piksel koymuşsun; pikseller CTA'larda olacak sadece"). CTA yüzeyi = renkli zeminli
|
||||||
sayfa bölümü. Kap `relative isolate overflow-hidden`; zemin ilk çocuk. Açık kartta
|
çağrı yüzeyi: mavi `CtaBandi`, koyu kapanış kartı `PikselCtaYuzeyi`, arama penceresindeki koyu
|
||||||
`ton="acik"` (silik mavi, `text-primary/70`), mavi bant ve koyu kartta `ton="koyu"` (beyaz).
|
kart. Beyaz içerik kartlarına (tadımlık, `/listem` üretim/kilit kartları, paket kartı, kaydet
|
||||||
`CtaBandi` ve `PikselCtaYuzeyi` de bunu kullanır. Kapsananlar: `/sonuc` "24 tercihlik listen
|
bandı, katalog üstü kompakt satır, boş durumlar, sıralama-yok sayfası) **konmaz** — 24 Eyl'de
|
||||||
hazır" kartı, `/listem` dört üretim kartı + boş durum + kilit kartı, tadımlık kartı,
|
denendi ve geri alındı. Kap `relative isolate overflow-hidden`; zemin ilk çocuk; kareler beyaz.
|
||||||
sıralama-yok sayfası, meraklısına kapanış kartı, ana sayfa ve `/paket` ana paket kartı, kaydet
|
Doku kabın gerçek ölçüsüne göre üretilir: yalnız kenar çerçevesinde (kısa kenarın %30'u), orta
|
||||||
bandı, katalog üstü kompakt satır, arama penceresi kartı. **Kapsam dışı:** form kartları (giriş,
|
tamamen boş; **küçük kare yok**, 2–4 hücrelik (17/27/37 px) kareler, iri olan seyrek ve daha
|
||||||
ödeme formu), durum kartları (ödeme sonucu), modal düğmeleri, hata/404 sayfası, yan kredi
|
silik (Bilal: "çok fazla piksel, küçük olanlar hiç olmasın").
|
||||||
kartları — bunlar tek aksiyona çağıran yüzey değil. Yeni bir CTA yüzeyi açan ajan zemini
|
|
||||||
ekler ve bu listeye yazar. Band üstündeki ikincil metin `text-white/90`, ince yazı `text-white/70`;
|
|
||||||
`slate-300`/`slate-400` yazılmaz.
|
|
||||||
|
|
||||||
**Kapanış yüzeyi — `PikselCtaYuzeyi`, `src/components/piksel-cta-yuzeyi.tsx` (yalnız ana
|
**Kapanış yüzeyi — `PikselCtaYuzeyi`, `src/components/piksel-cta-yuzeyi.tsx` (yalnız ana
|
||||||
sayfa kapanışı "Tercih listen, pişmanlık listesi olmasın").** Bilal'in kararı (24 Eyl 2026):
|
sayfa kapanışı "Tercih listen, pişmanlık listesi olmasın").** Bilal'in kararı (24 Eyl 2026):
|
||||||
@@ -719,10 +718,9 @@ yok** (Bilal, 24 Eyl 2026: kaldırıldı); `FUNNEL_METINLERI` yalnız arama penc
|
|||||||
nabız atar (`kt-piksel-nabiz`). Hareketi azalt: dolu, durağan. Renk her zaman
|
nabız atar (`kt-piksel-nabiz`). Hareketi azalt: dolu, durağan. Renk her zaman
|
||||||
`PikselListeAciklama` metniyle.
|
`PikselListeAciklama` metniyle.
|
||||||
- Piksel tablosunun arkası boş kalır (Bilal, 24 Eyl 2026: "arkasına çok piksel yığılmış"):
|
- Piksel tablosunun arkası boş kalır (Bilal, 24 Eyl 2026: "arkasına çok piksel yığılmış"):
|
||||||
telefon/tablette liste üstte ortada, dokunun boş bandında; `lg`'de liste sağ sütunda olduğu
|
tablo kabı `haric` ile zemine verilir, doku onun çevresini (14 px payla) her genişlikte boş
|
||||||
için doku yalnız sol %16'da ve seyrek (`PikselZemin bosBant={[0.16, 1]} yogunluk={0.7}`).
|
bırakır. Kural genel: bir kreatif ya da iri sayı piksel zeminin üstüne geliyorsa `haric` ile
|
||||||
Kural genel: bir kreatif ya da iri sayı piksel zeminin üstüne geliyorsa `bosBant` ile o
|
boşaltılır; doku ile kreatif üst üste binmez.
|
||||||
bölge boşaltılır; doku ile kreatif üst üste binmez.
|
|
||||||
- Bu yüzey **sayfada bir kez** ve yalnız kapanışta durur; ara paneller ve çekmece mavi banttır.
|
- Bu yüzey **sayfada bir kez** ve yalnız kapanışta durur; ara paneller ve çekmece mavi banttır.
|
||||||
Yeni bir kreatif fikri (veriyi piksele çeviren, imlece tepki veren) önce burada denenir.
|
Yeni bir kreatif fikri (veriyi piksele çeviren, imlece tepki veren) önce burada denenir.
|
||||||
- Çekmece başlığında denenen "gerçek liste" pikseli (12×2, her kare tercihin riski) **kaldırıldı**:
|
- Çekmece başlığında denenen "gerçek liste" pikseli (12×2, her kare tercihin riski) **kaldırıldı**:
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import {
|
|||||||
SectionEyebrow,
|
SectionEyebrow,
|
||||||
} from "@/components/pixel-decor";
|
} from "@/components/pixel-decor";
|
||||||
import { PikselCtaYuzeyi } from "@/components/piksel-cta-yuzeyi";
|
import { PikselCtaYuzeyi } from "@/components/piksel-cta-yuzeyi";
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import { MAX_REVIZYON, URUNLER } from "@/lib/credits";
|
import { MAX_REVIZYON, URUNLER } from "@/lib/credits";
|
||||||
import { VERI_YIL_SAYISI } from "@/lib/veri-kapsami";
|
import { VERI_YIL_SAYISI } from "@/lib/veri-kapsami";
|
||||||
import {
|
import {
|
||||||
@@ -555,9 +554,8 @@ export default function Home() {
|
|||||||
>
|
>
|
||||||
<Reveal
|
<Reveal
|
||||||
delay={0.08}
|
delay={0.08}
|
||||||
className="relative isolate overflow-hidden rounded-2xl border-2 border-orange-500 bg-white p-8 shadow-sm"
|
className="rounded-2xl border-2 border-orange-500 bg-white p-8 shadow-sm"
|
||||||
>
|
>
|
||||||
<PikselZemin seed={43} />
|
|
||||||
<div className="flex flex-wrap items-baseline justify-between gap-2">
|
<div className="flex flex-wrap items-baseline justify-between gap-2">
|
||||||
<h3 className="font-heading text-xl font-bold">
|
<h3 className="font-heading text-xl font-bold">
|
||||||
{URUNLER.paket.label}
|
{URUNLER.paket.label}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export function AramaFunnelKarti({ onSec }: { onSec: () => void }) {
|
|||||||
aria-label="Tercih listeni kur"
|
aria-label="Tercih listeni kur"
|
||||||
className="relative isolate mt-5 overflow-hidden rounded-2xl border border-blue-400/20 bg-slate-950 px-4 py-5 text-white sm:px-5"
|
className="relative isolate mt-5 overflow-hidden rounded-2xl border border-blue-400/20 bg-slate-950 px-4 py-5 text-white sm:px-5"
|
||||||
>
|
>
|
||||||
<PikselZemin seed={61} ton="koyu" />
|
<PikselZemin seed={61} />
|
||||||
<div className="grid items-center gap-4 sm:grid-cols-[minmax(0,1fr)_auto] sm:gap-5">
|
<div className="grid items-center gap-4 sm:grid-cols-[minmax(0,1fr)_auto] sm:gap-5">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<TypingAnimation
|
<TypingAnimation
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export function CtaBandi({
|
|||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<PikselZemin seed={seed} ton="koyu" className={buyuk ? "-inset-y-10" : undefined} />
|
<PikselZemin seed={seed} className={buyuk ? "-inset-y-10" : undefined} />
|
||||||
{children}
|
{children}
|
||||||
</Etiket>
|
</Etiket>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, type ReactNode } from "react";
|
import { useRef, useState, type ReactNode } from "react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
import { PikselZemin } from "@/components/piksel-zemin";
|
||||||
import { PikselListe, PikselListeAciklama } from "@/components/piksel-liste";
|
import { PikselListe, PikselListeAciklama } from "@/components/piksel-liste";
|
||||||
@@ -13,9 +13,6 @@ import { PikselListe, PikselListeAciklama } from "@/components/piksel-liste";
|
|||||||
* düğmeye ya da linke imleç/odak gelince 24 kare birden dolar — "listen
|
* düğmeye ya da linke imleç/odak gelince 24 kare birden dolar — "listen
|
||||||
* böyle hazır olur". Yazılıp silinen satır yok (Bilal, 24 Eyl 2026).
|
* böyle hazır olur". Yazılıp silinen satır yok (Bilal, 24 Eyl 2026).
|
||||||
*/
|
*/
|
||||||
// Geniş ekranda doku yalnız genişliğin ilk %16'sında (metnin sol boşluğu)
|
|
||||||
const SOL_KENAR: [number, number] = [0.16, 1];
|
|
||||||
|
|
||||||
export function PikselCtaYuzeyi({
|
export function PikselCtaYuzeyi({
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
@@ -27,6 +24,9 @@ export function PikselCtaYuzeyi({
|
|||||||
seed?: number;
|
seed?: number;
|
||||||
}) {
|
}) {
|
||||||
const [tamamla, setTamamla] = useState(false);
|
const [tamamla, setTamamla] = useState(false);
|
||||||
|
// Piksel tablosunun çevresi dokuda boş kalır (Bilal, 24 Eyl 2026:
|
||||||
|
// "tablonun arkasına çok piksel yığılmış"); ölçü gerçek yerleşimden.
|
||||||
|
const listeRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const hedefMi = (t: EventTarget | null) =>
|
const hedefMi = (t: EventTarget | null) =>
|
||||||
t instanceof Element && t.closest("a, button") != null;
|
t instanceof Element && t.closest("a, button") != null;
|
||||||
@@ -42,23 +42,15 @@ export function PikselCtaYuzeyi({
|
|||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* Telefon/tablet: liste üstte ortada, dokunun boş bandında. Geniş
|
<PikselZemin seed={seed} haric={listeRef} className="-inset-y-10" />
|
||||||
ekranda liste sağ sütunda — orası tamamen boş kalır, doku yalnız
|
|
||||||
sol kenarda ve seyrek (Bilal, 24 Eyl 2026: "tablonun arkasına çok
|
|
||||||
piksel yığılmış"). */}
|
|
||||||
<PikselZemin seed={seed} ton="koyu" className="-inset-y-10 lg:hidden" />
|
|
||||||
<PikselZemin
|
|
||||||
seed={seed}
|
|
||||||
ton="koyu"
|
|
||||||
bosBant={SOL_KENAR}
|
|
||||||
yogunluk={0.7}
|
|
||||||
className="-inset-y-10 hidden lg:block"
|
|
||||||
/>
|
|
||||||
<div className="grid items-center gap-8 px-5 py-10 sm:px-10 sm:py-12 lg:grid-cols-[minmax(0,1fr)_16rem] lg:gap-12">
|
<div className="grid items-center gap-8 px-5 py-10 sm:px-10 sm:py-12 lg:grid-cols-[minmax(0,1fr)_16rem] lg:gap-12">
|
||||||
<div className="flex min-w-0 flex-col items-center text-center lg:items-start lg:text-left">
|
<div className="flex min-w-0 flex-col items-center text-center lg:items-start lg:text-left">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
<div className="order-first flex flex-col items-center lg:order-none">
|
<div
|
||||||
|
ref={listeRef}
|
||||||
|
className="order-first flex flex-col items-center lg:order-none"
|
||||||
|
>
|
||||||
<PikselListe
|
<PikselListe
|
||||||
tamamla={tamamla}
|
tamamla={tamamla}
|
||||||
className="w-full max-w-[9rem] sm:max-w-[11rem] lg:max-w-[14rem]"
|
className="w-full max-w-[9rem] sm:max-w-[11rem] lg:max-w-[14rem]"
|
||||||
|
|||||||
@@ -1,31 +1,36 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import type { RefObject } from "react";
|
||||||
import { PixelMasonry } from "@/components/pixel-decor";
|
import { PixelMasonry } from "@/components/pixel-decor";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CTA yüzeylerinin piksel zemini (DESIGN.md §10.8) — tek kaynak. Bilal'in
|
* CTA yüzeylerinin piksel zemini (DESIGN.md §10.8) — tek kaynak. Bilal'in
|
||||||
* kararı (24 Eyl 2026): "piksel arka planları her CTA benzeri kısmın
|
* kararı (24 Eyl 2026): pikseller **yalnız CTA yüzeylerinde** (mavi bant,
|
||||||
* arkasında olmalı, masonry gibi büyüklü küçüklü." Kap `relative isolate
|
* kapanış kartı, arama penceresi kartı); beyaz içerik kartlarında değil
|
||||||
* overflow-hidden` olmalı; zemin ilk çocuk olarak konur.
|
* ("/sonuc'taki kartın arkasına da piksel koymuşsun; pikseller CTA'larda
|
||||||
|
* olacak sadece"). Beyaz kareler; kap `relative isolate overflow-hidden`
|
||||||
|
* olmalı, zemin ilk çocuk olarak konur.
|
||||||
*
|
*
|
||||||
* - `acik`: beyaz/açık kart — silik mavi kareler.
|
* Doku kabın gerçek ölçüsüne göre üretilir; kenar çerçevesi yoğun, orta
|
||||||
* - `koyu`: mavi bant ya da koyu kart — beyaz kareler.
|
* seyrek. Üstünde kreatif ya da iri sayı varsa `haric` ile o öğe verilir,
|
||||||
|
* çevresi boş kalır.
|
||||||
*/
|
*/
|
||||||
export function PikselZemin({
|
export function PikselZemin({
|
||||||
seed = 7,
|
seed = 7,
|
||||||
ton = "acik",
|
|
||||||
bosBant,
|
|
||||||
yogunluk,
|
yogunluk,
|
||||||
|
kenar,
|
||||||
|
haric,
|
||||||
className,
|
className,
|
||||||
}: {
|
}: {
|
||||||
/** Aynı ekrandaki iki yüzey farklı desen alsın */
|
/** Aynı ekrandaki iki yüzey farklı desen alsın */
|
||||||
seed?: number;
|
seed?: number;
|
||||||
ton?: "acik" | "koyu";
|
/** Doluluk çarpanı (1 varsayılan) */
|
||||||
/** Boş bırakılacak yatay bant (varsayılan orta %22–78); bkz. PixelMasonry */
|
|
||||||
bosBant?: [number, number];
|
|
||||||
/** Doluluk çarpanı */
|
|
||||||
yogunluk?: number;
|
yogunluk?: number;
|
||||||
|
/** Kenar çerçevesinin genişliği, kısa kenarın oranı (0.3 varsayılan) */
|
||||||
|
kenar?: number;
|
||||||
|
/** Çevresi boş bırakılacak öğe */
|
||||||
|
haric?: RefObject<HTMLElement | null>;
|
||||||
/** Dikey taşma payı vb. (varsayılan `-inset-y-6`) */
|
/** Dikey taşma payı vb. (varsayılan `-inset-y-6`) */
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
@@ -33,12 +38,16 @@ export function PikselZemin({
|
|||||||
<div
|
<div
|
||||||
aria-hidden
|
aria-hidden
|
||||||
className={cn(
|
className={cn(
|
||||||
"pointer-events-none absolute inset-x-0 -inset-y-6 -z-10",
|
"pointer-events-none absolute inset-x-0 -inset-y-6 -z-10 text-white",
|
||||||
ton === "acik" ? "text-primary/70" : "text-white",
|
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<PixelMasonry seed={seed} bosBant={bosBant} yogunluk={yogunluk} />
|
<PixelMasonry
|
||||||
|
seed={seed}
|
||||||
|
yogunluk={yogunluk}
|
||||||
|
kenar={kenar}
|
||||||
|
haric={haric}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useMemo, useRef, type CSSProperties, type ReactNode } from "react";
|
import {
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
type CSSProperties,
|
||||||
|
type ReactNode,
|
||||||
|
type RefObject,
|
||||||
|
} from "react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { usePixelHeat } from "@/components/use-pixel-heat";
|
import { usePixelHeat } from "@/components/use-pixel-heat";
|
||||||
|
|
||||||
@@ -74,41 +82,86 @@ function pixelRect(
|
|||||||
/**
|
/**
|
||||||
* CTA yüzeylerinin piksel zemini: büyüklü küçüklü kareler, masonry gibi
|
* CTA yüzeylerinin piksel zemini: büyüklü küçüklü kareler, masonry gibi
|
||||||
* hafif kaymış (Bilal, 24 Eyl 2026: "arka planda büyüklü küçüklü, masonry
|
* hafif kaymış (Bilal, 24 Eyl 2026: "arka planda büyüklü küçüklü, masonry
|
||||||
* şeklinde"). İçeriğin oturduğu orta bant boş kalır; kareler kenarlara doğru
|
* şeklinde"). Kabın **gerçek ölçüsüne** göre üretilir (ResizeObserver):
|
||||||
* yoğunlaşır. 3×3 hücrelik makro hücrelere 1–3 hücrelik tek kare düşer ve
|
* sabit bir çizimi kaplayacak şekilde ölçeklemek yüksek kartlarda görünen
|
||||||
* makro hücre içinde kaydırılır: kareler çakışmaz ama hizaya da girmez
|
* kısmı boş banda düşürüyordu ("hiç doku yok"). Yalnız kenar çerçevesinde,
|
||||||
* (§1.1 "doğal duruş"). Durağan zemin: imleç ısı fırçasına katılmaz
|
* orta tamamen boş; `haric` verilen öğenin (ör. 24'lük piksel tablosu)
|
||||||
* (Bilal, 24 Eyl 2026: "üzerine gelindiğinde bir şey olmasın").
|
* çevresi de boş kalır. Küçük (tek hücrelik) kare **yok** (Bilal, 24 Eyl
|
||||||
|
* 2026: "çok fazla piksel, küçük olanlar hiç olmasın"): 4×4 hücrelik makro
|
||||||
|
* hücrelere 2–4 hücrelik tek kare düşer ve makro hücre içinde kaydırılır:
|
||||||
|
* çakışmaz ama hizaya da girmez (§1.1 "doğal duruş"). Durağan zemin:
|
||||||
|
* imleç ısı fırçasına katılmaz.
|
||||||
|
* Sunucuda boş çizilir, ölçülünce belirir (dekor; aria-hidden).
|
||||||
*/
|
*/
|
||||||
// Varsayılan boş bant modül sabiti: her render'da yeni dizi olup useMemo'yu
|
|
||||||
// boşa düşürmesin (rendering-hoist-jsx)
|
|
||||||
const BOS_BANT_VARSAYILAN: [number, number] = [0.22, 0.78];
|
|
||||||
|
|
||||||
export function PixelMasonry({
|
export function PixelMasonry({
|
||||||
seed = 7,
|
seed = 7,
|
||||||
bosBant = BOS_BANT_VARSAYILAN,
|
|
||||||
yogunluk = 1,
|
yogunluk = 1,
|
||||||
|
kenar = 0.3,
|
||||||
|
haric,
|
||||||
className,
|
className,
|
||||||
}: {
|
}: {
|
||||||
seed?: number;
|
seed?: number;
|
||||||
/** Genişliğin bu oranları arasındaki bant boş kalır (içerik orada) */
|
|
||||||
bosBant?: [number, number];
|
|
||||||
/** Doluluk çarpanı; 1 varsayılan, 0.6 seyrek */
|
/** Doluluk çarpanı; 1 varsayılan, 0.6 seyrek */
|
||||||
yogunluk?: number;
|
yogunluk?: number;
|
||||||
|
/** Kenar çerçevesinin genişliği: kısa kenarın oranı (0.3 = %30) */
|
||||||
|
kenar?: number;
|
||||||
|
/** Çevresi boş bırakılacak öğe (kreatif, iri sayı) */
|
||||||
|
haric?: RefObject<HTMLElement | null>;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
const COLS = 42;
|
const svgRef = useRef<SVGSVGElement>(null);
|
||||||
const ROWS = 12;
|
const [olcu, setOlcu] = useState<{
|
||||||
const MAKRO = 3;
|
w: number;
|
||||||
|
h: number;
|
||||||
|
hx: number;
|
||||||
|
hy: number;
|
||||||
|
hw: number;
|
||||||
|
hh: number;
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const svg = svgRef.current;
|
||||||
|
if (!svg) return;
|
||||||
|
const olc = () => {
|
||||||
|
const r = svg.getBoundingClientRect();
|
||||||
|
const hr = haric?.current?.getBoundingClientRect();
|
||||||
|
const sonraki = {
|
||||||
|
w: Math.round(r.width),
|
||||||
|
h: Math.round(r.height),
|
||||||
|
hx: hr ? Math.round(hr.left - r.left) : 0,
|
||||||
|
hy: hr ? Math.round(hr.top - r.top) : 0,
|
||||||
|
hw: hr ? Math.round(hr.width) : 0,
|
||||||
|
hh: hr ? Math.round(hr.height) : 0,
|
||||||
|
};
|
||||||
|
setOlcu((onceki) =>
|
||||||
|
onceki &&
|
||||||
|
onceki.w === sonraki.w &&
|
||||||
|
onceki.h === sonraki.h &&
|
||||||
|
onceki.hx === sonraki.hx &&
|
||||||
|
onceki.hy === sonraki.hy &&
|
||||||
|
onceki.hw === sonraki.hw &&
|
||||||
|
onceki.hh === sonraki.hh
|
||||||
|
? onceki
|
||||||
|
: sonraki,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
olc();
|
||||||
|
const ro = new ResizeObserver(olc);
|
||||||
|
ro.observe(svg);
|
||||||
|
const h = haric?.current;
|
||||||
|
if (h) ro.observe(h);
|
||||||
|
return () => ro.disconnect();
|
||||||
|
}, [haric]);
|
||||||
|
|
||||||
|
const MAKRO = 4;
|
||||||
|
const PAY = 14; // hariç öğenin çevresinde bırakılan boşluk (px)
|
||||||
|
|
||||||
// Çıktı seed'e göre deterministik; render başına yeniden üretme
|
|
||||||
const pixels = useMemo(() => {
|
const pixels = useMemo(() => {
|
||||||
const cx = (COLS - 1) / 2;
|
if (!olcu || olcu.w === 0 || olcu.h === 0) return null;
|
||||||
const cy = (ROWS - 1) / 2;
|
const { w, h, hx, hy, hw, hh } = olcu;
|
||||||
const maxD = Math.sqrt(cx * cx + cy * cy);
|
const cols = Math.ceil(w / CELL);
|
||||||
const BAND_MIN = COLS * bosBant[0];
|
const rows = Math.ceil(h / CELL);
|
||||||
const BAND_MAX = COLS * bosBant[1];
|
const kisa = Math.min(w, h);
|
||||||
|
|
||||||
const sonuc: ReactNode[] = [];
|
const sonuc: ReactNode[] = [];
|
||||||
let accentIdx = 0;
|
let accentIdx = 0;
|
||||||
|
|
||||||
@@ -141,55 +194,57 @@ export function PixelMasonry({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
// İri kare daha silik: yazının yanında bağırmasın
|
// İri kare daha silik: yazının yanında bağırmasın
|
||||||
const op = opacityFor(x, y) * (n === 1 ? 1 : n === 2 ? 0.8 : 0.6);
|
const op = opacityFor(x, y) * (n === 2 ? 0.9 : n === 3 ? 0.7 : 0.55);
|
||||||
return (
|
return (
|
||||||
<rect key={key} {...shared} fill="currentColor" fillOpacity={op} />
|
<rect key={key} {...shared} fill="currentColor" fillOpacity={op} />
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let my = 0; my < ROWS / MAKRO; my++) {
|
const haricte = (px: number, py: number) =>
|
||||||
for (let mx = 0; mx < COLS / MAKRO; mx++) {
|
hw > 0 &&
|
||||||
|
px >= hx - PAY &&
|
||||||
|
px <= hx + hw + PAY &&
|
||||||
|
py >= hy - PAY &&
|
||||||
|
py <= hy + hh + PAY;
|
||||||
|
|
||||||
|
for (let my = 0; my < rows / MAKRO; my++) {
|
||||||
|
for (let mx = 0; mx < cols / MAKRO; mx++) {
|
||||||
const ox = mx * MAKRO;
|
const ox = mx * MAKRO;
|
||||||
const oy = my * MAKRO;
|
const oy = my * MAKRO;
|
||||||
const mcx = ox + MAKRO / 2;
|
const cxPx = (ox + MAKRO / 2) * CELL;
|
||||||
if (mcx > BAND_MIN && mcx < BAND_MAX) continue;
|
const cyPx = (oy + MAKRO / 2) * CELL;
|
||||||
// Kenarlara doğru artan doluluk
|
if (haricte(cxPx, cyPx)) continue;
|
||||||
const d = Math.sqrt((mcx - cx) ** 2 + (oy + MAKRO / 2 - cy) ** 2) / maxD;
|
// En yakın kenara uzaklık, kısa kenarın oranı olarak (0 kenar, 0.5 orta)
|
||||||
const density = (0.3 + 0.6 * d * d) * yogunluk;
|
const k = Math.min(cxPx, w - cxPx, cyPx, h - cyPx) / kisa;
|
||||||
if (hash(mx, my, seed) > density) {
|
// Yalnız çerçevede, kenara doğru artan doluluk; orta boş
|
||||||
// Boş makro hücrede ara sıra tek küçük piksel: doku kopmasın
|
if (k >= kenar) continue;
|
||||||
if (hash(mx, my, seed + 3) < 0.25 * yogunluk) {
|
const density = (0.06 + 0.5 * (1 - k / kenar) ** 1.6) * yogunluk;
|
||||||
const px = ox + Math.floor(hash(mx, my, seed + 4) * MAKRO);
|
if (hash(mx, my, seed) > density) continue;
|
||||||
const py = oy + Math.floor(hash(mx, my, seed + 5) * MAKRO);
|
|
||||||
sonuc.push(kare(px, py, 1, `k-${mx}-${my}`, false));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const r = hash(mx, my, seed + 7);
|
const r = hash(mx, my, seed + 7);
|
||||||
const n = r < 0.5 ? 1 : r < 0.85 ? 2 : 3;
|
// 2–4 hücre: orta boy sık, iri seyrek
|
||||||
|
const n = r < 0.5 ? 2 : r < 0.85 ? 3 : 4;
|
||||||
const serbest = MAKRO - n;
|
const serbest = MAKRO - n;
|
||||||
const kx = ox + Math.floor(hash(mx, my, seed + 11) * (serbest + 1));
|
const kx = ox + Math.floor(hash(mx, my, seed + 11) * (serbest + 1));
|
||||||
const ky = oy + Math.floor(hash(mx, my, seed + 13) * (serbest + 1));
|
const ky = oy + Math.floor(hash(mx, my, seed + 13) * (serbest + 1));
|
||||||
const accent = n < 3 && hash(mx, my, seed + 99) > 0.94;
|
const accent = n === 2 && hash(mx, my, seed + 99) > 0.95;
|
||||||
sonuc.push(kare(kx, ky, n, `m-${mx}-${my}`, accent));
|
sonuc.push(kare(kx, ky, n, `m-${mx}-${my}`, accent));
|
||||||
// Büyük karenin yanına küçük bir eş: büyüklü küçüklü ritim
|
|
||||||
if (n < 3 && hash(mx, my, seed + 17) < 0.45) {
|
|
||||||
const ex = kx + n < ox + MAKRO ? kx + n : kx - 1;
|
|
||||||
const ey = ky + n < oy + MAKRO ? ky + n : ky - 1;
|
|
||||||
if (ex >= ox && ey >= oy) sonuc.push(kare(ex, ey, 1, `e-${mx}-${my}`, false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sonuc;
|
return sonuc;
|
||||||
}, [seed, bosBant, yogunluk]);
|
}, [olcu, seed, yogunluk, kenar]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
viewBox={`0 0 ${COLS * CELL} ${ROWS * CELL}`}
|
ref={svgRef}
|
||||||
preserveAspectRatio="xMidYMid slice"
|
viewBox={olcu ? `0 0 ${olcu.w} ${olcu.h}` : undefined}
|
||||||
|
preserveAspectRatio="xMinYMin slice"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
className={cn("h-full w-full", className)}
|
className={cn(
|
||||||
|
"h-full w-full transition-opacity duration-500 motion-reduce:transition-none",
|
||||||
|
pixels ? "opacity-100" : "opacity-0",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{pixels}
|
{pixels}
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
// hariç her yerde görünür; kapatma oturum boyunca kalıcıdır (sessionStorage).
|
// hariç her yerde görünür; kapatma oturum boyunca kalıcıdır (sessionStorage).
|
||||||
// Exit-intent/agresif popup YOK (PRD kuralı).
|
// Exit-intent/agresif popup YOK (PRD kuralı).
|
||||||
|
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
@@ -61,9 +60,8 @@ export function KaydetBanner() {
|
|||||||
ref={gorunumRef}
|
ref={gorunumRef}
|
||||||
// Telefonda metin kendi satırında, düğme altında tam genişlik:
|
// Telefonda metin kendi satırında, düğme altında tam genişlik:
|
||||||
// yan yana dizince başlık kelime kelime kırılıyordu (375 px).
|
// yan yana dizince başlık kelime kelime kırılıyordu (375 px).
|
||||||
className="pointer-events-auto relative isolate mx-auto flex max-w-xl flex-wrap items-center gap-3 overflow-hidden rounded-2xl border border-slate-200 bg-white p-4 pr-14 shadow-xl sm:flex-nowrap sm:gap-4"
|
className="pointer-events-auto relative mx-auto flex max-w-xl flex-wrap items-center gap-3 rounded-2xl border border-slate-200 bg-white p-4 pr-14 shadow-xl sm:flex-nowrap sm:gap-4"
|
||||||
>
|
>
|
||||||
<PikselZemin seed={47} />
|
|
||||||
{/* Kullanıcının o anki işletim sisteminin logosu: "bu tarayıcıda"
|
{/* Kullanıcının o anki işletim sisteminin logosu: "bu tarayıcıda"
|
||||||
mesajını somutlaştırır */}
|
mesajını somutlaştırır */}
|
||||||
<div className="flex size-10 shrink-0 items-center justify-center rounded-xl border border-slate-200 bg-slate-50 text-slate-700">
|
<div className="flex size-10 shrink-0 items-center justify-center rounded-xl border border-slate-200 bg-slate-50 text-slate-700">
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
@@ -59,8 +58,7 @@ export function PaketSatinAl() {
|
|||||||
className="mt-10 grid gap-6 sm:grid-cols-[1fr_auto]"
|
className="mt-10 grid gap-6 sm:grid-cols-[1fr_auto]"
|
||||||
>
|
>
|
||||||
{/* Ana paket */}
|
{/* Ana paket */}
|
||||||
<section className="relative isolate overflow-hidden rounded-2xl border-2 border-orange-500 bg-white p-8 shadow-sm">
|
<section className="rounded-2xl border-2 border-orange-500 bg-white p-8 shadow-sm">
|
||||||
<PikselZemin seed={43} />
|
|
||||||
<div className="flex items-baseline justify-between">
|
<div className="flex items-baseline justify-between">
|
||||||
<h2 className="font-heading text-xl font-bold">
|
<h2 className="font-heading text-xl font-bold">
|
||||||
Tercih Dönemi Paketi
|
Tercih Dönemi Paketi
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
// context'ten okur. (Sihirbaz hunisi statik bir şemayla anlatılır — bkz.
|
// context'ten okur. (Sihirbaz hunisi statik bir şemayla anlatılır — bkz.
|
||||||
// huni-semasi.tsx.)
|
// huni-semasi.tsx.)
|
||||||
|
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import {
|
import {
|
||||||
createContext,
|
createContext,
|
||||||
useContext,
|
useContext,
|
||||||
@@ -235,8 +234,7 @@ export function DemoKapanisCta() {
|
|||||||
const profil = useTercihProfili();
|
const profil = useTercihProfili();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative isolate overflow-hidden rounded-2xl border border-slate-200 bg-white p-6 text-center">
|
<div className="rounded-2xl border border-slate-200 bg-white p-6 text-center">
|
||||||
<PikselZemin seed={41} />
|
|
||||||
<p className="font-heading text-base font-bold text-slate-900">
|
<p className="font-heading text-base font-bold text-slate-900">
|
||||||
{profil
|
{profil
|
||||||
? "Kuralları öğrendin — sayılar zaten senin sıralamanla hesaplandı."
|
? "Kuralları öğrendin — sayılar zaten senin sıralamanla hesaplandı."
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
// Kural: action cevabının hemen ardından yönlendiriciye TEK aksiyon gönder
|
// Kural: action cevabının hemen ardından yönlendiriciye TEK aksiyon gönder
|
||||||
// (router.replace); ikinci aksiyon (refresh) ancak o gezinme bitince.
|
// (router.replace); ikinci aksiyon (refresh) ancak o gezinme bitince.
|
||||||
|
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import { useEffect, useRef, useState, type ReactNode } from "react";
|
import { useEffect, useRef, useState, type ReactNode } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
@@ -265,8 +264,7 @@ export function ListeUretici({
|
|||||||
// Paketli kullanıcıya paket satma: onun ürünü top-up. Liste ve sohbet
|
// Paketli kullanıcıya paket satma: onun ürünü top-up. Liste ve sohbet
|
||||||
// geçmişi kalıcı; kredi yükleyince kaldığı yerden devam eder.
|
// geçmişi kalıcı; kredi yükleyince kaldığı yerden devam eder.
|
||||||
return (
|
return (
|
||||||
<section className="relative isolate mx-auto w-full max-w-2xl overflow-hidden rounded-2xl border border-slate-200 bg-white p-8 text-center sm:p-12">
|
<section className="mx-auto w-full max-w-2xl rounded-2xl border border-slate-200 bg-white p-8 text-center sm:p-12">
|
||||||
<PikselZemin seed={23} />
|
|
||||||
<Lock className="mx-auto size-8 text-slate-400" aria-hidden />
|
<Lock className="mx-auto size-8 text-slate-400" aria-hidden />
|
||||||
<h1 className="mt-4 font-heading text-xl font-bold">
|
<h1 className="mt-4 font-heading text-xl font-bold">
|
||||||
Kredin bu liste için yetmiyor
|
Kredin bu liste için yetmiyor
|
||||||
@@ -296,8 +294,7 @@ export function ListeUretici({
|
|||||||
|
|
||||||
if (durum.ad === "hata") {
|
if (durum.ad === "hata") {
|
||||||
return (
|
return (
|
||||||
<section className="relative isolate mx-auto w-full max-w-2xl overflow-hidden rounded-2xl border border-slate-200 bg-white p-8 text-center sm:p-12">
|
<section className="mx-auto w-full max-w-2xl rounded-2xl border border-slate-200 bg-white p-8 text-center sm:p-12">
|
||||||
<PikselZemin seed={23} />
|
|
||||||
<h1 className="font-heading text-xl font-bold">Liste kurulamadı</h1>
|
<h1 className="font-heading text-xl font-bold">Liste kurulamadı</h1>
|
||||||
<p className="mx-auto mt-2 max-w-md text-sm text-slate-600">
|
<p className="mx-auto mt-2 max-w-md text-sm text-slate-600">
|
||||||
{durum.mesaj}
|
{durum.mesaj}
|
||||||
@@ -347,8 +344,7 @@ function SunucuYokEkrani() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative isolate mx-auto w-full max-w-2xl overflow-hidden rounded-2xl border border-slate-200 bg-white p-8 text-center sm:p-12">
|
<section className="mx-auto w-full max-w-2xl rounded-2xl border border-slate-200 bg-white p-8 text-center sm:p-12">
|
||||||
<PikselZemin seed={23} />
|
|
||||||
<h1 className="font-heading text-xl font-bold">
|
<h1 className="font-heading text-xl font-bold">
|
||||||
Listen hazır, sunucuya şu an ulaşamıyoruz
|
Listen hazır, sunucuya şu an ulaşamıyoruz
|
||||||
</h1>
|
</h1>
|
||||||
@@ -379,8 +375,7 @@ function SunucuYokEkrani() {
|
|||||||
* "Tekrar dene" yok: tekrar taze requestId üretip ikinci üretimi başlatırdı. */
|
* "Tekrar dene" yok: tekrar taze requestId üretip ikinci üretimi başlatırdı. */
|
||||||
function SuruyorEkrani() {
|
function SuruyorEkrani() {
|
||||||
return (
|
return (
|
||||||
<section className="relative isolate mx-auto w-full max-w-2xl overflow-hidden rounded-2xl border border-slate-200 bg-white p-8 text-center sm:p-12">
|
<section className="mx-auto w-full max-w-2xl rounded-2xl border border-slate-200 bg-white p-8 text-center sm:p-12">
|
||||||
<PikselZemin seed={23} />
|
|
||||||
<h1 className="font-heading text-xl font-bold">Listen zaten hazırlanıyor</h1>
|
<h1 className="font-heading text-xl font-bold">Listen zaten hazırlanıyor</h1>
|
||||||
<p className="mx-auto mt-2 max-w-md text-sm text-slate-600">
|
<p className="mx-auto mt-2 max-w-md text-sm text-slate-600">
|
||||||
Bunu başka bir sekmede başlatmışsın. İki kez kurmayalım — kredin bu
|
Bunu başka bir sekmede başlatmışsın. İki kez kurmayalım — kredin bu
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
// ekranda. Harita ⇄ liste köprüsü (pinden satıra, satırdan haritaya) ve
|
// ekranda. Harita ⇄ liste köprüsü (pinden satıra, satırdan haritaya) ve
|
||||||
// paketsiz paywall kartları burada; veri çekimi sunucuda (page.tsx) kalır.
|
// paketsiz paywall kartları burada; veri çekimi sunucuda (page.tsx) kalır.
|
||||||
|
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import { useMemo, useRef, useState } from "react";
|
import { useMemo, useRef, useState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import {
|
import {
|
||||||
@@ -338,9 +337,8 @@ export function ListemGovde({
|
|||||||
|
|
||||||
<section
|
<section
|
||||||
ref={kilitKartRef}
|
ref={kilitKartRef}
|
||||||
className="relative isolate overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm"
|
className="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm"
|
||||||
>
|
>
|
||||||
<PikselZemin seed={59} />
|
|
||||||
<div className="border-b border-slate-100 p-6">
|
<div className="border-b border-slate-100 p-6">
|
||||||
<h3 className="font-heading text-xl font-bold tracking-tight">
|
<h3 className="font-heading text-xl font-bold tracking-tight">
|
||||||
Tablo ücretsiz.
|
Tablo ücretsiz.
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import { raporMaskele, ACIK_SATIR } from "@/lib/rapor-maske";
|
|||||||
import type { Mesaj } from "./sohbet-client";
|
import type { Mesaj } from "./sohbet-client";
|
||||||
import { ListemGovde } from "./listem-govde";
|
import { ListemGovde } from "./listem-govde";
|
||||||
import { ListemBosCta } from "./listem-bos-cta";
|
import { ListemBosCta } from "./listem-bos-cta";
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import { ListeUretici } from "./liste-uretici";
|
import { ListeUretici } from "./liste-uretici";
|
||||||
import { UretimBasladiOlayi } from "./uretim-basladi-olayi";
|
import { UretimBasladiOlayi } from "./uretim-basladi-olayi";
|
||||||
|
|
||||||
@@ -66,8 +65,7 @@ export async function ListemIcerik({
|
|||||||
|
|
||||||
if (!raporVar) {
|
if (!raporVar) {
|
||||||
const bosDurum = (
|
const bosDurum = (
|
||||||
<section className="relative isolate mx-auto flex max-w-2xl flex-col items-center overflow-hidden px-4 py-16 text-center">
|
<section className="mx-auto flex max-w-2xl flex-col items-center px-4 py-16 text-center">
|
||||||
<PikselZemin seed={29} />
|
|
||||||
<Sparkles className="size-10 text-primary" aria-hidden />
|
<Sparkles className="size-10 text-primary" aria-hidden />
|
||||||
<h1 className="mt-4 font-heading text-2xl font-bold">
|
<h1 className="mt-4 font-heading text-2xl font-bold">
|
||||||
Henüz Yapay Zeka listen yok
|
Henüz Yapay Zeka listen yok
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
// varsa /api/tadimlik'ten kategoriye özel satır çekilip yerinde değiştirilir
|
// varsa /api/tadimlik'ten kategoriye özel satır çekilip yerinde değiştirilir
|
||||||
// (seçim sunucuda kalır). Havuzda içerik yoksa hiç render edilmez.
|
// (seçim sunucuda kalır). Havuzda içerik yoksa hiç render edilmez.
|
||||||
|
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ArrowRight } from "lucide-react";
|
import { ArrowRight } from "lucide-react";
|
||||||
@@ -151,8 +150,7 @@ export function TadimlikSatiri({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative isolate mt-6 overflow-hidden rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:p-6">
|
<div className="mt-6 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:p-6">
|
||||||
<PikselZemin seed={31} />
|
|
||||||
{/* Rapor listesinin satırıyla aynı düzen (§4.15): ad sarar,
|
{/* Rapor listesinin satırıyla aynı düzen (§4.15): ad sarar,
|
||||||
üniversite adı altında, taban sıra sağda iri. */}
|
üniversite adı altında, taban sıra sağda iri. */}
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import { authClient } from "@/lib/auth-client";
|
|||||||
import { olay, siraKovasi } from "@/lib/analitik";
|
import { olay, siraKovasi } from "@/lib/analitik";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { CtaBandi } from "@/components/cta-bandi";
|
import { CtaBandi } from "@/components/cta-bandi";
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import { onbellekliJsonGetir } from "@/lib/istek-cache";
|
import { onbellekliJsonGetir } from "@/lib/istek-cache";
|
||||||
import { useTercihProfili } from "@/features/liste/hooks/use-tercih-profili";
|
import { useTercihProfili } from "@/features/liste/hooks/use-tercih-profili";
|
||||||
import type { SihirbazFacetleri } from "@/types/yokatlas";
|
import type { SihirbazFacetleri } from "@/types/yokatlas";
|
||||||
@@ -374,11 +373,10 @@ export function CtaSiraForm({
|
|||||||
<section
|
<section
|
||||||
aria-labelledby={baslikId}
|
aria-labelledby={baslikId}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative isolate overflow-hidden rounded-2xl border p-4 transition-colors duration-200 sm:p-5",
|
"rounded-2xl border p-4 transition-colors duration-200 sm:p-5",
|
||||||
profil ? "border-primary/20 bg-primary/5" : "border-slate-200 bg-white",
|
profil ? "border-primary/20 bg-primary/5" : "border-slate-200 bg-white",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<PikselZemin seed={53} />
|
|
||||||
<div className="grid">
|
<div className="grid">
|
||||||
<div
|
<div
|
||||||
ref={profil ? undefined : formRef}
|
ref={profil ? undefined : formRef}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { animate } from "motion/mini";
|
|||||||
import { useReducedMotion } from "motion/react";
|
import { useReducedMotion } from "motion/react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { CtaBandi } from "@/components/cta-bandi";
|
import { CtaBandi } from "@/components/cta-bandi";
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import { useGorunumOlayi } from "@/components/use-gorunum-olayi";
|
import { useGorunumOlayi } from "@/components/use-gorunum-olayi";
|
||||||
import { olay, olayBirKez, siraKovasi } from "@/lib/analitik";
|
import { olay, olayBirKez, siraKovasi } from "@/lib/analitik";
|
||||||
import type { SihirbazFacetleri } from "@/types/yokatlas";
|
import type { SihirbazFacetleri } from "@/types/yokatlas";
|
||||||
@@ -263,8 +262,7 @@ export function SihirbazBolumu({
|
|||||||
edilmez; panel yalnızca funnel CTA'larını gösterir, üretim ve
|
edilmez; panel yalnızca funnel CTA'larını gösterir, üretim ve
|
||||||
listenin kendisi /listem'de yaşar. */}
|
listenin kendisi /listem'de yaşar. */}
|
||||||
{raporVar ? (
|
{raporVar ? (
|
||||||
<section className="relative isolate mt-16 overflow-hidden rounded-2xl border border-slate-200 bg-white p-8 text-center sm:p-12">
|
<section className="mt-16 rounded-2xl border border-slate-200 bg-white p-8 text-center sm:p-12">
|
||||||
<PikselZemin seed={21} />
|
|
||||||
<h2 className="font-heading text-2xl font-bold sm:text-3xl">
|
<h2 className="font-heading text-2xl font-bold sm:text-3xl">
|
||||||
24 tercihlik listen hazır
|
24 tercihlik listen hazır
|
||||||
</h2>
|
</h2>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
// sayfayı tazele (URL değişmez); yoksa kapıyı aç. Sıra bilgisi localStorage'daki
|
// sayfayı tazele (URL değişmez); yoksa kapıyı aç. Sıra bilgisi localStorage'daki
|
||||||
// TercihProfili ile tüm uygulamada ortak, sunucu tablosu çerezden okur.
|
// TercihProfili ile tüm uygulamada ortak, sunucu tablosu çerezden okur.
|
||||||
|
|
||||||
import { PikselZemin } from "@/components/piksel-zemin";
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
@@ -43,8 +42,7 @@ export function SiraGerekli() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="relative isolate mx-auto flex max-w-2xl flex-col items-center overflow-hidden px-4 py-24 text-center">
|
<main className="mx-auto flex max-w-2xl flex-col items-center px-4 py-24 text-center">
|
||||||
<PikselZemin seed={37} />
|
|
||||||
<h1 className="font-heading text-3xl font-bold text-balance text-slate-900 sm:text-4xl">
|
<h1 className="font-heading text-3xl font-bold text-balance text-slate-900 sm:text-4xl">
|
||||||
Önce sıralamanı gir
|
Önce sıralamanı gir
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
Reference in New Issue
Block a user