playerberry.com — PlayerBerry yazılım stüdyosunun
kurumsal web sitesi. Ana sayfa, proje portföyü, blog, dijital ürün mağazası,
hakkımızda/iletişim ve yasal sayfaların yanı sıra sosyal profillere yönlendiren
kısa /link/<platform> adreslerini içerir. Site 11 dilde yayınlanır ve dil,
ziyaretçinin ülkesine göre otomatik seçilir.
| Alan | Araç |
|---|---|
| UI | Vue 3 (<script setup>, Composition API), vue-router 5 |
| Dil / derleme | TypeScript, Vite 8 (vue-tsc ile tip denetimi) |
| Çok dillilik | vue-i18n 11 — İngilizce paketle gelir, diğer kataloglar tembel yüklenir |
| Stil | Tailwind CSS v4 (@tailwindcss/vite); tasarım tokenları ve paylaşılan bileşen sınıfları src/assets/css/main.css, uzun metin/kod tipografisi prose.css; fontlar self-host (@fontsource-variable) |
| İçerik | Blog kod blokları için highlight.js; RSS ve sitemap üretimi için plugins/ altındaki yerel Vite eklentileri |
| Kalite | ESLint (flat config, Vue + TypeScript), Prettier biçimi, Vitest |
| Yayın | GitHub Pages — GitHub Actions ile otomatik, gh-pages paketiyle isteğe bağlı elle |
- Node.js 22 veya üzeri (CI Node 22 kullanır).
- pnpm 11 —
package.jsoniçindekipackageManageralanıpnpm@11.10.0olarak sabitlenmiştir;corepack enableile doğru sürüm otomatik gelir.
pnpm install| Komut | Ne yapar |
|---|---|
pnpm dev |
Geliştirme sunucusunu 8086 portunda açar (strictPort: port doluysa başka porta kaymaz, hata verip çıkar). |
pnpm build |
vue-tsc -b ile tip denetimi yapar, ardından vite build ile dist/ üretir (RSS ve sitemap dosyaları da bu adımda yazılır). |
pnpm preview |
Üretim çıktısını yine 8086 portunda yerel olarak sunar. |
pnpm lint |
ESLint'i tüm depo üzerinde çalıştırır. |
pnpm typecheck |
Yalnızca tip denetimi (vue-tsc -b). |
pnpm test |
Vitest birim testlerini bir kez çalıştırır (*.test.ts, kaynakların yanında). |
pnpm release |
Önce build alır, sonra dist/ içeriğini gh-pages dalına elle yayınlar. Normal akışta gerekmez (bkz. Yayınlama). |
Geliştirme sunucusunda Cloudflare bulunmadığından ülke tespiti başarısız olur ve site İngilizce açılır; diğer dilleri üst menüdeki dil seçiciden deneyin.
plugins/ Vite eklentileri: rss.ts (rss*.xml), sitemap.ts (sitemap.xml), prerender.ts (dist/<rota>.html kabukları)
public/ Olduğu gibi kopyalanan dosyalar: CNAME, 404.html (SPA geri dönüşü), ikonlar, robots.txt
src/
main.ts Uygulama girişi (router, i18n, Tailwind stili, global Icon bileşeni, v-spotlight/v-reveal)
i18n.ts vue-i18n kurulumu, katalogların tembel yüklenmesi, ülkeye göre dil seçimi
routes/ Rota tablosu, /link/* yönlendirmeleri ve sayfa meta (title/description/OG) yönetimi
views/ Sayfalar (Home, Projects, Blog, BlogPost, Store, AboutUs, Contact, yasal sayfalar, 404)
components/ Header, Footer, ProjectCard, PostCard, CodeBlock, Icon, ScrollProgress
composables/ usePostContent — blog makalesini aktif dilden (yoksa İngilizceden) okur
data/ İçerik meta verisi: projects.ts, products.ts, posts.ts
locales/ Dil katalogları: tr, en, es, fr, de, ru, ko, it, el, ja, zh (.json)
assets/js/ Vue'dan bağımsız yardımcılar: locales.ts, dates.ts, seo.ts (buildHead), meta.ts, postBlocks.ts, random.ts
assets/css/ main.css (Tailwind @theme tokenları + bileşen sınıfları), prose.css (blog/yasal tipografi, kod teması)
directives/ v-spotlight (işaretçi ışığı), v-reveal (kaydırınca görünme animasyonu)
İçerik ikiye ayrılır: yapısal meta veri TypeScript dosyalarında,
insan tarafından okunan metinler dil kataloglarında tutulur ve id/slug
ile eşleştirilir.
- Meta:
src/data/projects.ts—id,category(web|mobile|design|devops),year,tech(kart çipleri),gradient, isteğe bağlıurl(harici "ziyaret et" bağlantısı) vefeatured(ana sayfada öne çıkar). - Metin: her
src/locales/<dil>.jsoniçindeprojects.items.<id>.titleveprojects.items.<id>.description.
- Meta:
src/data/products.ts—id,price(USD;0"ücretsiz" etiketi basar),icon, isteğe bağlıbadge(popular|new),toneveurl. - Metin:
store.items.<id>.title,.descriptionve.category.
- Meta:
src/data/posts.ts—slug(URL:/blog/<slug>),date(ISO 8601, ör.2026-07-14),minutes,tags,gradient. Dizi en yeni yazı en üstte olacak şekilde sıralıdır. - Metin:
blog.posts.<slug>.title,.excerptve.body.bodybir dize dizisidir; her öğe bir bloktur:##ile başlayan satır bölüm başlığı,>ile başlayan satır alıntı,```ile çevrili dize kod bloğu, tek ters tırnak içindeki metin satır içi koddur. - Bir katalogda
blog.postsaltında ilgili yazı yoksa makale İngilizce içerikle gösterilir; yani her yazının en az İngilizce sürümü bulunmalıdır. - RSS beslemeleri Türkçe (
/rss.xml), İngilizce (/rss-en.xml) ve İspanyolca (/rss-es.xml) için üretilir; sitemap statik rotalar + tüm yazıları kapsar.
src/data/data.test.ts her projenin ve ürünün her dilde çevirisinin
bulunduğunu doğrular; yeni bir öğe eklerken tüm katalogları güncelleyin.
src/locales/<kod>.jsondosyasını oluşturun (en.jsonile aynı anahtar yapısı).src/i18n.tskataloglarıimport.meta.globile bulduğundan orada bir kayıt gerekmez.src/assets/js/locales.tsiçinde:SUPPORTED_LOCALESdizisine kodu ekleyin,LOCALE_NAMESiçine dil seçicide görünecek yerel adını yazın,FEED_PATHSiçine RSS yolunu ekleyin (kendi beslemesi yoksa/rss-en.xml),COUNTRY_LOCALESiçinde bu dile yönlendirilecek ülke kodlarını (ISO 3166-1 alpha-2) eşleyin.
- Tarih biçimi için
src/assets/js/dates.tsiçindekilocaleTagsharitasına BCP-47 etiketini ekleyin (eklenmezse tarihler İngilizce biçimlenir). src/assets/js/seo.tsiçindekiOG_LOCALES(Open Graph, ör.de_DE) veHREFLANG(BCP-47, ör.de) haritalarına girdi ekleyin; ikisi deRecord<Locale, …>olduğundan tip denetimi bunu zaten zorunlu kılar.
Dil tarayıcı diline göre değil, ziyaretçinin ülkesine göre seçilir:
- Adresteki dil öneki (
/tr/projects; arama motorlarının dizinlediği dil sürümü URL'leri, bkz. "SEO") o ziyaret için her şeyin önündedir; kalıcı olarak saklanmaz. Eski?lang=<kod>adresleri önekli biçime yönlendirilir. - Üst menüden elle seçilmiş bir dil (
localStorage→pb:locale) sonraki ziyaretlerde ülke tespitinin önüne geçer. Dil değiştirmek aynı sayfanın o dildeki adresine gider (/tr/projects); router'daki dil koruyucusu (localeGuard) kataloğu yükleyip dili etkinleştirir. Öneksiz bir adres, etkin dil İngilizce değilse o dilin önekine yönlendirilir; şablonlardaki bağlantılaruseLocalePath()ile zaten önekli üretilir. - Aksi hâlde Cloudflare'ın aynı kaynaktaki
/cdn-cgi/traceuç noktasındanloc=XXsatırı okunur veCOUNTRY_LOCALESile dile çevrilir. Sonuç oturum boyuncasessionStorage(pb:geo-locale) içinde saklanır. - Eşlenmemiş ülke, zaman aşımı (1,5 s) veya ağ hatası durumunda İngilizce kullanılır. Dil çözümlenmeden uygulama monte edilmez; böylece yanlış dilde bir ilk kare oluşmaz.
Site tek sayfalık bir uygulama olsa da arama motorları ve sosyal medya önizleyicileri için sayfa başına doğru meta veriyle sunulur:
- Dil sürümü URL'leri. Varsayılan dil (İngilizce) temiz adreste
(
/projects), diğer diller kendi öneklerinde (/tr/projects, ana sayfa/tr/) yaşar. Her sayfa kendi dil sürümünücanonicalolarak gösterir ve tüm sürümlerihreflang(x-default= temiz adres) ile listeler; blog yazıları yalnızca çevirisi bulunan dilleri (ARTICLE_LOCALES) listeler, diğer dillerde İngilizce sürümü canonical alır. Böylece Google, tarayıcısının ülkesine göre gösterilen tek bir dili değil her dili ayrı ayrı dizinleyebilir. - Tek kaynak. Başlık, açıklama, canonical, hreflang, Open Graph /
Twitter etiketleri,
robotsve JSON-LD (BreadcrumbList, BlogPosting)src/assets/js/seo.tsiçindeki safbuildHead()ile üretilir. Çalışma zamanındasrc/assets/js/meta.tsbunu DOM'a uygular (router her gezinmede ve dil değişiminde çağırır; blog yazısı kendi verisini geçer). - Önceden üretilmiş kabuklar.
plugins/prerender.ts, derlemeden sonra her dizinlenebilir rota ve her dil için bir kabuk yazar:dist/projects.html,dist/tr/projects.html,dist/tr/index.html,dist/blog/<slug>.html… Her kabukindex.html'in<!-- seo:start -->/<!-- seo:end -->işaretleri arasındaki bloğunu o sayfanın o dildeki meta verisiyle değiştirir ve<html lang>değerini ayarlar. GitHub Pages/tr/projectsisteğinitr/projects.htmlile karşıladığından tarayıcılar404.htmlyönlendirmesi yerine doğrudan200ve doğru meta veri alır; JavaScript çalıştırmayan sosyal medya önizleyicileri de her dilde sayfaya özgü başlık/açıklama görür. - Site geneli veri.
index.htmliçinde Organization/WebSite JSON-LD ve paylaşım görseli sabittir.plugins/sitemap.tsher sayfayı her dil sürümüyle (xhtml:linkalternatifleriyle) listeler;robots.txtsitemap'i işaret eder. 404 ve/link/*rotalarınoindexalır. - Sayfa başlıkları
meta.titles.*, açıklamalarmeta.*ve paylaşım görseli alt metnimeta.ogAltanahtarlarında, 11 dilde tutulur.
Canlı site GitHub Pages üzerinde, gh-pages dalından ve public/CNAME
sayesinde playerberry.com alan adıyla yayınlanır. Derin bağlantılar için
public/404.html, istenen adresi sessionStorage'a yazıp ana sayfaya
yönlendirir; index.html bu adresi router açılmadan geri yükler.
Akış (.github/workflows/deploy.yml):
stagedalına push edin (veya bir pull request açın).checkişi lint, typecheck ve testleri çalıştırır. Aynı dala yeni bir push gelirse devam eden denetim iptal edilir.- Yalnızca
stagedalındaki push'larda (pull request'lerde değil)deployişipnpm buildalır vedist/çıktısınıgh-pagesdalına gönderir. Yayınlar iptal edilmez, sıraya alınır; böylece yarım kalan bir push olmaz.
İş akışı Actions sekmesinden elle de tetiklenebilir; ancak dağıtım yine
yalnızca stage dalı seçildiğinde yapılır, başka bir dal seçilirse sadece
denetimler koşar. Acil bir durumda yerelden pnpm release ile de yayın
yapılabilir; bu komut önce derleme alır, sonra gh-pages dalına push eder.
Tek tema (koyu). Renk, font, yarıçap, easing ve animasyon tokenları
src/assets/css/main.css içindeki @theme bloğunda tanımlıdır ve Tailwind
utility'leri olarak kullanılır (bg-surface, text-berry, font-display,
ease-out-expo, animate-marquee …). Tekrarlanan desenler bileşen sınıfı
olarak aynı dosyadadır: .container-pb, .section, .eyebrow,
.section-title, .lead, .btn (+ .btn-primary/.btn-secondary/.btn-ghost,
.btn-lg/.btn-sm), .card (+ .card-static, .card-title), .chip,
.icon-tile, .badge, .link-arrow, .glass, .marquee, .aurora,
.noise, .reveal. Sayfaya özgü stil şablonlarda utility olarak kalır.
Hareket: yalnızca transform/opacity; v-reveal direktifi
(IntersectionObserver) öğeleri görünüme girince kademeli gösterir,
v-spotlight kartlarda işaretçiyi izleyen ışık üretir. Tüm animasyonlar
prefers-reduced-motion altında kapanır.
- Çalışma zamanı bağımlılığı olarak yalnızca Vue, vue-router ve vue-i18n var; ana paket ~150 kB (gzip ~55 kB). highlight.js yalnızca blog yazılarında ve sayfa boyandıktan sonra (boşta) yüklenir.
- Fontlar self-host ve
@fontsource-variableile alt kümelere bölünmüş; her dilin kabuğu yalnızca o dilin ihtiyaç duyduğu alt kümeleri (latin, Türkçe içinlatin-ext, Rusça içincyrillic…)preloadeder. plugins/prerender.tsher kabuğa o rotanın tembel görünüm chunk'ı ve dil kataloğu içinmodulepreloadekler (Vite manifest'inden); böylece SPA açılış zinciri bir tur kısalır. Uygulama, ilk gezinme çözülene kadar monte edilmez ve<main>en az bir viewport yüksekliğindedir — yerleşim kayması (CLS) sıfır.- Ölçüm:
pnpm build && pnpm previewsonrasıpnpm dlx lighthouse http://localhost:8086/ --preset=desktop.
- Kod yorumları ve JSDoc İngilizce yazılır; dosyalar Prettier biçimindedir.
- Vue tarafından bağımsız mantık (
src/assets/js/) Vue içe aktarmayan saf modüller olarak tutulur ve yanlarındaki*.test.tsdosyalarıyla test edilir. - Yeni kod göndermeden önce
pnpm lint && pnpm typecheck && pnpm testtemiz geçmelidir; CI aynı üçlüyü çalıştırır.