ahmed-abdelrhman/filament-media-gallery
Filament infolist entry for Spatie Media Library collections: renders a responsive media grid with an Alpine.js fullscreen lightbox for images and proper PDF cards that open in a new tab. Type-aware, no extra dependencies, works with Filament 3–5.
Install the Package:
composer require ahmed-abdelrhman/filament-media-gallery
No additional setup is required beyond auto-discovery.
First Use Case:
Replace SpatieMediaLibraryImageEntry in a Filament Infolist with MediaGalleryEntry for a model using Spatie Media Library.
use AhmedAbdelrhman\FilamentMediaGallery\Infolists\Components\MediaGalleryEntry;
MediaGalleryEntry::make('gallery')
->collection('coach_gallery')
->label('Gallery Images');
Where to Look First:
size(), rounded()).Define the Entry in Infolist:
public static function infolist(Infolist $infolist): Infolist {
return $infolist->schema([
MediaGalleryEntry::make('media')
->collection('portfolio_images')
->label('Portfolio'),
]);
}
Handle Related Models:
Use fromRelation() when media belongs to a child model (e.g., User → Profile):
MediaGalleryEntry::make('profile_media')
->collection('profile_photos')
->fromRelation('profile')
->visible(fn ($record) => $record->profile?->getMedia('profile_photos')->count() > 0);
Customize Appearance:
->size(300) (300×300px).->rounded().MediaGalleryEntry::make('thumbnails')
->collection('thumbnails')
->size(150)
->rounded()
->label('Team Photos');
Standalone Usage: Embed in custom Blade/Livewire components:
<x-media-gallery-viewer
:media="$model->getMedia('gallery')"
size="200"
rounded="true"
/>
Media Conversions:
Register thumbnail/preview conversions for optimal performance:
public function registerMediaConversions(Media $media = null): void {
$this->addMediaConversion('thumbnail')->width(150)->height(150)->nonQueued();
$this->addMediaConversion('preview')->width(400)->height(400)->nonQueued();
}
The component prioritizes thumbnail → preview → original URL.
Visibility Logic:
Use visible() to conditionally show galleries:
->visible(fn ($record) => $record->hasMedia('gallery'))
Panel Registration:
Explicitly register the plugin in AdminPanelProvider for panel-level access:
->plugins([
\AhmedAbdelrhman\FilamentMediaGallery\FilamentMediaGalleryPlugin::make(),
]);
Dark Mode:
No action needed—inherits Filament’s dark mode via Tailwind’s dark: variants.
Relation Misconfiguration:
Call to undefined method App\Models\User::getMedia().fromRelation() points to a valid relation method. Verify the related model has HasMedia traits.
// Correct: Relation exists and owns the media.
->fromRelation('coachProfile')
Empty Collections:
->visible(fn ($record) => $record->getMedia('collection')->count() > 0)
PDF Handling:
->visible(fn ($record) => $record->getMedia('collection')->where('mime_type', '!=', 'application/pdf')->count() > 0) to hide non-image galleries.Performance with Large Galleries:
limit():
$record->getMedia('gallery')->limit(30);
Lightbox Not Working:
media prop passes a valid Spatie\MediaLibrary\Models\Media collection.Broken Images:
thumbnail/preview).storage/app/public/convert/).CSS Overrides:
php artisan vendor:publish --tag=media-gallery-views
resources/views/vendor/filament-media-gallery/... to modify Tailwind classes.Custom Lightbox:
resources/views/vendor/filament-media-gallery/lightbox.blade.php to add animations or custom controls.Additional MIME Types:
video/mp4) by adding a new else-if branch for non-image/PDF media.Lazy Loading:
loading="lazy" to image tags in the published view for better performance.Accessibility:
aria-modal, aria-label) by editing the published Blade template.Default Size:
Omitting ->size() uses aspect-square, which may not suit all layouts. Explicitly set a size (e.g., ->size(250)) for consistency.
Rounded vs. Default:
->rounded() applies rounded-full; omit it for rounded-lg. Test both in dark/light mode to ensure visual harmony.
Plugin Registration:
While auto-discovered, explicitly registering the plugin in AdminPanelProvider ensures it’s available across all panels.
How can I help you explore Laravel packages today?