# Stil Editörü

> Studio stil editörü — _tecofStyles token modeli, 54 kontrol, masaüstü-öncelikli kırılımlar, hover/focus/active, serbest değerler, renk kaynakları, TecofRender’ın ürettiği CSS, safelist ve sayfalar arası stil senkronu.
>
> Kaynak: https://tecof-app-dev.vercel.app/editor-styles · Bölüm: Tema geliştirme · Son güncelleme: 2018-10-20

Inspector’daki **Stil** sekmesi seçili düğüme görsel stil uygular. Stiller ham class dizisi olarak değil, düğümün `_tecofStyles` prop’unda **yapısal token**’lar olarak saklanır; editör ve `TecofRender` bunları aynı yoldan sınıflara ve CSS’e çevirir.

<!-- preview:style-tokens -->

## Token modeli

```json
{
  "base": { "p": "8", "bg": "primary-500", "radius": "2xl" },
  "sm": { "p": "4" },
  "states": {
    "hover": { "bg": "primary-600" },
    "md:hover": { "bg": "primary-700" }
  }
}
```

`compileStyles()` bu modeli sınıf dizisine çevirir; her sınıf `!` (important) son ekiyle üretilir ki bileşenin kendi sınıflarını yensin:

```text
p-8! bg-primary-500! rounded-2xl! sm:p-4! hover:bg-primary-600! md:hover:bg-primary-700!
```

- Değer bir **token**’dır, Tailwind sınıfı değil: `p: "6"`, `bg: "primary-600"`, `radius: "xl"`.
- Serbest değerler köşeli parantezle yazılır: `"[40px]"`, `"[#ff6b00]"`, `"[var(--theme-color-primary)]"`.
- Model `node.props._tecofStyles` içinde kayıpsız gidip gelir; editör her kontrolün mevcut değerini gösterebilir.
- Kontrol listesi, preset’ler ve sınıf derlemesinin tek kaynağı paketin `STYLE_CONTROLS` dizisidir (54 kontrol).

## Kırılımlar masaüstü önceliklidir

> [!IMPORTANT] Tailwind’in mobil-öncelikli `md:` anlamı burada geçerli değil
> Sınıf adları Tailwind’e benzese de Studio’nun ürettiği CSS **masaüstü önceliklidir** (`max-width` medya sorguları). `base` ana (masaüstü) tasarımdır; her kırılım ekran **küçüldükçe** devreye giren bir geçersiz kılmadır. Bu sayede 375 px’lik mobil kanvas `sm` katmanını gerçekten düzenler.

| Katman | Uygulandığı ekran | Önek |
| :--- | :--- | :--- |
| `base` | Tüm ekranlar | — |
| `xl` | ≤ 1280 px | `xl:` |
| `lg` | ≤ 1024 px | `lg:` |
| `md` | ≤ 768 px (tablet ve altı) | `md:` |
| `sm` | ≤ 640 px (mobil) | `sm:` |

Dar bir ekran birden çok sorguya uyduğu için CSS büyükten küçüğe sırayla basılır; en dar katman kazanır. Editörde üst katmanda değer yoksa daha geniş katmandan **miras alınan** değer soluk ipucu olarak gösterilir; değer içeren katmanlar küçük bir noktayla işaretlenir.

**Durumlar:** `hover`, `focus`, `active`. Durum anahtarı çıplaksa (`hover`) tüm ekranlarda, `md:hover` biçimindeyse yalnız o kırılımda uygulanır (`base:hover` geçersizdir).

## Kontroller

| Grup | Kontroller (`*` serbest değer alır) |
| :--- | :--- |
| Yerleşim | `display`, `flexDir`, `justify`, `items`, `flexWrap`, `gap*`, `alignSelf`, `position`, `zIndex`, `overflow` |
| Boşluk | `p*`, `px*`, `py*`, `pt*`, `pb*`, `pl*`, `pr*`, `m*`, `mx*`, `my*`, `mt*`, `mb*`, `ml*`, `mr*`, `marginAlign` |
| Boyut | `w*`, `h*`, `maxW*` |
| Arka plan | `bg*`, `bgGradient`, `gradientFrom*`, `gradientTo*` |
| Tipografi | `fontFamily*`, `text*`, `fontSize`, `fontWeight`, `align`, `leading`, `tracking`, `textTransform`, `decoration` |
| Kenarlık | `radius`, `border`, `borderColor*` |
| Efektler | `shadow`, `opacity`, `blur`, `scale`, `rotate`, `transition`, `anim`, `animDelay`, `reveal`, `parallax` |

Serbest uzunluklar `[12px]`, `[1.5rem]`, `[50%]`, `[80vh]` biçimindedir (negatif yalnız margin’de); serbest renkler `[#hex]`, `[rgb(…)]`, `[rgba(…)]` ya da `[var(--theme-color-<anahtar>)]`; yazı tipi yalnız yerleşik `[var(--font-<id>)]`. `reveal` (görününce animasyon) ve `parallax` kontrolleri yayında `TecofRender`’ın küçük bir çalışma zamanıyla uygulanır; `prefers-reduced-motion`’a uyar.

## Renk kaynakları

Arka plan, metin ve kenarlık renkleri tek bir seçici panelinde beş kaynaktan seçilir:

| Kaynak | Saklanan token | Derlenen sınıf |
| :--- | :--- | :--- |
| Hızlı seçim | `white`, `black`, `transparent` | `bg-white!` |
| Tema renkleri (canlı) | `[var(--theme-color-primary)]` | `bg-[var(--theme-color-primary)]!` |
| Marka skalası (temanın `--color-primary-*` değişkenleri) | `primary-600` | `bg-primary-600!` |
| Tailwind paleti (22 renk × 11 ton) | `red-500` | `bg-red-500!` |
| Özel renk (seçici / hex) | `[#ff6b00]` | `bg-[#ff6b00]!` |

Tema renkleri `--theme-color-*` değişkenlerine bağlanır: tema panelinde rengi değiştirmek bu düğümü de değiştirir ([Canlı tema](/editor-theme)). Palet verisi `TAILWIND_PALETTE` ve `TAILWIND_SHADES` olarak dışa aktarılır.

## CSS’i kim üretir

`TecofRender`, dokümanda kullanılan her stil sınıfının CSS’ini **kendisi üretip** sayfaya `<style data-tecof-styles>` olarak basar; editör kanvası da aynı üreteci kullanır. Bu yüzden:

- `TecofRender` ile yayınlanan sayfalarda Tailwind safelist’i **gerekmez**,
- serbest değerler (`p-[10px]!`, `bg-[#ff0000]!`) de ek kurulum olmadan çalışır,
- editörde gördüğünüz ile yayındaki sonuç aynı kuralları paylaşır.

> [!CAUTION] Studio sınıflarını temanın Tailwind derlemesine eklemeyin
> Aynı sınıf adları için Tailwind mobil-öncelikli (`min-width`) kurallar üretir ve `TecofRender`’ın masaüstü-öncelikli kurallarıyla çakışır: ör. `md:p-[40px]!` Tailwind’de 768 px **ve üstünde**, Studio’da 768 px **ve altında** uygulanır. `TecofRender` kullanan temada `getSafelist()` çıktısını Tailwind `safelist`’ine ya da `@source inline()` içine koymayın.

`getSafelist()` (tüm preset sınıfları), `collectStyleClasses(styles)` ve `collectDocumentClasses(pageData)` (bir dokümanda kullanılan tüm sınıflar) analiz ve özel araçlar için dışa aktarılmaya devam eder; örneğin bir sayfanın hangi stil sınıflarını kullandığını raporlamak için:

```ts
import { collectDocumentClasses } from "@tecof/theme-editor";

const used = collectDocumentClasses(page.publishedData); // string[]
```

## Tema marka paleti

Stil editöründeki **marka skalası** token’ları (`primary-50` … `primary-950`) temanın renk değişkenine bağlanır: `TecofRender`, `bg-primary-600!` için `background-color: var(--color-primary-600, var(--tecof-brand-600))` üretir. `--tecof-brand-*` yalnız editörün CSS’inde tanımlıdır; yayın sayfasında rengin görünmesi için temanın `--color-primary-*` değişkenlerini tanımlaması gerekir. Tailwind v4’te bunu `@theme` bloğu yapar (değişkenleri CSS custom property olarak yayınlar). Tailwind paleti token’ları (`red-500` gibi) ise `var(--color-red-500, <varsayılan hex>)` olarak üretildiği için tema tanımlamasa da çalışır.

```css title="app/globals.css"
@import "tailwindcss";

@theme {
  --color-primary-50: #faffe4;
  --color-primary-100: #f2ffc5;
  --color-primary-200: #e3ff92;
  --color-primary-300: #ceff53;
  --color-primary-400: #b6fb20;
  --color-primary-500: #9ae600;
  --color-primary-600: #74b500;
  --color-primary-700: #588902;
  --color-primary-800: #476c08;
  --color-primary-900: #3c5b0c;
  --color-primary-950: #1d3300;
}
```

> [!NOTE] Editör arayüzü renkleri ayrıdır
> `--tecof-primary-*` ve `--tecof-accent*` değişkenleri yalnız editörün kendi arayüzünü boyar. Sayfa içeriği `--theme-*` (tema) ve temanın `@theme` değişkenlerinden beslenir; ikisini karıştırmayın.

## Sayfalar arası stil

Bir bileşenin stilini aynı temadaki diğer sayfalarda eşleşen bileşenlere taşıyabilirsiniz. Yalnız `_tecofStyles` taşınır; içerik değişmez.

| Mod | Nerede | Ne yapar |
| :--- | :--- | :--- |
| Tek seferlik | Stil sekmesi → “Diğer sayfalara uygula…”, `⌘K`, sağ tık menüsü | Seçilen sayfalardaki eşleşen bileşenlere stili bir kez yazar |
| Sürekli senkron | Stil sekmesi → “Bu bileşeni stil kaynağı yap” | Düğüme `_tecofStyleSync` yazar; sayfa her kaydedildiğinde backend yayılımı kendisi yapar |

Eşleşme kuralları (editör ve backend aynı): `node.type` aynı olmalı; “yalnız aynı adlı” seçilirse `props._layerName` ya da `props.name` eşit olmalı; **ortak bileşenler atlanır**; hedefte stil kaynağı olan düğüm ezilmez, çakışma olarak raporlanır. Stil birleştirilmez, **değiştirilir**; yalnız taslaklar yazılır (hedef sayfaları ayrıca yayınlayın); kaynak sayfa hedeflere dahil edilmez.

Kendi arayüzünü kuran host’lar için aynı kurallar dışa açıktır:

```ts
import { STYLE_SYNC_PROP, buildStyleMatch, buildStyleSyncFlag, isStyleSourceNode, mergeStyleSyncPages } from "@tecof/theme-editor";

const preview = await client.previewApplyStyles({ sourcePageId, sourceNodeId, styles, match: { type: "HeroSection" } });
await client.applyStylesToPages({ sourcePageId, sourceNodeId, styles, match: { type: "HeroSection" }, targetPageIds: ["…"], preview: false });
```

Uç: `POST /api/store/editor/apply-styles` (JWT + ekip/admin yetkisi).
