From 73647296dcf5aff67ca560c3dadbc77fc78be8a3 Mon Sep 17 00:00:00 2001 From: Kenneth Sese Date: Mon, 1 May 2023 20:57:47 -0600 Subject: [PATCH] Add stacking to images --- packages/tables/docs/03-columns/04-image.md | 68 +++++++++ .../views/columns/image-column.blade.php | 135 ++++++++++++++--- packages/tables/src/Columns/ImageColumn.php | 141 +++++++++++++++++- 3 files changed, 319 insertions(+), 25 deletions(-) diff --git a/packages/tables/docs/03-columns/04-image.md b/packages/tables/docs/03-columns/04-image.md index 9a78c646d0..4f9a50a93e 100644 --- a/packages/tables/docs/03-columns/04-image.md +++ b/packages/tables/docs/03-columns/04-image.md @@ -76,3 +76,71 @@ use Filament\Tables\Columns\ImageColumn; ImageColumn::make('logo') ->extraImgAttributes(['title' => 'Company logo']), ``` + +## Stacking images + +You may show a relationship of images as a stack using `stacked()`. The name of the relationship comes first, followed by a period, followed by the name of the column to display: + +```php +ImageColumn::make('users.avatar') + ->circular() + ->stacked() +``` + +### Using a separator + +Instead of using a relationship, you may use a separated string by passing the separator into `separator()`: + +```php +ImageColumn::make('product_images') + ->separator(',') + ->circular() + ->stacked() +``` + +### Setting a limit + +You may set a limit to the number of images you want to display by passing `limit()`: + +```php +ImageColumn::make('orderItems.image') + ->circular() + ->stacked() + ->limit(3) +``` + +### Showing the remaining images count + +When you set a limit you may also display the count of remaining images by passing `showRemaining()`. + +```php +ImageColumn::make('orderItems.image') + ->circular() + ->stacked() + ->limit(3) + ->showRemaining() +``` + +By default, `showRemaining()` will display the count of remaining images as a number stacked on the other images. If you prefer to show the count as a number after the images you may use `showRemainingAfterStack()`. You may also set the text size by using `remainingTextSize('xs')`; + +### Customizing the ring width + +The default ring width is `ring-3` but you may customize the ring width to be either `0`, `1`, `2`, or `4` which correspond to tailwinds `ring-widths`: `ring-0`, `ring-1`, `ring-2`, and `ring-4` respectively. + +```php +ImageColumn::make('users.avatar') + ->circular() + ->stacked() + ->ring(3) +``` + +### Customizing the overlap + +The default overlap is `-space-x-1` but you may customize the overlap to be either `0`, `1`, `2`, `3`, or `4` which correspond to tailwinds `space-x` options: `space-x-0`, `-space-x-1`, `-space-x-2`, `-space-x-3`, and `-space-x-4` respectively. + +```php +ImageColumn::make('users.avatar') + ->circular() + ->stacked() + ->overlap(3) +``` \ No newline at end of file diff --git a/packages/tables/resources/views/columns/image-column.blade.php b/packages/tables/resources/views/columns/image-column.blade.php index 8b50824da3..c9e92199d8 100644 --- a/packages/tables/resources/views/columns/image-column.blade.php +++ b/packages/tables/resources/views/columns/image-column.blade.php @@ -5,29 +5,120 @@ @php $height = $getHeight(); $width = $getWidth() ?? ($isCircular() || $isSquare() ? $height : null); + $overlap = $getOverlap() ?? 'sm'; + $imageCount = 0; + + $ring = match ($getRing()) { + 0 => 'ring-0', + 1 => 'ring-1', + 2 => 'ring-2', + 4 => 'ring-4', + default => 'ring', + }; + + $remainingTextSize = match ($getRemainingTextSize()) { + 'xs' => 'text-xs', + 'sm' => 'text-sm', + 'md' => 'text-md', + 'lg' => 'text-lg', + default => 'text-sm', + }; @endphp -
$isCircular() || $isSquare(), - 'rounded-full' => $isCircular(), - ]) - > - @if ($path = $getImagePath()) - class([ - 'object-cover object-center' => $isCircular() || $isSquare(), - ]) }} + @if ($isStacked()) +
+
'space-x-0', + 1 => '-space-x-1', + 2 => '-space-x-2', + 3 => '-space-x-3', + 4 => '-space-x-4', + default => '-space-x-1', + }, + ]) > - @endif -
+ @foreach (array_slice($getImages(), 0, $getLimit()) as $image) + @if ($path = $getImagePath($image)) + @php + $imageCount ++; + @endphp + class([ + 'max-w-none ring-white', + 'dark:ring-gray-800' => config('tables.dark_mode'), + 'rounded-full' => $isCircular(), + $ring, + ]) }} + > + @endif + @endforeach + + @if ($shouldShowRemaining() && (! $shouldShowRemainingAfterStack()) && ($imageCount < count($getImages()))) +
config('tables.dark_mode'), + 'rounded-full' => $isCircular(), + $remainingTextSize, + $ring, + ]) + > + + +{{ count($getImages()) - $imageCount }} + +
+ @endif + +
+ + @if ($shouldShowRemaining() && $shouldShowRemainingAfterStack() && ($imageCount < count($getImages()))) +
config('tables.dark_mode'), + $remainingTextSize, + ]) + > + +{{ count($getImages()) - $imageCount }} +
+ @endif + +
+ @else +
$isCircular() || $isSquare(), + 'rounded-full' => $isCircular(), + ]) + > + @if ($path = $getImagePath()) + class([ + 'object-cover object-center' => $isCircular() || $isSquare(), + ]) }} + > + @endif +
+ @endif diff --git a/packages/tables/src/Columns/ImageColumn.php b/packages/tables/src/Columns/ImageColumn.php index 7d28a62de2..93d5c680c5 100644 --- a/packages/tables/src/Columns/ImageColumn.php +++ b/packages/tables/src/Columns/ImageColumn.php @@ -28,6 +28,22 @@ class ImageColumn extends Column protected array $extraImgAttributes = []; + protected bool | Closure $isStacked = false; + + protected string | Closure | null $separator = null; + + protected int | Closure | null $overlap = null; + + protected int | Closure | null $ring = null; + + protected int | Closure | null $limit = null; + + protected bool | Closure $shouldShowRemaining = false; + + protected bool | Closure $shouldShowRemainingAfterStack = false; + + protected string | Closure | null $remainingTextSize = null; + protected function setUp(): void { parent::setUp(); @@ -118,10 +134,10 @@ class ImageColumn extends Column return $height; } - public function getImagePath(): ?string + public function getImagePath(string | null $image = null): ?string { - $state = $this->getState(); - + $state = $image ?: $this->getState(); + if (! $state) { return null; } @@ -219,4 +235,123 @@ class ImageColumn extends Column { return new ComponentAttributeBag($this->getExtraImgAttributes()); } + + public function stacked(bool | Closure $condition = true): static + { + $this->isStacked = $condition; + + return $this; + } + + public function isStacked(): bool + { + return $this->evaluate($this->isStacked); + } + + public function getImages(): array + { + $images = $this->getState(); + + if (is_array($images)) { + return $images; + } + + if (! ($separator = $this->getSeparator())) { + return []; + } + + $images = explode($separator, $images); + + if (count($images) === 1 && blank($images[0])) { + $images = []; + } + + return $images; + } + + public function separator(string | Closure | null $separator = ','): static + { + $this->separator = $separator; + + return $this; + } + + public function getSeparator(): ?string + { + return $this->evaluate($this->separator); + } + + public function overlap(int | Closure | null $overlap): static + { + $this->overlap = $overlap; + + return $this; + } + + public function getOverlap(): ?int + { + return $this->evaluate($this->overlap); + } + + public function ring(string | Closure | null $ring): static + { + $this->ring = $ring; + + return $this; + } + + public function getRing(): ?int + { + return $this->evaluate($this->ring); + } + + public function limit(int | Closure | null $limit = 3): static + { + $this->limit = $limit; + + return $this; + } + + public function getLimit(): ?int + { + return $this->evaluate($this->limit); + } + + public function showRemaining(bool | Closure $condition = true, bool | Closure $showRemainingAfterStack = false, string | Closure | null $remainingTextSize = null): static + { + $this->shouldShowRemaining = $condition; + $this->showRemainingAfterStack($showRemainingAfterStack); + $this->remainingTextSize($remainingTextSize); + + return $this; + } + + public function showRemainingAfterStack(bool | Closure $condition = true): static + { + $this->shouldShowRemainingAfterStack = $condition; + + return $this; + } + + public function shouldShowRemaining(): bool + { + return $this->evaluate($this->shouldShowRemaining); + } + + public function shouldShowRemainingAfterStack(): bool + { + return $this->evaluate($this->shouldShowRemainingAfterStack); + } + + public function remainingTextSize(string | Closure | null $remainingTextSize): static + { + $this->remainingTextSize = $remainingTextSize; + + return $this; + } + + public function getRemainingTextSize(): ?string + { + return $this->evaluate($this->remainingTextSize); + } }