Multi-Tenant Tema Sistemi - Tenant Tema, Logo Kurallari, Layout, Dark Mode
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
Tenant'in hangi temayi kullanacagi central veritabanindaki tenants tablosunda belirlenir. data JSON kolonuna tema adi yazilir.
-- Mevcut temalar SELECT theme_id, name, folder_name FROM themes; +----------+--------+-------------+ | theme_id | name | folder_name | +----------+--------+-------------+ | 1 | simple | simple | ← Fallback | 8 | panjur | panjur | | 9 | t-3 | t-3 | ← Panjur icin +----------+--------+-------------+
-- Tenant 3'e t-3 temasini ata UPDATE tenants SET data = '{"theme": "t-3"}' WHERE id = 3; -- Kontrol SELECT id, data FROM tenants WHERE id = 3; +----+------------------+ | id | data | +----+------------------+ | 3 | {"theme": "t-3"} | +----+------------------+
php artisan cache:clear php artisan view:clear php artisan responsecache:clear
{"theme": "tema-adi"}resources/views/themes/{tema-adi}/resources/views/themes/ | +-- simple/ ← FALLBACK (mevcut, dokunma) | +-- layouts/ | +-- homepage.blade.php | +-- t-1001/ ← Muzibu +-- t-2/ ← Ixtif +-- t-3/ ← Panjur +-- layouts/ | +-- app.blade.php (Ana layout) | +-- header.blade.php (Header) | +-- footer.blade.php (Footer) +-- homepage.blade.php (STANDALONE)
ONEMLI: Modul view'lari AYRI konumda! "Modul View Path'leri" bolumune bak.
Her temanin kendi header ve footer'i olmali. Fallback degil, temaya ozel.
Her tema kendi layouts/header.blade.php ve layouts/footer.blade.php dosyasina sahip olmali.
{{-- TUM sayfalarda ayni padding kullan --}} <div class="container mx-auto px-4 sm:px-6 md:px-8 lg:px-12 xl:px-16 2xl:px-20"> ... </div>
Gercek logo varsa SADECE logo gosterilir, yazi yazilmaz. Logo yoksa icon + site adi gosterilir.
@php
// Logo Service - ixtif pattern
$logoService = app(\App\Services\LogoService::class);
$logos = $logoService->getLogos();
$hasLogo = $logos['has_light'] || $logos['has_dark'];
@endphp
{{-- Logo Gosterimi --}}
@if($hasLogo)
{{-- Gercek logo var - SADECE logo, yazi YOK --}}
@if($logos['has_light'] && $logos['has_dark'])
<img src="{{ $logos['light_logo_url'] }}" class="dark:hidden h-10 w-auto">
<img src="{{ $logos['dark_logo_url'] }}" class="hidden dark:block h-10 w-auto">
@elseif($logos['has_light'])
<img src="{{ $logos['light_logo_url'] }}" class="h-10 w-auto">
@elseif($logos['has_dark'])
<img src="{{ $logos['dark_logo_url'] }}" class="h-10 w-auto">
@endif
@else
{{-- Logo yok - icon + yazi goster --}}
<div class="w-12 h-12 bg-primary-500 rounded-xl">
<i class="fa-blinds"></i>
</div>
<div>
<span>{{ $siteName }}</span>
<p>{{ $siteSlogan }}</p>
</div>
@endif
has_light - Light logo var mihas_dark - Dark logo var mihas_both - Ikisi de var milight_logo_url - Light URLdark_logo_url - Dark URL
app/Services/LogoService.php ← Service class
{{-- MINIMAL SUBHEADER - Sadece breadcrumb + title --}} <section class="bg-gray-50 dark:bg-gray-800 border-b py-4"> <nav>Breadcrumb</nav> <h1 class="text-2xl md:text-3xl font-bold">{{ $title }}</h1> </section>
{{-- Kare gorsel + gradient + beyaz yazi --}} <a class="group relative aspect-square rounded-xl overflow-hidden"> <img class="w-full h-full object-cover group-hover:scale-105"> <div class="absolute inset-0 bg-gradient-to-t from-black/70"></div> <h2 class="text-white">{{ $title }}</h2> </a> // DIKKAT: hover:-translate-y-2 KULLANMA (ziplamasin!)
// YANLIS - YAPMA!
$siteName = setting('site_name') ?: 'Varsayilan Ad';
@if($sitePhone)
<a href="tel:{{ $sitePhone }}">{{ $sitePhone }}</a>
@endif
<script>
if (localStorage.getItem('darkMode') === 'true' ||
(!localStorage.getItem('darkMode') &&
window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
}
</script>
<body x-data="{
darkMode: localStorage.getItem('darkMode') === 'true' ||
(!localStorage.getItem('darkMode') &&
window.matchMedia('(prefers-color-scheme: dark)').matches),
mobileMenu: false
}"
x-init="
document.documentElement.classList.toggle('dark', darkMode);
$watch('darkMode', val => {
localStorage.setItem('darkMode', val);
document.documentElement.classList.toggle('dark', val);
});
">
Laravel once Modules/ altindaki view'lara bakar, sonra resources/views/'a. Homepage icin her iki konumu da guncelle!
1. MODUL KONUMU (ONCELIKLI!): Modules/Page/resources/views/themes/t-3/homepage.blade.php 2. RESOURCES KONUMU: resources/views/themes/t-3/homepage.blade.php // UYARI: Degisiklik yapacaksan HER IKISINDE de yap! // Modules/ altindaki ONCELIKLI olarak yuklenir.
Modules/Page/resources/views/themes/ +-- simple/homepage.blade.php ← Fallback +-- t-3/homepage.blade.php ← Panjur (BURASI ONCELIKLI!) Modules/Service/resources/views/themes/ +-- simple/index.blade.php ← Fallback (tum tenantlar) +-- simple/show.blade.php Modules/Blog/resources/views/themes/ +-- simple/blog/index.blade.php +-- simple/blog/show.blade.php
Tip: Service/Blog icin t-3 ozel view yok, simple fallback kullaniliyor. Ozel tasarim istersen Modules/Service/resources/views/themes/t-3/ olustur.