From 78ad84922a73de13939a525b8cf32028f40a2867 Mon Sep 17 00:00:00 2001 From: bilalgursen Date: Mon, 5 Oct 2026 10:20:02 +0300 Subject: [PATCH] =?UTF-8?q?feat(tema):=20a=C3=A7=C4=B1k=20/=20koyu=20/=20s?= =?UTF-8?q?istem=20temas=C4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TemaSaglayici (next-themes) + alt bilgide TemaSecici - globals.css: .dark bloğunda palet token'ları çevrilir; bileşenlere dark: sınıfı yazılmaz - yüzeyler bg-white → bg-card, koyu haplar text-slate-50, SVG'lerde sabit renk yerine değişken - DESIGN.md §2.3 + tasarim-denetim kuralları (yuzey-beyaz, koyu-hap-beyaz-yazi, dark-sinif), AGENTS.md karanlık mod bölümü - docs: koyu tema denetimi raporu Co-Authored-By: Claude Fable 5.1 --- .agents/skills/kolaytercih-tasarim/SKILL.md | 4 +- AGENTS.md | 6 +- .../2026-10-04/koyu-tema-denetimi.md | 114 ++++++++++++ docs/tasarim/DESIGN.md | 80 ++++++--- scripts/tasarim-denetim.ts | 24 ++- src/app/globals.css | 167 ++++++++++++++---- src/app/iletisim/page.tsx | 2 +- src/app/layout.tsx | 14 +- src/app/page.tsx | 20 +-- src/components/arama-funnel-karti.tsx | 2 +- src/components/cta-bandi.tsx | 2 +- src/components/dev/dev-panel.tsx | 14 +- src/components/ozet-kart.tsx | 2 +- src/components/piksel-cta-yuzeyi.tsx | 2 +- src/components/pixel-decor.tsx | 2 +- src/components/site-footer.tsx | 4 +- src/components/tema-saglayici.tsx | 43 +++++ src/components/tema-secici.tsx | 61 +++++++ src/components/ui/avatar.tsx | 2 +- src/components/ui/badge.tsx | 6 +- src/components/ui/button.tsx | 8 +- src/components/ui/code-block.tsx | 7 +- src/components/ui/input.tsx | 2 +- src/components/ui/kbd.tsx | 2 +- src/components/ui/select.tsx | 8 +- src/components/ui/sonner.tsx | 12 +- src/components/ui/tabs.tsx | 12 +- src/components/ui/textarea.tsx | 2 +- .../components/bolum-program-listesi.tsx | 2 +- src/features/katalog/components/il-icerik.tsx | 4 +- .../katalog/components/katalog-arama.tsx | 48 ++--- .../katalog/components/program-netleri.tsx | 4 +- src/features/katalog/components/sayfalama.tsx | 6 +- .../katalog/components/sehir-cipleri.tsx | 2 +- .../katalog/components/sehir-yuzeyi.tsx | 2 +- .../katalog/components/tur-icerik.tsx | 6 +- .../katalog/components/turkiye-siralamasi.tsx | 2 +- .../katalog/components/uni-satirlari.tsx | 2 +- .../components/universite-program-tablosu.tsx | 2 +- src/features/katalog/components/urap-logo.tsx | 2 +- .../kullanici/components/dogrula-karti.tsx | 4 +- .../kullanici/components/giris-form.tsx | 4 +- .../kullanici/components/giris-karti.tsx | 4 +- .../kullanici/components/giris-linki.tsx | 2 +- .../kullanici/components/sign-out-button.tsx | 2 +- .../kullanici/components/user-nav.tsx | 4 +- .../liste/components/kaydet-banner.tsx | 2 +- .../liste/components/liste-cekmecesi.tsx | 4 +- .../liste/components/liste-durumu-satiri.tsx | 4 +- .../liste/components/listem-butonu.tsx | 2 +- .../liste/components/program-ekle-butonu.tsx | 2 +- .../liste/components/program-tablosu.tsx | 12 +- .../liste/components/secimlerim-paneli.tsx | 6 +- .../liste/components/tercih-haritasi.tsx | 26 +-- .../liste/components/yurtdisi-haritalar.tsx | 10 +- .../odeme/components/odeme-sayfasi.tsx | 4 +- .../odeme/components/odeme-sonuc-karti.tsx | 8 +- .../odeme/components/paket-satinal.tsx | 10 +- .../rapor/components/liste-uretici.tsx | 12 +- .../rapor/components/listem-govde.tsx | 2 +- .../rapor/components/rapor-listesi.tsx | 10 +- .../rapor/components/rapor-yazdir.tsx | 4 +- .../rapor/components/revizyon-kutusu.tsx | 6 +- .../rapor/components/tadimlik-satiri.tsx | 2 +- .../rehber/components/el-cizimi-sema.tsx | 2 +- .../rehber/components/rehber-listesi.tsx | 4 +- .../sihirbaz/components/cta-sira-form.tsx | 6 +- .../sihirbaz/components/hero-form.tsx | 2 +- .../sihirbaz/components/il-secim-haritasi.tsx | 4 +- .../sihirbaz/components/sihirbaz-adimlar.tsx | 10 +- 70 files changed, 637 insertions(+), 243 deletions(-) create mode 100644 docs/ekip-raporlari/2026-10-04/koyu-tema-denetimi.md create mode 100644 src/components/tema-saglayici.tsx create mode 100644 src/components/tema-secici.tsx diff --git a/.agents/skills/kolaytercih-tasarim/SKILL.md b/.agents/skills/kolaytercih-tasarim/SKILL.md index 58ec3af..f2585c3 100644 --- a/.agents/skills/kolaytercih-tasarim/SKILL.md +++ b/.agents/skills/kolaytercih-tasarim/SKILL.md @@ -66,7 +66,7 @@ dokunma hedefi < 44 px, uzun üniversite adı. (Tarayıcı açma kuralı AGENTS. **İstek:** "Üniversite sayfasına URAP kartı ekle." **Çıktı:** ```tsx -
+

URAP Türkiye

18 / 198

@@ -79,7 +79,7 @@ dokunma hedefi < 44 px, uzun üniversite adı. (Tarayıcı açma kuralı AGENTS. ## 5. Kısa yasak listesi `Badge` import'u · elle pill span · CTA'da `Sparkles`/emoji · `indigo/purple/gray/zinc` · gradyan metin · -parlama gölgesi · `whileHover scale` · her elemanda fade-up · `dark:` · Inter/Roboto/serif · `text-[#hex]` · renk tek başına anlam. +parlama gölgesi · `whileHover scale` · her elemanda fade-up · `dark:` · yüzeyde `bg-white` (yerine `bg-card`, §2.3) · Inter/Roboto/serif · `text-[#hex]` · renk tek başına anlam. ## 6. Rapor diff --git a/AGENTS.md b/AGENTS.md index 47da23b..4dd02f3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,9 +24,13 @@ Push emri geldiğinde önce lokalde `pnpm build` başarıyla geçmeli; geçmeden UI'a dokunan her iş (yeni ekran, bileşen, kart, modal, buton, form; mevcut arayüz değişikliği) önce `docs/tasarim/DESIGN.md` okunarak yapılır; renk, yazı tipi, köşe, gölge, boşluk ve tek kaynak bileşenlerin sınıf dizileri oradan **birebir** alınır, "yaklaşık aynısı" yazılmaz. Aşağıdaki rozet/çarpı/CTA kuralları o belgenin özetidir. Genel tasarım katalogları (`ui-ux-pro-max` gibi "50 stil, 97 palet" kütüphaneleri) bu projede kullanılmaz; yön zaten belli. İş bitmeden `pnpm tasarim:denetim` sıfır hata vermeli (`pnpm lint` bunu da koşar); betik `scripts/tasarim-denetim.ts`, kural eklerken DESIGN.md'deki bölüm numarasına atıf yap. +# Karanlık mod: token'la çalışır, `dark:` yazılmaz + +Sitede açık / koyu / sistem teması var (DESIGN.md §2.3). Karanlık mod `src/app/globals.css` içindeki `.dark` bloğunda palet token'ları çevrilerek çalışır (slate ölçeği ters döner, renkli açık zeminler koyu tona iner); bileşenlere `dark:` sınıfı yazılmaz. Yeni UI yazarken: yüzey zemini `bg-card`'dır (`bg-white` koyu temada da beyaz kalır — yalnız logo karosu gibi gerçekten beyaz kalması gereken yerde); koyu hap (`bg-slate-900`) yazısını `text-slate-50` ile alır; SVG/satır içi stilde sabit renk yerine `var(--card)`, `var(--color-slate-200)` gibi değişken kullanılır; koyu vurgu yüzeyi (`bg-slate-950`) `kt-koyu-yuzey` sınıfını taşır. `pnpm tasarim:denetim` bunları `yuzey-beyaz`, `koyu-hap-beyaz-yazi` ve `dark-sinif` kurallarıyla yakalar. + # Badge/eyebrow rozetleri: tek kaynak SectionEyebrow -Site genelindeki tüm badge/rozet/eyebrow elemanları ana sayfadaki section başlıklarının üstünde duran rozetle birebir aynı olmalı. Kanonik bileşen `src/components/pixel-decor.tsx` içindeki `SectionEyebrow`dur (piksel imzalı `PixelMark` ikonu + `inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3.5 py-1.5 text-xs font-semibold text-primary`; metin büyük-küçük harfli yazılır — uppercase yok). Yeni bir badge/eyebrow gerektiğinde `SectionEyebrow` kullan (`className` prop'u kenar boşluğu için var); `@/components/ui/badge`'deki `Badge` ile ya da elle yazılmış pill span'lerle yeni badge tasarlama. İnteraktif chip/buton pill'leri (filtre çipleri, nav butonları) bu kuralın dışındadır. +Site genelindeki tüm badge/rozet/eyebrow elemanları ana sayfadaki section başlıklarının üstünde duran rozetle birebir aynı olmalı. Kanonik bileşen `src/components/pixel-decor.tsx` içindeki `SectionEyebrow`dur (piksel imzalı `PixelMark` ikonu + `inline-flex items-center gap-2 rounded-full border border-slate-200 bg-card px-3.5 py-1.5 text-xs font-semibold text-primary`; metin büyük-küçük harfli yazılır — uppercase yok). Yeni bir badge/eyebrow gerektiğinde `SectionEyebrow` kullan (`className` prop'u kenar boşluğu için var); `@/components/ui/badge`'deki `Badge` ile ya da elle yazılmış pill span'lerle yeni badge tasarlama. İnteraktif chip/buton pill'leri (filtre çipleri, nav butonları) bu kuralın dışındadır. # UI tutarlılığı: ortak elemanlar tek kaynaktan diff --git a/docs/ekip-raporlari/2026-10-04/koyu-tema-denetimi.md b/docs/ekip-raporlari/2026-10-04/koyu-tema-denetimi.md new file mode 100644 index 0000000..4557603 --- /dev/null +++ b/docs/ekip-raporlari/2026-10-04/koyu-tema-denetimi.md @@ -0,0 +1,114 @@ +# Koyu tema — gözle denetim (tasarımcı, 4 Eki 2026) + +Lokal dev sunucusunda (çalışma ağacı, commit yok) koyu tema 375 / 768 / 1280 px'te gezildi. +Kod değiştirilmedi. Sunucu iş sonunda kapatıldı. + +**Neden tarayıcı açıldı:** kontrast, açık kalan lekeler, taşma ve koyu temadaki yüzey ayrımı koddan +görülemiyor; değişiklik canlıda da yok. + +## Özet (5 madde) + +1. Koyu tema genel olarak sağlam: gezilen ~20 ekranın çoğunda okunmayan yazı, beyaz leke ya da kaybolan kenarlık yok. +2. **Temaya bağlı 2 önemli hata var:** `/sonuc`'ta seçili sekmenin sayısı görünmüyor; `/paket`'te iyzico/Visa/Troy logoları koyu zeminde kayboluyor. +3. Temaya bağlı 1 kozmetik leke: arama penceresindeki "Üniversiteler" karosunun ikon kutusu beyaz kalıyor (`sky-*` çevrilmemiş). +4. Girişli ekranlara girilmedi; koddan iki risk çıktı (kilit ikonu, sohbetteki kod bloğu) — gözle doğrulanmalı. +5. Temayla ilgisi olmayan ama gezerken görülen 2 mobil taşma var (`/paket` canlıda da taşıyor; arama penceresinde çarpı ekran dışına çıkıyor). + +`pnpm tasarim:denetim`: **0 hata, 12 uyarı** (hepsi eski: `secimlerim-paneli.tsx` büyük harf etiket / tabular-nums, `meraklisina-demo.tsx` 12 px altı yazı). + +## Bulgular (önem sırasıyla) + +### Önemli + +**1. `/sonuc` — seçili dilim sekmesinde sayı okunmuyor** (375, 768, 1280) +- Görülen: seçili sekme koyu temada açık hapa dönüyor (doğru), "Dengeli" yazısı koyu (doğru), ama altındaki/yanındaki sayı ("186") beyaz kaldığı için açık hap üstünde görünmüyor. Sekme ikonu da (sarı terazi) açık hap üstünde çok silik. +- Kaynak: `src/features/liste/components/program-tablosu.tsx:234` → `text-white/70`; ikon `:75, :82, :89` → `renkAktif: text-red-400 / text-amber-400 / text-emerald-400` (koyu hap için seçilmiş açık tonlar). +- Kural: DESIGN.md §2.3 "koyu hap yazısını `text-slate-50` ile alır, `text-white` ile değil". +- Düzeltme: sayı `text-slate-50/70`. İkon için en basiti: seçili sekmede ikon da hapın yazı rengini alsın (`text-slate-50`); anlamı zaten etiket taşıyor. Renk korunacaksa `renkAktif` kaldırılıp `renk` kullanılır ama sarı açık hapta yine zayıf kalır. + +**2. `/paket` — iyzico logo bandı koyu zeminde kayboluyor** (375, 1280) +- Görülen: "VISA" ve "troy" neredeyse görünmüyor, iyzico yazısı silik. Footer'daki aynı bant beyaz hap üstünde ve sorunsuz. +- Kaynak: `src/features/odeme/components/paket-satinal.tsx:86-92` ve `src/features/odeme/components/odeme-sayfasi.tsx:90-96` — `kt-acik-logo` sınıfı yok (footer'da var: `site-footer.tsx:205`). +- Düzeltme: iki `Image`'a `kt-acik-logo` ekle. (Ödeme sayfası girişli; gözle bakılmadı, aynı kod.) +- Not: iyzico sözleşmesi logoların görünür olmasını istiyor; bu yüzden kozmetik değil. + +**3. `/listem` kilit satırı — ikon kaybolur** (koddan çıkarım, girişli ekran) +- `src/features/rapor/components/listem-govde.tsx:294` → `bg-orange-100 text-orange-700`. `orange-100` `.dark` bloğunda yok (açık şeftali kalır), `orange-700` ise açık tona çevrilmiş → açık zemin üstünde açık ikon. +- Düzeltme: `globals.css` `.dark` bloğuna `--color-orange-100` koyu karşılığı ekle (ör. `oklch(0.32 0.07 50)`), ya da sınıfı `bg-orange-50` yap. + +**4. Danışman sohbetinde kod bloğu** (koddan çıkarım, girişli ekran) +- `src/components/ui/code-block.tsx:36` → shiki teması sabit `github-light`: koyu yüzeyde koyu yazı. +- Düzeltme: temayı `useTheme().resolvedTheme`'e göre `github-dark` / `github-light` seç (toast'taki desenle aynı, §4.16). Danışman nadiren kod yazdığı için aciliyeti düşük. + +### Kozmetik + +**5. Arama penceresi (boş durum) — "Üniversiteler" karosu beyaz ikon kutusu** (1280; 375'te de aynı kod) +- Görülen: üç keşif karosundan ortadakinin ikon kutusu parlak beyaz/açık mavi; diğer ikisi koyu. +- Kaynak: `src/features/katalog/components/katalog-arama.tsx:95-97` → `bg-sky-300`, `bg-sky-50`, `bg-sky-100` (ve `:101` `bg-amber-300`). `.dark` bloğunda yalnız `sky-200` ve `sky-600` var. +- Düzeltme: `.dark` bloğuna `--color-sky-50`, `--color-sky-100` koyu ton ekle (§2.3 son madde: "yeni ton eklenince karşılığı yazılır"). + +**6. Mobil tarayıcı çubuğu rengi sistemi izliyor, siteyi değil** +- `src/app/layout.tsx:75-78` `themeColor` `prefers-color-scheme` ile seçiliyor. Sistem açık + sitede "Koyu" seçiliyse adres çubuğu açık renk kalır. Düşük öncelik; istenirse tema değişince `` güncellenir. + +**7. `/meraklisina` 375 px — beyaz şema kâğıdı üst çubuğun altından geçerken logo çevresi grileşiyor** +- Logo yazısı okunuyor ama bulanık katman kâğıdın beyazını taşıyor. Rehber kapaklarında aynı durum gözlenmedi (üst çubuk koyu kaldı). Bilal baksın; düzeltme şart değil. + +### Temayla ilgisi yok, gezerken görüldü + +**8. `/paket` 375 px — sayfa yatay taşıyor** (önemli; **canlıda da var**, kolaytercih.com/paket'te doğrulandı) +- Görülen: "299 TL" → "299 T", madde metinleri ve turuncu buton sağdan kesik. +- Muhtemel kaynak: `paket-satinal.tsx:58` `grid gap-6 sm:grid-cols-[1fr_auto]` — telefonda tek sütun `auto`; `:133` buton metni ("Giriş yap — ilk 3 tercihini ücretsiz gör") tek satırda sığmadığı için sütunu genişletiyor. +- Düzeltme: kaba `grid-cols-[minmax(0,1fr)]` (telefon) ve butona `whitespace-normal h-auto min-h-12` ya da metni kısalt. + +**9. Arama penceresi 375 px — sonuç gelince içerik sağa taşıyor, kapatma çarpısı ekran dışında** (önemli; canlıda doğrulanamadı) +- Görülen: "bilgisayar" yazınca uzun bölüm adı ve rehber kartı pencerenin sağ kenarından kesiliyor; giriş satırındaki çarpı görünmüyor. Sonuç yokken (boş/"bulunamadı") düzen doğru, çarpı yerinde. +- Muhtemel kaynak: `katalog-arama.tsx:396` — `DialogContent` `grid` ama sütun tanımı yok; `truncate` satırlar sütunu genişletiyor. +- Düzeltme: aynı satıra `grid-cols-[minmax(0,1fr)]`. + +**10. Sihirbaz — kapatma çarpısı üçüncü adım çubuğunun ucuna biniyor** (375, 1280; kozmetik) +- `sihirbaz-adimlar.tsx` adım çubuğu satırına sağdan çarpı kadar boşluk (`pr-12`). + +**11. `/giris` — "Giriş bağlantısı gönder" butonunda başta zarf ikonu** (kozmetik) +- AGENTS.md CTA kuralı: başta ikon yok, sonda `ArrowRight`. Kaynak `src/features/kullanici/components/giris-form.tsx:181` civarı. + +**12. Arama penceresi alt satırı** — sonuçlar listelenirken de "En az 2 harf yazarak ara" yazıyor (metin; kozmetik). + +## Sorunsuz bulunan ekranlar (koyu tema) + +- Ana sayfa 375 / 768 / 1280: hero + piksel harita, sorun kartları, üç adım, sayılar + dürüstlük notu, karşılaştırma tablosu, fiyat kartları, SSS, CTA bandı, footer, tema seçici, iyzico hapı. +- Üst çubuk: logo, orta nav, "Ara" (açık hap + koyu yazı) ve Kbd'ler, "Giriş yap", sıralama hapı, Listem sayacı, üst mavi bant, üst/alt blur. +- Arama penceresi 1280: giriş satırı, üniversite sonuçları + logo karoları, çarpı, koyu funnel kartı. +- `/universiteler`, `/universiteler/istanbul` (şehir yüzeyi + piksel harita), `/universite/ankara-universitesi` (özet kartlar, harita, program tabloları, eğilim çizgisi), akademik göstergeler çekmecesi, `/bolumler`, `/bolum/bilgisayar-muhendisligi` (375 + 1280), netler çekmecesi. +- Sihirbaz: sıralama penceresi, puan türü açılır listesi, alan çipleri, şehir çipleri + il seçim haritası, öncelik adımı. +- `/sonuc`: başlık, Türkiye haritası, tablo satırları, risk etiketleri (sekme hariç — bulgu 1). +- Liste çekmecesi, kaydet banner'ı, "Listene eklendi" bildirimi (açık düğme + koyu yazı). +- `/rehber` (kapaklar bilinçli beyaz), mermaid şemalı yazı, `/meraklisina` (dilim şeridi, huni şeması beyaz kâğıtta), `/giris`, `/iletisim`, `/gizlilik`, 404. +- Odak halkası: hero giriş alanı ve "Giriş yap" üstünde mavi halka görünür. +- Açık tema, ana sayfa 1280: hero, üç adım, tablo, fiyat, CTA bandı, footer — gerileme görülmedi. + +## Bakılamayanlar + +- Girişli ekranlar: `/listem` raporu, danışman sohbeti, `/odeme`, kredi/tercih değişti modalları. +- KKTC/yurt dışı haritaları (`yurtdisi-haritalar.tsx`) — test seçiminde çıkmadı. +- Tema değişirken titreme/flash: araç anlık kare yakalayamıyor; görünür bir bozulma fark edilmedi ama doğrulanmış sayılmaz. +- Hover hâlleri tek tek denenmedi (yalnız netler düğmesinde turuncu hover görüldü, sorunsuz). +- Ekran görüntüleri 1280'de %62 ölçekli geldi; ince kontrast farkları (silik gri metinler) gözle kesinleştirilemedi. + +## Bilal'in gözle bakması gerekenler + +1. `/sonuc` → seçili sekme (Hayal/Dengeli/Güvenli), koyu tema. +2. `/paket` → iyzico logo satırı, koyu tema; aynı sayfa telefonda sağdan kesik mi. +3. Telefonda arama → "bilgisayar" yaz → çarpı görünüyor mu. +4. Girişliyken `/listem` kilit satırı ve bir danışman yanıtı (kod bloğu varsa). +5. `/rehber` listesi koyu temada: beyaz kapaklar art arda — bilinçli karar, göze nasıl geldiğine bak. + +## Bilal'den istenen + +1. Bulgu 1 ve 2'nin commit öncesi düzeltilmesine onay (iki küçük sınıf değişikliği) — 1 dk. +2. Bulgu 8 ve 9 (mobil taşma, canlıda da var) için ayrı iş açılsın mı kararı — 2 dk. +3. Girişli ekranlara koyu temada bir kez göz atmak (liste yukarıda, madde 4) — 5 dk. + +## Not + +Önizleme tarayıcısında test verisi kaldı (sıralama 85.000, listede 3 program) ve tema "Koyu"da kalmış olabilir; +yalnız önizleme panelinin yerel depolamasında, koda ya da veritabanına yazılmadı. Form gönderimi, giriş, ödeme yapılmadı. diff --git a/docs/tasarim/DESIGN.md b/docs/tasarim/DESIGN.md index 86b9659..23ae169 100644 --- a/docs/tasarim/DESIGN.md +++ b/docs/tasarim/DESIGN.md @@ -48,15 +48,16 @@ ve üniversite sayfası. Bu hissi veren şeyler, ekrandan bağımsız: ### 1.2 Genel kurallar -- Zemin her zaman beyaz; koyu zemin yalnızca CTA bandı ve çekmece başlığı gibi tek bir - vurgu yüzeyinde (`PixelMasonry` ile: büyüklü küçüklü, hafif kaymış kareler). +- Açık temada zemin beyaz (koyu temada karşılığı, §2.3); koyu zemin yalnızca CTA bandı ve + çekmece başlığı gibi tek bir vurgu yüzeyinde (`PixelMasonry` ile: büyüklü küçüklü, hafif kaymış kareler). - İmza dekoratiftir ama rastgele değildir: deterministik ızgara (hücre 10, nokta 7.4, rx 2), imleç yaklaşınca turuncuya ısınan pikseller (`usePixelHeat`), uzaklaşınca yavaş soğuma. Piksel **veri taşıyorsa** (ör. `PixelSira`) kalır; iki bölüm arasına **süs olarak** konmuş piksel ayraç alt sayfalarda ve kompakt panellerde kullanılmaz. - Ton: öğrenciye "sen" diyen, sakin, vaatsiz. Süs yok, gösteriş yok; hareket yalnızca bir şey söylüyorsa var. -- **Karanlık mod yoktur.** `dark:` sınıfı yazılmaz (`.dark` token'ları shadcn kalıntısıdır). +- **Karanlık mod token'la çalışır, `dark:` sınıfı yazılmaz** (§2.3). Bileşen tek bir sınıf + dizisiyle yazılır; iki temada doğru görünmesi palet token'larının işidir. ## 2. Renk paleti ve rolleri @@ -123,6 +124,43 @@ turuncu **tek tondur: `orange-500`** — CTA butonunun turuncusuyla birebir ayn altında kalır (sitenin turuncu CTA'sı da aynı ikiliyi kullanır). Bu zeminlerde etiket `font-bold`, sayı en az `text-3xl`; uzun metin konmaz. +### 2.3 Karanlık mod + +Bilal'in kararı (4 Eki 2026): sitede açık / koyu / sistem teması var; varsayılan açık. +Seçici `src/components/tema-secici.tsx` (footer'da), sağlayıcı `src/components/tema-saglayici.tsx` +(`next-themes`, ``). Renklerin tek kaynağı `src/app/globals.css` içindeki +`.dark` bloğu. + +**Nasıl çalışır:** bileşenlere `dark:` yazılmaz; palet token'ları çevrilir. + +| Açık temadaki sınıf | Koyu temada ne olur | +|---|---| +| `bg-card` (yüzey: kart, hap, form alanı, modal, çekmece) | Koyu yüzey (`#111826`) | +| `bg-slate-50` (gövde zemini, kart içi ikincil kutu) | En koyu zemin (`#080e19`) | +| `slate-100…900` (metin, kenarlık, hover zemini) | Ölçek ters döner: `text-slate-900` açık başlık, `border-slate-200` koyu çizgi | +| `bg-orange-50/60`, `bg-amber-50`, `bg-emerald-50`, `bg-red-50`, `border-*-200` | Aynı rengin koyu tonu | +| `text-amber-900`, `text-emerald-800`, `text-red-600` gibi koyu renkli metin | Aynı rengin açık tonu | +| `text-white`, `bg-orange-500`, `bg-primary`, `bg-emerald-500`, `bg-red-500` | **Değişmez** | + +**Kurallar:** + +- **Yüzey `bg-card`'dır, `bg-white` değil.** `bg-white` koyu temada da beyaz kalır; yalnız + gerçekten beyaz kalması gereken yerde yazılır: üniversite logosu karosu (`uni-logo.tsx`), + kaydırıcı topuzu, rehber kapak görseli, renkli dolu zemin üstündeki `bg-white/15` ikon kutusu. +- **Koyu hap** (`bg-slate-900`: "Giriş yap", "Ara", sekme göstergesi, toast düğmesi) yazısını + `text-slate-50` ile alır, `text-white` ile değil: koyu temada hap açığa, yazı koyuya döner. +- **Koyu vurgu yüzeyi** (`bg-slate-950`: `PikselCtaYuzeyi`, `AramaFunnelKarti`) `kt-koyu-yuzey` + sınıfını taşır; iki temada koyu kalır, içindeki açık slate metinler çevrilmez. `slate-950` + metin rengi olarak kullanılmaz. +- **SVG ve satır içi stilde** sabit renk yerine değişken: `var(--card)`, `var(--color-slate-200)`, + `var(--kt-harita-dolu)`. Risk renkleri (`RISK_RENK`) ve logo renkleri iki temada aynıdır. +- **Açık kalan adalar:** el çizimi şemalar (`kt-sema-kagit`) ve iyzico logo bandı + (`kt-acik-logo`; footer, paket ve ödeme sayfası) koyu temada beyaz kâğıt/hap üstünde durur; + tek renk koyu logo (URAP) `kt-koyu-cevir` ile açığa çevrilir; yazdırma çıktısı her zaman açıktır + (`.dark` bloğu `@media screen` içinde). +- Yeni bir renk tonu ilk kez kullanılıyorsa (`bg-sky-50` gibi) `.dark` bloğuna karşılığı eklenir; + eklenmezse koyu temada açık renkli bir leke olarak kalır. + ## 3. Tipografi Dört arayüz yazı tipi (+ yalnız Kur'an metni için bir Arapça yazı tipi), her birinin tek bir işi var: @@ -199,7 +237,7 @@ bir dosyaya (`src/components/…`) çıkarılıp iki yer de oradan kullanır. ```tsx Nasıl çalışır? ``` -Sınıfı: `inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3.5 py-1.5 text-xs font-semibold text-primary` + başta `PixelMark`. +Sınıfı: `inline-flex items-center gap-2 rounded-full border border-slate-200 bg-card px-3.5 py-1.5 text-xs font-semibold text-primary` + başta `PixelMark`. `@/components/ui/badge` **kullanılmaz**; elle pill span yazılmaz. Filtre çipleri, nav butonları ve kimlik hapları (§4.12) bu kuralın dışındadır. Rozet **sayfa** bölüm başlıklarının üstündedir; çekmece ve modal başlıklarında kullanılmaz (§4.10, Bilal 24 Eyl 2026). @@ -211,7 +249,7 @@ Alt sayfada (`Drawer`) aynı sınıf seti `DrawerClose` üstünde kullanılır ( ### 4.4 Kart ve kutu - Landing/öne çıkan kart: `` + sağ üstte ``. (Kodda hâlâ `hover:border-primary/30 hover:shadow-primary/5`; §2.1 geçiş notu.) -- Sade kutu (form, panel, liste satırı): `rounded-2xl border border-slate-200 bg-white` (+ `p-5`/`p-6`). Küçük iç kutu: `rounded-xl border border-slate-200 bg-slate-50`. Not kutusu: `rounded-lg`. +- Sade kutu (form, panel, liste satırı): `rounded-2xl border border-slate-200 bg-card` (+ `p-5`/`p-6`). Küçük iç kutu: `rounded-xl border border-slate-200 bg-slate-50`. Not kutusu: `rounded-lg`. - İkon kutusu: `flex size-11 items-center justify-center rounded-xl bg-primary/10` içinde `size-5 text-primary` ikon. Kart içinde sayının yanında küçük hâli: `size-8 … sm:size-10` + `size-4 sm:size-5` ikon (§4.8). - Gölge: `shadow-sm` varsayılan; hover'da `shadow-lg shadow-orange-500/5`. Başka gölge yok. @@ -223,7 +261,7 @@ Nokta + metin: `` yanınd Form alanı da bir **hap**tır: üst çubuktaki arama/kullanıcı haplarıyla aynı kalıp (48 px, tam yuvarlak, slate-200 kenarlık, 16 px yazı). shadcn'in ince varsayılanı (`h-8 rounded-lg border-input md:text-sm`) bu projede yoktur; temel bileşenler 24 Eyl 2026'da bu dile çevrildi. -- **Metin alanı (`Input`)**: `h-12 w-full rounded-full border border-slate-200 bg-white px-5 text-base text-slate-900 placeholder:text-slate-400`; +- **Metin alanı (`Input`)**: `h-12 w-full rounded-full border border-slate-200 bg-card px-5 text-base text-slate-900 placeholder:text-slate-400`; hover `border-slate-300`; odak `border-primary ring-3 ring-ring/50`; hata (`aria-invalid`) `border-red-500 ring-3 ring-red-500/20`; devre dışı `bg-slate-50 opacity-50`. `md:text-sm` yok — gövde 16 px altına inmez (§3) ve iOS odakta yakınlaştırmaz. Kullanım yerinde yükseklik/köşe/zemin @@ -233,9 +271,9 @@ border-input md:text-sm`) bu projede yoktur; temel bileşenler 24 Eyl 2026'da bu `pointer-events-none absolute left-5 top-1/2 size-4 -translate-y-1/2 text-slate-400`, alan `pl-12`. - **Seçim (`SelectTrigger`)**: aynı hap — `h-12 pl-5 pr-4 text-base`, ok `text-slate-400`; `size="sm"` → `h-9 px-4 text-sm` (yalnız masaüstü tablo aksiyonu, §8). Açılan liste - `rounded-2xl border border-slate-200 bg-white p-1.5 shadow-lg`; satır `rounded-full py-2 pl-4 pr-9 text-base`, + `rounded-2xl border border-slate-200 bg-card p-1.5 shadow-lg`; satır `rounded-full py-2 pl-4 pr-9 text-base`, klavye/odak `bg-slate-100`, seçili işareti `text-primary`. -- **Çok satır (`Textarea`)**: hap değil sade kutu (§4.4): `min-h-24 rounded-2xl border border-slate-200 bg-white px-5 py-3 text-base`; +- **Çok satır (`Textarea`)**: hap değil sade kutu (§4.4): `min-h-24 rounded-2xl border border-slate-200 bg-card px-5 py-3 text-base`; hover/odak/hata metin alanıyla aynı. Sohbet kutusu (`prompt-input.tsx`) kenarlıksız ve şeffaf üstüne yazar; tek istisna. - **Kenarlıksız ham ``** yalnız kendi hap kabının içinde: il arama @@ -265,7 +303,7 @@ yanındaki 2×2). └──────────────────────┘ ``` -- Kap: `flex flex-col rounded-2xl border border-slate-200 bg-white p-4 sm:p-5`. +- Kap: `flex flex-col rounded-2xl border border-slate-200 bg-card p-4 sm:p-5`. - Sayı satırı: `flex items-start justify-between gap-1.5`; sayı §3 "Özet kartı sayısı"; ikon kutusu `flex size-8 shrink-0 items-center justify-center rounded-xl bg-primary/10 sm:size-10`. - `dl` anlamı için `dt` (başlık) DOM'da önce gelir, görsel sıra `order-*` ile kurulur. @@ -283,7 +321,7 @@ yanındaki 2×2). ### 4.9 Ayrıntı satırı — `AkademikAyrinti`, `akademik-ayrinti.tsx` Özet kartlarının altında "fazlası burada" satırı (Apple Sağlık'taki "Tüm verileri göster"). -- `mt-4 flex w-full items-center gap-4 rounded-2xl border border-slate-200 bg-white p-4 sm:p-5` +- `mt-4 flex w-full items-center gap-4 rounded-2xl border border-slate-200 bg-card p-4 sm:p-5` + hover §2.1 + `active:scale-[0.99]`. - Solda ikon kutusu (`size-11`), ortada iki satır: başlık `font-heading text-lg font-bold`, altında **önizleme** `truncate text-sm text-slate-500` — içeride ne olduğunu söyler ("Hoca @@ -293,7 +331,7 @@ yanındaki 2×2). ### 4.10 Alt sayfa (Drawer) içeriği Ayrıntı her zaman **alttan açılan sayfada** (`Drawer handleOnly`, tutamaçlı); ekranın ortasında açılan modal değil. Çekmece kabı ve çarpı `cta-sira-form.tsx`'teki çekmeceyle birebir: -`DrawerContent className="max-h-[92dvh] bg-white sm:mx-auto sm:max-w-2xl sm:border-x sm:border-slate-200 sm:shadow-2xl"`. +`DrawerContent className="max-h-[92dvh] bg-card sm:mx-auto sm:max-w-2xl sm:border-x sm:border-slate-200 sm:shadow-2xl"`. İçerik kuralları (Apple ayrıntı sayfası): - **Her ekranda ortalı:** başlık `px-10 text-center font-heading text-2xl font-bold`, altında @@ -351,7 +389,7 @@ aşağı kaymış, kare boyları farklı — ne tepeler ne bitişler hizalı.** ### 4.12 Kimlik hapları (tür, il) Başlığın altında kurumun kimliği; navbar haplarının ölçüsünde: -`inline-flex h-10 items-center gap-2 rounded-full border border-slate-200 bg-white px-4 text-sm font-semibold text-slate-800` +`inline-flex h-10 items-center gap-2 rounded-full border border-slate-200 bg-card px-4 text-sm font-semibold text-slate-800` + başta `size-4 text-primary` ikon (`Landmark` devlet, `Building2` vakıf, `MapPin` il). Tür renkle değil ikonla ayrılır. Rozet (§4.2) değildir. **Devlet/vakıf hapı tür sayfasına** (§4.18), **il hapı şehir sayfasına link**tir (Bilal, 24 Eyl 2026: "şehirlerin geçtiği her yer tıklanabilir") — aynı @@ -431,18 +469,18 @@ tablosu bu sabitleri kullanır, sınıfı elle yazmaz. - Tablo başlığı `h-12 text-sm font-semibold text-slate-500`; hücre dolgusu `py-4 pl-4 sm:pl-5`. ### 4.16 Bildirim (toast) — `src/components/ui/sonner.tsx` + `globals.css` -Tema **light'a sabit** (karanlık mod yok, §1.2): sistem koyu temadayken sonner açıklamayı beyaza -yakın griye çevirip beyaz zeminde okunmaz ediyordu (Bilal, 24 Eyl 2026: "toast açıklaması -okunmuyor"). Kutu `rounded-2xl border-slate-200`; başlık `font-semibold text-slate-900`; açıklama -`text-slate-600`; aksiyon düğmesi üst çubuktaki koyu hap (`h-9 rounded-full bg-slate-900` beyaz -yazı, hover `slate-700`). Metin §10.4: ne oldu + ne yapılacak; kilometre taşı toast'ları +Tema **sitenin temasını izler** (`useTheme().resolvedTheme`, §2.3), sistemin değil: sistem koyu +temadayken sonner açıklamayı beyaza yakın griye çevirip beyaz zeminde okunmaz ediyordu (Bilal, +24 Eyl 2026: "toast açıklaması okunmuyor"). Kutu `rounded-2xl border-slate-200`; başlık `font-semibold text-slate-900`; açıklama +`text-slate-600`; aksiyon düğmesi üst çubuktaki koyu hap (`h-9 rounded-full bg-slate-900`, +yazı `slate-50`, hover `slate-700`). Metin §10.4: ne oldu + ne yapılacak; kilometre taşı toast'ları (`program-ekle-butonu.tsx`) tek cümle açıklama + tek aksiyon taşır. ### 4.17 Şehir çipleri — `SehirCipleri`, `src/features/katalog/components/sehir-cipleri.tsx` Şehre göre üniversite gezinmesi (`/universiteler` üstü ve `/universiteler/[il]` altı). Sihirbazın il çipiyle aynı kalıp; etkileşimli çip olduğu için rozet (§4.2) değildir: `inline-flex h-10 cursor-pointer items-center gap-1.5 rounded-full border px-3.5 text-sm font-semibold transition-[background-color,border-color,color,transform] duration-150 active:scale-[0.97]` -+ pasif `border-slate-200 bg-white text-slate-700 hover:border-orange-500 hover:bg-orange-50/60 hover:text-orange-500`, ++ pasif `border-slate-200 bg-card text-slate-700 hover:border-orange-500 hover:bg-orange-50/60 hover:text-orange-500`, bulunulan şehir `border-primary bg-primary text-white` + `aria-current="page"`. Ad yanında üniversite sayısı `font-normal tabular-nums text-slate-400` (aktifte `text-white/80`). - Çip satırında yalnız **2+ üniversiteli** şehirler (≈28) durur; 90'ı aşkın şehrin tamamı @@ -450,7 +488,7 @@ bulunulan şehir `border-primary bg-primary text-white` + `aria-current="page"`. bakılan önde, ayrıntı bir dokunuş derinde"). Satırın sonunda "Tüm şehirler (N)" çipi. - Şehir sayfası (`il-icerik.tsx`) katalog detay düzenindedir (§5.2): yol satırı, **başlık yüzeyi** (`SehirYuzeyi`: `relative isolate overflow-hidden rounded-3xl border border-slate-200 - bg-white p-6 sm:p-8`, `PikselZemin ton="acik"` seed 31, harita kabı `haric`), içinde h1 + bg-card p-6 sm:p-8`, `PikselZemin ton="acik"` seed 31, harita kabı `haric`), içinde h1 "İstanbul Üniversiteleri Taban Puanları 2026", kimlik hapları (`MapPin` il + üniversite sayısı), özet paragraf; sağda (lg, 24rem sütun) ya da altta (telefon) **şehri temsil eden piksel harita** `SehirPikselHaritasi`. Sonra kompakt `CtaSiraForm`, `PagePixelDivider` @@ -602,7 +640,7 @@ Hareket kuralları (Apple, `motion/react`): | CTA: metin + sondaki `ArrowRight` | Başta `Sparkles`/yıldız ikonu, "✨" | | Nötr = slate; vurgu = primary mavi; aksiyon ve hover = orange-500 | `indigo/purple` primary, mor→mavi gradyan, `gray/zinc` nötr | | Hover'da tek turuncu (`orange-500`); liste satırı adı mavi (§2.1 istisnası) | Liste dışında hover'da mavi; aynı ekranda `orange-600` yazı + `orange-300` kenarlık | -| Kart: `rounded-2xl border-slate-200 bg-white shadow-sm` | Her şeyde `rounded-3xl`, camsı `backdrop-blur` kartlar, parlama gölgesi | +| Kart: `rounded-2xl border-slate-200 bg-card shadow-sm` | Her şeyde `rounded-3xl`, camsı `backdrop-blur` kartlar, parlama gölgesi | | Sayı kartın en iri öğesi, ikon sağda küçük | İkon üstte büyük, sayı küçük; BÜYÜK HARFLİ `text-xs` etiket | | Sayfada ≤4 özet sayı, fazlası ayrıntı satırı → alt sayfa | 6+ kartı sayfaya dizmek ya da hepsini yatay şeride sıkıştırmak | | Harita gibi nefes alanını olduğu gibi bırakmak | Nefes alanını küçültüp bilgi şeridine gömmek | @@ -613,7 +651,7 @@ Hareket kuralları (Apple, `motion/react`): | Başlık `font-heading`, vurgu `font-bricolage` | Inter/Roboto/serif, tek kelimelik BÜYÜK HARF etiket, 10–11 px yazı | | Risk rengi + metin etiketi; tür ayrımı ikonla | Renk tek başına, "yerleşirsin" gibi vaat cümlesi | | Üç kart yalnızca üç gerçek öğe varsa | Hero + üç kart iskeleti refleksi | -| Beyaz zemin, tek koyu vurgu yüzeyi | İstenmemiş karanlık mod, `dark:` sınıfı | +| Yüzey `bg-card`, tek koyu vurgu yüzeyi; karanlık mod token'dan (§2.3) | `dark:` sınıfı, yüzeyde `bg-white`, koyu hapta `text-white` | | Kapatma çarpısı `DialogContent` varsayılanı | Başka boyut/renkte çarpı | | Form alanı hap: `Input`/`SelectTrigger` varsayılanı (`h-12 rounded-full`), yalnız yerleşim sınıfı eklenir | Kullanım yerinde `h-9 rounded-lg bg-background`; kenarlıklı ham ``; `md:text-sm` | diff --git a/scripts/tasarim-denetim.ts b/scripts/tasarim-denetim.ts index 5457fbe..cb67f11 100644 --- a/scripts/tasarim-denetim.ts +++ b/scripts/tasarim-denetim.ts @@ -97,7 +97,7 @@ const KURALLAR: Kural[] = [ seviye: "hata", mesaj: "Elle yazılmış rozet; SectionEyebrow'u içe aktar (DESIGN.md §4.2)", muaf: /src\/components\/pixel-decor\.tsx$/, - bul: regexKurali(/rounded-full border border-slate-200 bg-white px-3\.5 py-1\.5/), + bul: regexKurali(/rounded-full border border-slate-200 bg-card px-3\.5 py-1\.5/), }, { ad: "modal-rozet", @@ -199,10 +199,28 @@ const KURALLAR: Kural[] = [ }, { ad: "dark-sinif", - seviye: "uyari", - mesaj: "Üründe karanlık mod yok; dark: sınıfı gereksiz (DESIGN.md §1)", + seviye: "hata", + mesaj: "Karanlık mod token'la çalışır; dark: sınıfı yazılmaz, .dark bloğuna karşılık eklenir (DESIGN.md §2.3)", + uiDahil: true, bul: regexKurali(/(?<=[\s"'`])dark:[a-z]/), }, + { + ad: "yuzey-beyaz", + seviye: "hata", + mesaj: "Yüzey zemini bg-card; bg-white koyu temada da beyaz kalır (DESIGN.md §2.3)", + // Bilinçli beyaz kalanlar: logo karosu, kaydırıcı topuzu, sabit paletli + // rehber kapağı. Renkli dolu zemin üstündeki bg-white/15 serbest. + uiDahil: true, + muaf: /src\/components\/(?:uni-logo|ui\/slider|ui\/skiper-ui\/skiper41)\.tsx$|src\/features\/rehber\/components\/rehber-kapak\.tsx$/, + bul: regexKurali(/(? destek@kolaytercih.com diff --git a/src/app/layout.tsx b/src/app/layout.tsx index c5e9f8f..ed58074 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -12,6 +12,7 @@ import { HeaderGate } from "@/components/header-gate"; import { DevPanelMount } from "@/components/dev/dev-panel-mount"; import { ConsoleAsr } from "@/components/console-asr"; import { CerezBilgi } from "@/components/cerez-bilgi"; +import { TemaSaglayici } from "@/components/tema-saglayici"; import { JsonLd, organizationJsonLd, webSiteJsonLd, SITE_URL } from "@/lib/seo"; import "./globals.css"; @@ -71,7 +72,11 @@ export const metadata: Metadata = { }; export const viewport: Viewport = { - themeColor: "#f8fafc", + // Gövde zemini (bg-slate-50) — açık ve koyu temadaki karşılığı + themeColor: [ + { media: "(prefers-color-scheme: light)", color: "#f8fafc" }, + { media: "(prefers-color-scheme: dark)", color: "#080e19" }, + ], }; export default function RootLayout({ @@ -82,16 +87,20 @@ export default function RootLayout({ return ( 'e `dark` sınıfını ve + // color-scheme'i yazar; sunucu HTML'iyle fark beklenen bir farktır. + suppressHydrationWarning // `h-full` verme: html auto yükseklikte içerikle büyür, viewport tabanı // body'deki min-h-dvh'den gelir. className={`${calSans.variable} ${clarityCity.variable} ${geistMono.variable} ${bricolage.variable} antialiased`} > + {/* Klavyeyle gelen için ilk durak: üst bandı ve menüyü atla (WCAG 2.4.1). Odaklanınca görünür, sitenin hap ölçüsünde. */} İçeriğe geç @@ -125,6 +134,7 @@ export default function RootLayout({ {/* Dev süperadmin paneli — prod build'de modül grafiğine bile girmez */} {process.env.NODE_ENV !== "production" ? : null} + {/* Rybbit analitik — afterInteractive: hydration sonrası client'ta diff --git a/src/app/page.tsx b/src/app/page.tsx index 0b69be4..fd564b1 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -243,7 +243,7 @@ export default function Home() {
-
+
Veri: YÖK Atlas @@ -364,7 +364,7 @@ export default function Home() { {steps.map((s, i) => ( -
+
{s.step} @@ -385,7 +385,7 @@ export default function Home() {
{[ @@ -466,10 +466,10 @@ export default function Home() { lg'de klasik dört sütunlu tablo. */} -
+
Robotlar ve botlar İnsan danışman @@ -508,7 +508,7 @@ export default function Home() {
-
+
@@ -590,7 +590,7 @@ export default function Home() { >

@@ -643,7 +643,7 @@ export default function Home() {
@@ -691,7 +691,7 @@ export default function Home() { {faqs.map((faq) => ( void }) { return (
diff --git a/src/components/cta-bandi.tsx b/src/components/cta-bandi.tsx index affd356..48106c0 100644 --- a/src/components/cta-bandi.tsx +++ b/src/components/cta-bandi.tsx @@ -47,7 +47,7 @@ export function CtaBandi({ className={cn( "relative isolate overflow-hidden rounded-2xl", ton === "beyaz" - ? "border border-slate-200 bg-white text-slate-900" + ? "border border-slate-200 bg-card text-slate-900" : "bg-primary text-white", buyuk ? "px-5 py-8 text-center sm:p-12" : "px-5 py-4 text-left sm:py-5", className, diff --git a/src/components/dev/dev-panel.tsx b/src/components/dev/dev-panel.tsx index 34979aa..b2b537f 100644 --- a/src/components/dev/dev-panel.tsx +++ b/src/components/dev/dev-panel.tsx @@ -52,8 +52,8 @@ const BASIS = // Yarı saydam malzeme; şeffaflık azaltılsın diyen kullanıcıya opak yüzey. const MALZEME = - "border border-white/60 bg-white/80 shadow-2xl shadow-slate-900/20 backdrop-blur-2xl backdrop-saturate-150 " + - "[@media(prefers-reduced-transparency:reduce)]:bg-white [@media(prefers-reduced-transparency:reduce)]:backdrop-blur-none"; + "border border-white/60 bg-card/80 shadow-2xl shadow-slate-900/20 backdrop-blur-2xl backdrop-saturate-150 " + + "[@media(prefers-reduced-transparency:reduce)]:bg-card [@media(prefers-reduced-transparency:reduce)]:backdrop-blur-none"; export function DevPanel() { const [acik, setAcik] = useState(false); @@ -139,7 +139,7 @@ export function DevPanel() { onClick={paneliAc} title="Dev süperadmin paneli" style={{ borderRadius: 18 }} - className={`fixed bottom-20 left-4 z-50 inline-flex h-9 cursor-pointer items-center gap-1.5 px-3 text-xs font-bold tracking-wide text-white ${MALZEME} !bg-slate-900/85 print:hidden ${BASIS} hover:!bg-slate-800/85`} + className={`fixed bottom-20 left-4 z-50 inline-flex h-9 cursor-pointer items-center gap-1.5 px-3 text-xs font-bold tracking-wide text-slate-50 ${MALZEME} !bg-slate-900/85 print:hidden ${BASIS} hover:!bg-slate-800/85`} > DEV @@ -186,7 +186,7 @@ export function DevPanel() { Oturum

{g ? ( -
+

{g.email}

{g.kredi} kredi · {g.hasPaket ? "paketli" : "paketsiz"} ·{" "} @@ -218,7 +218,7 @@ export function DevPanel() { value={email} onChange={(e) => setEmail(e.target.value)} placeholder="deneme@ornek.dev" - className="h-9 min-w-0 flex-1 rounded-lg border border-slate-900/10 bg-white/70 px-2.5 text-xs outline-none transition-colors duration-150 focus-visible:border-violet-400" + className="h-9 min-w-0 flex-1 rounded-lg border border-slate-900/10 bg-card/70 px-2.5 text-xs outline-none transition-colors duration-150 focus-visible:border-violet-400" />

diff --git a/src/components/tema-saglayici.tsx b/src/components/tema-saglayici.tsx new file mode 100644 index 0000000..452e129 --- /dev/null +++ b/src/components/tema-saglayici.tsx @@ -0,0 +1,43 @@ +"use client"; + +import { useEffect } from "react"; +import { ThemeProvider, useTheme } from "next-themes"; + +// Gövde zemini (bg-slate-50) — açık ve koyu temadaki karşılığı +const ZEMIN = { light: "#f8fafc", dark: "#080e19" }; + +/** + * Mobil adres çubuğu rengi: layout'taki `themeColor` sistemi izler; kullanıcı + * sitede sistemden farklı bir tema seçtiyse meta etiketleri ona eşitlenir. + */ +function AdresCubuguRengi() { + const { resolvedTheme } = useTheme(); + useEffect(() => { + const renk = resolvedTheme === "dark" ? ZEMIN.dark : ZEMIN.light; + for (const meta of document.querySelectorAll('meta[name="theme-color"]')) { + meta.setAttribute("content", renk); + } + }, [resolvedTheme]); + return null; +} + +/** + * Tema (DESIGN.md §2.3): 'e `dark` sınıfı yazılır, renkler + * globals.css'teki `.dark` token eşlemesinden gelir. Varsayılan açık tema; + * kullanıcı footer'daki TemaSecici ile koyu ya da "sistem"e geçer, seçim + * tarayıcıda saklanır. + */ +export function TemaSaglayici({ children }: { children: React.ReactNode }) { + return ( + + + {children} + + ); +} diff --git a/src/components/tema-secici.tsx b/src/components/tema-secici.tsx new file mode 100644 index 0000000..f4a2e0d --- /dev/null +++ b/src/components/tema-secici.tsx @@ -0,0 +1,61 @@ +"use client"; + +import { useSyncExternalStore } from "react"; +import { useTheme } from "next-themes"; +import { Monitor, Moon, Sun } from "lucide-react"; +import { cn } from "@/lib/utils"; + +const SECENEKLER = [ + { deger: "light", etiket: "Açık", ikon: Sun }, + { deger: "dark", etiket: "Koyu", ikon: Moon }, + { deger: "system", etiket: "Sistem", ikon: Monitor }, +] as const; + +const aboneOlma = () => () => {}; + +/** + * Tema seçici: açık / koyu / sistem (DESIGN.md §2.3). Seçili tema yalnızca + * tarayıcıda bilinir; sunucu HTML'inde hiçbir seçenek işaretli gelmez, + * hydration sonrası işaretlenir (yerleşim oynamaz). + */ +export function TemaSecici({ className }: { className?: string }) { + const { theme, setTheme } = useTheme(); + const tarayicida = useSyncExternalStore( + aboneOlma, + () => true, + () => false, + ); + + return ( +
+ {SECENEKLER.map(({ deger, etiket, ikon: Ikon }) => { + const secili = tarayicida && theme === deger; + return ( + + ); + })} +
+ ); +} diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx index 47ff2e2..6752e05 100644 --- a/src/components/ui/avatar.tsx +++ b/src/components/ui/avatar.tsx @@ -17,7 +17,7 @@ function Avatar({ data-slot="avatar" data-size={size} className={cn( - "group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten", + "group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6", className )} {...props} diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx index cacff11..b8b7d46 100644 --- a/src/components/ui/badge.tsx +++ b/src/components/ui/badge.tsx @@ -5,7 +5,7 @@ import { Slot } from "radix-ui" import { cn } from "@/lib/utils" const badgeVariants = cva( - "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", + "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 [&>svg]:pointer-events-none [&>svg]:size-3!", { variants: { variant: { @@ -13,11 +13,11 @@ const badgeVariants = cva( secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80", destructive: - "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20", + "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 [a]:hover:bg-destructive/20", outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground", ghost: - "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50", + "hover:bg-muted hover:text-muted-foreground", link: "text-primary underline-offset-4 hover:underline", }, }, diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 9704b5e..3a4c594 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -5,19 +5,19 @@ import { Slot } from "radix-ui" import { cn } from "@/lib/utils" const buttonVariants = cva( - "group/button inline-flex shrink-0 items-center justify-center rounded-full border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + "group/button inline-flex shrink-0 items-center justify-center rounded-full border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/80", outline: - "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", + "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground", ghost: - "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50", + "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground", destructive: - "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40", + "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20", link: "text-primary underline-offset-4 hover:underline", }, size: { diff --git a/src/components/ui/code-block.tsx b/src/components/ui/code-block.tsx index 1b529cb..7095095 100644 --- a/src/components/ui/code-block.tsx +++ b/src/components/ui/code-block.tsx @@ -1,6 +1,7 @@ "use client" import { cn } from "@/lib/utils" +import { useTheme } from "next-themes" import React, { useEffect, useState } from "react" export type CodeBlockProps = { @@ -33,11 +34,15 @@ export type CodeBlockCodeProps = { function CodeBlockCode({ code, language = "tsx", - theme = "github-light", + theme: temaProp, className, ...props }: CodeBlockCodeProps) { const [highlightedHtml, setHighlightedHtml] = useState(null) + // Tema verilmediyse sitenin temasını izler (DESIGN.md §2.3) + const { resolvedTheme } = useTheme() + const theme = + temaProp ?? (resolvedTheme === "dark" ? "github-dark" : "github-light") useEffect(() => { async function highlight() { diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index b99ef37..2b274c3 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -13,7 +13,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) { type={type} data-slot="input" className={cn( - "h-12 w-full min-w-0 rounded-full border border-slate-200 bg-white px-5 text-base text-slate-900 transition-colors duration-150 outline-none placeholder:text-slate-400 hover:border-slate-300 focus-visible:border-primary focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-slate-50 disabled:opacity-50 aria-invalid:border-red-500 aria-invalid:ring-3 aria-invalid:ring-red-500/20", + "h-12 w-full min-w-0 rounded-full border border-slate-200 bg-card px-5 text-base text-slate-900 transition-colors duration-150 outline-none placeholder:text-slate-400 hover:border-slate-300 focus-visible:border-primary focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-slate-50 disabled:opacity-50 aria-invalid:border-red-500 aria-invalid:ring-3 aria-invalid:ring-red-500/20", className )} {...props} diff --git a/src/components/ui/kbd.tsx b/src/components/ui/kbd.tsx index ff93b53..e370b23 100644 --- a/src/components/ui/kbd.tsx +++ b/src/components/ui/kbd.tsx @@ -5,7 +5,7 @@ function Kbd({ className, ...props }: React.ComponentProps<"kbd">) { { + const { resolvedTheme } = useTheme() return ( ) {