share-lt/app/Filament/Resources/Entries/Schemas/EntryForm.php

178 lines
9.8 KiB
PHP
Raw Normal View History

2026-01-02 13:58:06 +00:00
<?php
namespace App\Filament\Resources\Entries\Schemas;
use Filament\Actions\Action;
2026-01-02 13:58:06 +00:00
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\SpatieMediaLibraryFileUpload;
2026-01-02 13:58:06 +00:00
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
2026-01-02 13:58:06 +00:00
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
use Illuminate\Support\Facades\Storage;
2026-01-02 13:58:06 +00:00
use Illuminate\Support\Str;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
2026-01-02 13:58:06 +00:00
class EntryForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('title')
->required()
->live(onBlur: true)
2026-01-02 13:58:06 +00:00
->afterStateUpdated(function ($state, $set): void {
$set('slug', Str::slug((string) $state));
}),
TextInput::make('slug')
->required()
->dehydrated()
->readOnly(),
2026-01-02 13:58:06 +00:00
Textarea::make('description')
->columnSpanFull(),
SpatieMediaLibraryFileUpload::make('featured_image')
->collection('featured-image')
->image()
->imageEditor()
->disk('public')
->visibility('public')
->columnSpanFull()
->hintAction(
Action::make('featured_picker')
->label('Pick from Gallery')
->icon('heroicon-m-photo')
->schema([
Select::make('image_id')
->label('Select an existing image')
->allowHtml()
->options(function () {
return Media::latest()
->limit(30) // Limit to 30 most recent items for performance
->get(['id', 'file_name', 'name', 'uuid', 'collection_name', 'model_type', 'model_id', 'disk'])
->filter(function (Media $item) {
// Only include media items that have a valid disk
return $item->disk !== null;
})
->mapWithKeys(function (Media $item) {
try {
$url = $item->getUrl();
} catch (\Exception $e) {
// Skip items that can't generate URLs
return [];
}
$fileName = e($item->file_name);
$name = e($item->name ?? '');
// Smaller image preview for better performance
$html = "<div class='flex items-center gap-3'>" .
"<img src='{$url}' class='rounded' style='width:60px;height:60px;object-fit:cover;' alt='{$fileName}' loading='lazy' />" .
"<div class='flex flex-col'>" .
"<span class='font-medium text-sm'>{$name}</span>" .
"<span class='text-xs text-gray-500'>{$fileName}</span>" .
"</div></div>";
return [$item->id => $html];
})->toArray();
})
->searchable()
->preload()
->required(),
])
->action(function (array $data, SpatieMediaLibraryFileUpload $component) {
$record = $component->getRecord();
if (!$record) {
\Filament\Notifications\Notification::make()
->warning()
->title('Save the entry first')
->send();
return;
}
if ($mediaItem = Media::find($data['image_id'])) {
// Clear existing featured image
$record->clearMediaCollection('featured-image');
// Associate the existing media with this entry instead of copying
$mediaItem->update([
'model_type' => get_class($record),
'model_id' => $record->id,
'collection_name' => 'featured-image'
]);
// Update component state
$component->state([$mediaItem->uuid]);
\Filament\Notifications\Notification::make()
->success()
->title('Featured image set')
->send();
}
})
),
2026-01-02 13:58:06 +00:00
Toggle::make('is_published')
->required(),
Toggle::make('is_featured')
->required(),
DatePicker::make('published_at'),
RichEditor::make('content')
->columnSpanFull()
->hintAction(
Action::make('picker')
->label('Gallery Picker')
->icon('heroicon-m-photo')
->schema([
Select::make('image_url')
->label('Select an existing image')
->allowHtml()
->options(function () {
return Media::latest()
->limit(30) // Limit to 30 most recent items for performance
->get(['id', 'file_name', 'name', 'uuid', 'collection_name', 'model_type', 'model_id', 'disk'])
->filter(function (Media $item) {
// Only include media items that have a valid disk
return $item->disk !== null;
})
->mapWithKeys(function (Media $item) {
try {
$url = $item->getUrl();
} catch (\Exception $e) {
// Skip items that can't generate URLs
return [];
}
$fileName = e($item->file_name);
$name = e($item->name ?? '');
// Smaller image preview for better performance
$html = "<div class='flex items-center gap-3'>" .
"<img src='{$url}' class='rounded' style='width:60px;height:60px;object-fit:cover;' alt='{$fileName}' loading='lazy' />" .
"<div class='flex flex-col'>" .
"<span class='font-medium text-sm'>{$name}</span>" .
"<span class='text-xs text-gray-500'>{$fileName}</span>" .
"</div></div>";
return [$url => $html];
})->toArray();
})
->searchable()
->preload()
->required(),
])
->action(function (array $data, RichEditor $component) {
// We dispatch the URL to the browser to be inserted into TipTap
$component->getLivewire()->dispatch('insert-editor-content', [
'statePath' => $component->getStatePath(),
'html' => "<img src='{$data['image_url']}' alt=''>",
]);
})
),
2026-01-02 13:58:06 +00:00
]);
}
}