@tecof/theme-editor, Tecof temalarının görsel sayfa editörünü (Tecof Studio), kaydedilmiş sayfaları yayınlayan renderer’ı, editör alanlarını (field factory’ler), API istemcisini, stil ve tema motorunu tek pakette toplar. Bu bölüm paketin güncel sürümünü (0.0.96) kaynak koduna göre anlatır; tip tanımlarını doğrudan okumak için doküman MCP’sinin read_type_definition aracını kullanabilirsiniz.
Neler sunar#
| Parça | Ne yapar |
|---|---|
TecofEditor / TecofStudio | iframe kanvaslı görsel editör: sürükle-bırak, katmanlar, Inspector, stil ve tema panelleri, komut paleti, geri al/yinele, otomatik kayıt |
TecofRender | Kaydedilmiş sayfayı yayında render eder; stil CSS’ini, tema değişkenlerini ve fontları kendisi basar |
create*Field | Çok dilli metin, zengin metin, medya, bağlantı, renk, kod, ikon, tekrar eden satırlar, CMS ve e-ticaret seçicileri |
defineSection / defineElement, <Slot>, <TecofRoot> | Tema bileşeni yazarken slot, varsayılan çocuk ve kök className sözleşmesini otomatikleştirir |
TecofApiClient | Sayfa, medya, çeviri, CMS, ortak bileşen ve e-ticaret uçları için istemci |
@tecof/theme-editor/email | Pazarlama e-postası doküman modeli ve tablo tabanlı HTML render’ı |
Editör ile yayın aynı StudioConfig nesnesini ve aynı sayfa veri modelini kullanır. Editörde gördüğünüz bileşenler yayında yeniden yorumlanmaz; aynı registry üzerinden render edilir.
flowchart LR
A["StudioConfig: bileşenler ve alanlar"] --> B["TecofEditor: draftData yazar"]
B -->|"PUT /api/store/editor/:id"| C[("Tecof backend")]
C -->|"panelde yayınla"| D["publishedData"]
D -->|"POST /api/store/render"| E["TecofRender: yayın sayfası"]
A --> EEditör yalnız taslağı (draftData) yazar. Yayınlama (taslağın publishedData’ya kopyalanması) panelin ve backend’in işidir; paket publishedData’ya hiç dokunmaz. iframe’e gönderilen puck:publish mesajı da yalnız taslak kaydı tetikler.
Gereksinimler#
| Gereksinim | Sürüm | Not |
|---|---|---|
react, react-dom | ^18 || ^19 | Peer bağımlılık |
@tiptap/core, @tiptap/pm, @tiptap/react | ^3 | Zengin metin alanı (EditorField) için peer bağımlılık |
lucide-react | >=0.408.0 <2 | İkonlar; peer bağımlılık |
| Next.js | App Router önerilir | Editör ve renderer’ı içeren dosyalar istemci bileşenidir ("use client") |
Paket derlemesi her JS dosyasının başına 'use client' ekler; sunucu bileşeninden doğrudan içe aktarabilirsiniz ama editörü saran kendi bileşeninizi de istemci bileşeni yapın.
Kurulum#
npm install @tecof/theme-editor @tiptap/core @tiptap/pm @tiptap/react lucide-reactpnpm add @tecof/theme-editor @tiptap/core @tiptap/pm @tiptap/react lucide-reactyarn add @tecof/theme-editor @tiptap/core @tiptap/pm @tiptap/react lucide-reactbun add @tecof/theme-editor @tiptap/core @tiptap/pm @tiptap/react lucide-reactEditör arayüzü ve alanların stilleri tek CSS dosyasındadır. Editörün çalıştığı layout’ta bir kez içe aktarın:
import "@tecof/theme-editor/styles.css";Ortam değişkenleri#
Tecof temaları aşağıdaki genel değişkenlerle çalışır. tecof theme dev bunları .env.local dosyasına kendisi yazar (Tema hızlı başlangıç).
NEXT_PUBLIC_BASE_URL=https://api.tecof.com
NEXT_PUBLIC_CDN_URL=https://cdn.tecof.com
NEXT_PUBLIC_MERCHANT_SECRET_KEY=mağazanın-vitrin-anahtarı
NEXT_PUBLIC_THEME_ID=tema-kimliğiVitrin anahtarı (x-secret-key) genel bir değerdir; tarayıcı paketine girer. Bu yüzden backend editörün yazma uçlarında ayrıca kullanıcı JWT’si ister (aşağıdaki accessToken).
Provider#
TecofProvider bir TecofApiClient oluşturup alt bileşenlere taşır. Editör, alanlar (dil listesi, medya kütüphanesi, sayfa seçici) ve CMS’e bağlı tekrar eden slotlar bu bağlamı kullanır.
"use client";
import { TecofProvider } from "@tecof/theme-editor";
export function TecofProviderWrapper({ children }: { children: React.ReactNode }) {
return (
<TecofProvider
apiUrl={process.env.NEXT_PUBLIC_BASE_URL!}
secretKey={process.env.NEXT_PUBLIC_MERCHANT_SECRET_KEY!}
cdnUrl={process.env.NEXT_PUBLIC_CDN_URL}
themeId={process.env.NEXT_PUBLIC_THEME_ID}
>
{children}
</TecofProvider>
);
}| Prop | Tip | Açıklama |
|---|---|---|
apiUrl | string | Tecof API adresi (sondaki / temizlenir) |
secretKey | string | Mağazanın vitrin anahtarı; her istekte x-secret-key başlığı |
cdnUrl | string? | Medya adresleri için CDN kökü; verilmezse apiUrl |
themeId | string? | Çok temalı mağazada sayfa okuma/kaydetme isteklerinin doğru temaya gitmesi için |
children | ReactNode | — |
Bileşen içinden useTecof() ile { apiClient, apiUrl, secretKey, cdnUrl, themeId } okunur; provider dışında çağrılırsa hata fırlatır.
İlk entegrasyon: üç dosya#
1. Bileşen yapılandırması#
"use client";
import { defineElement, defineSection, type StudioConfig } from "@tecof/theme-editor";
const Button = defineElement({
label: "Buton",
fields: { text: { type: "text", label: "Metin" } },
defaultProps: { text: "Keşfet" },
render: (p) => <a className="rounded-full bg-black px-5 py-2.5 text-white">{p.text}</a>,
});
const Hero = defineSection({
label: "Hero",
category: "sections",
fields: { title: { type: "text", label: "Başlık" } },
slots: {
actions: { label: "Butonlar", layout: "row-wrap", gap: "md", default: ["Button"] },
},
defaultProps: { title: "Yeni sezon" },
render: (p, slots) => (
<section className="py-24 text-center">
<h1 className="text-5xl font-semibold">{p.title}</h1>
<div className="mt-8 flex justify-center">{slots.actions}</div>
</section>
),
});
export const editorConfig: StudioConfig = {
categories: {
sections: { title: "Bölümler", components: ["Hero"] },
elements: { title: "Elementler", components: ["Button"] },
},
components: { Hero, Button },
};defineSection slot alanlarını, varsayılan çocukları ve kökteki className sözleşmesini sizin yerinize kurar; ayrıntılar Bileşen yapılandırması sayfasında. Gerçek temalarda metinler genelde çok dilli alanlarla (createLanguageField, değer [{ code, value }]) tutulur: Alanlar.
2. Editör sayfası#
Tecof paneli tema editörünü iframe içinde /<editör rotası>/<pageId>?token=<JWT> biçiminde açar. Tema bu token’ı accessToken olarak editöre verir.
import EditorClient from "@/components/EditorClient";
export default async function EditorPage({
params,
searchParams,
}: {
params: Promise<{ id: string }>;
searchParams: Promise<{ token?: string }>;
}) {
const { id } = await params;
const { token } = await searchParams;
return <EditorClient pageId={id} accessToken={token} />;
}"use client";
import { TecofEditor } from "@tecof/theme-editor";
import { editorConfig } from "@/app/editor-config";
export default function EditorClient({ pageId, accessToken }: { pageId: string; accessToken?: string }) {
return (
<TecofEditor
pageId={pageId}
config={editorConfig}
accessToken={accessToken}
hostOrigin="https://app.tecof.com"
/>
);
}TecofEditor, TecofStudio’nun diğer adıdır; ikisi aynı editörü açar. Tüm prop’lar: Studio arayüzü.
3. Yayın sayfası#
TecofRender veri getirmez. Sayfayı sunucuda çekip renderer’a verin; editörle aynı editorConfig’i kullanın.
"use client";
import { TecofRender, type PuckPageData } from "@tecof/theme-editor";
import { editorConfig } from "@/app/editor-config";
export function RenderClient({ data, cmsData }: { data: PuckPageData; cmsData?: Record<string, unknown> | null }) {
return <TecofRender data={data} config={editorConfig} cmsData={cmsData} />;
}tecof-theme-core sayfa verisini POST /api/store/render ile alır ve taslak önizlemede (?showDraftData) draftData, yayında publishedData kullanır. Ayrıntı: Yayın render’ı ve Tema mimarisi.
Veri modeli#
Editörün kaydettiği doküman Puck uyumlu bir şekildir (PuckPageData):
interface PuckPageData {
content: Array<{ type: string; props: { id: string } & Record<string, unknown> }>; // kök düğümler
root: { props: Record<string, unknown> }; // sayfa geneli (tema, şema sürümü…)
zones: Record<string, Array<{ type: string; props: { id: string } & Record<string, unknown> }>>;
}- Kök düğümler
contentdizisinde, iç içe düğümlerzonesnesnesindedir. Zone anahtarı her zamanparentId:slotAdıbiçimindedir. props.iddüğümün kimliğidir; kopyalama, çoğaltma, yapıştırma ve şablon ekleme her zaman yeni id üretir.zonesnesnesindeki anahtar sırası görsel sırayı temsil etmez; kardeş sırası zone dizisinin kendi sırasıdır.- Bir düğüm silinince alt zone ağacı da temizlenir.
_ile başlayan prop’lar motora ayrılmıştır, bileşen prop’u olarak kullanmayın:_tecofStyles,_tecofTheme,_interactions,_startHidden,_locked,_hidden,_symbolOverrides,_variant,_schemaVersion,_layerName,_tecofStyleSync.- Aynı
sharedComponentIddeğerini taşıyan düğümler bir ortak bileşenin (symbol) örnekleridir: birinde yapılan değişiklik diğerlerine canlı yansır; örneğe özel alanlar_symbolOverridesile ayrılır.
Alt giriş noktaları#
| Giriş | İçerik |
|---|---|
@tecof/theme-editor | Editör, renderer, alanlar, API istemcisi, stil/tema yardımcıları, tipler |
@tecof/theme-editor/styles.css | Editör ve alan stilleri (./puck.css ve ./dist/styles.css eski takma adlardır) |
@tecof/theme-editor/under-construction | UnderConstruction bileşeni (title, description, subtitle?, logoUrl?, accentColor?) |
@tecof/theme-editor/email | E-posta doküman modeli: createEmailDocument, createEmailBlock, validateEmailDocument, renderEmailHtml |
E-posta modeli sürümlü bir blok dokümanıdır (kind: "tecof-email", version: 1). Yaprak bloklar logo, heading, text, button, image, divider, spacer, social, coupon, product, video, footer, menu, html; kap bloklar section (yalnız en üst düzey) ve columns (layout: 1, 1:1, 1:1:1, 1:1:1:1, 1:2, 2:1, 1:3, 3:1; yalnız yaprak alır). Doğruluk kaynağı backend derleyicisidir; paket aynı sözleşmeyi taşır.
import { createEmailBlock, createEmailDocument, renderEmailHtml, validateEmailDocument } from "@tecof/theme-editor/email";
const doc = createEmailDocument({
blocks: [
createEmailBlock("columns", { layout: "1:2", columns: [[createEmailBlock("image")], [createEmailBlock("text")]] }),
createEmailBlock("footer"),
],
});
validateEmailDocument(doc); // [] → geçerli
const html = renderEmailHtml(doc, { mergeData: {}, preserveMergeTags: false });Sonraki adımlar#
- Studio arayüzü: paneller, modlar,
TecofEditorprop’ları. - Bileşen yapılandırması:
ComponentConfig,defineSection, slot sözleşmesi. - Alanlar: tüm field factory’ler ve değer biçimleri.
- Stil editörü: token modeli, masaüstü-öncelikli kırılımlar, canlı önizleme.