Ürün5 Dakika Okuma
ahmetakyapi.com: Bu Siteyi Nasıl Kurdum
Projelerimi, yazdıklarımı ve kim olduğumu tek adreste toplamak için kurduğum site. Neden hazır bir şablon kullanmadım, sitede ne var, hangi teknolojileri seçtim ve hızlı kalması için neler yaptım.
Bu Yazıda10 Bölüm
Bir süre sonra projelerim GitHub’a, yazdıklarım not defterlerine, ekran görüntüleri de telefonun galerisine dağılmıştı. Birine “neler yapıyorsun” diye sorulduğunda gösterecek tek bir adres yoktu. ahmetakyapi.com o adres: projelerim, her birinin nasıl yapıldığını anlatan yazılar ve kim olduğum, hepsi aynı yerde. Şu an okuduğun sayfa da onun bir parçası.
Neden Kendim Yazdım
Hazır bir portfolyo şablonu ya da bir blog platformu işimi görürdü, hem de bir günde. Ama bu site aynı zamanda bir vitrin. Arayüz işi yapan birinin sitesi, nasıl iş çıkardığını da göstermeli; hazır şablonda yazı tipinden geçiş animasyonuna kadar her şey başkasının kararı oluyor.
Bir de deneme alanı lazımdı. Tarayıcıya yeni gelen özellikleri, mesela sayfalar arası geçişleri ya da kaydırmaya bağlı CSS animasyonlarını iş projesinde hemen kullanamıyorsun. Kendi sitende kullanıp nerede iyi, nerede sorunlu olduğunu görebiliyorsun. Bu sitedeki her şey önce burada denendi.
Sitede Neler Var
Ana Sayfa
Kısa bir tanıtım, sürükleyip döndürebildiğin bir dünya küresi, öne çıkan üç proje, iş deneyimim ve son yazılar.
Projeler
On üç proje; her birinin masaüstü ve telefon ekran görüntüleri, kullandığı teknolojiler, canlı adresi ve kaynak kodu. Platform, oyun ve araç diye süzülebiliyor. Listeden bir projeye tıklayınca görseli büyüyüp detay sayfasının kapağı oluyor.
Yazılar
Projelerin arkasındaki kararları anlatan yazılar. İçindekiler, kod blokları, tablolar, karşılaştırma kutuları ve GitHub üzerinden yorumlar var. Etikete göre süzme tamamen CSS ile çalışıyor.
Komut Paleti
⌘K ya da Ctrl+K ile açılıyor; sayfalara, projelere, yazılara ve tema değişimine klavyeden ulaşıyorsun.
Paylaşım Kartları
Her proje ve yazı için bağlantı önizlemesi otomatik çiziliyor. Başlığı değiştirdiğimde kart da kendiliğinden güncelleniyor.
Kullandığım Teknolojiler
| Parça | Ne Kullandım | Neden |
|---|---|---|
| Çatı | Next.js 16, React 19, TypeScript | Sayfalar derleme anında hazırlanıyor, sunucu bileşenleri tarayıcıya gereksiz JavaScript göndermiyor. |
| Stil | Tailwind CSS v4 | Renkler ve boşluklar tek bir token dosyasında; açık ve koyu tema aynı değişkenlerden besleniyor. |
| Geçişler | View Transitions | Sayfa değişirken içerik kayarak geliyor, proje kartı detay sayfasının kapağına dönüşüyor. |
| Animasyon | CSS kaydırma zaman çizelgesi | Kaydırınca beliren her şeyi tarayıcı yürütüyor; JavaScript yok. |
| İçerik | TypeScript dosyaları | Yazılar ve projeler kodun yanında, tipli; yanlış bir alan derlemeyi durduruyor. |
| Paylaşım Görseli | Satori | Her proje ve yazı için kendi bağlantı önizlemesi derlemede üretiliyor. |
| Yorumlar | Giscus | Yorumlar GitHub Discussions’ta duruyor; veritabanı tutmam gerekmiyor. |
| Yayın | Vercel | Ana dala gönderdiğim an birkaç dakikada canlıda. |
Sayfalar Neden Statik
Bir portfolyonun içeriği her ziyarette değişmiyor. O yüzden bütün sayfalar derleme sırasında bir kez üretiliyor ve ziyaretçiye hazır HTML olarak gidiyor. Sunucuda her istekte çalışan bir kod yok; sayfa CDN’den anında geliyor.
Tema seçimi bunu zorlaştıran tek şeydi. Tema bir çerezde duruyor ve sunucu çerezi okursa her sayfa dinamik oluyor, yani her ziyaret bir fonksiyon çağrısına dönüyor. Bunun yerine sayfanın başına birkaç yüz baytlık küçük bir betik koydum: ilk boyamadan önce çerezi okuyup doğru temayı yazıyor. Sayfa statik kalıyor, yanlış tema bir an bile görünmüyor.
// <head> içinde, her şeyden önce çalışır (sadeleştirilmiş hâli).
const m = document.cookie.match(/(?:^|; )theme=(dark|light)/)
document.documentElement.dataset.theme = m ? m[1] : 'light'Geçişler: Sayfa Değişirken Kopukluk Olmasın
Bir projeye tıkladığında listedeki kapak görseli büyüyüp detay sayfasının kapağı oluyor. Bunu tarayıcının View Transitions özelliği yapıyor; React 19’daki ViewTransition bileşeni de onu Next.js’in gezinmesine bağlıyor. Benim yaptığım tek şey iki uçtaki görsele aynı adı vermek.
<ViewTransition name={`project-${slug}`} share="morph" default="none">
<div className="aspect-[16/10] overflow-hidden rounded-card">
<ThemedImage {...shot} alt={title} />
</div>
</ViewTransition>Tarayıcı iki görselin konumunu ve boyutunu kendisi ölçüp aradaki hareketi çiziyor. Desteklemeyen tarayıcıda sayfa normal şekilde açılıyor; kaybedilen tek şey animasyon.
Animasyonlar Neden CSS
Sitenin ilk hâlinde animasyonlar için framer-motion kullanıyordum. Ana sayfanın indirdiği JavaScript’in yarısına yakını o kütüphaneydi. Yaptığı işlere tek tek bakınca hepsinin CSS ile yapılabildiğini gördüm ve kaldırdım.
Kaydırınca beliren kartlar artık animation-timeline: view() ile çalışıyor. Eleman ekrana girdikçe animasyon ilerliyor; zamanlayıcı da gözlemci de yok. Hepsi bir @supports bloğunun içinde, yani desteklemeyen tarayıcıda içerik zaten görünür hâlde duruyor.
- Ana Sayfa
- 181 → 104
- Projeler
- 179 → 99
- Yazı Sayfası
- 146 → 104
Hareketi azaltmayı seçmiş biri için animasyonların hepsi kapalı. Sayfa aynı, sadece kıpırdamıyor.
Küçük Ama Benim İçin Önemli Parçalar
Dünya Küresi
Ana sayfadaki küre bir harita kütüphanesi değil, düz bir <canvas>. Şehirleri enlem ve boylamdan ekrana çeviren birkaç satır trigonometri, aralarındaki yaylar ve üzerlerinde akan küçük noktalar. İstanbul’a dönük açılıyor; parmağınla ya da fareyle çevirebiliyorsun. Ekrandan çıkınca ya da sekme arkadayken çizim duruyor, pil yemiyor.
İmza
Başlıktaki el yazısı “Ahmet Akyapı” bir yazı tipi değil, SVG yolu. Yazı tipi indirilmediği için sayfa yüklenirken harfler kaymıyor; sayfa açılırken de kalem kâğıtta ilerliyormuş gibi soldan sağa yazılıyor.
Kod Boyayıcı
Yazılardaki kod blokları için hazır bir kütüphane kullanmadım. Yazılarda geçen dil sayısı beş; bunun için yazdığım küçük boyayıcı birkaç kilobayt tutuyor ve renkleri temadan alıyor.
Ekran Görüntüleri
Her projenin görseli açık ve koyu temada ayrı çekildi. İkisi de sayfada duruyor, hangisinin görüneceğine CSS karar veriyor; JavaScript beklenmiyor. Görseller zaten gösterileceği boyutta WebP, o yüzden bir optimizasyon servisine de ihtiyaç kalmadı.
İçerik Nasıl Yazılıyor
Yazılar bir veritabanında ya da Markdown dosyalarında değil, TypeScript dosyalarında duruyor. Her yazı bir blok listesi: paragraf, başlık, kod, tablo, karşılaştırma, adım adım akış. Bu sayede yazının içine tasarımı bozacak bir şey giremiyor; tanımadığı bir blok türü yazarsam derleme hemen hata veriyor. Bunun neden böyle olduğunu ayrı bir yazıda anlattım.
Başlık ve özet aynı dosyadan sitede, RSS’te ve paylaşım görselinde kullanılıyor. Okuma süresi de elle yazılmıyor, içerikten hesaplanıyor.
Telefonda da Rahat Olsun
Ziyaretlerin çoğu telefondan geliyor, o yüzden her sayfayı önce dar ekranda kontrol ediyorum. Tablolar telefonda yana kaymıyor, her satır kendi kartına dönüşüyor. Küre dikey kaydırmayı engellemiyor: hızlı kaydırırsan sayfa iner, basılı tutarsan küre döner. Başlık çentiğin altında kalmıyor, alt menü güvenli alana göre yerleşiyor.
Sırada Ne Var
Bu sitenin kendi ekran görüntüleri henüz yok; projeler sayfasında adından çizilen bir kapakla duruyor. Bir de yazıların İngilizce çevirilerini eklemek istiyorum. Site bitmiş bir şey değil; yeni bir şey öğrendikçe önce burada deniyorum.