From 6a5e26638c104f11cb327cd4e11e3c79232b5c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Mon, 3 Nov 2025 16:30:50 -0300 Subject: [PATCH] Add placeholder picker component to template forms: Integrated a new placeholder picker component in Footer, Header, Menu, and Section template forms to enhance user experience by allowing easy insertion of placeholder variables. Updated the TemplateService to support custom blade components and added localization for the new placeholder picker functionality. --- .../Schemas/FooterTemplateForm.php | 7 + .../Schemas/HeaderTemplateForm.php | 7 + .../Schemas/MenuTemplateForm.php | 7 + .../Schemas/SectionTemplateForm.php | 7 + app/Services/TemplateService.php | 35 +++ lang/en/placeholder-picker.php | 33 +++ lang/tr/placeholder-picker.php | 33 +++ .../views/components/custom/example.blade.php | 6 + .../views/components/custom/test.blade.php | 6 + .../components/placeholder-picker.blade.php | 275 ++++++++++++++++++ 10 files changed, 416 insertions(+) create mode 100644 lang/en/placeholder-picker.php create mode 100644 lang/tr/placeholder-picker.php create mode 100644 resources/views/components/custom/example.blade.php create mode 100644 resources/views/components/custom/test.blade.php create mode 100644 resources/views/components/placeholder-picker.blade.php diff --git a/app/Filament/Admin/Resources/FooterTemplates/Schemas/FooterTemplateForm.php b/app/Filament/Admin/Resources/FooterTemplates/Schemas/FooterTemplateForm.php index 20dd3f5..fe9a753 100644 --- a/app/Filament/Admin/Resources/FooterTemplates/Schemas/FooterTemplateForm.php +++ b/app/Filament/Admin/Resources/FooterTemplates/Schemas/FooterTemplateForm.php @@ -29,6 +29,13 @@ class FooterTemplateForm ->maxLength(255) ->columnSpanFull(), + // Placeholder Picker Component + View::make('components.placeholder-picker') + ->viewData([ + 'fieldName' => 'html_content', + ]) + ->columnSpanFull(), + CodeEditor::make('html_content') ->label(__('footer-templates.field_html_content')) ->required() diff --git a/app/Filament/Admin/Resources/HeaderTemplates/Schemas/HeaderTemplateForm.php b/app/Filament/Admin/Resources/HeaderTemplates/Schemas/HeaderTemplateForm.php index c99aed3..2519047 100644 --- a/app/Filament/Admin/Resources/HeaderTemplates/Schemas/HeaderTemplateForm.php +++ b/app/Filament/Admin/Resources/HeaderTemplates/Schemas/HeaderTemplateForm.php @@ -28,6 +28,13 @@ class HeaderTemplateForm ->maxLength(255) ->columnSpanFull(), + // Placeholder Picker Component + View::make('components.placeholder-picker') + ->viewData([ + 'fieldName' => 'html_content', + ]) + ->columnSpanFull(), + CodeEditor::make('html_content') ->label(__('header-templates.field_html_content')) ->required() diff --git a/app/Filament/Admin/Resources/MenuTemplates/Schemas/MenuTemplateForm.php b/app/Filament/Admin/Resources/MenuTemplates/Schemas/MenuTemplateForm.php index b16a743..a7bca8b 100644 --- a/app/Filament/Admin/Resources/MenuTemplates/Schemas/MenuTemplateForm.php +++ b/app/Filament/Admin/Resources/MenuTemplates/Schemas/MenuTemplateForm.php @@ -25,6 +25,13 @@ class MenuTemplateForm ->maxLength(255) ->columnSpanFull(), + // Placeholder Picker Component + View::make('components.placeholder-picker') + ->viewData([ + 'fieldName' => 'html_content', + ]) + ->columnSpanFull(), + CodeEditor::make('html_content') ->label(__('menu-templates.field_html_content')) ->required() diff --git a/app/Filament/Admin/Resources/SectionTemplates/Schemas/SectionTemplateForm.php b/app/Filament/Admin/Resources/SectionTemplates/Schemas/SectionTemplateForm.php index 2849380..e2f0d2f 100644 --- a/app/Filament/Admin/Resources/SectionTemplates/Schemas/SectionTemplateForm.php +++ b/app/Filament/Admin/Resources/SectionTemplates/Schemas/SectionTemplateForm.php @@ -28,6 +28,13 @@ class SectionTemplateForm ->maxLength(255) ->columnSpanFull(), + // Placeholder Picker Component + View::make('components.placeholder-picker') + ->viewData([ + 'fieldName' => 'html_content', + ]) + ->columnSpanFull(), + CodeEditor::make('html_content') ->label(__('section-templates.field_html_content')) ->required() diff --git a/app/Services/TemplateService.php b/app/Services/TemplateService.php index 67a4790..119eea0 100644 --- a/app/Services/TemplateService.php +++ b/app/Services/TemplateService.php @@ -39,6 +39,11 @@ class TemplateService [$type, $name] = $parts; + // Skip custom.* placeholders - they are blade components, not form fields + if ($type === 'custom') { + continue; + } + $label = str($name)->title()->replace('_', ' ')->toString(); // Get existing value from existingData if provided @@ -268,6 +273,7 @@ class TemplateService * Replace placeholders in HTML with actual data * Supports both {text.title} and {{text.title}} formats * Also supports {menu} and {staticMenu} placeholders for menu rendering + * Also supports {custom.component_name} for custom blade components */ public static function replacePlaceholders(string $html, array $data): string { @@ -283,10 +289,39 @@ class TemplateService $html = str_replace('{staticMenu}', $renderedStaticMenu, $html); } + // Handle custom blade components: {custom.component_name} + preg_match_all('/\{custom\.([a-z_]+)\}/i', $html, $customMatches); + if (!empty($customMatches[0])) { + foreach ($customMatches[0] as $index => $fullMatch) { + $componentName = $customMatches[1][$index] ?? null; + if ($componentName) { + $viewPath = "components.custom.{$componentName}"; + if (view()->exists($viewPath)) { + try { + $renderedComponent = view($viewPath)->render(); + $html = str_replace($fullMatch, $renderedComponent, $html); + } catch (\Exception $e) { + // If rendering fails, remove the placeholder or show error + $html = str_replace($fullMatch, "", $html); + } + } else { + // Component doesn't exist, remove placeholder or show notice + $html = str_replace($fullMatch, "", $html); + } + } + } + } + // First, parse all placeholders in the format {type.field_name} + // Exclude custom.* from this regex to avoid double processing preg_match_all('/\{([a-z]+\.[a-z_]+)\}/i', $html, $matches); $placeholders = array_unique($matches[1] ?? []); + // Filter out custom.* placeholders as they're already handled above + $placeholders = array_filter($placeholders, function($placeholder) { + return !str_starts_with($placeholder, 'custom.'); + }); + // Replace each placeholder foreach ($placeholders as $placeholder) { // Try to find the value in data with various key formats diff --git a/lang/en/placeholder-picker.php b/lang/en/placeholder-picker.php new file mode 100644 index 0000000..4ceb7e7 --- /dev/null +++ b/lang/en/placeholder-picker.php @@ -0,0 +1,33 @@ + 'Placeholder Variables', + 'click_to_insert' => 'Click to insert into editor', + 'special_placeholders' => 'Special Placeholders', + + // Placeholder Types + 'type_text' => 'Text', + 'type_email' => 'Email', + 'type_url' => 'URL', + 'type_tel' => 'Telephone', + 'type_number' => 'Number', + 'type_textarea' => 'Textarea', + 'type_richtext' => 'Rich Text', + 'type_markdown' => 'Markdown', + 'type_code' => 'Code', + 'type_date' => 'Date', + 'type_datetime' => 'Date & Time', + 'type_time' => 'Time', + 'type_image' => 'Image', + 'type_images' => 'Images (Multiple)', + 'type_file' => 'File', + 'type_files' => 'Files (Multiple)', + 'type_select' => 'Select', + 'type_multiselect' => 'Multi Select', + 'type_checkbox' => 'Checkbox', + 'type_radio' => 'Radio', + 'type_toggle' => 'Toggle', + 'type_color' => 'Color', + 'type_tags' => 'Tags', +]; + diff --git a/lang/tr/placeholder-picker.php b/lang/tr/placeholder-picker.php new file mode 100644 index 0000000..dd95440 --- /dev/null +++ b/lang/tr/placeholder-picker.php @@ -0,0 +1,33 @@ + 'Placeholder Değişkenleri', + 'click_to_insert' => 'Tıklayarak editöre ekle', + 'special_placeholders' => 'Özel Placeholder\'lar', + + // Placeholder Tipleri + 'type_text' => 'Metin', + 'type_email' => 'E-posta', + 'type_url' => 'URL', + 'type_tel' => 'Telefon', + 'type_number' => 'Sayı', + 'type_textarea' => 'Çok Satırlı Metin', + 'type_richtext' => 'Zengin Metin', + 'type_markdown' => 'Markdown', + 'type_code' => 'Kod', + 'type_date' => 'Tarih', + 'type_datetime' => 'Tarih ve Saat', + 'type_time' => 'Saat', + 'type_image' => 'Resim', + 'type_images' => 'Resimler (Çoklu)', + 'type_file' => 'Dosya', + 'type_files' => 'Dosyalar (Çoklu)', + 'type_select' => 'Seçim', + 'type_multiselect' => 'Çoklu Seçim', + 'type_checkbox' => 'Onay Kutusu', + 'type_radio' => 'Radyo Butonu', + 'type_toggle' => 'Aç/Kapa', + 'type_color' => 'Renk', + 'type_tags' => 'Etiketler', +]; + diff --git a/resources/views/components/custom/example.blade.php b/resources/views/components/custom/example.blade.php new file mode 100644 index 0000000..9bfb1bc --- /dev/null +++ b/resources/views/components/custom/example.blade.php @@ -0,0 +1,6 @@ +
+

Örnek Custom Component

+

Bu component'i template içinde {custom.example} yazarak kullanabilirsiniz.

+

Bu dosyayı dilediğiniz gibi özelleştirebilir ve yeniden kullanabilirsiniz.

+
+ diff --git a/resources/views/components/custom/test.blade.php b/resources/views/components/custom/test.blade.php new file mode 100644 index 0000000..12f977a --- /dev/null +++ b/resources/views/components/custom/test.blade.php @@ -0,0 +1,6 @@ +
+

Custom Test Component

+

Bu bir örnek custom component'tir. Bu dosyayı dilediğiniz gibi özelleştirebilirsiniz.

+

Template içinde {custom.test} yazarak bu component'i çağırabilirsiniz.

+
+ diff --git a/resources/views/components/placeholder-picker.blade.php b/resources/views/components/placeholder-picker.blade.php new file mode 100644 index 0000000..3191dab --- /dev/null +++ b/resources/views/components/placeholder-picker.blade.php @@ -0,0 +1,275 @@ +@php + // Desteklenen placeholder tipleri ve açıklamaları + $placeholderTypes = [ + 'text' => ['label' => __('placeholder-picker.type_text'), 'examples' => ['company_name', 'title', 'description', 'subtitle']], + 'email' => ['label' => __('placeholder-picker.type_email'), 'examples' => ['contact', 'support', 'info', 'sales']], + 'url' => ['label' => __('placeholder-picker.type_url'), 'examples' => ['website', 'facebook', 'twitter', 'linkedin']], + 'tel' => ['label' => __('placeholder-picker.type_tel'), 'examples' => ['phone', 'mobile', 'fax', 'hotline']], + 'number' => ['label' => __('placeholder-picker.type_number'), 'examples' => ['price', 'quantity', 'age', 'year']], + 'textarea' => ['label' => __('placeholder-picker.type_textarea'), 'examples' => ['content', 'about', 'description', 'notes']], + 'richtext' => ['label' => __('placeholder-picker.type_richtext'), 'examples' => ['content', 'article', 'post', 'body']], + 'markdown' => ['label' => __('placeholder-picker.type_markdown'), 'examples' => ['content', 'documentation', 'readme']], + 'code' => ['label' => __('placeholder-picker.type_code'), 'examples' => ['snippet', 'example', 'script']], + 'date' => ['label' => __('placeholder-picker.type_date'), 'examples' => ['publish_date', 'event_date', 'birthday']], + 'datetime' => ['label' => __('placeholder-picker.type_datetime'), 'examples' => ['created_at', 'updated_at', 'event_time']], + 'time' => ['label' => __('placeholder-picker.type_time'), 'examples' => ['start_time', 'end_time', 'opening_time']], + 'image' => ['label' => __('placeholder-picker.type_image'), 'examples' => ['logo', 'banner', 'avatar', 'thumbnail']], + 'images' => ['label' => __('placeholder-picker.type_images'), 'examples' => ['gallery', 'photos', 'slider_images']], + 'file' => ['label' => __('placeholder-picker.type_file'), 'examples' => ['document', 'pdf', 'download']], + 'files' => ['label' => __('placeholder-picker.type_files'), 'examples' => ['documents', 'attachments']], + 'select' => ['label' => __('placeholder-picker.type_select'), 'examples' => ['category', 'status', 'type']], + 'multiselect' => ['label' => __('placeholder-picker.type_multiselect'), 'examples' => ['tags', 'categories', 'features']], + 'checkbox' => ['label' => __('placeholder-picker.type_checkbox'), 'examples' => ['is_active', 'is_featured', 'is_published']], + 'radio' => ['label' => __('placeholder-picker.type_radio'), 'examples' => ['gender', 'type', 'status']], + 'toggle' => ['label' => __('placeholder-picker.type_toggle'), 'examples' => ['is_active', 'is_enabled', 'is_visible']], + 'color' => ['label' => __('placeholder-picker.type_color'), 'examples' => ['primary_color', 'background_color', 'text_color']], + 'tags' => ['label' => __('placeholder-picker.type_tags'), 'examples' => ['tags', 'keywords', 'labels']], + ]; + + // Field name'i component'ten al + $fieldName = $fieldName ?? 'html_content'; +@endphp + +
+
+
+
+ + + + + {{ __('placeholder-picker.title') }} + +
+ + + + + + +
+ +
+
+ @foreach($placeholderTypes as $type => $info) +
+

+ {{ $info['label'] }} +

+
+ @foreach($info['examples'] as $example) + @php + $placeholder = $type . '.' . $example; + @endphp + + @endforeach +
+
+ @endforeach + + +
+

+ {{ __('placeholder-picker.special_placeholders') }} +

+
+ + +
+
+
+
+
+
+ +