# Tecof Theme Editor — Tam AI Bağlamı > Bu dosya @tecof/theme-editor için AI odaklı rehberi ve repository teknik belgelerini tek bir Markdown bağlamında birleştirir. - Sürüm: 0.0.45 - Dil: Türkçe - Kaynak önceliği: AI_GUIDE.md → README.md → docs/TAILWIND.md → ARCHITECTURE.md - Çelişki halinde kod ve exported TypeScript tipleri son doğruluk kaynağıdır. --- # Tecof Theme Editor — AI Entegrasyon Rehberi Bu dosya, bir yapay zekâ asistanının `@tecof/theme-editor` hakkında doğru ve tutarlı cevap vermesi için kısa, normatif bağlam sağlar. ## Paket kimliği - Paket: `@tecof/theme-editor` - Belgelenen sürüm: `0.0.45` - Çalışma zamanı: React 18 veya React 19 - Amaç: Tecof mağaza ve içerik sayfaları için görsel Studio editörü, yayın renderer'ı, API istemcisi ve gelişmiş alan bileşenleri - Ana export'lar: `TecofProvider`, `TecofEditor`, `TecofStudio`, `TecofRender`, `TecofPicture`, `TecofApiClient` - `TecofEditor`, güncel Studio editörünün public adıdır. ## Cevap üretme kuralları 1. Editör ve public renderer için aynı `StudioConfig` kullanılmalıdır. 2. `TecofRender` veri getirmez. Önceden yüklenmiş `PuckPageData` alır. 3. Paket UI stilleri için uygulama girişinde `@tecof/theme-editor/styles.css` import edilmelidir. 4. Studio'nun ürettiği dinamik Tailwind class'ları production build tarafından kendiliğinden bulunmaz. Preset'ler için `getSafelist()`, arbitrary değerler için kaydedilmiş sayfalarda `collectDocumentClasses()` kullanılmalıdır. 5. Tema, `root.props._tecofTheme` içinde saklanır. Public sayfada `generateCSSVariables()` çıktısı uygulanmalıdır. 6. Embed senaryosunda `hostOrigin` verilmelidir. Verilmezse geriye uyumluluk nedeniyle `postMessage` hedefi `*` olur. 7. Registry'deki component type adı değişirse eski kayıtlar için `config.migrations` tanımlanmalıdır. 8. Native HTML5 drag-and-drop dokunmatik cihazlarda tam edit deneyimi sunmaz. Public renderer responsive çalışmaya devam eder. 9. Bilinmeyen bir API veya özellik uydurulmamalıdır. Önce MCP araması veya ilgili kaynak okunmalıdır. ## Minimum kurulum ```bash npm install @tecof/theme-editor react react-dom ``` ```tsx import { TecofEditor, TecofProvider, TecofRender, } from "@tecof/theme-editor"; import "@tecof/theme-editor/styles.css"; ``` ## Veri modeli ```ts interface PuckPageData { content: Array<{ type: string; props: Record; }>; root: { props: Record; }; zones: Record; }>>; } ``` Root node'lar `content` dizisinde bulunur. İç içe node'lar `zones` nesnesinde `parentId:zoneName` anahtarıyla saklanır. ## StudioConfig özeti ```ts const config = { components: { Hero: { label: "Hero", category: "content", fields: { title: { type: "text", label: "Başlık" }, }, defaultProps: { title: "Yeni başlık", }, render: ({ title }) =>

{title}

, }, }, categories: { content: { title: "İçerik", components: ["Hero"], }, }, templates: [], permissions: { drag: true, delete: true, duplicate: true, edit: true, }, migrations: { version: 1, }, }; ``` Component config; `fields`, `defaultProps`, `render`, `inline`, `acceptsChildren`, `maxItems`, `allowedParents`, `permissions`, `resolvePermissions`, `resolveFields` ve `resolveData` seçeneklerini destekler. ## Alanlar Yerleşik alan tipleri: - `text` - `textarea` - `select` - `number` - `boolean` - `toggle` - `range` - `radio` - `array` - `object` - `slot` Gelişmiş alan factory'leri: - `createLanguageField`: Merchant dilleri ve çeviri - `createEditorField`: TipTap zengin metin editörü - `createUploadField`: Medya kütüphanesi, FilePond, sıkıştırma ve Doka - `createLinkField`: Merchant sayfası veya manuel URL seçimi - `createColorField`: HEX, alpha, swatch ve EyeDropper - `createCodeEditorField`: Monaco kod editörü - `createRepeaterField`: Tekrarlanan satırlar - `createCmsCollectionField`: CMS koleksiyon ve alan eşleme - `createIconField`: İkon seçimi - `createExternalField`: Üçüncü taraf listeden kayıt seçimi `text` ve `textarea` alanlarında CMS bağlama varsayılan olarak açıktır. Kaydedilen token formatı `{{ data.shortcode }}` şeklindedir. Public render sırasında ham kayıt `cmsData` prop'u ile verilmelidir. ## TecofEditor önemli prop'ları | Prop | Anlamı | Varsayılan | |---|---|---| | `pageId` | Backend sayfa kimliği | zorunlu | | `config` | Ortak component registry | zorunlu | | `accessToken` | Save isteği Authorization değeri | yok | | `hostOrigin` | Güvenli postMessage origin'i | `*` | | `autoSave` | Debounce'lu otomatik draft kaydı | `false` | | `autoSaveDelay` | Autosave gecikmesi | `2000` ms | | `warnOnUnsavedChanges` | Sekme kapanış uyarısı | `true` | | `onChange` | Yaklaşık 300 ms debounce'lu değişiklik callback'i | yok | | `onSave` | Başarılı kayıt callback'i | yok | ## API Client `TecofApiClient` aşağıdaki public metotları sunar: - `getPage(id, signal?)` - `savePage(id, draftData, title?, accessToken?)` - `getPublishedPage(slug, locale?)` - `getMerchantInfo()` - `uploadFile(file, folder?)` - `getUploads(page, limit)` - `getPages()` - `translate(text, sourceLang, locales, isHtml?)` - `getComponentPreview(domain, componentName)` İstekler `x-secret-key` header'ını kullanır. Upload isteğinde multipart `Content-Type` header'ı tarayıcı tarafından oluşturulmalıdır. ## Tailwind ve tema Studio stilleri node'un `_tecofStyles` prop'unda yapısal token olarak saklar. `compileStyles()` bu modeli class string'ine dönüştürür. ```ts { base: { p: "4", bg: "primary-600" }, md: { p: "[40px]" }, states: { hover: { bg: "primary-700" }, "md:hover": { bg: "primary-800" }, }, } ``` Desteklenen breakpoint'ler `base`, `sm`, `md`, `lg`, `xl`; state'ler `hover`, `focus`, `active` değerleridir. Arbitrary değerler köşeli parantezle saklanır. Tecof primary renk kuralı: - Ana vurgu: `#74b500` (`primary-600`) - Hover: `#588902` (`primary-700`) - Vurgu zemini üstü metin: `#1d3300` (`primary-950`) ## postMessage protokolü Parent'tan editöre: - `puck:save` - `puck:publish` - `puck:undo` - `puck:redo` - `puck:viewport` Editörden parent'a: - `puck:changed` - `puck:saved` - `puck:saveError` - `puck:itemSelected` - `puck:itemDeselected` `puck:` prefix'i geriye dönük host uyumluluğu için korunur. ## Hızlı teşhis ### Yayında Studio stilleri görünmiyor 1. Paket CSS import'unu kontrol et. 2. `getSafelist()` çıktısını Tailwind build'e ekle. 3. Arbitrary değerler varsa `collectDocumentClasses()` çalıştır. 4. Tema renkleri eksikse public root'ta tema CSS değişkenlerini üret. ### Editörde görünen component yayında görünmüyor 1. Editör ve renderer'ın aynı config'i kullandığını kontrol et. 2. Kaydedilmiş `type` değerinin registry'de bulunduğunu kontrol et. 3. Type değiştiyse migration ekle. ### iframe mesajları çalışmıyor 1. `hostOrigin` ile parent origin'inin birebir aynı olduğunu kontrol et. 2. Mesajı `iframe.contentWindow` hedefine gönder. 3. `event.origin` doğrulamasını ve `puck:` mesaj tipini kontrol et. --- # @tecof/theme-editor Tecof platform için **sayfa editörü**, **render motoru** ve **gelişmiş alan bileşenleri** kütüphanesi. > API Client, Context Provider, Tecof Studio editörü, çok dilli alan yöneticileri, medya yöneticisi, link seçici, resim görüntüleyici ve tema araçları içerir. > > **Studio öne çıkanlar:** komut paleti (⌘K), görsel stil editörü + **canlı tema editörü**, CMS veri bağlama, bölüm şablonları, yan yana slot düzeni, boşluk (box-model) overlay'i ve tam klavye kısayolları. --- ## Kurulum ```bash npm install @tecof/theme-editor react react-dom ``` ## Hızlı Başlangıç ### 1. TecofProvider ile Sarma ```tsx import { TecofProvider } from "@tecof/theme-editor"; {children} ``` ### 2. Editör Sayfası ```tsx "use client"; import { TecofEditor } from "@tecof/theme-editor"; import { tecofConfig } from "@/tecof-config"; export default function EditorPage({ params }) { return ; } ``` ### 3. Public Sayfa (Render) ```tsx import { TecofRender } from "@tecof/theme-editor"; ``` --- ## Bileşenler ### `` Tüm Tecof bileşenlerini sarar ve API client context'i sağlar. | Prop | Tip | Açıklama | |------|-----|----------| | `apiUrl` | `string` | Backend API base URL | | `secretKey` | `string` | Merchant secret key | | `children` | `ReactNode` | Alt bileşenler | ### `` Tecof Studio sayfa editörü. Otomatik fetch/save, iframe postMessage desteği, canvas DnD, katman paneli ve inspector içerir. | Prop | Tip | Açıklama | |------|-----|----------| | `pageId` | `string` | Düzenlenecek sayfa ID'si | | `config` | `Config` | Tecof/Puck-compatible component configuration | | `accessToken` | `string` | Kayıt isteklerinde Authorization header | | `onSave` | `(data) => void` | Kayıt sonrası callback | | `onChange` | `(data) => void` | Her değişiklikte callback (≈300ms debounce'lu) | | `hostOrigin` | `string` | Embed senaryosunda izin verilen parent origin. Verilirse hem gönderilen hem **gelen** postMessage'lar bu origin'e kısıtlanır (güvenlik). Verilmezse `'*'` (geriye uyumlu). | | `className` | `string` | Ek CSS sınıfı | > `TecofEditor`, `TecofStudio`'nun takma adıdır (`TecofEditor = TecofStudio`) — ikisi de aynı editörü açar. ### `` Önceden yüklenmiş sayfa verisini render eder. Fetch akışı için `TecofApiClient.getPublishedPage(slug, locale?)` kullanılıp dönen `draftData`/sayfa verisi bu bileşene verilir. | Prop | Tip | Açıklama | |------|-----|----------| | `data` | `PuckPageData` | Sayfa verisi | | `config` | `Config` | Tecof/Puck-compatible component configuration | | `cmsData` | `object` | CMS template sayfaları için ham kayıt verisi | | `className` | `string` | Ek CSS sınıfı | ### `` Akıllı medya bileşeni — görsel/video otomatik algılama, responsive boyutlar, fancybox desteği. ```tsx import { TecofPicture } from "@tecof/theme-editor"; import Image from "next/image"; // Basit kullanım // Fill modu // Next.js Image ile // Fancybox lightbox ``` | Prop | Tip | Açıklama | |------|-----|----------| | `data` | `UploadedFile` | Yüklenen dosya verisi | | `alt` | `string` | Alt metin | | `size` | `thumbnail \| medium \| large \| full` | Responsive boyut | | `fill` | `boolean` | Parent'ı kaplar | | `ImageComponent` | `ComponentType` | Özel image bileşeni (örn: Next.js Image) | | `imageProps` | `Record` | ImageComponent'e ek prop'lar | | `fancybox` | `boolean` | Fancybox lightbox desteği | --- ## Custom Fields (Editör Alanları) Tüm alanlar `createXField()` factory fonksiyonları ile Tecof/Puck-compatible config'e entegre edilir. ### LanguageField — Çok Dilli Metin Sekmeli çok dilli metin girişi. Merchant ayarlarından dilleri otomatik çeker. ```tsx import { createLanguageField } from "@tecof/theme-editor"; fields: { title: createLanguageField({ label: "Başlık" }), description: createLanguageField({ label: "Açıklama", isTextarea: true, textareaRows: 4, }), htmlContent: createLanguageField({ label: "HTML İçerik", isHtml: true, }), } ``` **Özellikler:** - 🌐 Otomatik dil algılama (merchant ayarlarından) - 📋 **Hızlı Doldur** — Aktif sekmedeki metni tüm dillere kopyalar - 🔄 **Çevir** — Aktif metni API üzerinden diğer dillere otomatik çevirir (DeepL / Google / OpenAI / Ollama) - `isHtml` desteği — HTML taglarını koruyarak çeviri yapar | Option | Tip | Default | Açıklama | |--------|-----|---------|----------| | `isTextarea` | `boolean` | `false` | Textarea modu | | `textareaRows` | `number` | `3` | Textarea satır sayısı | | `placeholder` | `string` | `''` | Placeholder metni | | `isHtml` | `boolean` | `false` | HTML içerik çevirisi | --- ### EditorField — Zengin Metin Editörü TipTap tabanlı, çok dilli WYSIWYG editörü. ```tsx fields: { content: createEditorField({ label: "İçerik" }), } ``` **Özellikler:** Bold, italic, link, liste, heading ve daha fazlası. --- ### UploadField — Gelişmiş Medya Yöneticisi Görsel önizleme tile'ları + tek giriş noktalı sekmeli medya drawer'ı (Kütüphane / Yükle / Referans) + FilePond yükleme + Doka görsel düzenleyici. ```tsx fields: { images: createUploadField({ label: "Görseller", allowMultiple: true, maxFiles: 10, maxFileSize: "50MB", }), document: createUploadField({ label: "Doküman", allowMultiple: false, acceptedTypes: ["application/pdf"], }), } ``` **Özellikler:** - 🖼️ **Görsel önizleme tile grid'i** — Seçili medya küçük liste satırı yerine kare önizleme tile'ları olarak gösterilir; hover'da kaldır butonu. - ➕ **Tek giriş noktası** — Bir "ekle" tile'ı drawer'ı açar; tüm kaynaklar **sekme** halinde: **Kütüphane** (sunucudaki dosyalar), **Yükle** (FilePond), **Referans** (CMS değişkeni). - 🔗 **CMS Referansı** — `{{ data.alan }}` ile dinamik görsel bağlama (CMS şablon sayfaları için). - 🖌️ **Doka Görsel Düzenleyici** — Kırp, döndür, parlaklık, kontrast, markup, çıkartma. - 🗜️ **Resim Sıkıştırma** — Otomatik WebP dönüşümü (browser-image-compression). - 📄 24+ dosya türü desteği (görseller, PDF, Office, CSV, video). - 🇹🇷 Tamamen Türkçe etiketler (FilePond + Doka). | Option | Tip | Default | Açıklama | |--------|-----|---------|----------| | `allowMultiple` | `boolean` | `true` | Çoklu dosya | | `maxFiles` | `number` | `100` | Maksimum dosya sayısı | | `maxFileSize` | `string` | `100MB` | Tek dosya limiti | | `maxTotalFileSize` | `string` | `200MB` | Toplam limit | | `acceptedTypes` | `string[]` | `[all]` | İzin verilen MIME türleri | | `folder` | `string` | `/` | Yüklemelerin hedef klasörü | | `imageCompressionEnabled` | `boolean` | `true` | Sıkıştırma aktif | | `imageCompressionOptions` | `object` | `{maxSizeMB:1,…}` | Sıkıştırma ayarları (maxSizeMB, maxWidthOrHeight, fileType) | | `allowReorder` | `boolean` | `true` | FilePond'da sürükle-bırak sıralama | | `showUploadedFiles` | `boolean` | `false` | _(kullanımdan kalktı — yeni tile arayüzünde etkisiz)_ | --- ### LinkField — Sayfa / URL Seçici Mevcut sayfalardan seçim veya manuel URL girişi. ```tsx fields: { link: createLinkField({ label: "Bağlantı" }), ctaLink: createLinkField({ label: "CTA Link", showTarget: true, placeholder: "https://example.com", }), } ``` **Özellikler:** - 📄 **Sayfa Seç** — Vaul drawer ile merchant sayfalarını listeler, aranabilir - 🔗 **Manuel Link** — URL + etiket + hedef (aynı/yeni sekme) girişi - 🟢 Durum göstergesi (yayınlanmış / değiştirilmiş / taslak) - 🏷️ Tip badge'i (Sayfa / Link) | Option | Tip | Default | Açıklama | |--------|-----|---------|----------| | `showTarget` | `boolean` | `true` | Hedef sekme seçici | | `placeholder` | `string` | `https://...` | URL placeholder | **Değer Tipi (`LinkFieldValue`):** ```ts { url: string; // "/about" veya "https://..." label?: string; // "Hakkımızda" target?: "_self" | "_blank"; type?: "page" | "custom"; } ``` --- ### CodeEditorField — Kod Editörü Monaco Editor tabanlı syntax-highlighted kod editörü. ```tsx fields: { customHtml: createCodeEditorField({ label: "Özel Kod", defaultLanguage: "html", }), jsonConfig: createCodeEditorField({ label: "Config", defaultLanguage: "json", }), } ``` --- ### ColorField — Renk Seçici Popover tabanlı gelişmiş renk seçici: doygunluk/parlaklık karesi, hue + alpha kaydırıcıları, swatch paleti, ekrandan renk seçme (EyeDropper) ve inline HEX girişi. ```tsx import { createColorField } from "@tecof/theme-editor"; fields: { bgColor: createColorField({ label: "Arka Plan Rengi" }), textColor: createColorField({ label: "Metin Rengi", showOpacity: true, defaultColor: "#18181b", }), accentColor: createColorField({ label: "Vurgu Rengi", swatches: ["#18181b", "#74b500", "#ffffff", "#ef4444"], }), } ``` **Özellikler:** - 🎨 **SV Karesi + Hue/Alpha** — Doygunluk/parlaklık karesi ve hue + (opsiyonel) alpha kaydırıcıları; pointer ile sürüklenir. - 🔤 **Inline HEX** — Monospace alanda doğrudan HEX kodu yazma (3/6/8 haneli). - 🎯 **Swatch Paleti** — Hızlı seçim için özelleştirilebilir renk noktaları. - 💧 **EyeDropper** — Destekleyen tarayıcılarda ekranın herhangi bir yerinden renk seçme. - 🕘 **Son Kullanılanlar** — `localStorage` üzerinden son renkler. - 🔲 **Opaklık** — Opsiyonel alpha kaydırıcısı (8 haneli hex + checkerboard önizleme). - ↩️ **Sıfırla** — Varsayılan renge geri dönme butonu. | Option | Tip | Default | Açıklama | |--------|-----|---------|----------| | `showOpacity` | `boolean` | `false` | Alpha/opaklık kaydırıcısı | | `swatches` | `string[]` | `[built-in]` | Popover'daki hızlı renk noktaları (hex listesi) | | `defaultColor` | `string` | `''` | Varsayılan/sıfırlama rengi | | `placeholder` | `string` | `#000000` | HEX giriş placeholder | | `showReset` | `boolean` | `true` | Sıfırlama butonu göster | > ⚠️ Eski `showPresets` / `presetColors` seçenekleri kaldırıldı; yerine `swatches` kullanın. --- ### CmsCollectionField — Koleksiyon Bağlama Bir bileşeni CMS koleksiyonuna bağlar; koleksiyon seçer, limit/sıralama ayarlar ve bileşenin "slot"larını koleksiyon alanlarına eşler (liste/tekrar eden içerik için). ```tsx import { createCmsCollectionField } from "@tecof/theme-editor"; fields: { source: createCmsCollectionField({ label: "Veri Kaynağı", defaultLimit: 6, slots: { title: { label: "Başlık", fieldTypes: ["text"] }, image: { label: "Görsel", fieldTypes: ["image"] }, link: { label: "Bağlantı" }, }, }), } ``` | Option | Tip | Default | Açıklama | |--------|-----|---------|----------| | `defaultLimit` | `number` | `10` | Çekilecek öğe sayısı varsayılanı | | `showLimit` | `boolean` | `true` | Limit kontrolü göster | | `showSort` | `boolean` | `true` | Sıralama kontrolü göster (özel / yeni→eski / eski→yeni) | | `slots` | `Record` | — | Bileşenin ihtiyaç duyduğu veri slotları; her biri bir CMS alanına eşlenir | **Değer Tipi (`CmsCollectionFieldValue`):** ```ts { collectionSlug: string; collectionName?: string; limit?: number; sort?: "newest" | "oldest" | "custom"; fieldMap?: Record; // slotKey → CMS field shortcode } ``` --- ### CMS Veri Bağlama (Metin / Textarea) Yerleşik `text` ve `textarea` alanlarının yanında bir **`{ }` bağlama butonu** görünür. Tıklayınca koleksiyon → alan seçilir ve alana bir `{{ data.shortcode }}` referans token'ı eklenir — elle yazmaya gerek kalmaz. Koleksiyonlar popover açılınca `getCmsCollections()` ile yüklenir. ```tsx fields: { // Bağlama butonu görünür (varsayılan) title: { type: "text", label: "Başlık" }, // Bağlamayı kapat staticLabel: { type: "text", label: "Sabit Etiket", bindable: false }, } ``` | Option | Tip | Default | Açıklama | |--------|-----|---------|----------| | `bindable` | `boolean` | `true` | `text`/`textarea` alanında CMS bağlama butonunu göster/gizle | > Token formatı `{{ data. }}`'dır ve render sırasında `cmsData`'ya göre çözülür (CMS şablon sayfaları). `TecofRender`'a ham kayıt `cmsData` prop'u ile verilir. --- ### Ortak Alan Seçenekleri (BaseField) Tüm `create*Field()` factory fonksiyonları aşağıdaki ortak seçenekleri destekler: | Option | Tip | Açıklama | |--------|-----|----------| | `label` | `string` | Inspector'da görünen alan etiketi | | `labelIcon` | `ReactElement` | Etiketin yanında gösterilen ikon (ör: Lucide) | | `visible` | `boolean` | Alanın sidebar'da görünür olup olmadığı | ```tsx import { Globe, Image, Palette } from "lucide-react"; fields: { title: createLanguageField({ label: "Başlık", labelIcon: , }), bgColor: createColorField({ label: "Arka Plan", labelIcon: , }), logo: createUploadField({ label: "Logo", labelIcon: , visible: true, }), } ``` --- ## Slot Düzeni & Bölüm Şablonları ### Slot (DropZone) Yönü — `orientation` `slot` tipi alanlar varsayılan olarak çocukları **alt alta** dizer. `orientation: 'horizontal'` ile **yan yana** (flex-row + wrap) dizilir. Editör, drop eksenini render edilen düzene göre otomatik algılar (yatayda sol/sağ, dikeyde üst/alt göstergesi) ve sürükle-bırak sıralaması buna göre çalışır. ```tsx fields: { columns: { type: "slot", orientation: "horizontal" }, // yan yana blocks: { type: "slot" }, // varsayılan: dikey } ``` Bileşen kendi `renderDropZone` çağrısında da geçebilir: ```tsx render: ({ puck }) => puck.renderDropZone({ zone: "cols", orientation: "horizontal" }), ``` | Değer | Açıklama | |-------|----------| | `'vertical'` _(default)_ | Çocuklar alt alta | | `'horizontal'` | Çocuklar yan yana (satır + sarma) | > Hem editörde hem `TecofRender` ile yayınlanan sayfada aynı düzen uygulanır. ### Bölüm Şablonları — `config.templates` "Bölüm Ekle" penceresindeki **Şablonlar** sekmesinde gösterilen, tek tıkla eklenen hazır bölümler. Şablon bir **alt ağaç**tır (kök node + zones) ve eklenirken tüm id'ler **taze üretilir**, yani aynı şablonu defalarca ekleyebilirsiniz. ```tsx const config = { components: { /* ... */ }, templates: [ { id: "hero-cta", label: "Hero + İki Buton", thumbnail: "/templates/hero.png", // opsiyonel önizleme görseli payload: { node: { type: "Hero", props: { id: "t-hero", title: "Başlık" } }, zones: { "t-hero:actions": [ { type: "Button", props: { id: "t-b1", text: "Başla" } }, { type: "Button", props: { id: "t-b2", text: "Daha Fazla" } }, ], }, }, }, ], }; ``` **`SectionTemplate` tipi:** | Alan | Tip | Açıklama | |------|-----|----------| | `id` | `string` | Benzersiz kimlik (React key olarak da kullanılır) | | `label` | `string` | Şablon kütüphanesinde görünen ad | | `category` | `string?` | Opsiyonel kategori | | `thumbnail` | `string?` | Opsiyonel önizleme görseli URL'i (yoksa jenerik ikon) | | `payload.node` | `TecofNode` | Eklenecek kök node | | `payload.zones` | `Record?` | Kök node'un alt zone'ları (anahtar: `nodeId:slotAdı`) | ### Inline Bileşenler — `inline` Varsayılan olarak editör her bileşeni bir `.tecof-node-wrapper` div'i ile sarar (seçim/hover/drag bu wrapper üzerinden çalışır). Bileşenin **kendi kök elemanının** sürükleme tutamacı olması gerekiyorsa (ör. sarmalayıcı div'in düzeni bozduğu durumlar), `ComponentConfig`'te `inline: true` verin ve bileşen `puck.dragRef`'i kök elemanına bağlasın. ```tsx components: { InlineButton: { label: "Inline Buton", inline: true, render: ({ puck, text }) => ( ), }, } ``` | Option (`ComponentConfig`) | Tip | Default | Açıklama | |--------|-----|---------|----------| | `inline` | `boolean` | `false` | Editör wrapper div'ini kaldırır; bileşen `puck.dragRef`'i kök elemanına eklemelidir | --- ## API Client ```tsx import { TecofApiClient } from "@tecof/theme-editor"; const client = new TecofApiClient("https://api.example.com", "secret-key"); ``` | Metot | Açıklama | |-------|----------| | `getPage(id)` | Sayfa draft'ını getir | | `savePage(id, data)` | Sayfa kaydet | | `getPublishedPage(slug, locale?)` | Yayınlanmış sayfayı getir | | `getMerchantInfo()` | Dil ayarlarını getir | | `uploadFile(file, folder?)` | Dosya yükle | | `getUploads(page, limit)` | Yüklenen dosyaları listele | | `getPages()` | Merchant sayfalarını listele | | `translate(text, sourceLang, locales, isHtml?)` | Metni birden çok dile çevir | | `cdnUrl` | CDN base URL | --- ## Backend API Endpoints Kütüphane aşağıdaki endpoint'leri kullanır (`x-secret-key` header ile): | Method | Endpoint | Açıklama | |--------|----------|----------| | `GET` | `/api/store/editor/:id` | Sayfa draft'ını getir | | `PUT` | `/api/store/editor/:id` | Sayfa kaydet | | `POST` | `/api/store/render` | Yayınlanmış sayfayı getir (slug + locale) | | `GET` | `/api/store/merchant-info` | Merchant dil ayarları | | `POST` | `/api/store/upload` | Dosya yükle | | `GET` | `/api/store/uploads` | Yüklenen dosyaları listele | | `GET` | `/api/store/pages` | Merchant sayfalarını listele | | `POST` | `/api/store/translate` | Metni çok dile çevir | --- ## Utility Fonksiyonları ```tsx import { getDefaultTheme, generateCSSVariables, mergeTheme, hexToHsl, hslToHex, lighten, darken, } from "@tecof/theme-editor"; ``` | Fonksiyon | Açıklama | |-----------|----------| | `getDefaultTheme()` | Varsayılan tema config'i | | `generateCSSVariables(theme)` | ThemeConfig → CSS custom properties | | `mergeTheme(base, overrides)` | Tema config deep-merge | | `hexToHsl(hex)` | Hex → HSL dönüşümü | | `hslToHex(h, s, l)` | HSL → Hex dönüşümü | | `lighten(hex, amount)` | Rengi açar | | `darken(hex, amount)` | Rengi koyulaştırır | --- ## iframe postMessage API `TecofEditor` iframe içinde çalıştığında parent ile iletişim kurar: ```ts // Parent → Editor iframe.postMessage({ type: "puck:save" }, "*"); iframe.postMessage({ type: "puck:publish" }, "*"); iframe.postMessage({ type: "puck:undo" }, "*"); iframe.postMessage({ type: "puck:redo" }, "*"); iframe.postMessage({ type: "puck:viewport", width: "375px" }, "*"); // Editor → Parent window.addEventListener("message", (e) => { if (e.data.type === "puck:changed") { /* değişiklik var (debounce'lu) */ } if (e.data.type === "puck:saved") { /* başarıyla kaydedildi, e.data.data güncel draft */ } if (e.data.type === "puck:saveError") { /* kayıt hatası */ } if (e.data.type === "puck:itemSelected") { /* e.data.item = { type, id } */ } if (e.data.type === "puck:itemDeselected") { /* seçim kalktı */ } }); ``` > **Güvenlik:** `hostOrigin` prop'u verildiğinde gelen mesajlar `e.origin`'e göre > doğrulanır ve giden mesajlar yalnızca o origin'e gönderilir. Embed senaryosunda > `hostOrigin` vermeniz önerilir; aksi halde `'*'` kullanılır (geriye uyumluluk). > Tüm köprü `src/studio/bridge.ts` içinde soyutlanmıştır. --- ## Klavye Kısayolları (Studio) | Kısayol | İşlem | |---|---| | `⌘/Ctrl + K` | **Komut paleti** aç/kapat (eylemler + bileşen ekleme) | | `⌘/Ctrl + Z` | Geri al | | `⌘/Ctrl + Shift + Z` · `⌘/Ctrl + Y` | Yinele | | `⌘/Ctrl + C` / `X` / `V` | Kopyala / Kes / Yapıştır (seçili node'lar) | | `⌘/Ctrl + D` | Çoğalt (çoklu seçimde toplu) | | `⌘/Ctrl + S` | Taslak kaydet | | `Delete` / `Backspace` | Sil (çoklu seçimde toplu) | | `↑` / `↓` / `←` / `→` | Kardeş node'lar arası seçim gezinme (↑/← önceki, ↓/→ sonraki) | | `⌘/Ctrl + Tık` · `Shift + Tık` | Çoklu seçime ekle/çıkar | | `Esc` | Komut paletini kapat, yoksa seçimi kaldır | ### Komut Paleti (⌘K) Tek bir aramadan **eylemleri** (geri/ileri al, kopyala/kes/yapıştır, çoğalt, sil, önizleme, panelleri aç/kapat, kaydet — her birinin kısayolu yanında listelenir) ve **bileşen eklemeyi** (config'deki tüm bileşenler) çalıştırır. Ok tuşları ile gezilir, `Enter` ile uygulanır, `Esc` ile kapanır. > Kopyalanan node'lar `localStorage` (`tecof:clipboard:v1`) üzerinden sekmeler/sayfalar > arası yapıştırılabilir; yapıştırmada id'ler taze üretilir. --- ## CSS ve Tema Yapısı Kütüphane %100 oranında izole bir CSS altyapısı sunar. Önceden kullanılan inline "CSS-in-JS" tarzı sabit tasarımlar kaldırılmış, field modüllerine ait tüm UI stilleri (EditorField, LinkField, UploadField vs.) merkezi `dist/styles.css` içerisine taşınmıştır. Tasarım çakışmalarını önlemek için kütüphanenin sunduğu tüm CSS sınıfları sadece `.tecof-[component]-[element]` (örnek: `.tecof-upload-file-list`) ön ekini kullanır. Tüm editör arayüzü `src/styles.css` içindeki `:root` token'larından beslenir. ### Renk Paleti (lime-green) `:root` altında tam bir `--tecof-primary-50…950` lime-green paleti tanımlıdır. **Kural: `600` ana renk, `700` hover.** Bileşenler doğrudan `-500/-600` skalasını değil, **semantik accent token'larını** kullanır: | Token | Değer | Kullanım | |---|---|---| | `--tecof-accent` | `primary-600` (`#74b500`) | Ana vurgu (buton, aktif sınır) | | `--tecof-accent-hover` | `primary-700` (`#588902`) | Hover | | `--tecof-accent-active` | `primary-800` | Active/basılı | | `--tecof-accent-fg` | `primary-950` (`#1d3300`) | Accent zemini üstü **koyu yazı** (AA) | | `--tecof-accent-subtle` | `primary-50` | Tint arka plan | | `--tecof-accent-text` | `primary-700` | Açık zeminde okunur accent metin | | `--tecof-accent-ring` | `rgba(116,181,0,.30)` | Focus halkası | > Lime zemin üzerine beyaz yazı kontrast bırakmadığı için accent dolgular **koyu yazı** (`--tecof-accent-fg`) kullanır. Bu token'lar yalnızca editör arayüzünü boyar; kullanıcı sitesinin teması (`--theme-*`, `generateCSSVariables`) etkilenmez. Studio arayüzü de aynı sistemdedir: canvas, drop zone, selection overlay, inspector ve field loader'ları bu accent token'larını ve `.tecof-skeleton*` primitive'lerini kullanır. **Tüm yükleme durumları skeleton loader'dır** (spinner yalnızca buton-içi mikro yüklemede). Inline style yalnızca gerçek runtime değerleri için bırakılır (örn. seçili node overlay koordinatı, layer indent CSS değişkeni, kullanıcı renk swatch'ı veya dışarıdan gelen render style prop'u). ### Studio Editör Özellikleri - **Düzenleme / Önizleme modu** — Üst bardaki toggle ile. Düzenleme'de tıklayınca bileşen seçilir, link/butonlar pasiftir; Önizleme'de link ve butonlar canlı çalışır, editör çerçevesi gizlenir. - **Inline metin düzenleme** — Canvas'taki metne çift tıklayın; düzenlenen öğe accent kenarlıkla işaretlenir (öğenin kendi arka plan/yazı rengi korunur), Enter kaydeder, Esc iptal eder. Bileşenler düzenlenebilir metni `data-tecof-prop="propAdı"` (ve çok dilli için `data-tecof-lang`) ile işaretleyebilir; aksi halde string-eşleştirme fallback'i devreye girer. - **Çoklu seçim + kopyala/yapıştır** — `⌘/Ctrl/Shift + tık` ile çoklu seçim; kopyala/kes/yapıştır (sekmeler arası `localStorage`), toplu sil/çoğalt. Bkz. [Klavye Kısayolları](#klavye-kısayolları-studio). - **Görsel stil editörü (Tailwind)** — Inspector'daki "Stil" sekmesi; breakpoint + state bazlı (`md:hover:` dahil), preset token'lar, serbest (arbitrary) değerler ve **canlı tema renkleri** (`--theme-color-*`). Daha az belirgin katmandan **devralınan değerler** soluk ipucu olarak gösterilir. Bkz. [docs/TAILWIND.md](docs/TAILWIND.md). - **Komut paleti (⌘K)** — Tek aramadan tüm eylemler + bileşen ekleme; kısayollar listelenir, ok tuşlarıyla gezilir. - **Canlı tema editörü** — Seçim yokken Inspector'daki "Tema" sekmesi; renk/tipografi/spacing düzenlenir ve değişiklik hem editöre hem canvas'a `--theme-*` CSS değişkenleri olarak **anında** uygulanır. Tema `root.props._tecofTheme`'de saklanır (kayda dahil, undo/redo'lu). - **Boşluk (box-model) overlay'i** — Bir öğenin üzerine gelince **padding (yeşil)** içeride, **margin (amber)** dışarıda devtools tarzı renkli gösterilir. - **Yan yana slot düzeni** — `slot` alanlarına `orientation: 'horizontal'` verilerek çocuklar yan yana dizilir; sürükle-bırak drop yönü (sol/sağ ↔ üst/alt) otomatik algılanır. - **Ok tuşuyla gezinme** — Seçili node'dan kardeşlerine ↑/↓/←/→ ile geçiş. - **Görsel blok paleti** — Sol panelde bileşenler, varsa render önizleme görselleriyle (lazy yüklenir). - **Çökme dayanıklılığı** — Bir bileşenin render hatası tüm canvas'ı düşürmez; node bazında error boundary ile izole edilir, prop düzeltilince kendiliğinden toparlanır. - **Global dil** — Çoklu dilli içerikte dil, üst bardaki tek seçiciden (merchant-info) değiştirilir. Alanlar yalnızca aktif dili düzenler; alan-içi dil sekmeleri Studio'da gizlenir (provider yoksa eski sekmeli mod geçerlidir — geriye uyum). Bkz. `studio/language/LanguageContext`. - **Daraltılabilir paneller** — Sol (blok/katman) ve sağ (inspector) paneller üst bar butonlarıyla daraltılıp ince ikon rayına iner; canvas genişler. - **Performans** — Ağır editör alanları (Monaco / TipTap / FilePond) ayrı chunk'lara bölünüp talep üzerine yüklenir; ana paket ~1.37 MB → ~210 KB. ### Stil Editörü & Tailwind Inspector "Stil" sekmesi, node'lara yapısal token modeli (`node.props._tecofStyles`) olarak stil uygular ve bunu Tailwind class string'ine derler. Üretimde class'ların purge edilmemesi için host Tailwind config'ine safelist eklenmelidir: ```js import { getSafelist, collectDocumentClasses } from "@tecof/theme-editor"; export default { // Preset token'ların tamamı (sonlu) + sonlu tema-renk arbitrary'leri: safelist: [ ...getSafelist(), // Serbest (arbitrary) değerler için kaydedilmiş sayfalardan toplayın: ...savedPages.flatMap((p) => collectDocumentClasses(p.draftData)), ], }; ``` - `getSafelist()` — editörün üretebileceği tüm **preset** class'larını (token × breakpoint × state, `md:hover:` dahil) + sonlu **tema-renk** arbitrary'lerini (`bg-[var(--theme-color-primary)]`) döndürür. - `collectStyleClasses(styles)` / `collectDocumentClasses(pageData)` — kaydedilmiş bir sayfadaki tüm stil class'larını (kullanıcının girdiği `p-[10px]`, `bg-[#ff0000]` gibi **serbest** değerler dahil) toplar; build aşamasında safelist'e ekleyin. > `TecofRender` (yayın renderer'ı) artık `_tecofStyles`'ı editörle birebir aynı `compileStyles` akışıyla `className`'e derler — yani görsel stil editörünün çıktısı yayınlanan sayfada da uygulanır. Tam entegrasyon (Tailwind v4 `@theme`, arbitrary değerler, breakpoint/state, tema renkleri) için: **[docs/TAILWIND.md](docs/TAILWIND.md)**. Editör alanlarının tam verimle (FilePond, Doka Editor vs.) düzgün işleyebilmesi için bu CSS dosyasını layout ana dosyanıza dahil edin: ```tsx // Ana Layout / Editor bileşenine yakın import "@tecof/theme-editor/dist/styles.css"; ``` --- ## Geliştirme ```bash npm run dev # Watch mode (tsup) npm run build # Production build + CSS bundle npm run lint # ESLint npm run test # Vitest npm run storybook # Storybook ``` ## Lisans MIT © Tecof --- # Tecof Studio — Tailwind Entegrasyonu Bu belge, Studio'nun **görsel stil editörünün** (Inspector → "Stil" sekmesi) Tailwind ile nasıl çalıştığını ve host uygulamanın bunu üretimde (production) nasıl doğru kuracağını anlatır. --- ## 1. Mimari: "stil niyeti" → Tailwind class Studio, bir node'a uygulanan stilleri **ham class string'i olarak değil, yapısal token modeli** olarak saklar. Model `node.props._tecofStyles` altında yaşar (`STYLES_PROP` sabiti): ```ts // NodeStyles { base?: { p: '4', bg: 'primary-600' }, // prefixsiz (mobile-first) sm?: { ... }, // sm: md?: { p: '[10px]' }, // md: (arbitrary value) lg?: { ... }, // lg: xl?: { ... }, // xl: states?: { hover: { bg: 'primary-700' }, // hover: (base breakpoint) 'md:hover': { bg: 'primary-800' }, // md:hover: (breakpoint-scoped state) } } ``` Bu model `compileStyles()` ile tek bir Tailwind class string'ine derlenir: ```ts compileStyles({ base: { p: '4', bg: 'primary-600' }, md: { p: '[10px]' }, states: { hover: { bg: 'primary-700' } }, }) // → "p-4 bg-primary-600 md:p-[10px] hover:bg-primary-700" ``` Derlenen string, render sırasında bileşenin `className`'ine eklenir (`NodeRenderer` editörde, `TecofRender` üretimde aynı akışı izler). **Neden token modeli?** - UI sürülebilir kalır (her kontrol mevcut değeri gösterebilir). - Responsive + state varyantları birinci sınıf vatandaştır. - Her property sonlu bir token kümesine bağlandığı için **tam bir safelist üretilebilir** (bkz. §3). - `node.props._tecofStyles` içinde kayıpsız round-trip yapar. Tek doğruluk kaynağı: [`src/studio/style/tokens.ts`](../src/studio/style/tokens.ts) (`STYLE_CONTROLS`). Bu dizi aynı anda üç şeyi sürer: editör UI'ı, class derlemesi (`toClass`) ve safelist. --- ## 2. Tailwind v4 + `@theme` token'ları Stil editörü **Tailwind v4** hedefler. Marka paleti CSS değişkenleridir; host uygulamanın `@theme` bloğunda `--color-primary-*` tanımlaması gerekir ki editördeki `bg-primary-600`, `text-primary-700` gibi class'lar gerçek renge karşılık gelsin: ```css /* app.css (host) */ @import "tailwindcss"; @theme { --color-primary-50: #f3f9e6; --color-primary-100: #e4f1c2; /* … */ --color-primary-600: #74b500; /* ana marka rengi */ --color-primary-700: #588902; --color-primary-950: #1d3300; } ``` > Not: `--tecof-primary-*` değişkenleri yalnızca **editör arayüzünü** boyar > (chrome). Sayfa içeriğine uygulanan `primary-*` class'ları ise host'un > `@theme`'inden beslenir. İkisini karıştırmayın. ### Semantik tema renkleri (`--theme-color-*`) Stil editörünün renk kontrolleri, marka skalasına ek olarak **canlı tema renklerini** de sunar (`Tema · Ana renk`, `Tema · Metin`, …). Bunlar `--theme-color-*` CSS değişkenlerine işaret eden sonlu arbitrary değerlerdir; `bg`/`text`/`border` için sırasıyla `bg-[var(--theme-color-primary)]` gibi class'lara derlenir ve `getSafelist()` bunları otomatik kapsar — yani ekstra Tailwind `@theme` kurulumu gerekmez, yalnızca `--theme-color-*` değişkenlerinin tanımlı olması yeterlidir. Bu değişkenler `generateCSSVariables(theme)` çıktısıyla üretilir. Studio'daki **canlı tema editörü** (Inspector → seçim yokken "Tema" sekmesi) bu değişkenleri hem editöre hem canvas iframe'ine anında enjekte eder; yayında ise host, `generateCSSVariables` çıktısını sayfaya dahil etmelidir. Tema, sayfanın `root.props._tecofTheme`'inde saklanır. --- ## 3. Üretimde class'ların var olması: Safelist Tailwind kullanılmayan class'ları purge eder. Editörde seçilen bir class, kaynak kodda string olarak geçmediği için (veritabanındaki sayfa JSON'unda yaşar) Tailwind onu **göremez** ve üretim CSS'ine dahil etmez. İki strateji vardır: ### 3a. Preset class'lar → `getSafelist()` Editörün üretebileceği **tüm preset** class'lar sonludur. Paket bunları hazır verir: ```js // tailwind.config.js (veya v4'te CSS @source / safelist mekanizması) import { getSafelist } from "@tecof/theme-editor"; export default { safelist: getSafelist(), // ... }; ``` `getSafelist()` her token × her kontrol × her breakpoint/state prefix'ini döndürür — **breakpoint × state kombinasyonları dahil** (ör. `p-4`, `md:p-4`, `hover:bg-primary-700`, `md:hover:bg-primary-600`, …). Ayrıca **sonlu tema-renk arbitrary'lerini** de içerir (ör. `bg-[var(--theme-color-primary)]`, `text-[var(--theme-color-foreground)]`), çünkü tema renkleri sabit bir kümedir. Böylece editörde seçilebilen her preset ve tema rengi üretimde kesinlikle bulunur. ### 3b. Arbitrary (custom) değerler → `collectDocumentClasses` Kullanıcı `p-[10px]`, `bg-[#ff0000]` gibi **serbest değerler** girebilir (bkz. §4). Bunlar sonsuz olduğu için statik safelist'e sığmaz **ve** kaydedilmiş sayfa JSON'unda yaşadığı için Tailwind'in content tarayıcısı da göremez. Çözüm: kaydedilmiş sayfalardan **gerçekten kullanılan** class'ları toplayıp safelist'e eklemek. Paket bunun için iki yardımcı verir: ```js import { getSafelist, collectDocumentClasses } from "@tecof/theme-editor"; // Build aşamasında yayınlanan/taslak sayfaları gezin: const dynamic = savedPages.flatMap((p) => collectDocumentClasses(p.draftData)); export default { safelist: [...getSafelist(), ...dynamic], // ... }; ``` - `collectStyleClasses(styles)` — tek bir `NodeStyles` nesnesinin derlendiği tüm class'ları (preset + arbitrary) döndürür. - `collectDocumentClasses(pageData)` — bir sayfanın kökü + içeriği + tüm zone'larındaki her node'un stil class'larını tekilleştirerek döndürür. > Tam dinamik (DB'den beslenen) senaryolarda bu listeyi her sayfa kaydında > yanında saklayıp build'de safelist'e verebilir veya Tailwind'i runtime'da > çalıştırabilirsiniz. Çoğu kullanım için **preset + tema renkleri** (`getSafelist`) > tek başına yeterlidir; serbest değer açtığınızda yukarıdaki tarayıcıyı ekleyin. --- ## 4. Arbitrary (serbest) değerler Arbitrary değerler `NodeStyles` içinde **köşeli parantezle** saklanır: `'[10px]'`, `'[#ff0000]'`. Preset'ler çıplaktır (`'4'`, `'primary-600'`). Bir kontrolün `arbitraryPrefix`'i varsa, kullanıcının girdiği ham `V` değeri `prefix-[V]`'ye derlenir: | Kontrol | Arbitrary girdi | Derlenen class | |---|---|---| | `p` (padding) | `10px` | `p-[10px]` | | `bg` (arka plan) | `#ff0000` | `bg-[#ff0000]` | | `gap` | `2.5rem` | `gap-[2.5rem]` | Editörde her arbitrary-destekli kontrolün yanında `+` toggle'ı vardır; açınca serbest değer input'u çıkar. Arbitrary değer girildiğinde preset seçimi boşalır. `isArbitrary` / `toArbitrary` / `arbitraryRaw` yardımcıları kodlamayı yönetir. Hangi kontroller arbitrary destekler: boşluk/boyut (`p, px, py, m, mx, my, gap, w, h, maxW`) ve renkler (`bg, text, borderColor`). Segment toggle'ları (display, flex yönü vb.) bilinçli olarak desteklemez. --- ## 5. Breakpoint & state varyantları | Katman | Prefix | Örnek | |---|---|---| | `base` | _(yok)_ | `p-4` | | `sm` | `sm:` | `sm:p-6` | | `md` | `md:` | `md:p-8` | | `lg` | `lg:` | `lg:flex-row` | | `xl` | `xl:` | `xl:max-w-6xl` | | `hover` | `hover:` | `hover:bg-primary-700` | | `focus` | `focus:` | `focus:border-primary-600` | | `active` | `active:` | `active:opacity-90` | Editörde üst segmentlerden katman seçilir; **override içeren** breakpoint/state artık küçük bir nokta (`tecof-style-seg-dot`) ile işaretlenir. **Breakpoint-bazlı state'ler:** State'ler artık breakpoint'e özeldir. `states` anahtarı çıplaksa (`hover`) base breakpoint'e, `${bp}:${state}` formatındaysa (`md:hover`) yalnızca o breakpoint'e uygulanır ve sırasıyla `hover:…` / `md:hover:…` olarak derlenir. Eski çıplak anahtarlar geriye dönük çalışır. `getSafelist()` tüm breakpoint × state kombinasyonlarını kapsar. Ayrıca üst breakpoint'i (örn. `md`) düzenlerken bir property'de değer yoksa, daha az belirgin katmandan **devralınan değer** ilgili kontrolün yanında soluk bir ipucu olarak gösterilir (yalnızca editör UI'ı; çıktı etkilenmez). --- ## 6. Editör canvas'ında stiller nasıl görünür? Canvas bir `