From 5e1f6516022275abe69855278c248ec10d260e7c Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Sat, 13 Sep 2025 06:48:04 +0545 Subject: [PATCH 1/7] feat: extending ImageColumn with ->preview() --- .../components/image-preview-modal.blade.php | 305 ++++++++++++++++++ src/CommonServiceProvider.php | 53 +++ 2 files changed, 358 insertions(+) create mode 100644 resources/views/components/image-preview-modal.blade.php diff --git a/resources/views/components/image-preview-modal.blade.php b/resources/views/components/image-preview-modal.blade.php new file mode 100644 index 0000000..2316a7b --- /dev/null +++ b/resources/views/components/image-preview-modal.blade.php @@ -0,0 +1,305 @@ +
+
+ +
+ + +
+ +
+

+ +
+
+ +
+
+
+ + + + \ No newline at end of file diff --git a/src/CommonServiceProvider.php b/src/CommonServiceProvider.php index ff470d4..6fd5aff 100644 --- a/src/CommonServiceProvider.php +++ b/src/CommonServiceProvider.php @@ -3,6 +3,9 @@ namespace Eclipse\Common; use Eclipse\Common\Foundation\Providers\PackageServiceProvider; +use Exception; +use Filament\Support\Facades\FilamentView; +use Filament\Tables\Columns\ImageColumn; use Spatie\LaravelPackageTools\Package as SpatiePackage; class CommonServiceProvider extends PackageServiceProvider @@ -12,6 +15,7 @@ class CommonServiceProvider extends PackageServiceProvider public function configurePackage(SpatiePackage|Package $package): void { $package->name(static::$name) + ->hasViews() ->hasTranslations(); } @@ -27,4 +31,53 @@ public function register(): self return $this; } + + public function bootingPackage(): void + { + ImageColumn::macro( + 'preview', + function (?callable $config = null) { + return $this->extraImgAttributes(function ($record, $column) use ($config): array { + $imageUrls = $column->getState(); + if (! is_array($imageUrls)) { + $imageUrls = $imageUrls ? [$imageUrls] : []; + } + + $lightboxData = []; + foreach ($imageUrls as $index => $imageUrl) { + try { + $configData = $config ? $config($record, $column) : []; + + if (is_array($configData) && isset($configData[0]) && is_array($configData[0])) { + $configData = $configData[0]; + } + + $lightboxData[] = [ + 'url' => $imageUrl, + 'title' => $configData['title'] ?? '', + 'link' => $configData['link'] ?? '', + ]; + } catch (Exception $e) { + $lightboxData[] = [ + 'url' => $imageUrl, + 'title' => '', + 'link' => '', + ]; + } + } + + return [ + 'class' => 'cursor-pointer image-preview-trigger', + 'onclick' => 'event.stopPropagation(); return false;', + 'data-lightbox-config' => json_encode($lightboxData), + ]; + }); + } + ); + + FilamentView::registerRenderHook( + 'panels::body.end', + fn (): string => view('eclipse-common::components.image-preview-modal')->render() + ); + } } From 51824e8eb9cf3bcfa458f818c5f12891ea652cd9 Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Sun, 14 Sep 2025 11:42:39 +0545 Subject: [PATCH 2/7] fix: failing github actions --- .github/workflows/linter.yml | 5 ++++- .github/workflows/test-runner.yml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index a548779..817a9bd 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -22,7 +22,10 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.head_ref }} + # Checkout the actual branch, not a specific commit + ref: ${{ github.head_ref || github.ref_name }} + # Fetch the full history to avoid shallow clone issues + fetch-depth: 0 - name: Run Laravel Pint uses: aglipanci/laravel-pint-action@latest diff --git a/.github/workflows/test-runner.yml b/.github/workflows/test-runner.yml index 4a1f073..b81008c 100644 --- a/.github/workflows/test-runner.yml +++ b/.github/workflows/test-runner.yml @@ -41,7 +41,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.head_ref }} + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} - name: Validate composer.json and composer.lock run: composer validate --strict From 82dc8b1443e18ea334d36ed0bbe764b071064efb Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Thu, 18 Sep 2025 07:55:18 +0545 Subject: [PATCH 3/7] feat: lightbox should handle both horizantal & verticall image in table & adding another reusable component here --- .../components/image-preview-modal.blade.php | 115 +++++++++++------- .../components/placeholder-image.blade.php | 36 ++++++ src/CommonServiceProvider.php | 8 ++ src/Foundation/Helpers/MediaHelper.php | 17 +++ 4 files changed, 131 insertions(+), 45 deletions(-) create mode 100644 resources/views/components/placeholder-image.blade.php create mode 100644 src/Foundation/Helpers/MediaHelper.php diff --git a/resources/views/components/image-preview-modal.blade.php b/resources/views/components/image-preview-modal.blade.php index 2316a7b..0f3bbba 100644 --- a/resources/views/components/image-preview-modal.blade.php +++ b/resources/views/components/image-preview-modal.blade.php @@ -211,57 +211,40 @@ function imagePreviewLightbox() { }, openFromTable(imageElement) { - const rows = document.querySelectorAll('tbody tr'); + const allRows = document.querySelectorAll('tbody tr'); this.images = []; let clickedIndex = 0; - - rows.forEach((row) => { - const imgContainer = row.querySelector('.fi-ta-image'); - if (imgContainer) { - const imgs = imgContainer.querySelectorAll('.image-preview-trigger'); - - imgs.forEach((img) => { - const configData = img.dataset.lightboxConfig; - - if (configData) { - try { - const lightboxData = JSON.parse(configData); - const matchingImageData = lightboxData.find(data => - img.src.includes(data.url) || data.url.includes(img.src) || data.url === img.src - ); - - if (matchingImageData) { - this.images.push({ - url: img.src, - title: matchingImageData.title || '', - link: matchingImageData.link || '', - filename: img.alt || '' - }); - - if (img === imageElement) { - clickedIndex = this.images.length - 1; - } - return; - } - } catch (e) { - console.error('Error parsing lightbox config:', e); - } - } - const imageData = { - url: img.src, - title: '', - link: '', - filename: img.alt || '' - }; - - this.images.push(imageData); - - if (img === imageElement) { + const imageGrid = []; + let maxColumns = 0; + + allRows.forEach((row) => { + const rowImages = row.querySelectorAll('.fi-ta-image .image-preview-trigger'); + const rowImageArray = Array.from(rowImages); + imageGrid.push(rowImageArray); + maxColumns = Math.max(maxColumns, rowImageArray.length); + }); + + let clickedRowIndex = -1; + let clickedColIndex = -1; + + imageGrid.forEach((rowImages, rowIndex) => { + rowImages.forEach((img, colIndex) => { + if (img === imageElement) { + clickedRowIndex = rowIndex; + clickedColIndex = colIndex; + } + }); + }); + + imageGrid.forEach((rowImages, rowIndex) => { + rowImages.forEach((img, colIndex) => { + this.addImageToCollection(img, imageElement, () => { + if (rowIndex === clickedRowIndex && colIndex === clickedColIndex) { clickedIndex = this.images.length - 1; } }); - } + }); }); if (this.images.length > 0) { @@ -271,6 +254,48 @@ function imagePreviewLightbox() { } }, + addImageToCollection(img, imageElement, onMatch) { + const configData = img.dataset.lightboxConfig; + + if (configData) { + try { + const lightboxData = JSON.parse(configData); + const matchingImageData = lightboxData.find(data => + img.src.includes(data.url) || data.url.includes(img.src) || data.url === img.src + ); + + if (matchingImageData) { + this.images.push({ + url: img.src, + title: matchingImageData.title || '', + link: matchingImageData.link || '', + filename: img.alt || '' + }); + + if (img === imageElement) { + onMatch(); + } + return; + } + } catch (e) { + console.error('Error parsing lightbox config:', e); + } + } + + const imageData = { + url: img.src, + title: '', + link: '', + filename: img.alt || '' + }; + + this.images.push(imageData); + + if (img === imageElement) { + onMatch(); + } + }, + open() { this.isOpen = true; document.body.style.overflow = 'hidden'; diff --git a/resources/views/components/placeholder-image.blade.php b/resources/views/components/placeholder-image.blade.php new file mode 100644 index 0000000..e0a14ce --- /dev/null +++ b/resources/views/components/placeholder-image.blade.php @@ -0,0 +1,36 @@ +@php + $centerX = $width / 2; + $centerY = $height / 2; + $area = $width * $height; + $averageDimension = sqrt($area); + $fontSize = max(20, min(64, $averageDimension / 2.5)); + $aspectRatio = max($width, $height) / min($width, $height); + if ($aspectRatio > 3) { + $fontSize *= 0.9; + } + + $fontSize = round($fontSize, 1); +@endphp + + + @if ($text) + + {{ $text }} + + @else + @php + $scale = min($width, $height) / 120; + $iconWidth = 120 * $scale; + $iconHeight = 120 * $scale; + $offsetX = ($width - $iconWidth) / 2; + $offsetY = ($height - $iconHeight) / 2; + @endphp + + + + @endif + diff --git a/src/CommonServiceProvider.php b/src/CommonServiceProvider.php index 6fd5aff..021640a 100644 --- a/src/CommonServiceProvider.php +++ b/src/CommonServiceProvider.php @@ -43,6 +43,14 @@ function (?callable $config = null) { $imageUrls = $imageUrls ? [$imageUrls] : []; } + $imageUrls = array_filter($imageUrls, function ($url): bool { + return ! str_starts_with($url, 'data:image/svg+xml;base64,'); + }); + + if (empty($imageUrls)) { + return []; + } + $lightboxData = []; foreach ($imageUrls as $index => $imageUrl) { try { diff --git a/src/Foundation/Helpers/MediaHelper.php b/src/Foundation/Helpers/MediaHelper.php new file mode 100644 index 0000000..130fa2f --- /dev/null +++ b/src/Foundation/Helpers/MediaHelper.php @@ -0,0 +1,17 @@ + $text, + 'width' => $width, + 'height' => $height, + ])->render(); + + return 'data:image/svg+xml;base64,'.base64_encode($svg); + } +} From fd6acef7590863b390e7b7f6d7155c8a94cb3785 Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Thu, 18 Sep 2025 11:02:38 +0545 Subject: [PATCH 4/7] feat: adding SliderColumn & moving assets to seperate file --- resources/dist/slider-column.css | 124 +++++++ resources/dist/slider-column.js | 155 ++++++++ .../components/image-preview-modal.blade.php | 330 ------------------ .../slider-column-lightbox.blade.php | 45 +++ .../Filament/Tables/Columns/SliderColumn.php | 121 +++++++ src/CommonServiceProvider.php | 62 +--- 6 files changed, 455 insertions(+), 382 deletions(-) create mode 100644 resources/dist/slider-column.css create mode 100644 resources/dist/slider-column.js delete mode 100644 resources/views/components/image-preview-modal.blade.php create mode 100644 resources/views/components/slider-column-lightbox.blade.php create mode 100644 src/Admin/Filament/Tables/Columns/SliderColumn.php diff --git a/resources/dist/slider-column.css b/resources/dist/slider-column.css new file mode 100644 index 0000000..65c389a --- /dev/null +++ b/resources/dist/slider-column.css @@ -0,0 +1,124 @@ +[x-cloak] { display: none !important; } + +.image-preview-lightbox-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 9999 !important; + background-color: rgba(0, 0, 0, 0.7); + backdrop-filter: blur(10px); + display: flex; + align-items: center; + justify-content: center; + padding: 80px; +} + +.image-preview-lightbox-container { + position: relative; + max-width: 90vw; + max-height: 90vh; + display: flex; + align-items: center; + justify-content: center; + z-index: 9999 !important; +} + +.image-preview-lightbox-close { + position: absolute; + top: -50px; + right: 0; + color: white; + background: none; + border: none; + cursor: pointer; + padding: 10px; + opacity: 0.8; + transition: opacity 0.2s; +} + +.image-preview-lightbox-close:hover { + opacity: 1; +} + +.image-preview-lightbox-close svg { + width: 32px; + height: 32px; +} + +.image-preview-lightbox-image-wrapper { + position: relative; + display: flex; + align-items: center; + justify-content: center; + background-color: #1f2937; + border-radius: 8px; + overflow: hidden; + max-width: 90vw; + max-height: 85vh; +} + +.image-preview-lightbox-image { + max-width: 100%; + max-height: 85vh; + width: auto; + height: auto; + object-fit: contain; + display: block; +} + +.image-preview-lightbox-nav { + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: rgba(255, 255, 255, 0.1); + color: white; + border: none; + border-radius: 50%; + width: 48px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: background-color 0.2s; +} + +.image-preview-lightbox-nav:hover { + background-color: rgba(255, 255, 255, 0.2); +} + +.image-preview-lightbox-nav.prev { + left: -60px; +} + +.image-preview-lightbox-nav.next { + right: -60px; +} + +.image-preview-lightbox-nav svg { + width: 24px; + height: 24px; +} + +.image-preview-lightbox-info { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: linear-gradient(to top, rgba(0, 0, 0, 0.9), transparent); + padding: 24px; + color: white; + border-radius: 0 0 8px 8px; +} + +.image-preview-lightbox-title { + font-size: 18px; + font-weight: 600; + margin: 0 0 8px 0; +} + +.image-preview-lightbox-link { + margin: 8px 0 0 0; +} \ No newline at end of file diff --git a/resources/dist/slider-column.js b/resources/dist/slider-column.js new file mode 100644 index 0000000..0730a47 --- /dev/null +++ b/resources/dist/slider-column.js @@ -0,0 +1,155 @@ +window.imagePreviewLightbox = function() { + return { + isOpen: false, + currentIndex: 0, + images: [], + currentImage: { + url: '', + title: '', + link: '', + filename: '' + }, + + getDisplayName() { + return this.currentImage.title || this.currentImage.filename || ''; + }, + + init() { + const self = this; + document.addEventListener('click', function(e) { + if (e.target.classList.contains('image-preview-trigger')) { + e.preventDefault(); + e.stopPropagation(); + self.openFromTable(e.target); + } + }, true); + document.addEventListener('keydown', (e) => { + if (this.isOpen) { + if (e.key === 'ArrowLeft') { + e.preventDefault(); + this.previous(); + } else if (e.key === 'ArrowRight') { + e.preventDefault(); + this.next(); + } + } + }); + }, + + openFromTable(imageElement) { + const allRows = document.querySelectorAll('tbody tr'); + this.images = []; + let clickedIndex = 0; + + const imageGrid = []; + let maxColumns = 0; + + allRows.forEach((row) => { + const rowImages = row.querySelectorAll('.fi-ta-image .image-preview-trigger'); + const rowImageArray = Array.from(rowImages); + imageGrid.push(rowImageArray); + maxColumns = Math.max(maxColumns, rowImageArray.length); + }); + + let clickedRowIndex = -1; + let clickedColIndex = -1; + + imageGrid.forEach((rowImages, rowIndex) => { + rowImages.forEach((img, colIndex) => { + if (img === imageElement) { + clickedRowIndex = rowIndex; + clickedColIndex = colIndex; + } + }); + }); + + imageGrid.forEach((rowImages, rowIndex) => { + rowImages.forEach((img, colIndex) => { + this.addImageToCollection(img, imageElement, () => { + if (rowIndex === clickedRowIndex && colIndex === clickedColIndex) { + clickedIndex = this.images.length - 1; + } + }); + }); + }); + + if (this.images.length > 0) { + this.currentIndex = clickedIndex; + this.updateCurrentImage(); + this.open(); + } + }, + + addImageToCollection(img, imageElement, onMatch) { + const configData = img.dataset.lightboxConfig; + + if (configData) { + try { + const lightboxData = JSON.parse(configData); + const matchingImageData = lightboxData.find(data => + img.src.includes(data.url) || data.url.includes(img.src) || data.url === img.src + ); + + if (matchingImageData) { + this.images.push({ + url: img.src, + title: matchingImageData.title || '', + link: matchingImageData.link || '', + filename: img.alt || '' + }); + + if (img === imageElement) { + onMatch(); + } + return; + } + } catch (e) { + console.error('Error parsing lightbox config:', e); + } + } + + const imageData = { + url: img.src, + title: '', + link: '', + filename: img.alt || '' + }; + + this.images.push(imageData); + + if (img === imageElement) { + onMatch(); + } + }, + + open() { + this.isOpen = true; + document.body.style.overflow = 'hidden'; + }, + + close() { + this.isOpen = false; + document.body.style.overflow = ''; + }, + + next() { + if (this.images.length > 0) { + this.currentIndex = (this.currentIndex + 1) % this.images.length; + this.updateCurrentImage(); + } + }, + + previous() { + if (this.images.length > 0) { + this.currentIndex = (this.currentIndex - 1 + this.images.length) % this.images.length; + this.updateCurrentImage(); + } + }, + + updateCurrentImage() { + if (this.images[this.currentIndex]) { + this.currentImage = this.images[this.currentIndex]; + } + } + }; +}; \ No newline at end of file diff --git a/resources/views/components/image-preview-modal.blade.php b/resources/views/components/image-preview-modal.blade.php deleted file mode 100644 index 0f3bbba..0000000 --- a/resources/views/components/image-preview-modal.blade.php +++ /dev/null @@ -1,330 +0,0 @@ -
-
- -
- - -
- -
-

- -
-
- -
-
-
- - - - \ No newline at end of file diff --git a/resources/views/components/slider-column-lightbox.blade.php b/resources/views/components/slider-column-lightbox.blade.php new file mode 100644 index 0000000..acbb51d --- /dev/null +++ b/resources/views/components/slider-column-lightbox.blade.php @@ -0,0 +1,45 @@ +
+
+ +
+ + +
+ +
+

+ +
+
+ +
+
+
\ No newline at end of file diff --git a/src/Admin/Filament/Tables/Columns/SliderColumn.php b/src/Admin/Filament/Tables/Columns/SliderColumn.php new file mode 100644 index 0000000..94c713f --- /dev/null +++ b/src/Admin/Filament/Tables/Columns/SliderColumn.php @@ -0,0 +1,121 @@ +extraImgAttributes(function (Model $record, $column): array { + $imageUrls = $this->getImageUrls($column); + + if (empty($imageUrls)) { + return []; + } + + $lightboxData = []; + foreach ($imageUrls as $imageUrl) { + $lightboxData[] = [ + 'url' => $imageUrl, + 'title' => $this->getTitle($record), + 'link' => $this->getLink($record), + 'filename' => basename($imageUrl), + ]; + } + + return [ + 'class' => 'cursor-pointer image-preview-trigger hover:opacity-75 transition-opacity', + 'onclick' => 'event.stopPropagation(); return false;', + 'data-lightbox-config' => json_encode($lightboxData), + ]; + }); + } + + public function title(string|Closure $title): static + { + $this->titleCallback = $title; + + return $this; + } + + public function link(string|Closure $link): static + { + $this->linkCallback = $link; + + return $this; + } + + protected function getImageUrls($column): array + { + $imageUrls = $column->getState(); + + if (! is_array($imageUrls)) { + $imageUrls = $imageUrls ? [$imageUrls] : []; + } + + return array_filter($imageUrls, function ($url) { + if (! filled($url)) { + return false; + } + + return ! $this->isPlaceholderImage($url); + }); + } + + protected function isPlaceholderImage(string $url): bool + { + $placeholderPatterns = [ + 'data:image/svg+xml;base64,', // SVG placeholders + 'placeholder', // URLs containing 'placeholder' + 'via.placeholder.com', // Placeholder service + 'picsum.photos', // Lorem Picsum placeholder + 'dummyimage.com', // Dummy image service + 'placehold.it', // Placehold.it service + '/placeholder', // Local placeholder paths + ]; + + foreach ($placeholderPatterns as $pattern) { + if (str_contains(strtolower($url), strtolower($pattern))) { + return true; + } + } + + return false; + } + + protected function getTitle(Model $record): string + { + if ($this->titleCallback) { + return $this->evaluate($this->titleCallback, ['record' => $record]); + } + + foreach (['name', 'title'] as $attr) { + if (isset($record->{$attr})) { + $value = $record->{$attr}; + + return is_array($value) ? ($value[app()->getLocale()] ?? reset($value)) : $value; + } + } + + return class_basename($record).' #'.$record->getKey(); + } + + protected function getLink(Model $record): ?string + { + if ($this->linkCallback) { + return $this->evaluate($this->linkCallback, ['record' => $record]); + } + + return null; + } +} diff --git a/src/CommonServiceProvider.php b/src/CommonServiceProvider.php index 021640a..d55c39f 100644 --- a/src/CommonServiceProvider.php +++ b/src/CommonServiceProvider.php @@ -3,9 +3,10 @@ namespace Eclipse\Common; use Eclipse\Common\Foundation\Providers\PackageServiceProvider; -use Exception; +use Filament\Support\Assets\Css; +use Filament\Support\Assets\Js; +use Filament\Support\Facades\FilamentAsset; use Filament\Support\Facades\FilamentView; -use Filament\Tables\Columns\ImageColumn; use Spatie\LaravelPackageTools\Package as SpatiePackage; class CommonServiceProvider extends PackageServiceProvider @@ -16,7 +17,8 @@ public function configurePackage(SpatiePackage|Package $package): void { $package->name(static::$name) ->hasViews() - ->hasTranslations(); + ->hasTranslations() + ->hasAssets(); } public function register(): self @@ -34,58 +36,14 @@ public function register(): self public function bootingPackage(): void { - ImageColumn::macro( - 'preview', - function (?callable $config = null) { - return $this->extraImgAttributes(function ($record, $column) use ($config): array { - $imageUrls = $column->getState(); - if (! is_array($imageUrls)) { - $imageUrls = $imageUrls ? [$imageUrls] : []; - } - - $imageUrls = array_filter($imageUrls, function ($url): bool { - return ! str_starts_with($url, 'data:image/svg+xml;base64,'); - }); - - if (empty($imageUrls)) { - return []; - } - - $lightboxData = []; - foreach ($imageUrls as $index => $imageUrl) { - try { - $configData = $config ? $config($record, $column) : []; - - if (is_array($configData) && isset($configData[0]) && is_array($configData[0])) { - $configData = $configData[0]; - } - - $lightboxData[] = [ - 'url' => $imageUrl, - 'title' => $configData['title'] ?? '', - 'link' => $configData['link'] ?? '', - ]; - } catch (Exception $e) { - $lightboxData[] = [ - 'url' => $imageUrl, - 'title' => '', - 'link' => '', - ]; - } - } - - return [ - 'class' => 'cursor-pointer image-preview-trigger', - 'onclick' => 'event.stopPropagation(); return false;', - 'data-lightbox-config' => json_encode($lightboxData), - ]; - }); - } - ); + FilamentAsset::register([ + Css::make('slider-column', asset('vendor/eclipse-common/slider-column.css')), + Js::make('slider-column', asset('vendor/eclipse-common/slider-column.js')), + ], 'eclipse-common'); FilamentView::registerRenderHook( 'panels::body.end', - fn (): string => view('eclipse-common::components.image-preview-modal')->render() + fn (): string => view('eclipse-common::components.slider-column-lightbox')->render() ); } } From 3c8192a582832b46883f6edb8002b56ce9e38f54 Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Thu, 18 Sep 2025 11:11:52 +0545 Subject: [PATCH 5/7] fix: resolve circular dep --- composer.json | 1 - src/Admin/Filament/Tables/Columns/SliderColumn.php | 8 +------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/composer.json b/composer.json index b963a9c..37984ab 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,6 @@ "spatie/laravel-package-tools": "^1.19" }, "require-dev": { - "eclipsephp/catalogue-plugin": "dev-main", "laravel/pint": "^1.21", "orchestra/testbench": "^10.1", "pestphp/pest": "^3.7", diff --git a/src/Admin/Filament/Tables/Columns/SliderColumn.php b/src/Admin/Filament/Tables/Columns/SliderColumn.php index 94c713f..4172719 100644 --- a/src/Admin/Filament/Tables/Columns/SliderColumn.php +++ b/src/Admin/Filament/Tables/Columns/SliderColumn.php @@ -75,13 +75,7 @@ protected function getImageUrls($column): array protected function isPlaceholderImage(string $url): bool { $placeholderPatterns = [ - 'data:image/svg+xml;base64,', // SVG placeholders - 'placeholder', // URLs containing 'placeholder' - 'via.placeholder.com', // Placeholder service - 'picsum.photos', // Lorem Picsum placeholder - 'dummyimage.com', // Dummy image service - 'placehold.it', // Placehold.it service - '/placeholder', // Local placeholder paths + 'data:image/svg+xml;base64,', ]; foreach ($placeholderPatterns as $pattern) { From 5b3254368a9bc297c6a149e6df37b5ee83d23af6 Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Thu, 18 Sep 2025 11:23:35 +0545 Subject: [PATCH 6/7] fix: suppressing circular dep --- tests/Unit/Foundation/Models/Scopes/ActiveScopeTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Unit/Foundation/Models/Scopes/ActiveScopeTest.php b/tests/Unit/Foundation/Models/Scopes/ActiveScopeTest.php index dacceca..481499b 100644 --- a/tests/Unit/Foundation/Models/Scopes/ActiveScopeTest.php +++ b/tests/Unit/Foundation/Models/Scopes/ActiveScopeTest.php @@ -4,6 +4,9 @@ use Eclipse\Common\Foundation\Models\Scopes\ActiveScope; test('active scope works', function () { + if (! class_exists('Eclipse\Catalogue\Models\Group')) { + $this->markTestSkipped('Catalogue plugin not available'); + } // Create an inactive product group $group = Group::factory()->inactive()->create(); From d391ae0873a1687397f93f42d685a7981bdfce5d Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Sat, 20 Sep 2025 12:04:34 +0545 Subject: [PATCH 7/7] feat: implementing requested changes --- .../Tables/Columns/ImageColumn.php} | 65 +++++++++++-------- src/{Foundation => }/Helpers/MediaHelper.php | 2 +- 2 files changed, 39 insertions(+), 28 deletions(-) rename src/{Admin/Filament/Tables/Columns/SliderColumn.php => Filament/Tables/Columns/ImageColumn.php} (60%) rename src/{Foundation => }/Helpers/MediaHelper.php (90%) diff --git a/src/Admin/Filament/Tables/Columns/SliderColumn.php b/src/Filament/Tables/Columns/ImageColumn.php similarity index 60% rename from src/Admin/Filament/Tables/Columns/SliderColumn.php rename to src/Filament/Tables/Columns/ImageColumn.php index 4172719..f145434 100644 --- a/src/Admin/Filament/Tables/Columns/SliderColumn.php +++ b/src/Filament/Tables/Columns/ImageColumn.php @@ -1,44 +1,55 @@ extraImgAttributes(function (Model $record, $column): array { - $imageUrls = $this->getImageUrls($column); + protected bool $previewEnabled = false; - if (empty($imageUrls)) { - return []; - } - - $lightboxData = []; - foreach ($imageUrls as $imageUrl) { - $lightboxData[] = [ - 'url' => $imageUrl, - 'title' => $this->getTitle($record), - 'link' => $this->getLink($record), - 'filename' => basename($imageUrl), + public function preview(bool $condition = true): static + { + $this->previewEnabled = $condition; + + if ($this->previewEnabled) { + $this->extraImgAttributes(function (Model $record, $column): array { + $imageUrls = $this->getImageUrls($column); + + if (empty($imageUrls)) { + return []; + } + + $lightboxData = []; + foreach ($imageUrls as $imageUrl) { + $lightboxData[] = [ + 'url' => $imageUrl, + 'title' => $this->getTitle($record), + 'link' => $this->getLink($record), + 'filename' => basename($imageUrl), + ]; + } + + return [ + 'class' => 'cursor-pointer image-preview-trigger hover:opacity-75 transition-opacity', + 'onclick' => 'event.stopPropagation(); return false;', + 'data-lightbox-config' => json_encode($lightboxData), ]; - } + }); + } - return [ - 'class' => 'cursor-pointer image-preview-trigger hover:opacity-75 transition-opacity', - 'onclick' => 'event.stopPropagation(); return false;', - 'data-lightbox-config' => json_encode($lightboxData), - ]; - }); + return $this; + } + + protected function setUp(): void + { + parent::setUp(); } public function title(string|Closure $title): static diff --git a/src/Foundation/Helpers/MediaHelper.php b/src/Helpers/MediaHelper.php similarity index 90% rename from src/Foundation/Helpers/MediaHelper.php rename to src/Helpers/MediaHelper.php index 130fa2f..48115c1 100644 --- a/src/Foundation/Helpers/MediaHelper.php +++ b/src/Helpers/MediaHelper.php @@ -1,6 +1,6 @@