Tema Geliştirme

12 min readUpdated 27 Apr 2026

VeloCMS teması dediğimiz şey aslında üç React bileşenini (BlogLayout, PostLayout ve PageLayout) ve bir de theme.json manifest dosyasını dışa aktaran bir TypeScript paketinden ibaret. Bütün sözleşme bu kadar basit. PocketBase'i, çoklu kiracılı yönlendirmeyi (multi-tenant routing) ya da ISR'ın nasıl çalıştığını bilmenize gerek yok. Siz sadece layout bileşenlerinizi oluşturun ve manifest'e bağlayın, gerisini VeloCMS halleder.

theme.json manifest dosyası

Her tema bir theme.json dosyasıyla başlar. Mağaza, temanızı anlamak, uyumluluğu doğrulamak ve önizleme kartını oluşturmak için işte bu dosyayı okur. ThemeManifest arayüzünün tamamı src/lib/themes/sdk/types.ts altında bulunuyor. İşte size minimal bir örnek:

theme.json
{
      "$schema": "https://velocms.org/schemas/theme-manifest.json",
      "name": "velocms-theme-aurora",
      "displayName": "Aurora",
      "version": "1.0.0",
      "description": "A clean, distraction-free reading theme with subtle gradient accents.",
      "author": {
        "name": "Jane Dev",
        "email": "[email protected]",
        "url": "https://janedev.io"
      },
      "type": "layout",
      "category": "personal",
      "tags": ["minimal", "reading", "personal-blog"],
      "engines": {
        "velocms": ">=1.0.0"
      },
      "preview": {
        "thumbnail": "./preview/thumbnail.png",
        "screenshots": [
          "./preview/blog-listing.png",
          "./preview/post-detail.png"
        ]
      },
      "exports": {
        "components": {
          "BlogLayout": "./src/BlogLayout.tsx",
          "PostLayout": "./src/PostLayout.tsx",
          "PageLayout": "./src/PageLayout.tsx"
        }
      },
      "pricing": {
        "model": "free"
      }
    }
json

Layout bileşen sözleşmeleri

Üç layout bileşeniniz de tipli proplar alır. VeloCMS, gönderileri, site ayarlarını ve üye oturum verilerini bu arayüzler üzerinden size geçirir. Yani sizin herhangi bir veri çekmenize gerek kalmaz. Tipler src/components/themes/types.ts dosyasından geliyor:

src/BlogLayout.tsx
import type { BlogLayoutProps } from "@velocms/theme-sdk";
    
    export default function BlogLayout({
      posts,
      settings,
      siteUrl,
      searchEnabled,
      member,
      currentPage,
      totalPages,
    }: BlogLayoutProps) {
      return (
        <main>
          <h1>{settings?.site_name ?? "My Blog"}</h1>
          <ul>
            {posts.map((post) => (
              <li key={post.id}>
                <a href={`${siteUrl}/blog/${post.slug}`}>{post.title}</a>
              </li>
            ))}
          </ul>
        </main>
      );
    }
typescript
src/PostLayout.tsx
import type { PostLayoutProps } from "@velocms/theme-sdk";
    
    export default function PostLayout({
      post,
      settings,
      siteUrl,
      jsonLd,
      member,
      relatedPosts,
    }: PostLayoutProps) {
      return (
        <article>
          <h1>{post.title}</h1>
          {/* jsonLd is a pre-built schema object — pass it to a <script> tag */}
          <script
            type="application/ld+json"
            dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
          />
          <div dangerouslySetInnerHTML={{ __html: post.content_html ?? "" }} />
        </article>
      );
    }
typescript

OKLCH token sistemi

VeloCMS, tüm renk token'ları için OKLCH kullanır. Bu sadece estetik bir tercih değil; OKLCH size algısal olarak tutarlı renk skalaları sunar. Yani marka renginizin %30 açıklıktaki hali, HSL'de olduğu gibi tuhaf, karanlık bir karmaşaya dönüşmez, gerçekten de ana rengin %30'u kadar parlak olur. Her temanın globals.css içinde tanımlanmış şu CSS değişkenlerine erişimi var:

/* Core semantic tokens — always available in theme components */
    :root {
      --background: oklch(0.98 0 0);
      --foreground: oklch(0.15 0 0);
      --card: oklch(1 0 0);
      --card-foreground: oklch(0.15 0 0);
      --muted: oklch(0.96 0.005 240);
      --muted-foreground: oklch(0.55 0.01 240);
      --border: oklch(0.9 0.005 240);
      --ring: oklch(0.55 0.16 264);
      --primary: oklch(0.55 0.16 264);
      --primary-foreground: oklch(0.98 0 0);
    }
    
    /* Dark mode — automatically applied via .dark class on <html> */
    .dark {
      --background: oklch(0.12 0.005 240);
      --foreground: oklch(0.95 0 0);
      /* ... */
    }
css

Tema bileşenlerinizde bu token'lara referans veren Tailwind sınıflarını kullanın: bg-background, text-foreground, border-border gibi. Sakın hex kodlarını doğrudan yazmayın. Eğer öyle yaparsanız, temanız kullanıcının aydınlık/karanlık mod ayarına uymaz ve önizlemede bozuk görünür.

DemoFixtures ile yerel önizleme

Temanızı mağazaya göndermeden önce gerçekçi görünen verilerle test etmek oldukça kolay. Tema SDK'sı, sentetik gönderiler, site ayarları ve üye oturum verileri içeren bir DemoFixtures nesnesini dışa aktarır. Geliştirme yaparken bunu layout bileşenlerinize prop olarak geçmeniz yeterli:

preview/index.tsx
import { DemoFixtures } from "@velocms/theme-sdk/testing";
    import BlogLayout from "../src/BlogLayout";
    
    // Use the DemoFixtures for local development
    export default function Preview() {
      return (
        <BlogLayout
          posts={DemoFixtures.posts}
          settings={DemoFixtures.settings}
          siteUrl="http://localhost:3000"
          searchEnabled={false}
          member={null}
          currentPage={1}
          totalPages={1}
        />
      );
    }
typescript

Çalışan bir VeloCMS örneğindeki /preview/themes/[slug] rotası da aslında aynı işi yapar: kayıtlı temanızı yükler ve DemoFixtures verileriyle render eder. Mağazadaki küçük resim de zaten bu şekilde oluşturuluyor.

Mağazaya gönderim

Yayınlamaya hazır olduğunuzda, VeloCMS'te /developers adresine gidin. Gönderim süreci sizden theme.json manifest dosyanızı, 600x400 boyutunda bir küçük resim, en az iki tam sayfa ekran görüntüsü ve kısa bir açıklama isteyecek. Onay süreci 2-5 iş günü sürer; listelemeden önce erişilebilirlik, karanlık mod desteği ve mobil uyumluluk gibi konuları inceliyoruz.

Gelir paylaşımı 80/20 şeklinde: her satışın %80'i size kalır, %20'sini VeloCMS alır. Ücretsiz temalarda herhangi bir gelir paylaşımı söz konusu değil. Ödemeler aylık olarak Stripe Connect üzerinden yapılıyor, bu yüzden gönderim yaparken bir Stripe hesabınızın olması gerekecek.

Referans

theme.json manifesti — tüm alanlar

AlanTipGerekliAçıklama
`name``string`EvetTemanızın benzersiz kimliği. npm formatında olmalı.
`version``string`EvetSemantik versiyonlama (örn. "1.0.0").
`description``string`EvetTemanızın kısa, tek cümlelik özeti.
`author``string`EvetSizin veya şirketinizin adı.
`authorUrl``string`HayırWeb sitenize veya portfolyonuza bir bağlantı.
`tags``string[]`HayırTemayı tanımlayan bir string dizisi (örn. "minimal", "dark", "portfolio").
`price``number`EvetUSD sent cinsinden fiyat (örn. $10.00 için 1000). Ücretsiz için 0.
`engine``string`EvetTemanın uyumlu olduğu VeloCMS versiyonu. "*" kullanın.

Layout bileşen propları

Bunlar, VeloCMS'in üç layout bileşeninize geçtiği TypeScript prop tiplerinin birebir aynısıdır. Tasarımınızı bunlara göre yapın; asıl sözleşme budur, yukarıdaki rehber bölümlerindeki örnekler değil.

ArayüzPropTipOpsiyonelAçıklama
`BlogLayoutProps``posts``Post[]`HayırYayınlanmış tüm gönderilerin bir dizisi.
`BlogLayoutProps``site``SiteSettings`HayırGlobal site ayarları (başlık, açıklama vb.).
`BlogLayoutProps``member``MemberSession | null`HayırMevcut giriş yapmış üye veya null.
`PostLayoutProps``post``Post`HayırMevcut sayfanın tam gönderi nesnesi.
`PostLayoutProps``site``SiteSettings`HayırGlobal site ayarları.
`PostLayoutProps``member``MemberSession | null`HayırMevcut giriş yapmış üye veya null.
`PageLayoutProps``page``Page`HayırMevcut sayfanın tam sayfa nesnesi.
`PageLayoutProps``site``SiteSettings`HayırGlobal site ayarları.
`PageLayoutProps``member``MemberSession | null`HayırMevcut giriş yapmış üye veya null.

OKLCH token referansı

CSS değişkeniVarsayılan (aydınlık)Varsayılan (karanlık)Kullanım
`--background``oklch(1 0 0)``oklch(0.17 0.01 230)`Sayfa arka plan rengi.
`--foreground``oklch(0.17 0.01 230)``oklch(0.98 0.01 230)`Ana metin rengi.
`--card``oklch(1 0 0)``oklch(0.17 0.01 230)`Kartlar ve konteynerler için arka plan.
`--card-foreground``oklch(0.17 0.01 230)``oklch(0.98 0.01 230)`Kartların içindeki metin rengi.
`--popover``oklch(1 0 0)``oklch(0.17 0.01 230)`Açılır pencereler ve menüler için arka plan.
`--popover-foreground``oklch(0.17 0.01 230)``oklch(0.98 0.01 230)`Açılır pencerelerin içindeki metin rengi.
`--primary``oklch(0.45 0.15 260)``oklch(0.7 0.2 260)`Butonlar, linkler için ana marka rengi.
`--primary-foreground``oklch(0.98 0.01 230)``oklch(0.2 0.02 260)`Ana renkli arka planlar üzerindeki metin rengi.
`--border``oklch(0.8 0.01 240)``oklch(0.25 0.02 240)`İnce kenarlıklar ve ayırıcılar.
`--input``oklch(0.8 0.01 240)``oklch(0.25 0.02 240)`Girdi alanları için kenarlık rengi.

Token'lara eşlenen Tailwind sınıfları

Tailwind sınıfıCSS değişkeniKullanım amacı
`bg-background``--background`Ana sayfa arka planı.
`text-foreground``--foreground`Ana metin.
`bg-card`, `text-card-foreground``--card`, `--card-foreground`Kartlar, konteynerler.
`bg-popover`, `text-popover-foreground``--popover`, `--popover-foreground`Açılır menüler, diyaloglar.
`bg-primary`, `text-primary-foreground``--primary`, `--primary-foreground`Butonlar, etiketler, linkler.
`border-border``--border`Ayırıcılar, dış hatlar.
`border-input``--input`Form girdileri.

Tema gönderim kontrol listesi

GereksinimNasıl doğrulanır
Geçerli `theme.json`Tema dizininizde `npx @velocms/theme-sdk validate` komutunu çalıştırın.
Karanlık mod desteğiİşletim sisteminizi karanlık moda alıp tüm sayfaları kontrol edin.
Mobil uyumlulukTarayıcı geliştirici araçlarını kullanarak iPhone, iPad ve Android görünümlerini kontrol edin.
Erişilebilirlik (WCAG AA)Kontrast ve ARIA sorunlarını kontrol etmek için WAVE veya Axe gibi bir tarayıcı eklentisi kullanın.
Konsol hatası yokTarayıcı konsolunu açın ve temanızda gezinin. Konsol boş olmalı.
OKLCH token'ları kullanılıyorKodunuzda `#` veya `rgb(` araması yapın. Elle girilmiş renklere izin verilmez.

Dahili tema implementasyonları

Tema slug'ıŞunlar için idealŞunun için buradan başlayın…
`terminal`Minimalist bloglar, yazarlar.Mümkün olan en basit implementasyon.
`aurora`Fotoğraf ağırlıklı bloglar, portfolyolar.`next/image` ile gelişmiş resim yönetimi.
`origin`Kurumsal bloglar, pazarlama siteleri.Karmaşık layout'lar ve çok sayıda özel bileşen.