# Tema Varlıkları

https://dev.wisecp.com/tr/tema-varliklari

Bir temanın stil dosyaları, betikleri, görselleri ve yazı tipleri nerede durur ve bu dördün neden yalnız ikisi sürüm sorgusu alır.

## Genel Bakış

Tarayıcının bir temadan indirdiği her şey temanın `assets/` dizininde durur ve tek bir fonksiyonla adreslenir. Kaydedilen, paketlenen ya da derlenen bir şey yoktur: dosya koyduğunuz yerdedir.

Stil dosyaları ve betikler, dosyanın değişiklik zamanından üretilen bir önbellek kırma sorgusuyla döner. Yazı tipleri ve görseller bilerek temiz döner.

## Yapı

### assets/ dizininin içi

Düzen bir gelenektir, zorunluluk değil: fonksiyon `assets/` altındaki her yolu kabul eder. Sayılar dağıtılan `WStyle` temasından alınmıştır.

```bash
assets/
├── css/                    50 stil dosyası: default.css, theme.css, sonra yüzey başına bir tane
│   └── libs/               5 üçüncü parti paket: bootstrap-icons, fontawesome, fonts, prism, wcp-table
├── js/                     55 betik: default.js, money.js, sonra yüzey başına bir tane
│   └── libs/               6 üçüncü parti paket: tom-select, intl-tel-input, jspdf, ...
├── images/                 27 giriş, gruplu: hero/, logo/, banks/, avatars/, addons/
├── videos/                 bir görselden ağır olan her şey
├── favicon.svg             diğer varlıklar gibi adreslenir
└── component-showcase.html temanın kendi primitiflerinin canlı kataloğu
```

`default.css` ve `default.js` her sayfada yüklenir, yani bedelini her ziyaretçi öder. Bir sayfanın adını taşıyan stil dosyası yalnız o sayfanın view'ından bağlanır.

`component-showcase.html` temanın kendi bileşen kataloğudur. Yeni işaretleme yazmadan önce tarayıcıda açın.

## Adım Adım

### 1. Dosyayı Yerine Koyun

1. Dosyayı `assets/` altına, `css/`, `js/` ya da `images/` içine bırakın.
2. Sayfaya özel bir dosyaya o sayfanın adını verin: `css/balance.css`, `js/balance.js`.
3. Üçüncü parti paketler değiştirilmeden `css/libs/` ya da `js/libs/` içine girer; yükseltmek bir dizin değişimine iner.

Dizini izleyen bir şey yoktur: dosya erişilebilir ama referanssızdır.

### 2. Bir View'dan Bağlayın

1. Site geneli dosyalar kabuğun head bölümüne, bir kez konur.
2. Bir sayfanın kendi stil dosyası o view'ın `{block name=head}` bloğuna girer.
3. Bir sayfanın kendi betiği `{block name=scripts}` bloğuna girer, `head` bloğuna asla. Çekirdek betikler o bloktan önce geldiği için head'e konan bir betik çok erken çalışır ve sessizce kırılır.
4. Yolu `assets/` dizinine göre yazın. Gerisini fonksiyon ekler.

Sayfayı yenileyip işaretlemeyi okuyun. `?v=1753974812` ile biten bağlantı sizin dosyanızdır. Sorgusuz bağlantı aşağıdaki teşhistir.

### 3. PHP'den Referans Verin

1. `hooks.php` içinde ya da başka herhangi bir PHP'de, aynı fonksiyonu aktif tema üzerinde çağırın.
2. Kabuğu düzenlemek yerine bir kanca noktasından işaretleme enjekte edin. İsteğe bağlı stil dosyası ikinci bir head kopyası olmadan dağıtılır.

Enjekte edilen etiket kanca noktasının her yerinde, aynı sürüm sorgusuyla görünür.

### 4. Yazı Tipi Ekleyin

1. `woff2` dosyalarını ve onların `@font-face` stil dosyasını birlikte `css/libs/fonts/` altına koyun.
2. O stil dosyasının içinde yazı tipi dosyalarına **göreli** referans verin. Tarayıcılar `url()` ifadesini sayfaya göre değil stil dosyasına göre çözer.
3. Stil dosyasını normal etiketle bağlayın ve ilk boyamanın gerektirdiği yazı tipini önden yükleyin.
4. Yazı tipi kendi stil dosyasında hash'li bir sorgu taşıyorsa, aynı sorguyu önden yüklemede birebir tekrarlayın.

Ağ panelinde yazı tipi başına tek istek görünür. İki istek, önden yükleme ile stil dosyasının anlaşamadığını gösterir.

## Referans

### Adresleme Fonksiyonu

```php
public function assetUrl(string $path = ''): string;

// $path  temanın assets/ dizinine göre. Baştaki eğik çizgi kırpılır,
//        yani 'css/default.css' ile '/css/default.css' aynı istektir.
//        Boş dize assets dizininin kendisini döner.
//
// döner  {APP_URI}/templates/website/{Tema}/assets/{$path}
//        artı, uzantı css ya da js ise VE dosya diskte varsa ?v={mtime}
```

| Argüman | Dönen adres | Sürüm sorgusu |
| --- | --- | --- |
| `'css/default.css'` | `.../assets/css/default.css?v=1753974812` | Evet, dosyanın değişiklik zamanı |
| `'js/home.js'` | `.../assets/js/home.js?v=1753902114` | Evet |
| `'images/hero/banner.webp'` | `.../assets/images/hero/banner.webp` | Hayır, bilerek |
| `'css/libs/fonts/x.woff2'` | `.../assets/css/libs/fonts/x.woff2` | Hayır, bilerek |
| `'css/typo.css'` (böyle dosya yok) | `.../assets/css/typo.css` | Yok. Adres yine döner ve 404 verir |
| `''` | `.../assets/` | Yok |

Sürüm sorgusu **olmadan** dönen bağlantı, dosyanın diskte olmadığını söyler.

### View İçinden Çağırmak

```html
<!-- Smarty: tek adlandırılmış parametre, 'path' -->
<link rel="stylesheet" href="{asset path='css/balance.css'}">
<script src="{asset path='js/balance.js'}" defer></script>

<!-- Twig: tek konumsal argüman -->
<link rel="stylesheet" href="{{ asset('css/balance.css') }}">

<!-- Düz PHP tema ve view dışındaki her PHP -->
<link rel="stylesheet" href="<?= Theme::active()->assetUrl('css/balance.css') ?>">
```

- **{asset path='...'}**: Smarty. Tek adlandırılmış parametre, tek. Adını yanlış yazarsanız etiket boş yola düşer ve bağlantı çıplak assets dizinini gösterir.
- **asset('...')**: Twig. Konumsaldır ve kum havuzunun fonksiyon izin listesinde yer alır. Aynı çözüm, aynı dize.
- **Theme::active()->assetUrl()**: PHP. İki etiketin de altta çağırdığı şey. `hooks.php` içinden ve şablon dışında işaretleme üreten her yerden kullanın.
- **$tadress**: Her sayfa tema dizininin adresini düz değişken olarak da alır. `assets/` değil tema köküdür, sürüm sorgusu taşımaz.

## Örnek

### Site Geneli Varlıklar, Bir Kez, Kabukta

Dağıtılan bir kabuğun head bölümü, varlık satırlarına indirilmiş hâliyle. Sıra bilinçlidir.

```html
<link rel="icon" type="image/svg+xml" href="{asset path='favicon.svg'}">

<!-- Sorgu, bootstrap-icons.min.css'in kendi src satırında zaten duran hash'tir.
     Yanlış yazarsanız tarayıcı yazı tipini iki kez indirir. -->
<link rel="preload" href="{asset path='css/libs/bootstrap-icons/fonts/bootstrap-icons.woff2'}?e34853135f9e39acf64315236852cd5a"
      as="font" type="font/woff2" crossorigin>

<link rel="stylesheet" href="{asset path='css/libs/bootstrap-icons/bootstrap-icons.min.css'}">
<link rel="stylesheet" href="{asset path='css/libs/fonts/manrope.css'}">
<link rel="stylesheet" href="{asset path='css/theme.css'}">
<link rel="stylesheet" href="{asset path='css/default.css'}">
<link rel="stylesheet" href="{asset path='css/default-dark.css'}">

<!-- Yalnız gerektiği yerde yüklenir; kararı ikinci bir kabuk değil bir değişken verir. -->
{if $is_client_area}<link rel="stylesheet" href="{asset path='css/client-nav.css'}">{/if}

<!-- Çekirdek betikler, sayfanın kendi bloğundan önce. -->
<script src="{asset path='js/bootstrap.bundle.min.js'}" defer></script>
<script src="{asset path='js/money.js'}" defer></script>
<script src="{asset path='js/default.js'}" defer></script>
```

### Sayfa Varlıkları, İhtiyaç Duyan View'da

Gerçek bir view'ın iki varlık bloğu. Stil dosyaları `head`, betikler `scripts` bloğunda. Kütüphane aynı blokta, betiğin üstünde.

```smarty
{extends file='layouts/default.tpl'}

{block name=head}
    <link rel="stylesheet" href="{asset path='css/account-settings.css'}">
    <link rel="stylesheet" href="{asset path='css/libs/wcp-table/table.css'}">
    <link rel="stylesheet" href="{asset path='css/balance.css'}">
{/block}

{block name=scripts}
    {* Önce kütüphane, sonra onu kullanan sayfa betiği: aynı blok, belge sırası. *}
    <script src="{asset path='js/libs/wcp-table/table.js'}" defer></script>
    <script src="{asset path='js/balance.js'}" defer></script>
{/block}

{block name=content}
    {* ... *}
{/block}
```

```php
// Kanca noktası bir dize alır ve olduğu gibi basar; etiketi burada kurun ve
// kabuğa dokunmayın. Aynı fonksiyon, aynı sürüm sorgusu.
Hook::add("ui:client.head.css", 1, function (): string {
    $href = Theme::active()->assetUrl('css/extra.css');

    return '<link rel="stylesheet" href="' . $href . '">';
});
```

## Tuzaklar

> **Sürüm sorgusu yoksa dosya orada değildir**
> 
> Bir adres ancak fonksiyon dosyayı diskte bulduğunda sürümlenir. Arkasında sorgu olmayan bir bağlantı yanlış bir yoldur ve 404 almak üzeredir.

> **Yazı tipleri ve görseller bilerek sürümsüzdür, "düzeltmeyin"**
> 
> Bir yazı tipi iki kez istenir: bir kez önden yükleme etiketinizle, bir kez de yazı tipi stil dosyasındaki `url()` ile. Fonksiyon ikincisine hiç dokunmaz. Önden yüklemeyi sürümlerseniz iki adres eşleşmez. Önden yükleme boşa gider ve `font-display: optional` bildirilmiş bir yüz ilk boyamayı kaçırır.

> **Önden yüklemenin sorgusu stil dosyasınınkiyle harfi harfine aynı olmalıdır**
> 
> İkon yazı tipi gibi paketler kendi hash'li sorgularını `src:` satırında taşır. Önden yüklemede birebir tekrarlayın, yoksa tarayıcı yazı tipini iki kez indirir. Hash'i paketin kendi stil dosyasından okuyun.

> **Head'deki bir sayfa betiği çok erken çalışan bir betiktir**
> 
> Ertelenmiş betikler belge sırasıyla çalışır. `{block name=head}` içine taşınan bir sayfa betiği temanın çekirdek betiğinden önce çalışır, global nesnesini göremez ve hatasız biçimde kırılır. Tek istisna, çekirdek betiğin tükettiği kütüphanelerdir: onlar head'de, çekirdeğin üstünde yüklenir.

> **CSS içindeki url() stil dosyasına göre çözülür**
> 
> Adresleme fonksiyonu işaretleme içindir. Bir stil dosyasının içinden referans verilen arka plan görseli, yazı tipi dosyası ya da SVG maskesi o stil dosyasına göre çözülür. Fonksiyondan geçmez. Bu referansları göreli tutun ve dosyaları onları adlandıran stil dosyasının yanında bırakın.

## İlgili Makaleler

- [Tema Motoru](https://dev.wisecp.com/tr/tema-motoru)
- [Tema Anatomisi](https://dev.wisecp.com/tr/tema-anatomisi)
- [İlk Temanız](https://dev.wisecp.com/tr/ilk-temaniz)
- [Tema Performansı ve Önbellekleme](https://dev.wisecp.com/tr/tema-performansi-ve-onbellek)
- [Tema Kancaları ve Çıktı Filtreleri](https://dev.wisecp.com/tr/tema-kancalari-ve-cikti-filtreleri)
