added fixes: warning
some files likely wont be needed and wer added by ai to fix things that were no longer needed !!!
This commit is contained in:
parent
8e1650653b
commit
93c977d1f5
5 changed files with 288 additions and 38 deletions
|
|
@ -40,6 +40,7 @@ class EntryForm
|
|||
->disk('public')
|
||||
->visibility('public')
|
||||
->columnSpanFull()
|
||||
->dehydrated(false)
|
||||
->hintAction(
|
||||
Action::make('featured_picker')
|
||||
->label('Pick from Gallery')
|
||||
|
|
@ -49,40 +50,36 @@ class EntryForm
|
|||
->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;
|
||||
})
|
||||
return Media::where('model_type', 'temp')
|
||||
->where('model_id', 0)
|
||||
->where('disk', 'public')
|
||||
->latest()
|
||||
->limit(30)
|
||||
->get(['id', 'file_name', 'name', 'disk'])
|
||||
->mapWithKeys(function (Media $item) {
|
||||
try {
|
||||
$url = $item->getUrl();
|
||||
$fileName = e($item->file_name);
|
||||
$name = e($item->name ?? '');
|
||||
|
||||
$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];
|
||||
} 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) {
|
||||
->action(function (array $data, SpatieMediaLibraryFileUpload $component): void {
|
||||
$record = $component->getRecord();
|
||||
|
||||
if (!$record) {
|
||||
|
|
@ -92,25 +89,56 @@ class EntryForm
|
|||
->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]);
|
||||
|
||||
|
||||
if (!$data['image_id']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sourceMedia = Media::find($data['image_id']);
|
||||
if (!$sourceMedia || !file_exists($sourceMedia->getPath())) {
|
||||
\Filament\Notifications\Notification::make()
|
||||
->danger()
|
||||
->title('Image file not found')
|
||||
->send();
|
||||
return;
|
||||
}
|
||||
|
||||
$sourceFile = $sourceMedia->getPath();
|
||||
$tempCopy = sys_get_temp_dir() . '/' . uniqid() . '_' . $sourceMedia->file_name;
|
||||
copy($sourceFile, $tempCopy);
|
||||
|
||||
try {
|
||||
// Verify record has ID
|
||||
if (!$record->id) {
|
||||
\Filament\Notifications\Notification::make()
|
||||
->danger()
|
||||
->title('Entry must be saved first')
|
||||
->send();
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the copy to the entry's featured-image collection
|
||||
$newMedia = $record->addMedia($tempCopy)
|
||||
->usingName($sourceMedia->name ?: pathinfo($sourceMedia->file_name, PATHINFO_FILENAME))
|
||||
->usingFileName($sourceMedia->file_name)
|
||||
->toMediaCollection('featured-image', 'public');
|
||||
|
||||
// Dispatch event for app.js to handle
|
||||
$component->getLivewire()->dispatch('featured-image-added', ['mediaId' => $newMedia->id]);
|
||||
|
||||
\Filament\Notifications\Notification::make()
|
||||
->success()
|
||||
->title('Featured image set')
|
||||
->title('Image added to featured image')
|
||||
->send();
|
||||
} catch (\Exception $e) {
|
||||
\Filament\Notifications\Notification::make()
|
||||
->danger()
|
||||
->title('Error: ' . $e->getMessage())
|
||||
->send();
|
||||
} finally {
|
||||
if (file_exists($tempCopy)) {
|
||||
unlink($tempCopy);
|
||||
}
|
||||
}
|
||||
})
|
||||
),
|
||||
|
|
|
|||
108
app/Livewire/GalleryPicker.php
Normal file
108
app/Livewire/GalleryPicker.php
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
|
||||
class GalleryPicker extends Component
|
||||
{
|
||||
#[\Livewire\Attributes\Reactive]
|
||||
public $entryId;
|
||||
|
||||
public $mediaItems = [];
|
||||
public $selectedMediaId = null;
|
||||
public $showModal = false;
|
||||
|
||||
#[\Livewire\Attributes\On('open-gallery-picker')]
|
||||
public function openPicker($entryId): void
|
||||
{
|
||||
$this->entryId = $entryId;
|
||||
$this->loadMediaItems();
|
||||
$this->showModal = true;
|
||||
}
|
||||
|
||||
public function loadMediaItems(): void
|
||||
{
|
||||
$this->mediaItems = Media::where('model_type', 'temp')
|
||||
->where('model_id', 0)
|
||||
->where('disk', 'public')
|
||||
->latest()
|
||||
->limit(30)
|
||||
->get(['id', 'file_name', 'name', 'disk'])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function selectMedia($mediaId): void
|
||||
{
|
||||
$this->selectedMediaId = $mediaId;
|
||||
}
|
||||
|
||||
public function copyToEntry(): void
|
||||
{
|
||||
if (!$this->selectedMediaId || !$this->entryId) {
|
||||
$this->dispatch('notify-error', ['message' => 'Please select an image']);
|
||||
return;
|
||||
}
|
||||
|
||||
$sourceMedia = Media::find($this->selectedMediaId);
|
||||
if (!$sourceMedia) {
|
||||
$this->dispatch('notify-error', ['message' => 'Media not found']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the entry
|
||||
$entry = \App\Models\Entry::find($this->entryId);
|
||||
if (!$entry) {
|
||||
$this->dispatch('notify-error', ['message' => 'Entry not found']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get source file
|
||||
$sourceFile = $sourceMedia->getPath();
|
||||
if (!file_exists($sourceFile)) {
|
||||
$this->dispatch('notify-error', ['message' => 'Source file not found']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create temp copy
|
||||
$tempCopy = sys_get_temp_dir() . '/' . uniqid() . '_' . $sourceMedia->file_name;
|
||||
copy($sourceFile, $tempCopy);
|
||||
|
||||
try {
|
||||
// Clear existing featured image
|
||||
$entry->clearMediaCollection('featured-image');
|
||||
|
||||
// Add to entry
|
||||
$newMedia = $entry->addMedia($tempCopy)
|
||||
->usingName($sourceMedia->name ?: pathinfo($sourceMedia->file_name, PATHINFO_FILENAME))
|
||||
->usingFileName($sourceMedia->file_name)
|
||||
->toMediaCollection('featured-image', 'public');
|
||||
|
||||
// Close modal and notify
|
||||
$this->showModal = false;
|
||||
$this->selectedMediaId = null;
|
||||
$this->dispatch('media-selected', ['mediaId' => $newMedia->id, 'fileName' => $newMedia->file_name]);
|
||||
$this->dispatch('notify-success', ['message' => 'Image added to entry']);
|
||||
} finally {
|
||||
if (file_exists($tempCopy)) {
|
||||
unlink($tempCopy);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('notify-error', ['message' => 'Error: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function closePicker(): void
|
||||
{
|
||||
$this->showModal = false;
|
||||
$this->selectedMediaId = null;
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.gallery-picker');
|
||||
}
|
||||
}
|
||||
|
|
@ -33,6 +33,16 @@ document.addEventListener('livewire:init', () => {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
Livewire.on('featured-image-added', (data) => {
|
||||
console.log('Received featured-image-added event:', data);
|
||||
const payload = Array.isArray(data) ? data[0] : data;
|
||||
|
||||
// Reload the page to show the updated featured image
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
|
||||
console.log('Testing if app.js is still running');
|
||||
32
resources/views/components/featured-image-display.blade.php
Normal file
32
resources/views/components/featured-image-display.blade.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<div>
|
||||
@php
|
||||
$record = $this->data;
|
||||
if ($record && isset($record['id'])) {
|
||||
$entry = \App\Models\Entry::find($record['id']);
|
||||
$media = $entry ? $entry->getMedia('featured-image') : [];
|
||||
} else {
|
||||
$media = [];
|
||||
}
|
||||
@endphp
|
||||
|
||||
<div class="space-y-2">
|
||||
<label class="text-sm font-medium text-gray-700">Featured Image</label>
|
||||
@if(count($media) > 0)
|
||||
<div class="space-y-2">
|
||||
@foreach($media as $item)
|
||||
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg border border-gray-200">
|
||||
<div class="flex items-center gap-3">
|
||||
<img src="{{ $item->getUrl() }}" alt="" class="w-16 h-16 object-cover rounded">
|
||||
<div>
|
||||
<p class="text-sm font-medium">{{ $item->name }}</p>
|
||||
<p class="text-xs text-gray-500">{{ $item->file_name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p class="text-sm text-gray-500">No featured image selected</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
72
resources/views/livewire/gallery-picker.blade.php
Normal file
72
resources/views/livewire/gallery-picker.blade.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<div>
|
||||
@if($showModal ?? false)
|
||||
<div class="fixed inset-0 z-50 overflow-y-auto">
|
||||
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<!-- Background overlay -->
|
||||
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" wire:click="closePicker()"></div>
|
||||
|
||||
<!-- Modal panel -->
|
||||
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-lg font-medium text-gray-900">
|
||||
Select Image from Gallery
|
||||
</h3>
|
||||
<button wire:click="closePicker()" class="text-gray-400 hover:text-gray-500">
|
||||
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if(empty($mediaItems ?? []))
|
||||
<p class="text-center text-gray-500 py-8">No images in gallery</p>
|
||||
@else
|
||||
<div class="grid grid-cols-3 gap-4 max-h-96 overflow-y-auto">
|
||||
@foreach($mediaItems ?? [] as $item)
|
||||
<button
|
||||
wire:click="selectMedia({{ $item['id'] }})"
|
||||
class="relative group overflow-hidden rounded-lg border-2 transition-colors {{ ($selectedMediaId ?? null) === $item['id'] ? 'border-blue-500 bg-blue-50' : 'border-gray-200 hover:border-gray-300' }}"
|
||||
>
|
||||
<img
|
||||
src="{{ asset('storage/' . $item['disk'] . '/' . $item['id'] . '/' . $item['file_name']) }}"
|
||||
alt="{{ $item['name'] ?? $item['file_name'] }}"
|
||||
class="w-full h-32 object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
@if(($selectedMediaId ?? null) === $item['id'])
|
||||
<div class="absolute inset-0 bg-blue-500 bg-opacity-20 flex items-center justify-center">
|
||||
<svg class="h-8 w-8 text-blue-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
@endif
|
||||
<div class="absolute bottom-0 left-0 right-0 bg-black bg-opacity-50 text-white text-xs px-2 py-1 opacity-0 group-hover:opacity-100 transition-opacity truncate">
|
||||
{{ $item['name'] ?? $item['file_name'] }}
|
||||
</div>
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse gap-3">
|
||||
<button
|
||||
wire:click="copyToEntry"
|
||||
:disabled="!($selectedMediaId ?? null)"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed sm:w-auto sm:text-sm"
|
||||
>
|
||||
Add Image
|
||||
</button>
|
||||
<button
|
||||
wire:click="closePicker()"
|
||||
class="w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue