v5 - Media Eklendi

t-{id} Tema Yapisi

Multi-Tenant Tema Sistemi - SEO, Dark Mode, Leonardo AI, Media Olusturma

1. Felsefe

t-{id} = Tenant temasi. Sadece ozel dosyalar burada.

simple = Fallback (mevcut, zaten var). t-{id}'de yoksa buradan alir.

Ornek: t-3/homepage.blade.php var -> onu kullan, t-3/blog/show.blade.php yok -> simple'dan al

2. Klasor Yapisi

resources/views/themes/
|
+-- simple/                         ← FALLBACK (mevcut, dokunma)
|   +-- layouts/
|   +-- homepage.blade.php
|
+-- t-1001/                         ← Muzibu
+-- t-2/                            ← Ixtif
+-- t-3/                            ← Panjur
    +-- homepage.blade.php          (STANDALONE)

ONEMLI: Modul view'lari AYRI konumda! "Modul View Path'leri" bolumune bak.

3. SEO Meta Tag Implementasyonu

Basit Anlatim

SEO etiketleri, Google'in sitenizi anlamasini saglar. Title, description, Open Graph, Twitter Cards ve Schema.org otomatik olusturur.

Kullanim

<!-- head icine ekle -->
<x-seo-meta />

<!-- Otomatik uretir: -->
<title>Sayfa Basligi</title>
<meta name="description" content="...">
<meta property="og:title" content="...">
<script type="application/ld+json">{Schema.org}</script>

Dosya Konumu

resources/views/components/seo-meta.blade.php   ← Component
app/View/Components/SeoMeta.php                 ← Class

4. Dark/Light Mode

1. FOUC Onleme (head icinde)

<script>
    if (localStorage.getItem('darkMode') === 'true' ||
        (!localStorage.getItem('darkMode') &&
         window.matchMedia('(prefers-color-scheme: dark)').matches)) {
        document.documentElement.classList.add('dark');
    }
</script>

2. Tailwind Config

tailwind.config = {
    darkMode: 'class',  // class bazli!
}

3. Alpine.js Toggle

<button x-data="{ dark: ... }"
    @click="dark = !dark; localStorage.setItem('darkMode', dark);
            document.documentElement.classList.toggle('dark', dark)">
    <i :class="dark ? 'fa-sun' : 'fa-moon'"></i>
</button>

5. Media Olusturma & Leonardo AI

Basit Anlatim

Leonardo AI API ile otomatik gorsel uretimi. Service, Page, Blog gibi modeller icin hero gorseli olusturur ve Spatie Media Library'ye ekler.

Helper Fonksiyon (Queue)

// Kullanim - Otomatik queue'ya gonder
generate_ai_cover($model, 'Baslik', 'type');

// Ornekler:
generate_ai_cover($service, $service->title, 'service');
generate_ai_cover($page, $page->title, 'page');
generate_ai_cover($blog, $blog->title, 'blog');

// Dosya: Modules/MediaManagement/helpers.php

Senkron Uretim (Direkt)

// LeonardoAIService direkt kullanim
$leonardo = app(\App\Services\Media\LeonardoAIService::class);

$imageData = $leonardo->generateFromPrompt($prompt, [
    'width' => 1472,
    'height' => 832,
    'style' => 'stock_photo',  // cinematic, dynamic, hdr, vibrant...
]);

if ($imageData && !empty($imageData['url'])) {
    $model->addMediaFromUrl($imageData['url'])
        ->usingFileName('hero.jpg')
        ->withCustomProperties([
            'ai_generated' => true,
            'prompt' => $prompt,
        ])
        ->toMediaCollection('hero');
}

// Dosya: app/Services/Media/LeonardoAIService.php

Toplu Gorsel Uretimi (Script)

// /tmp/generate-images.php
<?php
$tenant = \App\Models\Tenant::find(3);
tenancy()->initialize($tenant);

$leonardo = app(\App\Services\Media\LeonardoAIService::class);

// Tutarli renk paleti icin ortak stil
$colorStyle = ", professional photography, warm orange and cool gray
               color palette, modern industrial aesthetic, 4k quality";

$prompts = [
    1 => 'Technician repairing shutter mechanism' . $colorStyle,
    2 => 'Modern motorized roller shutter' . $colorStyle,
    // ...
];

foreach ($prompts as $id => $prompt) {
    $service = \Modules\Service\App\Models\Service::find($id);
    if ($service->hasMedia('hero')) continue; // Skip if exists

    $imageData = $leonardo->generateFromPrompt($prompt, [
        'width' => 1472, 'height' => 832, 'style' => 'stock_photo'
    ]);

    if ($imageData) {
        $service->addMediaFromUrl($imageData['url'])
            ->toMediaCollection('hero');
    }
    sleep(5); // Rate limit
}

// Calistir:
php artisan tinker /tmp/generate-images.php

Leonardo Style Secenekleri

cinematic - Sinematik
stock_photo - Stok Foto
dynamic - Dinamik
hdr - HDR
vibrant - Canli
moody - Atmosferik

API Konfigurasyonu

# .env dosyasinda:
LEONARDO_API_KEY=your-api-key-here

# config/services.php:
'leonardo' => [
    'api_key' => env('LEONARDO_API_KEY'),
],

Prompt Ipuclari

  • Tutarli Renk: Her prompt'a ayni renk paleti ekle
  • Kalite: "professional photography, 4k quality, photorealistic"
  • Boyut: 1472x832 (16:9) veya 832x832 (1:1)
  • Rate Limit: Her istek arasinda 3-5 saniye bekle

6. Modul View Path'leri

Her modul (Page, Service, Blog) kendi view dosyalarini kendi klasorunde tutar. Ana resources/views degil, Modules klasoru icinde!

Modules/Page/resources/views/themes/
+-- simple/homepage.blade.php      ← Fallback
+-- ixtif/homepage.blade.php
+-- t-3/homepage.blade.php         ← Panjur

Modules/Service/resources/views/themes/
+-- simple/service/index.blade.php
+-- simple/service/show.blade.php

Modules/Blog/resources/views/themes/
+-- simple/blog/index.blade.php
+-- simple/blog/show.blade.php

7. Ixtif'ten Alinan Pattern'ler

SEO

  • <x-seo-meta />
  • Open Graph + Twitter Cards
  • Schema.org JSON-LD

Dark Mode

  • FOUC prevention script
  • localStorage persistence
  • Alpine.js toggle

FontAwesome

  • Self-hosted Pro
  • fa-light ikonlar

Helpers

  • setting('key')
  • thumb($media, w, h)

8. Tespit Edilen Sorunlar

1. Tenant Model Type (Tinker'da)

Tinker'da tenant context'i baslatirken dogru model kullan:

// YANLIS: Tenant::find(3);
// YANLIS: \Stancl\Tenancy\Database\Models\Tenant::find(3);

// DOGRU:
$tenant = \App\Models\Tenant::find(3);
tenancy()->initialize($tenant);

2. Modul 404 Hatasi - Tenant Atamasi

Service/Page modulu 404 donuyorsa module_tenants tablosunda atama eksik olabilir:

// Central DB'de calistir:
INSERT INTO module_tenants (module_id, tenant_id, is_active, created_at, updated_at)
VALUES (27, 3, true, NOW(), NOW());

// module_id: modules tablosundan Service = 27, Page = 12
// tenant_id: tenants tablosundan

3. Tinker'da Heredoc Parse Error

Cok satirli string'lerde parse error olursa:

// PHP dosyasina yaz:
/tmp/script.php

// Tinker ile calistir:
php artisan tinker /tmp/script.php

9. Yeni Tema Checklist