From ef743e0d036847651cbf486ebf69ff4f0caa8bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Wed, 29 Oct 2025 15:47:48 -0300 Subject: [PATCH] Enhance settings management: Added support for new form types including color picker, code editor, rich editor, markdown editor, tags input, checkbox list, radio buttons, toggle buttons, and slider in the SettingForm. Updated the Setting model to handle these new types and modified the migration to include them in the type enum. Enhanced localization files to support new type labels in both English and Turkish. --- .../Settings/Schemas/SettingForm.php | 195 +++++++++++++++++- .../Settings/Tables/SettingsTable.php | 13 ++ app/Models/Setting.php | 99 ++++++++- ..._filament_form_types_to_settings_table.php | 60 ++++++ lang/en/settings.php | 25 +++ lang/tr/settings.php | 25 +++ 6 files changed, 414 insertions(+), 3 deletions(-) create mode 100644 database/migrations/2025_10_29_183814_add_filament_form_types_to_settings_table.php diff --git a/app/Filament/Admin/Resources/Settings/Schemas/SettingForm.php b/app/Filament/Admin/Resources/Settings/Schemas/SettingForm.php index 52a09e1..bf7ac58 100644 --- a/app/Filament/Admin/Resources/Settings/Schemas/SettingForm.php +++ b/app/Filament/Admin/Resources/Settings/Schemas/SettingForm.php @@ -10,6 +10,17 @@ use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\DateTimePicker; use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\Repeater; +use Filament\Forms\Components\ColorPicker; +use Filament\Forms\Components\CodeEditor; +use Filament\Forms\Components\CodeEditor\Enums\Language as CodeEditorLanguage; +use Filament\Forms\Components\RichEditor; +use Filament\Forms\Components\MarkdownEditor; +use Filament\Forms\Components\TagsInput; +use Filament\Forms\Components\CheckboxList; +use Filament\Forms\Components\Radio; +use Filament\Forms\Components\ToggleButtons; +use Filament\Forms\Components\Slider; +use Filament\Forms\Components\KeyValue; use Filament\Schemas\Components\Section; use Filament\Schemas\Components\Utilities\Get; use Filament\Schemas\Components\Utilities\Set; @@ -61,6 +72,16 @@ class SettingForm 'file' => __('settings.type_file'), 'date' => __('settings.type_date'), 'datetime' => __('settings.type_datetime'), + 'color_picker' => __('settings.type_color_picker'), + 'code_editor' => __('settings.type_code_editor'), + 'rich_editor' => __('settings.type_rich_editor'), + 'markdown_editor' => __('settings.type_markdown_editor'), + 'tags_input' => __('settings.type_tags_input'), + 'checkbox_list' => __('settings.type_checkbox_list'), + 'radio' => __('settings.type_radio'), + 'toggle_buttons' => __('settings.type_toggle_buttons'), + 'slider' => __('settings.type_slider'), + 'key_value' => __('settings.type_key_value'), ]) ->live() ->afterStateUpdated(fn (Set $set) => $set('value', null)), @@ -85,10 +106,10 @@ class SettingForm ->label(__('settings.value')) ->helperText(__('settings.value_helper')) ->required() - ->visible(fn (Get $get) => !in_array($get('type'), ['boolean', 'file', 'date', 'datetime', 'array'])) + ->visible(fn (Get $get) => in_array($get('type'), ['string', 'text', 'json'])) ->rows(fn (Get $get) => $get('type') === 'text' ? 5 : 3) ->formatStateUsing(function ($state, $record) { - if ($record && !in_array($record->type, ['boolean', 'file', 'date', 'datetime', 'array'])) { + if ($record && in_array($record->type, ['string', 'text', 'json'])) { return $record->value; } return $state; @@ -193,6 +214,176 @@ class SettingForm }) ->columnSpanFull(), + ColorPicker::make('value_color_picker') + ->label(__('settings.value')) + ->helperText(__('settings.value_helper')) + ->required() + ->visible(fn (Get $get) => $get('type') === 'color_picker') + ->formatStateUsing(function ($state, $record) { + if ($record && $record->type === 'color_picker') { + return $record->value; + } + return $state; + }) + ->columnSpanFull(), + + CodeEditor::make('value_code_editor') + ->label(__('settings.value')) + ->helperText(__('settings.value_helper')) + ->required() + ->visible(fn (Get $get) => $get('type') === 'code_editor') + ->language(CodeEditorLanguage::Php) + ->formatStateUsing(function ($state, $record) { + if ($record && $record->type === 'code_editor') { + return $record->value; + } + return $state; + }) + ->columnSpanFull(), + + RichEditor::make('value_rich_editor') + ->label(__('settings.value')) + ->helperText(__('settings.value_helper')) + ->required() + ->visible(fn (Get $get) => $get('type') === 'rich_editor') + ->fileAttachmentsDisk('public') + ->fileAttachmentsDirectory('settings') + ->toolbarButtons([ + 'attachFiles', + 'blockquote', + 'bold', + 'bulletList', + 'codeBlock', + 'h2', + 'h3', + 'italic', + 'link', + 'orderedList', + 'redo', + 'strike', + 'underline', + 'undo', + ]) + ->formatStateUsing(function ($state, $record) { + if ($record && $record->type === 'rich_editor') { + return $record->value; + } + return $state; + }) + ->columnSpanFull(), + + MarkdownEditor::make('value_markdown_editor') + ->label(__('settings.value')) + ->helperText(__('settings.value_helper')) + ->required() + ->visible(fn (Get $get) => $get('type') === 'markdown_editor') + ->formatStateUsing(function ($state, $record) { + if ($record && $record->type === 'markdown_editor') { + return $record->value; + } + return $state; + }) + ->columnSpanFull(), + + TagsInput::make('value_tags_input') + ->label(__('settings.value')) + ->helperText(__('settings.value_helper')) + ->required() + ->visible(fn (Get $get) => $get('type') === 'tags_input') + ->separator(',') + ->formatStateUsing(function ($state, $record) { + if ($record && $record->type === 'tags_input') { + $decoded = json_decode($record->value, true); + return is_array($decoded) ? $decoded : []; + } + return is_array($state) ? $state : []; + }) + ->columnSpanFull(), + + CheckboxList::make('value_checkbox_list') + ->label(__('settings.value')) + ->helperText(__('settings.value_helper')) + ->required() + ->visible(fn (Get $get) => $get('type') === 'checkbox_list') + ->options(fn () => [ + 'option1' => __('settings.checkbox_option_1'), + 'option2' => __('settings.checkbox_option_2'), + 'option3' => __('settings.checkbox_option_3'), + ]) + ->formatStateUsing(function ($state, $record) { + if ($record && $record->type === 'checkbox_list') { + $decoded = json_decode($record->value, true); + return is_array($decoded) ? $decoded : []; + } + return is_array($state) ? $state : []; + }) + ->columnSpanFull(), + + Radio::make('value_radio') + ->label(__('settings.value')) + ->helperText(__('settings.value_helper')) + ->required() + ->visible(fn (Get $get) => $get('type') === 'radio') + ->options(fn () => [ + 'option1' => __('settings.radio_option_1'), + 'option2' => __('settings.radio_option_2'), + 'option3' => __('settings.radio_option_3'), + ]) + ->formatStateUsing(function ($state, $record) { + if ($record && $record->type === 'radio') { + return $record->value; + } + return $state; + }) + ->columnSpanFull(), + + ToggleButtons::make('value_toggle_buttons') + ->label(__('settings.value')) + ->helperText(__('settings.value_helper')) + ->required() + ->visible(fn (Get $get) => $get('type') === 'toggle_buttons') + ->options(fn () => [ + 'option1' => __('settings.toggle_option_1'), + 'option2' => __('settings.toggle_option_2'), + 'option3' => __('settings.toggle_option_3'), + ]) + ->formatStateUsing(function ($state, $record) { + if ($record && $record->type === 'toggle_buttons') { + return $record->value; + } + return $state; + }) + ->columnSpanFull(), + + Slider::make('value_slider') + ->label(__('settings.value')) + ->helperText(__('settings.value_helper')) + ->required() + ->visible(fn (Get $get) => $get('type') === 'slider') + ->range(minValue: 0, maxValue: 100) + ->step(1) + ->formatStateUsing(function ($state, $record) { + if ($record && $record->type === 'slider') { + return (int) $record->value; + } + return $state ?? 0; + }) + ->columnSpanFull(), + + KeyValue::make('value_key_value') + ->label(__('settings.value')) + ->helperText(__('settings.value_helper')) + ->required() + ->visible(fn (Get $get) => $get('type') === 'key_value') + ->formatStateUsing(function ($state, $record) { + if ($record && $record->type === 'key_value') { + $decoded = json_decode($record->value, true); + return is_array($decoded) ? $decoded : []; + } + return is_array($state) ? $state : []; + }) + ->columnSpanFull(), + Toggle::make('is_active') ->label(__('settings.is_active')) ->helperText(__('settings.is_active_helper')) diff --git a/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php b/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php index 1f5bd10..ae1b375 100644 --- a/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php +++ b/app/Filament/Admin/Resources/Settings/Tables/SettingsTable.php @@ -111,6 +111,19 @@ class SettingsTable 'float' => __('settings.type_float'), 'array' => __('settings.type_array'), 'json' => __('settings.type_json'), + 'file' => __('settings.type_file'), + 'date' => __('settings.type_date'), + 'datetime' => __('settings.type_datetime'), + 'color_picker' => __('settings.type_color_picker'), + 'code_editor' => __('settings.type_code_editor'), + 'rich_editor' => __('settings.type_rich_editor'), + 'markdown_editor' => __('settings.type_markdown_editor'), + 'tags_input' => __('settings.type_tags_input'), + 'checkbox_list' => __('settings.type_checkbox_list'), + 'radio' => __('settings.type_radio'), + 'toggle_buttons' => __('settings.type_toggle_buttons'), + 'slider' => __('settings.type_slider'), + 'key_value' => __('settings.type_key_value'), ]), TernaryFilter::make('is_active') diff --git a/app/Models/Setting.php b/app/Models/Setting.php index eec21c2..4ad7442 100644 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -19,6 +19,16 @@ class Setting extends Model 'value_date', 'value_datetime', 'value_array', + 'value_color_picker', + 'value_code_editor', + 'value_rich_editor', + 'value_markdown_editor', + 'value_tags_input', + 'value_checkbox_list', + 'value_radio', + 'value_toggle_buttons', + 'value_slider', + 'value_key_value', 'type', 'group', 'label', @@ -86,6 +96,86 @@ class Setting extends Model $this->attributes['value'] = is_array($value) ? json_encode($value) : $value; } + /** + * Set value from color picker + */ + public function setValueColorPickerAttribute($value) + { + $this->attributes['value'] = $value; + } + + /** + * Set value from code editor + */ + public function setValueCodeEditorAttribute($value) + { + $this->attributes['value'] = $value; + } + + /** + * Set value from rich editor + */ + public function setValueRichEditorAttribute($value) + { + $this->attributes['value'] = $value; + } + + /** + * Set value from markdown editor + */ + public function setValueMarkdownEditorAttribute($value) + { + $this->attributes['value'] = $value; + } + + /** + * Set value from tags input + */ + public function setValueTagsInputAttribute($value) + { + $this->attributes['value'] = is_array($value) ? json_encode($value) : $value; + } + + /** + * Set value from checkbox list + */ + public function setValueCheckboxListAttribute($value) + { + $this->attributes['value'] = is_array($value) ? json_encode($value) : $value; + } + + /** + * Set value from radio + */ + public function setValueRadioAttribute($value) + { + $this->attributes['value'] = $value; + } + + /** + * Set value from toggle buttons + */ + public function setValueToggleButtonsAttribute($value) + { + $this->attributes['value'] = $value; + } + + /** + * Set value from slider + */ + public function setValueSliderAttribute($value) + { + $this->attributes['value'] = (string) $value; + } + + /** + * Set value from key value + */ + public function setValueKeyValueAttribute($value) + { + $this->attributes['value'] = is_array($value) ? json_encode($value) : $value; + } + /** * Get setting by key */ @@ -126,10 +216,17 @@ class Setting extends Model 'boolean' => filter_var($value, FILTER_VALIDATE_BOOLEAN), 'integer' => (int) $value, 'float' => (float) $value, - 'array', 'json' => json_decode($value, true), + 'array', 'json', 'tags_input', 'checkbox_list', 'key_value' => json_decode($value, true), 'file' => $value, // File path as string 'date' => $value, // Date as string (Y-m-d format) 'datetime' => $value, // DateTime as string (Y-m-d H:i:s format) + 'color_picker' => $value, // Color as hex string + 'code_editor' => $value, // Code as string + 'rich_editor' => $value, // HTML as string + 'markdown_editor' => $value, // Markdown as string + 'radio' => $value, // Radio selection as string + 'toggle_buttons' => $value, // Toggle selection as string + 'slider' => (int) $value, // Slider value as integer default => $value, }; } diff --git a/database/migrations/2025_10_29_183814_add_filament_form_types_to_settings_table.php b/database/migrations/2025_10_29_183814_add_filament_form_types_to_settings_table.php new file mode 100644 index 0000000..eb05baf --- /dev/null +++ b/database/migrations/2025_10_29_183814_add_filament_form_types_to_settings_table.php @@ -0,0 +1,60 @@ +enum('type', [ + 'string', + 'text', + 'boolean', + 'integer', + 'float', + 'array', + 'json', + 'file', + 'date', + 'datetime', + 'color_picker', + 'code_editor', + 'rich_editor', + 'markdown_editor', + 'tags_input', + 'checkbox_list', + 'radio', + 'toggle_buttons', + 'slider', + 'key_value', + ])->default('string')->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('settings', function (Blueprint $table) { + $table->enum('type', [ + 'string', + 'text', + 'boolean', + 'integer', + 'float', + 'array', + 'json', + 'file', + 'date', + 'datetime', + ])->default('string')->change(); + }); + } +}; diff --git a/lang/en/settings.php b/lang/en/settings.php index b983bae..54135cb 100644 --- a/lang/en/settings.php +++ b/lang/en/settings.php @@ -62,6 +62,16 @@ return [ 'type_file' => 'File', 'type_date' => 'Date', 'type_datetime' => 'Date & Time', + 'type_color_picker' => 'Color Picker', + 'type_code_editor' => 'Code Editor', + 'type_rich_editor' => 'Rich Text Editor', + 'type_markdown_editor' => 'Markdown Editor', + 'type_tags_input' => 'Tags Input', + 'type_checkbox_list' => 'Checkbox List', + 'type_radio' => 'Radio Button', + 'type_toggle_buttons' => 'Toggle Buttons', + 'type_slider' => 'Slider', + 'type_key_value' => 'Key-Value Pairs', // Groups 'group_general' => 'General', @@ -91,6 +101,21 @@ return [ 'array_active' => 'Active', 'array_add_item' => 'Add Item', + // Checkbox options (placeholder, can be customized per setting) + 'checkbox_option_1' => 'Option 1', + 'checkbox_option_2' => 'Option 2', + 'checkbox_option_3' => 'Option 3', + + // Radio options (placeholder, can be customized per setting) + 'radio_option_1' => 'Option 1', + 'radio_option_2' => 'Option 2', + 'radio_option_3' => 'Option 3', + + // Toggle options (placeholder, can be customized per setting) + 'toggle_option_1' => 'Option 1', + 'toggle_option_2' => 'Option 2', + 'toggle_option_3' => 'Option 3', + // Filters 'filter_group' => 'By Group', 'filter_type' => 'By Type', diff --git a/lang/tr/settings.php b/lang/tr/settings.php index 6c472ff..07c4095 100644 --- a/lang/tr/settings.php +++ b/lang/tr/settings.php @@ -62,6 +62,16 @@ return [ 'type_file' => 'Dosya', 'type_date' => 'Tarih', 'type_datetime' => 'Tarih ve Saat', + 'type_color_picker' => 'Renk Seçici', + 'type_code_editor' => 'Kod Editörü', + 'type_rich_editor' => 'Zengin Metin Editörü', + 'type_markdown_editor' => 'Markdown Editörü', + 'type_tags_input' => 'Etiket Girişi', + 'type_checkbox_list' => 'Çoklu Seçim', + 'type_radio' => 'Radio Buton', + 'type_toggle_buttons' => 'Toggle Butonları', + 'type_slider' => 'Kaydırıcı', + 'type_key_value' => 'Anahtar-Değer Çiftleri', // Groups 'group_general' => 'Genel', @@ -91,6 +101,21 @@ return [ 'array_active' => 'Aktif', 'array_add_item' => 'Öğe Ekle', + // Checkbox options (placeholder, can be customized per setting) + 'checkbox_option_1' => 'Seçenek 1', + 'checkbox_option_2' => 'Seçenek 2', + 'checkbox_option_3' => 'Seçenek 3', + + // Radio options (placeholder, can be customized per setting) + 'radio_option_1' => 'Seçenek 1', + 'radio_option_2' => 'Seçenek 2', + 'radio_option_3' => 'Seçenek 3', + + // Toggle options (placeholder, can be customized per setting) + 'toggle_option_1' => 'Seçenek 1', + 'toggle_option_2' => 'Seçenek 2', + 'toggle_option_3' => 'Seçenek 3', + // Filters 'filter_group' => 'Gruba Göre', 'filter_type' => 'Tipe Göre',