From eae9523cde0443080bcccfd2af78c05e5903250d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Wed, 29 Oct 2025 16:58:05 -0300 Subject: [PATCH 1/8] Add DatabaseSeeder and enhance settings management: Created DatabaseSeeder to seed initial data, including a test user. Updated ListSettings page to support group filtering and added new settings groups in localization files. Enhanced SettingForm and SettingsTable to accommodate new group options and improved UI for settings management. --- .../database/seeders/DatabaseSeeder.php | 29 + .../Resources/Settings/Pages/ListSettings.php | 95 +- .../Settings/Schemas/SettingForm.php | 8 + .../Settings/Tables/SettingsTable.php | 13 - database/seeders/DatabaseSeeder.php | 5 + database/seeders/SettingSeeder.php | 1116 ++++++++++++++++- lang/en/settings.php | 13 + lang/tr/settings.php | 13 + .../settings/pages/list-settings.blade.php | 122 ++ 9 files changed, 1350 insertions(+), 64 deletions(-) create mode 100644 's/home/truncgil/web/citrus.truncgil.com/public_html/database/seeders/DatabaseSeeder.php create mode 100644 resources/views/filament/admin/resources/settings/pages/list-settings.blade.php diff --git a/'s/home/truncgil/web/citrus.truncgil.com/public_html/database/seeders/DatabaseSeeder.php b/'s/home/truncgil/web/citrus.truncgil.com/public_html/database/seeders/DatabaseSeeder.php new file mode 100644 index 0000000..15a4df5 --- /dev/null +++ b/'s/home/truncgil/web/citrus.truncgil.com/public_html/database/seeders/DatabaseSeeder.php @@ -0,0 +1,29 @@ +call([ + SettingSeeder::class, + ]); + + // User::factory(10)->create(); + + User::factory()->create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + } +} + diff --git a/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php b/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php index c07e9c9..f72d940 100644 --- a/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php +++ b/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php @@ -3,18 +3,37 @@ namespace App\Filament\Admin\Resources\Settings\Pages; use App\Filament\Admin\Resources\Settings\SettingResource; +use App\Filament\Admin\Resources\Settings\Tables\SettingsTable; use Filament\Actions\CreateAction; +use Filament\Forms\Concerns\InteractsWithForms; +use Filament\Forms\Contracts\HasForms; use Filament\Resources\Pages\ListRecords; +use Filament\Support\Icons\Heroicon; +use Illuminate\Contracts\Support\Htmlable; -class ListSettings extends ListRecords +class ListSettings extends ListRecords implements HasForms { + use InteractsWithForms; + protected static string $resource = SettingResource::class; + public ?string $activeGroup = null; + + public function getView(): string + { + return 'filament.admin.resources.settings.pages.list-settings'; + } + public function getTitle(): string { return __('settings.title'); } + public function getHeading(): string | Htmlable + { + return __('settings.title'); + } + protected function getHeaderActions(): array { return [ @@ -22,4 +41,78 @@ class ListSettings extends ListRecords ->label(__('settings.create')), ]; } + + public function mount(): void + { + parent::mount(); + + // Query string'den activeGroup' 별 al, yoksa tüm ayarları göster (null) + $this->activeGroup = request()->query('group', null); + } + + public function getGroups(): \Illuminate\Support\Collection + { + return \App\Models\Setting::whereNull('deleted_at') + ->select('group') + ->distinct() + ->orderBy('group') + ->pluck('group') + ->mapWithKeys(function ($group) { + return [$group => __("settings.group_{$group}")]; + }); + } + + public function setActiveGroup(?string $group): void + { + $this->activeGroup = $group; + } + + protected function getTableQuery(): \Illuminate\Database\Eloquent\Builder + { + $query = parent::getTableQuery(); + + // Eğer bir grup seçildiyse filtrele + if ($this->activeGroup) { + $query->where('group', $this->activeGroup); + } + + return $query; + } + + protected function getGroupIcon(?string $group): string + { + if (!$group) { + return 'heroicon-o-squares-2x2'; + } + + return match($group) { + 'general' => 'heroicon-o-cog-6-tooth', + 'theme' => 'heroicon-o-paint-brush', + 'localization' => 'heroicon-o-language', + 'email' => 'heroicon-o-envelope', + 'seo' => 'heroicon-o-magnifying-glass', + 'social' => 'heroicon-o-share', + 'security' => 'heroicon-o-shield-check', + 'upload' => 'heroicon-o-cloud-arrow-up', + 'payment' => 'heroicon-o-credit-card', + 'notification' => 'heroicon-o-bell', + 'cache' => 'heroicon-o-arrow-path', + 'api' => 'heroicon-o-code-bracket', + 'logging' => 'heroicon-o-document-text', + 'performance' => 'heroicon-o-bolt', + 'integration' => 'heroicon-o-puzzle-piece', + default => 'heroicon-o-squares-2x2', + }; + } + + protected function getGroupCount(?string $group): int + { + if (!$group) { + return \App\Models\Setting::whereNull('deleted_at')->count(); + } + + return \App\Models\Setting::where('group', $group) + ->whereNull('deleted_at') + ->count(); + } } diff --git a/app/Filament/Admin/Resources/Settings/Schemas/SettingForm.php b/app/Filament/Admin/Resources/Settings/Schemas/SettingForm.php index bf7ac58..e70976b 100644 --- a/app/Filament/Admin/Resources/Settings/Schemas/SettingForm.php +++ b/app/Filament/Admin/Resources/Settings/Schemas/SettingForm.php @@ -92,12 +92,20 @@ class SettingForm ->required() ->options([ 'general' => __('settings.group_general'), + 'theme' => __('settings.group_theme'), + 'localization' => __('settings.group_localization'), 'email' => __('settings.group_email'), 'seo' => __('settings.group_seo'), 'social' => __('settings.group_social'), 'security' => __('settings.group_security'), + 'upload' => __('settings.group_upload'), 'payment' => __('settings.group_payment'), 'notification' => __('settings.group_notification'), + 'cache' => __('settings.group_cache'), + 'api' => __('settings.group_api'), + 'logging' => __('settings.group_logging'), + 'performance' => __('settings.group_performance'), + 'integration' => __('settings.group_integration'), 'other' => __('settings.group_other'), ]) ->default('general'), diff --git a/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php b/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php index ae1b375..234061a 100644 --- a/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php +++ b/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php @@ -88,19 +88,6 @@ class SettingsTable ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ - SelectFilter::make('group') - ->label(__('settings.filter_group')) - ->options([ - 'general' => __('settings.group_general'), - 'email' => __('settings.group_email'), - 'seo' => __('settings.group_seo'), - 'social' => __('settings.group_social'), - 'security' => __('settings.group_security'), - 'payment' => __('settings.group_payment'), - 'notification' => __('settings.group_notification'), - 'other' => __('settings.group_other'), - ]), - SelectFilter::make('type') ->label(__('settings.filter_type')) ->options([ diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index d01a0ef..6f892db 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -13,6 +13,11 @@ class DatabaseSeeder extends Seeder */ public function run(): void { + // Settings seed + $this->call([ + SettingSeeder::class, + ]); + // User::factory(10)->create(); User::factory()->create([ diff --git a/database/seeders/SettingSeeder.php b/database/seeders/SettingSeeder.php index e750004..487976c 100644 --- a/database/seeders/SettingSeeder.php +++ b/database/seeders/SettingSeeder.php @@ -3,7 +3,6 @@ namespace Database\Seeders; use App\Models\Setting; -use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; class SettingSeeder extends Seeder @@ -14,14 +13,16 @@ class SettingSeeder extends Seeder public function run(): void { $settings = [ - // Genel Ayarlar + // ========================================== + // GENEL AYARLAR (general) + // ========================================== [ 'key' => 'site_name', 'value' => 'Citrus Platform', 'type' => 'string', 'group' => 'general', 'label' => 'Site Adı', - 'description' => 'Web sitesinin adı', + 'description' => 'Web sitesinin başlığı', 'is_public' => true, 'is_active' => true, ], @@ -31,17 +32,77 @@ class SettingSeeder extends Seeder 'type' => 'text', 'group' => 'general', 'label' => 'Site Açıklaması', - 'description' => 'Web sitesinin açıklaması', + 'description' => 'Web sitesinin kısa açıklaması', 'is_public' => true, 'is_active' => true, ], [ 'key' => 'site_keywords', - 'value' => 'citrus, platform, web, modern', - 'type' => 'string', + 'value' => json_encode(['citrus', 'platform', 'web', 'modern']), + 'type' => 'tags_input', 'group' => 'general', 'label' => 'Site Anahtar Kelimeleri', - 'description' => 'SEO için anahtar kelimeler', + 'description' => 'SEO için anahtar kelimeler (virgülle ayrılmış)', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'site_logo', + 'value' => '', + 'type' => 'file', + 'group' => 'general', + 'label' => 'Site Logosu', + 'description' => 'Üst kısımda görünecek logo dosyası', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'site_favicon', + 'value' => '', + 'type' => 'file', + 'group' => 'general', + 'label' => 'Site Favicon', + 'description' => 'Tarayıcı sekmesinde görünecek favicon', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'site_version', + 'value' => '1.0.0', + 'type' => 'string', + 'group' => 'general', + 'label' => 'Site Versiyonu', + 'description' => 'Uygulama versiyon numarası', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'site_url', + 'value' => 'https://citrus.truncgil.com', + 'type' => 'string', + 'group' => 'general', + 'label' => 'Site URL', + 'description' => 'Web sitesinin tam adresi', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'default_language', + 'value' => 'tr', + 'type' => 'toggle_buttons', + 'group' => 'general', + 'label' => 'Varsayılan Dil', + 'description' => 'Site varsayılan dili', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'available_languages', + 'value' => json_encode(['tr', 'en']), + 'type' => 'checkbox_list', + 'group' => 'general', + 'label' => 'Aktif Diller', + 'description' => 'Sitede kullanılacak diller', 'is_public' => true, 'is_active' => true, ], @@ -55,14 +116,384 @@ class SettingSeeder extends Seeder 'is_public' => false, 'is_active' => true, ], - - // E-posta Ayarları + [ + 'key' => 'maintenance_message', + 'value' => '

Site Bakımda

Yakında döneceğiz...

', + 'type' => 'rich_editor', + 'group' => 'general', + 'label' => 'Bakım Modu Mesajı', + 'description' => 'Bakım modundayken gösterilecek mesaj', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'copyright_text', + 'value' => '© 2024 Citrus Platform. Tüm hakları saklıdır.', + 'type' => 'text', + 'group' => 'general', + 'label' => 'Telif Hakkı Metni', + 'description' => 'Alt kısımda görünecek telif hakkı metni', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'contact_phone', + 'value' => '+90 555 555 55 55', + 'type' => 'string', + 'group' => 'general', + 'label' => 'İletişim Telefonu', + 'description' => 'İletişim telefon numarası', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'contact_email', + 'value' => 'info@citrus.truncgil.com', + 'type' => 'string', + 'group' => 'general', + 'label' => 'İletişim E-posta', + 'description' => 'İletişim e-posta adresi', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'contact_address', + 'value' => 'İstanbul, Türkiye', + 'type' => 'text', + 'group' => 'general', + 'label' => 'İletişim Adresi', + 'description' => 'İletişim fiziksel adresi', + 'is_public' => true, + 'is_active' => true, + ], + + // ========================================== + // TEMA VE RENK AYARLARI (theme) + // ========================================== + [ + 'key' => 'theme_primary_color', + 'value' => '#3b82f6', + 'type' => 'color_picker', + 'group' => 'theme', + 'label' => 'Primary Color', + 'description' => 'Ana tema rengi (Tailwind/Bootstrap primary)', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_secondary_color', + 'value' => '#6b7280', + 'type' => 'color_picker', + 'group' => 'theme', + 'label' => 'Secondary Color', + 'description' => 'İkincil tema rengi', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_success_color', + 'value' => '#10b981', + 'type' => 'color_picker', + 'group' => 'theme', + 'label' => 'Success Color', + 'description' => 'Başarı mesajları için renk', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_danger_color', + 'value' => '#ef4444', + 'type' => 'color_picker', + 'group' => 'theme', + 'label' => 'Danger Color', + 'description' => 'Hata ve uyarı mesajları için renk', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_warning_color', + 'value' => '#f59e0b', + 'type' => 'color_picker', + 'group' => 'theme', + 'label' => 'Warning Color', + 'description' => 'Uyarı mesajları için renk', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_info_color', + 'value' => '#06b6d4', + 'type' => 'color_picker', + 'group' => 'theme', + 'label' => 'Info Color', + 'description' => 'Bilgi mesajları için renk', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_light_color', + 'value' => '#f9fafb', + 'type' => 'color_picker', + 'group' => 'theme', + 'label' => 'Light Color', + 'description' => 'Açık renk', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_dark_color', + 'value' => '#1f2937', + 'type' => 'color_picker', + 'group' => 'theme', + 'label' => 'Dark Color', + 'description' => 'Koyu renk', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_body_background', + 'value' => '#ffffff', + 'type' => 'color_picker', + 'group' => 'theme', + 'label' => 'Body Background Color', + 'description' => 'Sayfa arka plan rengi', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_text_color', + 'value' => '#111827', + 'type' => 'color_picker', + 'group' => 'theme', + 'label' => 'Text Color', + 'description' => 'Varsayılan metin rengi', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_mode', + 'value' => 'light', + 'type' => 'toggle_buttons', + 'group' => 'theme', + 'label' => 'Tema Modu', + 'description' => 'Açık, koyu veya otomatik tema', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'theme_border_radius', + 'value' => '8', + 'type' => 'slider', + 'group' => 'theme', + 'label' => 'Border Radius (px)', + 'description' => 'Öğelerin köşe yuvarlaklığı (0-20 arası)', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'custom_css', + 'value' => '/* Özel CSS kodlarınızı buraya ekleyin */', + 'type' => 'code_editor', + 'group' => 'theme', + 'label' => 'Özel CSS', + 'description' => 'Site genelinde uygulanacak özel CSS kodları', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'custom_js', + 'value' => '// Özel JavaScript kodlarınızı buraya ekleyin', + 'type' => 'code_editor', + 'group' => 'theme', + 'label' => 'Özel JavaScript', + 'description' => 'Site genelinde uygulanacak özel JavaScript kodları', + 'is_public' => false, + 'is_active' => true, + ], + + // ========================================== + // LOKALİZASYON AYARLARI (localization) + // ========================================== + [ + 'key' => 'timezone', + 'value' => 'Europe/Istanbul', + 'type' => 'string', + 'group' => 'localization', + 'label' => 'Zaman Dilimi', + 'description' => 'Sunucu zaman dilimi (Europe/Istanbul, UTC, vb.)', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'date_format', + 'value' => 'd/m/Y', + 'type' => 'radio', + 'group' => 'localization', + 'label' => 'Tarih Formatı', + 'description' => 'Tarih gösterim formatı', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'time_format', + 'value' => '24', + 'type' => 'toggle_buttons', + 'group' => 'localization', + 'label' => 'Saat Formatı', + 'description' => '12 veya 24 saatlik format', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'currency', + 'value' => 'TRY', + 'type' => 'string', + 'group' => 'localization', + 'label' => 'Para Birimi', + 'description' => 'Varsayılan para birimi kodu (TRY, USD, EUR)', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'currency_symbol', + 'value' => '₺', + 'type' => 'string', + 'group' => 'localization', + 'label' => 'Para Birimi Sembolü', + 'description' => 'Para birimi sembolü', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'currency_position', + 'value' => 'after', + 'type' => 'radio', + 'group' => 'localization', + 'label' => 'Para Birimi Konumu', + 'description' => 'Sembolün fiyatın önünde mi arkasında mı olacağı', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'thousands_separator', + 'value' => '.', + 'type' => 'string', + 'group' => 'localization', + 'label' => 'Binlik Ayırıcı', + 'description' => 'Sayılarda binlik ayırıcı karakter', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'decimal_separator', + 'value' => ',', + 'type' => 'string', + 'group' => 'localization', + 'label' => 'Ondalık Ayırıcı', + 'description' => 'Sayılarda ondalık ayırıcı karakter', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'decimal_places', + 'value' => '2', + 'type' => 'integer', + 'group' => 'localization', + 'label' => 'Ondalık Basamak Sayısı', + 'description' => 'Para birimi için ondalık basamak sayısı', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'week_start_day', + 'value' => 'Monday', + 'type' => 'radio', + 'group' => 'localization', + 'label' => 'Haftanın İlk Günü', + 'description' => 'Haftanın başlangıç günü', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'calendar_type', + 'value' => 'Gregorian', + 'type' => 'toggle_buttons', + 'group' => 'localization', + 'label' => 'Takvim Tipi', + 'description' => 'Gregorian veya Miladi takvim', + 'is_public' => true, + 'is_active' => true, + ], + + // ========================================== + // E-POSTA AYARLARI (email) + // ========================================== + [ + 'key' => 'mail_driver', + 'value' => 'smtp', + 'type' => 'radio', + 'group' => 'email', + 'label' => 'Mail Driver', + 'description' => 'E-posta gönderim yöntemi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'mail_host', + 'value' => 'smtp.gmail.com', + 'type' => 'string', + 'group' => 'email', + 'label' => 'SMTP Host', + 'description' => 'SMTP sunucu adresi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'mail_port', + 'value' => '587', + 'type' => 'integer', + 'group' => 'email', + 'label' => 'SMTP Port', + 'description' => 'SMTP port numarası', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'mail_username', + 'value' => '', + 'type' => 'string', + 'group' => 'email', + 'label' => 'SMTP Kullanıcı Adı', + 'description' => 'SMTP kullanıcı adı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'mail_password', + 'value' => '', + 'type' => 'string', + 'group' => 'email', + 'label' => 'SMTP Şifre', + 'description' => 'SMTP şifresi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'mail_encryption', + 'value' => 'tls', + 'type' => 'toggle_buttons', + 'group' => 'email', + 'label' => 'SMTP Şifreleme', + 'description' => 'TLS veya SSL şifreleme', + 'is_public' => false, + 'is_active' => true, + ], [ 'key' => 'mail_from_address', 'value' => 'noreply@citrus.truncgil.com', 'type' => 'string', 'group' => 'email', - 'label' => 'E-posta Gönderen Adres', + 'label' => 'Gönderen E-posta Adresi', 'description' => 'Sistem e-postalarının gönderileceği adres', 'is_public' => false, 'is_active' => true, @@ -72,7 +503,7 @@ class SettingSeeder extends Seeder 'value' => 'Citrus Platform', 'type' => 'string', 'group' => 'email', - 'label' => 'E-posta Gönderen İsim', + 'label' => 'Gönderen İsim', 'description' => 'Sistem e-postalarının gönderen adı', 'is_public' => false, 'is_active' => true, @@ -88,7 +519,32 @@ class SettingSeeder extends Seeder 'is_active' => true, ], - // SEO Ayarları + // ========================================== + // SOSYAL MEDYA AYARLARI (social) + // ========================================== + [ + 'key' => 'social_links', + 'value' => json_encode([ + 'facebook' => '', + 'twitter' => '', + 'instagram' => '', + 'linkedin' => '', + 'youtube' => '', + 'tiktok' => '', + 'github' => '', + 'discord' => '', + ]), + 'type' => 'key_value', + 'group' => 'social', + 'label' => 'Sosyal Medya Linkleri', + 'description' => 'Sosyal medya platformlarının URL\'leri', + 'is_public' => true, + 'is_active' => true, + ], + + // ========================================== + // SEO AYARLARI (seo) + // ========================================== [ 'key' => 'seo_meta_title', 'value' => 'Citrus Platform - Modern Web Platformu', @@ -110,7 +566,17 @@ class SettingSeeder extends Seeder 'is_active' => true, ], [ - 'key' => 'seo_google_analytics', + 'key' => 'seo_meta_keywords', + 'value' => json_encode(['citrus', 'platform', 'web', 'modern', 'laravel']), + 'type' => 'tags_input', + 'group' => 'seo', + 'label' => 'SEO Meta Anahtar Kelimeler', + 'description' => 'Varsayılan SEO meta anahtar kelimeler', + 'is_public' => true, + 'is_active' => true, + ], + [ + 'key' => 'seo_google_analytics_id', 'value' => '', 'type' => 'string', 'group' => 'seo', @@ -119,57 +585,77 @@ class SettingSeeder extends Seeder 'is_public' => false, 'is_active' => true, ], - - // Sosyal Medya Ayarları [ - 'key' => 'social_facebook', + 'key' => 'seo_google_tag_manager_id', 'value' => '', 'type' => 'string', - 'group' => 'social', - 'label' => 'Facebook URL', - 'description' => 'Facebook sayfa URL\'si', + 'group' => 'seo', + 'label' => 'Google Tag Manager ID', + 'description' => 'Google Tag Manager takip kodu', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'seo_bing_webmaster', + 'value' => '', + 'type' => 'string', + 'group' => 'seo', + 'label' => 'Bing Webmaster Tools', + 'description' => 'Bing Webmaster doğrulama kodu', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'seo_robots_txt', + 'value' => "User-agent: *\nAllow: /", + 'type' => 'code_editor', + 'group' => 'seo', + 'label' => 'Robots.txt İçeriği', + 'description' => 'Robots.txt dosyası içeriği', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'seo_sitemap_url', + 'value' => '/sitemap.xml', + 'type' => 'string', + 'group' => 'seo', + 'label' => 'Sitemap URL', + 'description' => 'XML sitemap dosyasının adresi', 'is_public' => true, 'is_active' => true, ], [ - 'key' => 'social_twitter', - 'value' => '', + 'key' => 'seo_canonical_url', + 'value' => 'https://citrus.truncgil.com', 'type' => 'string', - 'group' => 'social', - 'label' => 'Twitter URL', - 'description' => 'Twitter profil URL\'si', + 'group' => 'seo', + 'label' => 'Canonical URL', + 'description' => 'Varsayılan canonical URL', 'is_public' => true, 'is_active' => true, ], [ - 'key' => 'social_instagram', - 'value' => '', - 'type' => 'string', - 'group' => 'social', - 'label' => 'Instagram URL', - 'description' => 'Instagram profil URL\'si', - 'is_public' => true, + 'key' => 'seo_opengraph_enabled', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'seo', + 'label' => 'Open Graph Etiketleri', + 'description' => 'Open Graph meta etiketleri aktif mi?', + 'is_public' => false, 'is_active' => true, ], - [ - 'key' => 'social_linkedin', - 'value' => '', - 'type' => 'string', - 'group' => 'social', - 'label' => 'LinkedIn URL', - 'description' => 'LinkedIn profil URL\'si', - 'is_public' => true, - 'is_active' => true, - ], - - // Güvenlik Ayarları + + // ========================================== + // GÜVENLİK AYARLARI (security) + // ========================================== [ 'key' => 'security_max_login_attempts', 'value' => '5', - 'type' => 'integer', + 'type' => 'slider', 'group' => 'security', 'label' => 'Maksimum Giriş Denemesi', - 'description' => 'Kullanıcı hesabının kilitlenmesi için maksimum giriş denemesi', + 'description' => 'Kullanıcı hesabının kilitlenmesi için maksimum giriş denemesi (3-10 arası)', 'is_public' => false, 'is_active' => true, ], @@ -193,15 +679,181 @@ class SettingSeeder extends Seeder 'is_public' => false, 'is_active' => true, ], - - // Bildirim Ayarları + [ + 'key' => 'security_password_min_length', + 'value' => '8', + 'type' => 'slider', + 'group' => 'security', + 'label' => 'Şifre Minimum Uzunluk', + 'description' => 'Şifre için minimum karakter sayısı (6-20 arası)', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'security_password_require_uppercase', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'security', + 'label' => 'Şifrede Büyük Harf Zorunlu', + 'description' => 'Şifrede en az bir büyük harf olmalı mı?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'security_password_require_lowercase', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'security', + 'label' => 'Şifrede Küçük Harf Zorunlu', + 'description' => 'Şifrede en az bir küçük harf olmalı mı?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'security_password_require_numbers', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'security', + 'label' => 'Şifrede Rakam Zorunlu', + 'description' => 'Şifrede en az bir rakam olmalı mı?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'security_password_require_symbols', + 'value' => '0', + 'type' => 'boolean', + 'group' => 'security', + 'label' => 'Şifrede Özel Karakter Zorunlu', + 'description' => 'Şifrede en az bir özel karakter olmalı mı?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'security_api_rate_limit', + 'value' => '60', + 'type' => 'integer', + 'group' => 'security', + 'label' => 'API Rate Limit', + 'description' => 'Dakikada maksimum API isteği sayısı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'security_ip_whitelist', + 'value' => json_encode([]), + 'type' => 'tags_input', + 'group' => 'security', + 'label' => 'IP Whitelist', + 'description' => 'Yönetim paneline erişebilecek IP adresleri (boş = tüm IP\'ler)', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'security_csrf_protection', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'security', + 'label' => 'CSRF Koruması', + 'description' => 'CSRF koruması aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + + // ========================================== + // DOSYA YÜKLEME AYARLARI (upload) + // ========================================== + [ + 'key' => 'upload_max_size', + 'value' => '10', + 'type' => 'slider', + 'group' => 'upload', + 'label' => 'Maksimum Yükleme Boyutu (MB)', + 'description' => 'Dosya yükleme için maksimum boyut (1-100 MB arası)', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'upload_allowed_image_types', + 'value' => json_encode(['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg']), + 'type' => 'tags_input', + 'group' => 'upload', + 'label' => 'İzin Verilen Resim Formatları', + 'description' => 'Yüklenebilecek resim dosya türleri', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'upload_allowed_document_types', + 'value' => json_encode(['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt']), + 'type' => 'tags_input', + 'group' => 'upload', + 'label' => 'İzin Verilen Belge Formatları', + 'description' => 'Yüklenebilecek belge dosya türleri', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'upload_allowed_video_types', + 'value' => json_encode(['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm']), + 'type' => 'tags_input', + 'group' => 'upload', + 'label' => 'İzin Verilen Video Formatları', + 'description' => 'Yüklenebilecek video dosya türleri', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'upload_image_quality', + 'value' => '85', + 'type' => 'slider', + 'group' => 'upload', + 'label' => 'Resim Kalitesi (%)', + 'description' => 'Yüklenen resimlerin sıkıştırma kalitesi (1-100 arası)', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'upload_storage_driver', + 'value' => 'local', + 'type' => 'radio', + 'group' => 'upload', + 'label' => 'Storage Driver', + 'description' => 'Dosya saklama yöntemi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'upload_cdn_url', + 'value' => '', + 'type' => 'string', + 'group' => 'upload', + 'label' => 'CDN URL', + 'description' => 'CDN sunucusu adresi (boş bırakılabilir)', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'upload_folder_structure', + 'value' => 'date', + 'type' => 'radio', + 'group' => 'upload', + 'label' => 'Klasör Yapısı', + 'description' => 'Dosyaların saklanma klasör yapısı', + 'is_public' => false, + 'is_active' => true, + ], + + // ========================================== + // BİLDİRİM AYARLARI (notification) + // ========================================== [ 'key' => 'notification_email_enabled', 'value' => '1', 'type' => 'boolean', 'group' => 'notification', 'label' => 'E-posta Bildirimleri', - 'description' => 'E-posta bildirimleri gönderilsin mi?', + 'description' => 'E-posta bildirimleri aktif mi?', 'is_public' => false, 'is_active' => true, ], @@ -211,7 +863,7 @@ class SettingSeeder extends Seeder 'type' => 'boolean', 'group' => 'notification', 'label' => 'SMS Bildirimleri', - 'description' => 'SMS bildirimleri gönderilsin mi?', + 'description' => 'SMS bildirimleri aktif mi?', 'is_public' => false, 'is_active' => true, ], @@ -221,7 +873,371 @@ class SettingSeeder extends Seeder 'type' => 'boolean', 'group' => 'notification', 'label' => 'Push Bildirimleri', - 'description' => 'Push bildirimleri gönderilsin mi?', + 'description' => 'Push bildirimleri aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'notification_in_app_enabled', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'notification', + 'label' => 'İn-App Bildirimleri', + 'description' => 'Uygulama içi bildirimler aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'notification_channels', + 'value' => json_encode(['email', 'in_app']), + 'type' => 'checkbox_list', + 'group' => 'notification', + 'label' => 'Aktif Bildirim Kanalları', + 'description' => 'Aktif olacak bildirim kanalları', + 'is_public' => false, + 'is_active' => true, + ], + + // ========================================== + // CACHE AYARLARI (cache) + // ========================================== + [ + 'key' => 'cache_driver', + 'value' => 'file', + 'type' => 'radio', + 'group' => 'cache', + 'label' => 'Cache Driver', + 'description' => 'Cache saklama yöntemi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'cache_duration', + 'value' => '60', + 'type' => 'integer', + 'group' => 'cache', + 'label' => 'Cache Süresi (dakika)', + 'description' => 'Cache\'in geçerlilik süresi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'cache_enabled', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'cache', + 'label' => 'Cache Aktif', + 'description' => 'Cache sistemi aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'cache_prefix', + 'value' => 'citrus_', + 'type' => 'string', + 'group' => 'cache', + 'label' => 'Cache Prefix', + 'description' => 'Cache anahtarları için önek', + 'is_public' => false, + 'is_active' => true, + ], + + // ========================================== + // ÖDEME AYARLARI (payment) + // ========================================== + [ + 'key' => 'payment_default_gateway', + 'value' => 'stripe', + 'type' => 'radio', + 'group' => 'payment', + 'label' => 'Varsayılan Ödeme Gateway\'i', + 'description' => 'Varsayılan ödeme servisi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'payment_test_mode', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'payment', + 'label' => 'Test Modu', + 'description' => 'Ödeme test modunda mı?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'payment_currency', + 'value' => 'TRY', + 'type' => 'string', + 'group' => 'payment', + 'label' => 'Ödeme Para Birimi', + 'description' => 'Ödemeler için para birimi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'payment_tax_rate', + 'value' => '20', + 'type' => 'float', + 'group' => 'payment', + 'label' => 'Vergi Oranı (%)', + 'description' => 'Varsayılan vergi oranı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'payment_methods', + 'value' => json_encode(['credit_card', 'bank_transfer']), + 'type' => 'checkbox_list', + 'group' => 'payment', + 'label' => 'Ödeme Yöntemleri', + 'description' => 'Aktif ödeme yöntemleri', + 'is_public' => false, + 'is_active' => true, + ], + + // ========================================== + // API AYARLARI (api) + // ========================================== + [ + 'key' => 'api_rate_limit', + 'value' => '60', + 'type' => 'integer', + 'group' => 'api', + 'label' => 'API Rate Limit', + 'description' => 'Dakikada maksimum API isteği sayısı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'api_auth_method', + 'value' => 'jwt', + 'type' => 'radio', + 'group' => 'api', + 'label' => 'API Kimlik Doğrulama Yöntemi', + 'description' => 'API için kimlik doğrulama yöntemi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'api_key_expiration', + 'value' => '30', + 'type' => 'integer', + 'group' => 'api', + 'label' => 'API Key Geçerlilik Süresi (gün)', + 'description' => 'API anahtarının geçerlilik süresi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'api_versioning_enabled', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'api', + 'label' => 'API Versiyonlama', + 'description' => 'API versiyonlama aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + + // ========================================== + // LOGGING AYARLARI (logging) + // ========================================== + [ + 'key' => 'log_level', + 'value' => 'info', + 'type' => 'radio', + 'group' => 'logging', + 'label' => 'Log Seviyesi', + 'description' => 'Kaydedilecek log seviyesi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'log_driver', + 'value' => 'daily', + 'type' => 'radio', + 'group' => 'logging', + 'label' => 'Log Driver', + 'description' => 'Log saklama yöntemi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'log_retention_days', + 'value' => '30', + 'type' => 'integer', + 'group' => 'logging', + 'label' => 'Log Saklama Süresi (gün)', + 'description' => 'Log dosyalarının saklanma süresi', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'log_error_reporting', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'logging', + 'label' => 'Hata Raporlama', + 'description' => 'Hata raporlama aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + + // ========================================== + // PERFORMANS AYARLARI (performance) + // ========================================== + [ + 'key' => 'performance_query_cache_enabled', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'performance', + 'label' => 'Query Cache Aktif', + 'description' => 'Veritabanı sorgu cache\'i aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'performance_asset_minification', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'performance', + 'label' => 'Asset Minification', + 'description' => 'CSS/JS dosyalarının küçültülmesi aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'performance_cdn_enabled', + 'value' => '0', + 'type' => 'boolean', + 'group' => 'performance', + 'label' => 'CDN Aktif', + 'description' => 'CDN kullanımı aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'performance_lazy_loading_enabled', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'performance', + 'label' => 'Lazy Loading Aktif', + 'description' => 'Resimler için lazy loading aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'performance_image_optimization', + 'value' => '1', + 'type' => 'boolean', + 'group' => 'performance', + 'label' => 'Resim Optimizasyonu', + 'description' => 'Otomatik resim optimizasyonu aktif mi?', + 'is_public' => false, + 'is_active' => true, + ], + + // ========================================== + // ENTEGRASYON AYARLARI (integration) + // ========================================== + [ + 'key' => 'integration_recaptcha_site_key', + 'value' => '', + 'type' => 'string', + 'group' => 'integration', + 'label' => 'reCAPTCHA Site Key', + 'description' => 'Google reCAPTCHA site anahtarı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'integration_recaptcha_secret_key', + 'value' => '', + 'type' => 'string', + 'group' => 'integration', + 'label' => 'reCAPTCHA Secret Key', + 'description' => 'Google reCAPTCHA gizli anahtarı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'integration_google_maps_api_key', + 'value' => '', + 'type' => 'string', + 'group' => 'integration', + 'label' => 'Google Maps API Key', + 'description' => 'Google Maps API anahtarı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'integration_stripe_public_key', + 'value' => '', + 'type' => 'string', + 'group' => 'integration', + 'label' => 'Stripe Public Key', + 'description' => 'Stripe public anahtarı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'integration_stripe_secret_key', + 'value' => '', + 'type' => 'string', + 'group' => 'integration', + 'label' => 'Stripe Secret Key', + 'description' => 'Stripe gizli anahtarı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'integration_paypal_client_id', + 'value' => '', + 'type' => 'string', + 'group' => 'integration', + 'label' => 'PayPal Client ID', + 'description' => 'PayPal client ID', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'integration_paypal_secret', + 'value' => '', + 'type' => 'string', + 'group' => 'integration', + 'label' => 'PayPal Secret', + 'description' => 'PayPal secret anahtarı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'integration_aws_access_key', + 'value' => '', + 'type' => 'string', + 'group' => 'integration', + 'label' => 'AWS Access Key', + 'description' => 'Amazon Web Services erişim anahtarı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'integration_aws_secret_key', + 'value' => '', + 'type' => 'string', + 'group' => 'integration', + 'label' => 'AWS Secret Key', + 'description' => 'Amazon Web Services gizli anahtarı', + 'is_public' => false, + 'is_active' => true, + ], + [ + 'key' => 'integration_aws_region', + 'value' => 'us-east-1', + 'type' => 'string', + 'group' => 'integration', + 'label' => 'AWS Region', + 'description' => 'Amazon Web Services bölgesi', 'is_public' => false, 'is_active' => true, ], diff --git a/lang/en/settings.php b/lang/en/settings.php index 54135cb..6bafed3 100644 --- a/lang/en/settings.php +++ b/lang/en/settings.php @@ -75,12 +75,20 @@ return [ // Groups 'group_general' => 'General', + 'group_theme' => 'Theme', + 'group_localization' => 'Localization', 'group_email' => 'Email', 'group_seo' => 'SEO', 'group_social' => 'Social Media', 'group_security' => 'Security', + 'group_upload' => 'Upload', 'group_payment' => 'Payment', 'group_notification' => 'Notification', + 'group_cache' => 'Cache', + 'group_api' => 'API', + 'group_logging' => 'Logging', + 'group_performance' => 'Performance', + 'group_integration' => 'Integration', 'group_other' => 'Other', // Validation messages @@ -121,5 +129,10 @@ return [ 'filter_type' => 'By Type', 'filter_active' => 'Active', 'filter_public' => 'Public', + + // Tabs + 'tabs_title' => 'Setting Groups', + 'settings_count' => 'settings', + 'all_settings' => 'All Settings', ]; diff --git a/lang/tr/settings.php b/lang/tr/settings.php index 07c4095..d67862d 100644 --- a/lang/tr/settings.php +++ b/lang/tr/settings.php @@ -75,12 +75,20 @@ return [ // Groups 'group_general' => 'Genel', + 'group_theme' => 'Tema', + 'group_localization' => 'Lokalizasyon', 'group_email' => 'E-posta', 'group_seo' => 'SEO', 'group_social' => 'Sosyal Medya', 'group_security' => 'Güvenlik', + 'group_upload' => 'Dosya Yükleme', 'group_payment' => 'Ödeme', 'group_notification' => 'Bildirim', + 'group_cache' => 'Cache', + 'group_api' => 'API', + 'group_logging' => 'Logging', + 'group_performance' => 'Performans', + 'group_integration' => 'Entegrasyon', 'group_other' => 'Diğer', // Validation messages @@ -121,5 +129,10 @@ return [ 'filter_type' => 'Tipe Göre', 'filter_active' => 'Aktif', 'filter_public' => 'Herkese Açık', + + // Tabs + 'tabs_title' => 'Ayar Grupları', + 'settings_count' => 'ayar', + 'all_settings' => 'Tüm Ayarlar', ]; diff --git a/resources/views/filament/admin/resources/settings/pages/list-settings.blade.php b/resources/views/filament/admin/resources/settings/pages/list-settings.blade.php new file mode 100644 index 0000000..2c73fd1 --- /dev/null +++ b/resources/views/filament/admin/resources/settings/pages/list-settings.blade.php @@ -0,0 +1,122 @@ + + + + + From edf8949a6a6be6b6ae32d98bae7e7f18768ed7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Wed, 29 Oct 2025 17:02:43 -0300 Subject: [PATCH 2/8] Refactor ListSettings page to implement tabbed navigation: Removed custom Blade view and integrated tab functionality for settings groups. Enhanced group filtering and localization support for settings display. --- .../Resources/Settings/Pages/ListSettings.php | 80 ++++-------- .../settings/pages/list-settings.blade.php | 122 ------------------ 2 files changed, 27 insertions(+), 175 deletions(-) delete mode 100644 resources/views/filament/admin/resources/settings/pages/list-settings.blade.php diff --git a/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php b/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php index f72d940..ba5671a 100644 --- a/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php +++ b/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php @@ -3,27 +3,19 @@ namespace App\Filament\Admin\Resources\Settings\Pages; use App\Filament\Admin\Resources\Settings\SettingResource; -use App\Filament\Admin\Resources\Settings\Tables\SettingsTable; +use App\Models\Setting; use Filament\Actions\CreateAction; -use Filament\Forms\Concerns\InteractsWithForms; -use Filament\Forms\Contracts\HasForms; +use Filament\Schemas\Components\Tabs; +use Filament\Schemas\Components\Tabs\Tab; + use Filament\Resources\Pages\ListRecords; -use Filament\Support\Icons\Heroicon; use Illuminate\Contracts\Support\Htmlable; +use Illuminate\Database\Eloquent\Builder; -class ListSettings extends ListRecords implements HasForms +class ListSettings extends ListRecords { - use InteractsWithForms; - protected static string $resource = SettingResource::class; - public ?string $activeGroup = null; - - public function getView(): string - { - return 'filament.admin.resources.settings.pages.list-settings'; - } - public function getTitle(): string { return __('settings.title'); @@ -42,41 +34,34 @@ class ListSettings extends ListRecords implements HasForms ]; } - public function mount(): void + public function getTabs(): array { - parent::mount(); - - // Query string'den activeGroup' 별 al, yoksa tüm ayarları göster (null) - $this->activeGroup = request()->query('group', null); - } + $tabs = []; - public function getGroups(): \Illuminate\Support\Collection - { - return \App\Models\Setting::whereNull('deleted_at') + // "Tüm Ayarlar" tab'ı ekle + $allCount = Setting::query()->count(); + $tabs['all'] = Tab::make(__('settings.all_settings')) + ->icon($this->getGroupIcon(null)) + ->badge($allCount); + + // Her grup için tab oluştur + $groups = Setting::query() ->select('group') ->distinct() ->orderBy('group') - ->pluck('group') - ->mapWithKeys(function ($group) { - return [$group => __("settings.group_{$group}")]; - }); - } + ->pluck('group'); - public function setActiveGroup(?string $group): void - { - $this->activeGroup = $group; - } - - protected function getTableQuery(): \Illuminate\Database\Eloquent\Builder - { - $query = parent::getTableQuery(); - - // Eğer bir grup seçildiyse filtrele - if ($this->activeGroup) { - $query->where('group', $this->activeGroup); + foreach ($groups as $group) { + $count = Setting::where('group', $group)->count(); + $label = __("settings.group_{$group}"); + + $tabs[$group] = Tab::make($label) + ->icon($this->getGroupIcon($group)) + ->badge($count) + ->modifyQueryUsing(fn (Builder $query) => $query->where('group', $group)); } - - return $query; + + return $tabs; } protected function getGroupIcon(?string $group): string @@ -104,15 +89,4 @@ class ListSettings extends ListRecords implements HasForms default => 'heroicon-o-squares-2x2', }; } - - protected function getGroupCount(?string $group): int - { - if (!$group) { - return \App\Models\Setting::whereNull('deleted_at')->count(); - } - - return \App\Models\Setting::where('group', $group) - ->whereNull('deleted_at') - ->count(); - } } diff --git a/resources/views/filament/admin/resources/settings/pages/list-settings.blade.php b/resources/views/filament/admin/resources/settings/pages/list-settings.blade.php deleted file mode 100644 index 2c73fd1..0000000 --- a/resources/views/filament/admin/resources/settings/pages/list-settings.blade.php +++ /dev/null @@ -1,122 +0,0 @@ - - - - - From e704146df9976db432a38c55042024a8d90c907a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Wed, 29 Oct 2025 17:06:12 -0300 Subject: [PATCH 3/8] Update cursor rules for Filament 4.x: Refined tab usage guidelines, clarified namespace imports, and emphasized the distinction between resource list page tabs and form/schema tabs. Added critical notes on incorrect usage of Tab components and provided examples for proper implementation. --- .cursorrules | 92 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/.cursorrules b/.cursorrules index 2c586b7..871db0a 100644 --- a/.cursorrules +++ b/.cursorrules @@ -102,11 +102,85 @@ use Filament\Forms\Components\FileUpload; use Filament\Schemas\Components\Section; // ✅ Doğru use Filament\Schemas\Components\Grid; // ✅ Doğru use Filament\Schemas\Components\Fieldset; // ✅ Doğru +use Filament\Schemas\Components\Flex; // ✅ Doğru -// Tabs components (ÖNEMLİ: Forms namespace!) -use Filament\Forms\Components\Tabs; // ✅ Doğru -// Tab kullanımı: Tabs\Tab::make() şeklinde kullan -// Import gerekmez, Tabs namespace'i üzerinden erişilir +// Tabs components (ÖNEMLİ: Schemas namespace!) +use Filament\Schemas\Components\Tabs; // ✅ Doğru +use Filament\Schemas\Components\Tabs\Tab; // ✅ Doğru +// FORM/INFOLIST içindeki tab'lar için yukarıdaki import'ları kullan + +// Wizard component (Schemas namespace!) +use Filament\Schemas\Components\Wizard; +use Filament\Schemas\Components\Wizard\Step; + +// Infolist entry components +use Filament\Infolists\Components\TextEntry; +use Filament\Infolists\Components\IconEntry; +use Filament\Infolists\Components\ImageEntry; +``` + +#### **Filament 4.x TAB KULLANIM KURALLARI (KRİTİK!):** + +Filament 4.x'te **iki farklı Tab sistemi** vardır: + +**1. Resource List Pages Tabs (getTabs() metodu):** +```php +// ❌ YANLIŞ - Bu class Filament 4.x'te YOK! +use Filament\Resources\Components\Tab; + +// ✅ DOĞRU - ListRecords page'lerinde getTabs() için +use Filament\Schemas\Components\Tabs\Tab; + +// Örnek kullanım: +class ListSettings extends ListRecords +{ + public function getTabs(): array + { + return [ + 'all' => Tab::make('Tümü') + ->icon('heroicon-o-squares-2x2') + ->badge(100) + ->modifyQueryUsing(fn (Builder $query) => $query), + + 'active' => Tab::make('Aktif') + ->icon('heroicon-o-check') + ->badge(50) + ->modifyQueryUsing(fn (Builder $query) => $query->where('is_active', true)), + ]; + } +} +``` + +**2. Form/Schema Tabs (Form içinde kullanım):** +```php +// ✅ DOĞRU - Form/Schema içinde tabs için +use Filament\Schemas\Components\Tabs; +use Filament\Schemas\Components\Tabs\Tab; + +// Örnek kullanım: +public static function form(Schema $schema): Schema +{ + return $schema + ->components([ + Tabs::make('Tabs') + ->tabs([ + Tab::make('Genel Bilgiler') + ->icon('heroicon-o-information-circle') + ->schema([ + TextInput::make('name'), + // ... + ]), + Tab::make('SEO') + ->icon('heroicon-o-magnifying-glass') + ->schema([ + TextInput::make('meta_title'), + // ... + ]), + ]) + ->columnSpanFull() + ->persistTabInQueryString(), + ]); +} ``` #### **YANLIŞ KULLANIM (Eski Filament 3.x):** @@ -115,6 +189,8 @@ use Filament\Forms\Components\Tabs; // ✅ Doğru use Filament\Tables\Actions\EditAction; // ❌ use Filament\Forms\Components\Section; // ❌ use Filament\Forms\Components\Grid; // ❌ +use Filament\Forms\Components\Tabs; // ❌ Forms namespace altında Tabs YOK +use Filament\Resources\Components\Tab; // ❌ Bu class hiç YOK // ❌ YANLIŞ - Eski metod adları $table @@ -122,14 +198,18 @@ $table ->bulkActions([...]) // ❌ Kullanma! ``` -#### **ÖZET:** +#### **ÖZET (Filament 4.x Import Referansı):** - ✅ **Table Actions:** `Filament\Actions\` namespace - ✅ **Table Columns:** `Filament\Tables\Columns\` namespace - ✅ **Table Filters:** `Filament\Tables\Filters\` namespace - ✅ **Form Inputs:** `Filament\Forms\Components\` namespace -- ✅ **Layout Components:** `Filament\Schemas\Components\` namespace (Section, Grid, Tabs) +- ✅ **Layout Components:** `Filament\Schemas\Components\` namespace +- ✅ **Tabs (Tüm Kullanımlar):** `Filament\Schemas\Components\Tabs\Tab` (Her yerde bu!) +- ✅ **Infolist Entries:** `Filament\Infolists\Components\` namespace - ✅ **Table Methods:** `->recordActions()` ve `->toolbarActions()` +**Önemli Not:** Filament 4.x'te `Filament\Resources\Components\Tab` diye bir class **YOK**. Tüm tab kullanımları `Filament\Schemas\Components\Tabs\Tab` ile yapılır! + ### Dil Dosyası Yapısı Date: Wed, 29 Oct 2025 17:10:05 -0300 Subject: [PATCH 4/8] Implement dynamic tab content for ListSettings page: Added getTabsContentComponent method to manage tab content dynamically, enhancing the tab functionality and improving user experience in settings navigation. --- .../Resources/Settings/Pages/ListSettings.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php b/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php index ba5671a..3ef4e4d 100644 --- a/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php +++ b/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php @@ -5,9 +5,9 @@ namespace App\Filament\Admin\Resources\Settings\Pages; use App\Filament\Admin\Resources\Settings\SettingResource; use App\Models\Setting; use Filament\Actions\CreateAction; +use Filament\Schemas\Components\Component; use Filament\Schemas\Components\Tabs; use Filament\Schemas\Components\Tabs\Tab; - use Filament\Resources\Pages\ListRecords; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Builder; @@ -64,6 +64,18 @@ class ListSettings extends ListRecords return $tabs; } + public function getTabsContentComponent(): Component + { + $tabs = $this->getCachedTabs(); + + return Tabs::make() + ->livewireProperty('activeTab') + ->contained(false) + ->tabs($tabs) + ->vertical() + ->hidden(empty($tabs)); + } + protected function getGroupIcon(?string $group): string { if (!$group) { From 307a94d6fdc7aff3bff49cd9fd98d3a71469d438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Wed, 29 Oct 2025 17:12:06 -0300 Subject: [PATCH 5/8] Add max content width for ListSettings page: Implemented getMaxContentWidth method to set the maximum content width to full, enhancing the layout and responsiveness of the settings page. --- .../Admin/Resources/Settings/Pages/ListSettings.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php b/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php index 3ef4e4d..f1d473a 100644 --- a/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php +++ b/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php @@ -9,6 +9,7 @@ use Filament\Schemas\Components\Component; use Filament\Schemas\Components\Tabs; use Filament\Schemas\Components\Tabs\Tab; use Filament\Resources\Pages\ListRecords; +use Filament\Support\Enums\Width; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Builder; @@ -34,6 +35,11 @@ class ListSettings extends ListRecords ]; } + public function getMaxContentWidth(): Width | string | null + { + return Width::Full; + } + public function getTabs(): array { $tabs = []; From 50fff6332b9ed06ad0562d4c734a7cbee4225813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Wed, 29 Oct 2025 17:28:39 -0300 Subject: [PATCH 6/8] Comment out group column in SettingsTable: Temporarily disabled the group column display in the settings table to streamline the interface while maintaining localization support for active status. --- .../Admin/Resources/Settings/Tables/SettingsTable.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php b/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php index 234061a..6553802 100644 --- a/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php +++ b/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php @@ -58,13 +58,13 @@ class SettingsTable default => 'gray', }) ->formatStateUsing(fn (string $state): string => __("settings.type_{$state}")), - + /* TextColumn::make('group') ->label(__('settings.table_group')) ->badge() ->color('primary') ->formatStateUsing(fn (string $state): string => __("settings.group_{$state}")), - + */ IconColumn::make('is_active') ->label(__('settings.table_active')) ->boolean() From a30f3ce86a721af6321843fec550afcce3aaec17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Wed, 29 Oct 2025 17:34:02 -0300 Subject: [PATCH 7/8] Remove unused getTabsContentComponent method from ListSettings page: Streamlined the code by eliminating the method that managed tab content dynamically, as it was no longer necessary for the current implementation. --- .../Resources/Settings/Pages/ListSettings.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php b/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php index f1d473a..d37f88c 100644 --- a/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php +++ b/app/Filament/Admin/Resources/Settings/Pages/ListSettings.php @@ -5,8 +5,6 @@ namespace App\Filament\Admin\Resources\Settings\Pages; use App\Filament\Admin\Resources\Settings\SettingResource; use App\Models\Setting; use Filament\Actions\CreateAction; -use Filament\Schemas\Components\Component; -use Filament\Schemas\Components\Tabs; use Filament\Schemas\Components\Tabs\Tab; use Filament\Resources\Pages\ListRecords; use Filament\Support\Enums\Width; @@ -70,18 +68,6 @@ class ListSettings extends ListRecords return $tabs; } - public function getTabsContentComponent(): Component - { - $tabs = $this->getCachedTabs(); - - return Tabs::make() - ->livewireProperty('activeTab') - ->contained(false) - ->tabs($tabs) - ->vertical() - ->hidden(empty($tabs)); - } - protected function getGroupIcon(?string $group): string { if (!$group) { From 22a955a79e92bb4e4294c6b6dca7fd6f2d033d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Wed, 29 Oct 2025 17:51:14 -0300 Subject: [PATCH 8/8] Update SettingsTable to conditionally display group column: Re-enabled the group column with visibility control based on the active tab, while maintaining localization support for the column labels. --- .../Admin/Resources/Settings/Tables/SettingsTable.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php b/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php index 6553802..cb1f6c7 100644 --- a/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php +++ b/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php @@ -58,13 +58,14 @@ class SettingsTable default => 'gray', }) ->formatStateUsing(fn (string $state): string => __("settings.type_{$state}")), - /* + TextColumn::make('group') ->label(__('settings.table_group')) ->badge() ->color('primary') + ->visible(fn ($livewire) => $livewire->activeTab === 'all') ->formatStateUsing(fn (string $state): string => __("settings.group_{$state}")), - */ + IconColumn::make('is_active') ->label(__('settings.table_active')) ->boolean()