diff --git a/.idea/ntspi-new.iml b/.idea/ntspi-new.iml
index 6aafdfe..3cc4d86 100644
--- a/.idea/ntspi-new.iml
+++ b/.idea/ntspi-new.iml
@@ -179,6 +179,10 @@
+
+
+
+
diff --git a/.idea/php.xml b/.idea/php.xml
index 39687c1..1a2252c 100644
--- a/.idea/php.xml
+++ b/.idea/php.xml
@@ -190,6 +190,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/Filament/Resources/SlideResource.php b/app/Filament/Resources/SlideResource.php
new file mode 100644
index 0000000..5a44f89
--- /dev/null
+++ b/app/Filament/Resources/SlideResource.php
@@ -0,0 +1,214 @@
+schema([
+ Forms\Components\Section::make('Быстрая настройка слайда')->schema([
+ Forms\Components\Grid::make()->schema([
+ Forms\Components\Select::make('model_select')
+ ->name('')
+ ->label('Выбор типа данных')
+ ->options([
+ 'Post' => 'Новость',
+ 'Page' => 'Страница',
+ 'Event' => 'Мероприятие',
+ 'Custom' => 'Кастомная ссылка',
+ ])
+ ->afterStateUpdated(function (string $operation, string|null $state, Forms\Set $set, Forms\Get $get) {
+ if ($get('model_select') === 'Custom') {
+ $set('model', null);
+ $set('title', null);
+ $set('content', null);
+ $set('link', null);
+ };
+ })->live(onBlur: true),
+
+ Forms\Components\Select::make('model')
+ ->label('Поиск данных')
+ ->name('')
+ ->live(onBlur: true)
+ ->searchable()
+ ->live(onBlur: true)
+ ->afterStateUpdated(function (string $operation, string|null $state, Forms\Set $set, Forms\Get $get) {
+ if ($get('model_select') === 'Post') {
+ $post = Post::find($state);
+ $set('title', $post->title);
+ $relativeUrl = parse_url(route('client.post.show', $post->slug), PHP_URL_PATH);
+ $set('link', $relativeUrl);
+ };
+ if ($get('model_select') === 'Page') {
+ $page = Page::find($state);
+ $set('title', $page->title);
+ $set('link', $page->path);
+ };
+ if ($get('model_select') === 'Event') {
+ $event = Event::find($state);
+ $set('title', $event->title);
+ $relativeUrl = parse_url(route('client.event.show', $event->slug), PHP_URL_PATH);
+ $set('link', $relativeUrl);
+ };
+
+ })
+ ->options(function (Forms\Get $get) {
+ if ($get('model_select') === 'Post') {
+ return Post::where('status', '=', 'published')->pluck('title', 'id');
+ };
+ if ($get('model_select') === 'Page') {
+ return Page::where('title', '!=', null)->pluck('title', 'id');
+ };
+ if ($get('model_select') === 'Event') {
+ return Event::all()->pluck('title', 'id');
+ };
+ if ($get('model_select') === 'Custom') {
+ return [];
+ };
+ }),
+ ]),
+ ]),
+ Forms\Components\Section::make('Слайдер')->schema([
+
+ Forms\Components\Section::make('Информация слайда')->schema([
+ Forms\Components\TextInput::make('title')
+ ->label('Заголовок слайда'),
+ Forms\Components\Textarea::make('content')
+ ->label('Текст слайда'),
+ Forms\Components\Grid::make()->schema([
+ ColorPicker::make('color_theme')
+ ->label('Цвет текста')
+ ->default('#ffffff')
+ ->required(),
+ Forms\Components\ToggleButtons::make('settings.text_position')
+ ->options([
+ 'left' => 'Текст слева',
+ 'center' => 'Текст по середине',
+ 'right' => 'Текст справа'
+ ])
+ ->inline()->default('left')->grouped()
+ ->label('Позиция текста на слайде'),
+ ]),
+ Forms\Components\Grid::make()->schema([
+ Toggle::make('active_button')
+ ->label('Использовать кнопку для ссылки (Ссылка будет открываться при нажатии на слайд)')
+ ->inline(false)
+ ->default(true) // Проверяем, есть ли текст в link_text
+ ->live()
+ ->afterStateHydrated(function (Toggle $component, $state, $get) {
+ if ($state === null && !empty($get('settings.link_text'))) {
+ $component->state(true); // Устанавливаем значение по умолчанию
+ }
+ })
+ ->dehydrated(false),
+ Forms\Components\TextInput::make('settings.link_text')
+ ->default('Читать')
+ ->label('Текст кнопки')
+ ->disabled(fn (Forms\Get $get) => !$get('active_button'))
+ ]),
+ ]),
+ Forms\Components\Section::make('Изображение')->schema([
+ FileUpload::make('image.url')
+ ->label('Изображение')
+ ->image()
+ ->optimize('webp')
+ ->resize(50)
+ ->disk('public')
+ ->directory('images')
+ ->imageEditor()
+ ->required(),
+ ToggleButtons::make('image.shading')->inline()->grouped()->label('Уровень затемнения изображения')->options([
+ '1' => 'Без затемнения',
+ '0.7' => 'Слабое затемнение',
+ '0.5' => 'Среднее затемнение',
+ '0.3' => 'Сильное затемнение',
+ ]),
+ ]),
+ Forms\Components\Section::make('Общая часть')->schema([
+ Forms\Components\Grid::make()->schema([
+ DateTimePicker::make('start_time')
+ ->label('Слайд начинается с')
+ ->native()
+ ->displayFormat('d/m/Y')
+ ->default(Carbon::now())
+ ->maxDate(Carbon::now()->addWeeks(2)),
+ DateTimePicker::make('end_time')
+ ->label('Слайд действует до')
+ ->native()
+ ->displayFormat('d/m/Y')
+ ->default(Carbon::now()->addWeeks(2))
+ ->minDate(Carbon::now())
+ ->maxDate(Carbon::now()->addMonth()),
+ ]),
+ Forms\Components\TextInput::make('link')
+ ->label('Ссылка кнопки')
+ ->required(),
+ ]),
+
+ Toggle::make('is_active')->default(true)->label('Активный слайдер')->inline(false),
+ ]),
+ ]);
+ }
+
+ public static function table(Table $table): Table
+ {
+ return $table
+ ->reorderable('sort')
+ ->defaultSort('sort')
+ ->columns([
+ Tables\Columns\TextColumn::make('title'),
+ Tables\Columns\ToggleColumn::make('is_active')
+ ])
+ ->filters([
+ //
+ ])
+ ->actions([
+ Tables\Actions\EditAction::make(),
+ ])
+ ->bulkActions([
+ Tables\Actions\BulkActionGroup::make([
+ Tables\Actions\DeleteBulkAction::make(),
+ ]),
+ ]);
+ }
+
+ public static function getRelations(): array
+ {
+ return [
+ //
+ ];
+ }
+
+ public static function getPages(): array
+ {
+ return [
+ 'index' => Pages\ListSlides::route('/'),
+ 'create' => Pages\CreateSlide::route('/create'),
+ 'edit' => Pages\EditSlide::route('/{record}/edit'),
+ ];
+ }
+}
diff --git a/app/Filament/Resources/SlideResource/Pages/CreateSlide.php b/app/Filament/Resources/SlideResource/Pages/CreateSlide.php
new file mode 100644
index 0000000..451c52f
--- /dev/null
+++ b/app/Filament/Resources/SlideResource/Pages/CreateSlide.php
@@ -0,0 +1,19 @@
+schema([
+ Forms\Components\Section::make()->schema([
+ Forms\Components\TextInput::make('title')
+ ->label('Заголовок слайдера'),
+ Toggle::make('is_active')->default(true)->label('Активный слайдер')->inline(false),
+ ]),
+ ]);
+ }
+
+ public static function table(Table $table): Table
+ {
+ return $table
+ ->columns([
+ //
+ ])
+ ->filters([
+ //
+ ])
+ ->actions([
+ Tables\Actions\EditAction::make(),
+ ])
+ ->bulkActions([
+ Tables\Actions\BulkActionGroup::make([
+ Tables\Actions\DeleteBulkAction::make(),
+ ]),
+ ]);
+ }
+
+ public static function getRelations(): array
+ {
+ return [
+ //
+ ];
+ }
+
+ public static function getPages(): array
+ {
+ return [
+ 'index' => Pages\ListSliders::route('/'),
+ 'create' => Pages\CreateSlider::route('/create'),
+ 'edit' => Pages\EditSlider::route('/{record}/edit'),
+ ];
+ }
+}
diff --git a/app/Filament/Resources/SliderResource/Pages/CreateSlider.php b/app/Filament/Resources/SliderResource/Pages/CreateSlider.php
new file mode 100644
index 0000000..6db7b76
--- /dev/null
+++ b/app/Filament/Resources/SliderResource/Pages/CreateSlider.php
@@ -0,0 +1,12 @@
+ 'array',
+ 'image' => 'array',
+ ];
+
+ public function slider(): BelongsTo
+ {
+ return $this->belongsTo(Slider::class);
+ }
}
diff --git a/app/Models/Slider.php b/app/Models/Slider.php
index 76524bc..ed5b598 100644
--- a/app/Models/Slider.php
+++ b/app/Models/Slider.php
@@ -4,6 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
class Slider extends Model
{
@@ -11,13 +12,10 @@ class Slider extends Model
protected $guarded = false;
- protected $casts = [
- 'settings' => 'array',
- 'image' => 'array',
- ];
- public function slidable()
+ public function slides(): HasMany
{
- return $this->morphTo();
+ return $this->hasMany(Slide::class);
}
+
}
diff --git a/database/migrations/2025_03_13_223400_create_sliders_table.php b/database/migrations/2025_03_13_223400_create_sliders_table.php
new file mode 100644
index 0000000..27bbf66
--- /dev/null
+++ b/database/migrations/2025_03_13_223400_create_sliders_table.php
@@ -0,0 +1,29 @@
+id();
+ $table->string('title');
+ $table->boolean('is_active');
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('sliders');
+ }
+};
diff --git a/database/migrations/2025_03_13_223411_create_slides_table.php b/database/migrations/2025_03_13_223411_create_slides_table.php
new file mode 100644
index 0000000..0561321
--- /dev/null
+++ b/database/migrations/2025_03_13_223411_create_slides_table.php
@@ -0,0 +1,36 @@
+id();
+ $table->string('title');
+ $table->text('content');
+ $table->string('image');
+ $table->string('link');
+ $table->string('link_text');
+ $table->string('color_theme');
+ $table->boolean('is_active')->default(true);
+ $table->integer('sort')->nullable();
+ $table->foreignId('slider_id')->references('id')->on('sliders')->onDelete('cascade');
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('slides');
+ }
+};
diff --git a/package-lock.json b/package-lock.json
index fa12f12..02c218c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -26,7 +26,8 @@
"js-cookie": "^3.0.5",
"preline": "^1.9.0",
"slugify": "^1.6.6",
- "vue3-yandex-smartcaptcha": "^1.0.0"
+ "vue3-yandex-smartcaptcha": "^1.0.0",
+ "vuex": "^4.1.0"
},
"devDependencies": {
"@inertiajs/vue3": "^1.0.0",
@@ -1037,6 +1038,11 @@
"@vue/shared": "3.5.11"
}
},
+ "node_modules/@vue/devtools-api": {
+ "version": "6.6.4",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
+ "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="
+ },
"node_modules/@vue/reactivity": {
"version": "3.5.11",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.11.tgz",
@@ -6218,6 +6224,17 @@
"vue": "^3.3.8"
}
},
+ "node_modules/vuex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.1.0.tgz",
+ "integrity": "sha512-hmV6UerDrPcgbSy9ORAtNXDr9M4wlNP4pEFKye4ujJF8oqgFFuxDCdOLS3eNoRTtq5O3hoBDh9Doj1bQMYHRbQ==",
+ "dependencies": {
+ "@vue/devtools-api": "^6.0.0-beta.11"
+ },
+ "peerDependencies": {
+ "vue": "^3.2.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index d3665d5..28cfd65 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,8 @@
"js-cookie": "^3.0.5",
"preline": "^1.9.0",
"slugify": "^1.6.6",
- "vue3-yandex-smartcaptcha": "^1.0.0"
+ "vue3-yandex-smartcaptcha": "^1.0.0",
+ "vuex": "^4.1.0"
},
"name": "ntspi-reborn",
"description": "

",
diff --git a/resources/js/Components/ClientMainSlider.vue b/resources/js/Components/ClientMainSlider.vue
index d0cc5fa..f0b1b55 100644
--- a/resources/js/Components/ClientMainSlider.vue
+++ b/resources/js/Components/ClientMainSlider.vue
@@ -69,6 +69,8 @@