feat: Add image gallery support for ImageColumn and ImageEntry with macros

This commit is contained in:
al-saloul
2025-12-13 03:18:41 +03:00
parent ad5c47c1a2
commit 0d84725271
5 changed files with 244 additions and 0 deletions

View File

@@ -2,6 +2,18 @@
All notable changes to `filament-image-gallery` will be documented in this file.
## v2.1.0 - 2025-12-13
### Added
- `imageGallery()` macro for `Filament\Tables\Columns\ImageColumn`
- `imageGallery()` macro for `Filament\Infolists\Components\ImageEntry`
- Support for using standard Filament Image components with the gallery viewer
## v2.0.6 - 2024-12-12
### Fixed
- Minor bug fixes
## v2.0.5 - 2024-12-11
### Fixed

View File

@@ -42,6 +42,32 @@ A Filament plugin for displaying image galleries with zoom, rotate, flip, and fu
composer require al-saloul/filament-image-gallery
```
## Quick Usage
You can use the `imageGallery()` method on any standard Filament `ImageColumn` or `ImageEntry` to enable the gallery viewer.
### Table Column
```php
use Filament\Tables\Columns\ImageColumn;
ImageColumn::make('images')
->circular()
->stacked()
->limit(3)
->imageGallery() // Enables the gallery viewer
```
### Infolist Entry
```php
use Filament\Infolists\Components\ImageEntry;
ImageEntry::make('images')
->imageGallery() // Enables the gallery viewer
```
## Usage
### Table Column

View File

@@ -0,0 +1,94 @@
@php
$state = $getState();
if ($state instanceof \Illuminate\Support\Collection) {
$state = $state->all();
}
$state = \Illuminate\Support\Arr::wrap($state);
$limit = $getLimit();
$limitedState = $limit ? array_slice($state, 0, $limit) : $state;
$remaining = $limit ? max(0, count($state) - $limit) : 0;
$isCircular = $isCircular();
$isSquare = $isSquare();
$isStacked = $isStacked();
$overlap = $isStacked ? ($getOverlap() ?? 2) : null;
$defaultWidth = $getWidth();
$defaultHeight = $getHeight();
$defaultWidth = $defaultWidth ? (is_numeric($defaultWidth) ? $defaultWidth . 'px' : $defaultWidth) : '40px';
$defaultHeight = $defaultHeight ? (is_numeric($defaultHeight) ? $defaultHeight . 'px' : $defaultHeight) : '40px';
$galleryId = 'gallery-' . str_replace(['{', '}', '-'], '', (string) \Illuminate\Support\Str::uuid());
@endphp
<div
id="{{ $galleryId }}"
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class([
'fi-ta-image',
'flex items-center',
match ($overlap) {
1 => '-space-x-1 rtl:space-x-reverse',
2 => '-space-x-2 rtl:space-x-reverse',
3 => '-space-x-3 rtl:space-x-reverse',
4 => '-space-x-4 rtl:space-x-reverse',
5 => '-space-x-5 rtl:space-x-reverse',
6 => '-space-x-6 rtl:space-x-reverse',
7 => '-space-x-7 rtl:space-x-reverse',
8 => '-space-x-8 rtl:space-x-reverse',
default => 'gap-1.5',
},
])
}}
data-viewer-gallery
wire:ignore.self
>
@foreach ($limitedState as $stateItem)
<img
src="{{ $getImageUrl($stateItem) }}"
style="
height: {{ $defaultHeight }};
width: {{ $defaultWidth }};
cursor: pointer;
"
{{
$getExtraImgAttributeBag()
->class([
'max-w-none object-cover object-center curor',
'rounded-full' => $isCircular,
'rounded-lg' => $isSquare,
'ring-white dark:ring-gray-900' => $isStacked,
'ring-2' => $isStacked && ($overlap === null || $overlap > 0),
])
}}
/>
@endforeach
@if ($remaining > 0 && ($limitedRemainingText ?? true))
<div
style="
min-height: {{ $defaultHeight }};
min-width: {{ $defaultWidth }};
height: {{ $defaultHeight }};
width: {{ $defaultWidth }};
"
@class([
'flex items-center justify-center font-medium text-gray-500',
])
>
<span class="-ms-0.5 text-xs">
+{{ $remaining }}
</span>
</div>
@endif
</div>
@once
<x-image-gallery::viewer-script />
@endonce

View File

@@ -0,0 +1,99 @@
@php
$state = $getState();
if ($state instanceof \Illuminate\Support\Collection) {
$state = $state->all();
}
$state = \Illuminate\Support\Arr::wrap($state);
$limit = $getLimit();
$limitedState = $limit ? array_slice($state, 0, $limit) : $state;
$remaining = $limit ? max(0, count($state) - $limit) : 0;
$isCircular = $isCircular();
$isSquare = $isSquare();
$isStacked = $isStacked();
$overlap = $isStacked ? ($getOverlap() ?? 2) : null;
$defaultWidth = $getWidth();
$defaultHeight = $getHeight();
$defaultWidth = $defaultWidth ? (is_numeric($defaultWidth) ? $defaultWidth . 'px' : $defaultWidth) : 'auto';
$defaultHeight = $defaultHeight ? (is_numeric($defaultHeight) ? $defaultHeight . 'px' : $defaultHeight) : '150px';
$galleryId = 'gallery-' . str_replace(['{', '}', '-'], '', (string) \Illuminate\Support\Str::uuid());
@endphp
<x-dynamic-component :component="$getEntryWrapperView()" :entry="$entry">
<div
id="{{ $galleryId }}"
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class([
'fi-in-image',
'flex items-center',
match ($overlap) {
1 => '-space-x-1 rtl:space-x-reverse',
2 => '-space-x-2 rtl:space-x-reverse',
3 => '-space-x-3 rtl:space-x-reverse',
4 => '-space-x-4 rtl:space-x-reverse',
5 => '-space-x-5 rtl:space-x-reverse',
6 => '-space-x-6 rtl:space-x-reverse',
7 => '-space-x-7 rtl:space-x-reverse',
8 => '-space-x-8 rtl:space-x-reverse',
default => 'gap-1.5',
},
])
}}
data-viewer-gallery
wire:ignore.self
>
@foreach ($limitedState as $stateItem)
<img
src="{{ $getImageUrl($stateItem) }}"
style="
height: {{ $defaultHeight }};
width: {{ $defaultWidth }};
cursor: pointer;
"
{{
$getExtraImgAttributeBag()
->class([
'max-w-none object-cover object-center',
'rounded-full' => $isCircular,
'rounded-lg' => $isSquare,
'ring-white dark:ring-gray-900' => $isStacked,
'ring-2' => $isStacked && ($overlap === null || $overlap > 0),
])
}}
/>
@endforeach
@if ($remaining > 0 && ($limitedRemainingText ?? true))
<div
style="
min-height: {{ $defaultHeight }};
min-width: {{ $defaultWidth }};
height: {{ $defaultHeight }};
width: {{ $defaultWidth }};
"
@class([
'flex items-center justify-center bg-gray-100 font-medium text-gray-500 ring-white dark:bg-gray-800 dark:text-gray-400 dark:ring-gray-900',
'rounded-full' => $isCircular,
'rounded-lg' => $isSquare,
'ring-2' => $isStacked && ($overlap === null || $overlap > 0),
])
>
<span class="-ms-0.5 text-xs">
+{{ $remaining }}
</span>
</div>
@endif
</div>
@once
<x-image-gallery::viewer-script />
@endonce
</x-dynamic-component>

View File

@@ -29,6 +29,19 @@ class ImageGalleryServiceProvider extends PackageServiceProvider
$this->getAssets(),
$this->getAssetPackageName()
);
\Filament\Tables\Columns\ImageColumn::macro('imageGallery', function () {
$this->view('image-gallery::columns.image-column-gallery');
$this->disabledClick();
return $this;
});
\Filament\Infolists\Components\ImageEntry::macro('imageGallery', function () {
$this->view('image-gallery::infolists.entries.image-entry-gallery');
return $this;
});
}
protected function getAssetPackageName(): ?string