diff --git a/docs/MediaGallery.md b/docs/MediaGallery.md index 12397f4..f317400 100644 --- a/docs/MediaGallery.md +++ b/docs/MediaGallery.md @@ -36,7 +36,7 @@ MediaGallery::make('images') ```php MediaGallery::make('images') - ->columns(6) // Number of columns (default: 4) + ->mediaColumns(6) // Number of columns (default: 4) ->thumbnailHeight(200) // Thumbnail height in pixels (default: 150) ->preview() // Enable lightbox preview (disabled by default) ->orderable() // Enable drag & drop reordering (disabled by default) @@ -46,7 +46,7 @@ MediaGallery::make('images') ```php MediaGallery::make('images') - ->columns([ + ->mediaColumns([ 'default' => 2, 'sm' => 3, 'lg' => 4, @@ -57,7 +57,7 @@ MediaGallery::make('images') ## Methods Available ### Layout Control -- `columns(int|array)` - Set number of grid columns or responsive column configuration (default: 4) +- `mediaColumns(int|array)` - Set number of grid columns or responsive column configuration (default: 4) - `thumbnailHeight(int)` - Set thumbnail image height in pixels (default: 150) ### Interactive Features @@ -108,7 +108,7 @@ MediaGallery::make('images') ->collection('gallery') ->allowUploads() ->preview() // Enables lightbox - ->columns(3) + ->mediaColumns(3) ->thumbnailHeight(180) ``` @@ -118,7 +118,7 @@ MediaGallery::make('images') ->collection('portfolio') ->allowUploads() ->orderable() // Enables drag & drop - ->columns(5) + ->mediaColumns(5) ->maxFiles(50) ``` @@ -135,7 +135,7 @@ MediaGallery::make('images') MediaGallery::make('images') ->collection('external-media') ->allowUrlUploads() // Only URL uploads - ->columns(6) + ->mediaColumns(6) ``` ### Complete Configuration @@ -144,7 +144,7 @@ MediaGallery::make('images') ->collection('products') ->allowUploads() // Enable both upload methods ->maxFiles(20) - ->columns(4) + ->mediaColumns(4) ->thumbnailHeight(180) ->preview() // Enable lightbox ->orderable() // Enable reordering @@ -156,7 +156,7 @@ MediaGallery::make('images') MediaGallery::make('images') ->collection(fn () => $this->record?->category . '-images') ->maxFiles(fn () => $this->record?->isPremium() ? 50 : 10) - ->columns(fn () => $this->getColumnCount()) + ->mediaColumns(fn () => $this->getColumnCount()) ``` ## Default Behaviors diff --git a/resources/css/media-gallery.css b/resources/css/media-gallery.css index 77be8dc..80a86ee 100644 --- a/resources/css/media-gallery.css +++ b/resources/css/media-gallery.css @@ -2,6 +2,12 @@ display: none !important; } +.eclipse-media-gallery { + display: flex; + flex-direction: column; + gap: 1rem; +} + .eclipse-media-gallery [draggable="true"] { cursor: move; } @@ -10,6 +16,291 @@ cursor: grabbing; } +.eclipse-media-gallery-header { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +@media (min-width: 640px) { + .eclipse-media-gallery-header { + flex-direction: row; + align-items: center; + justify-content: space-between; + } +} + +.eclipse-media-gallery-bulk-controls { + display: flex; + align-items: center; + gap: 0.75rem; +} + +.eclipse-media-gallery-select-label { + display: flex; + align-items: center; + gap: 0.5rem; + cursor: pointer; +} + +.eclipse-media-gallery-select-text { + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 500; + color: rgb(55 65 81); + user-select: none; +} + +.dark .eclipse-media-gallery-select-text { + color: rgb(209 213 219); +} + +.eclipse-media-gallery-bulk-actions { + display: flex; + align-items: center; + gap: 0.5rem; + margin-left: 0.5rem; +} + +.eclipse-media-gallery-action-buttons { + display: flex; + align-items: center; + gap: 0.5rem; + flex-shrink: 0; +} + +.eclipse-media-gallery-grid-wrapper { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.eclipse-media-gallery-grid { + display: grid; + gap: 0.75rem; +} + +.eclipse-media-gallery-card { + position: relative; + overflow: hidden; + transition: all 300ms; + border-radius: 0.75rem; + background-color: rgb(255 255 255); + box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + --tw-ring-color: rgb(0 0 0 / 0.05); +} + +.dark .eclipse-media-gallery-card { + background-color: rgb(17 24 39); + --tw-ring-color: rgb(255 255 255 / 0.1); +} + +.eclipse-media-gallery-card.draggable { + cursor: move; +} + +.eclipse-media-gallery-card.hoverable:hover { + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.eclipse-media-gallery-card.selected { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + --tw-ring-color: rgb(59 130 246); + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + background-color: rgb(239 246 255); +} + +.dark .eclipse-media-gallery-card.selected { + --tw-ring-color: rgb(96 165 250); + background-color: rgb(30 58 138 / 0.2); +} + +.eclipse-media-gallery-card.dragged { + opacity: 0.5; +} + +.eclipse-media-gallery-card.drag-over { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + --tw-ring-color: rgb(96 165 250); + background-color: rgb(239 246 255); +} + +.dark .eclipse-media-gallery-card.drag-over { + background-color: rgb(30 58 138 / 0.2); +} + +.eclipse-image-card-container { + position: relative; + background-color: rgb(243 244 246); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} + +.eclipse-image-card-img { + max-width: 100%; + max-height: 100%; + width: auto; + height: auto; + object-fit: contain; + user-select: none; + pointer-events: none; +} + +.eclipse-image-card-img.clickable { + cursor: pointer; + pointer-events: auto; +} + +.eclipse-image-card-cover-badge { + position: absolute; + z-index: 20; + top: 8px; + left: 8px; +} + +.eclipse-image-card-content { + padding: 0.75rem; +} + +.eclipse-image-card-title { + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 500; + color: rgb(17 24 39); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dark .eclipse-image-card-title { + color: rgb(243 244 246); +} + +.eclipse-image-card-description { + font-size: 0.75rem; + line-height: 1rem; + color: rgb(75 85 99); + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.dark .eclipse-image-card-description { + color: rgb(156 163 175); +} + +.eclipse-image-card-actions { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + margin-top: 0.5rem; +} + +.eclipse-image-card-buttons { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.eclipse-media-gallery-empty { + text-align: center; + border-radius: 0.75rem; + background-color: rgb(249 250 251 / 0.3); + min-height: 280px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 1.5rem; + padding: 3rem 1.5rem; + border-width: 2px; + border-style: dashed; + border-color: rgb(209 213 219); +} + +.dark .eclipse-media-gallery-empty { + background-color: rgb(17 24 39 / 0.3); + border-color: rgb(75 85 99); +} + +.eclipse-media-gallery-empty-content { + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; +} + +.eclipse-media-gallery-empty-icon-wrapper { + padding: 1rem; + border-radius: 9999px; + background-color: rgb(243 244 246); +} + +.dark .eclipse-media-gallery-empty-icon-wrapper { + background-color: rgb(31 41 55); +} + +.eclipse-media-gallery-empty-icon { + height: 3rem; + width: 3rem; + color: rgb(156 163 175); +} + +.dark .eclipse-media-gallery-empty-icon { + color: rgb(107 114 128); +} + +.eclipse-media-gallery-empty-text { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.eclipse-media-gallery-empty-title { + font-size: 1rem; + line-height: 1.5rem; + font-weight: 600; + color: rgb(55 65 81); +} + +.dark .eclipse-media-gallery-empty-title { + color: rgb(229 231 235); +} + +.eclipse-media-gallery-empty-description { + font-size: 0.875rem; + line-height: 1.25rem; + color: rgb(107 114 128); + max-width: 32rem; +} + +.dark .eclipse-media-gallery-empty-description { + color: rgb(156 163 175); +} + +.eclipse-media-gallery-empty-actions { + display: flex; + align-items: center; + gap: 0.75rem; + margin-top: 0.5rem; +} + .eclipse-image-lightbox-overlay { position: fixed; top: 0; @@ -135,19 +426,47 @@ line-height: 1.5; } -.eclipse-image-card-container { - background-color: #f3f4f6; - cursor: pointer; +.eclipse-icon-sm { + height: 1rem; + width: 1rem; +} + +.eclipse-icon-md { + height: 1.5rem; + width: 1.5rem; +} + +.eclipse-icon-lg { + height: 2rem; + width: 2rem; +} + +.eclipse-icon-xl { + height: 3rem; + width: 3rem; +} + +.eclipse-media-preview { display: flex; + flex-direction: column; align-items: center; - justify-content: center; - overflow: hidden; + gap: 0.5rem; } -.eclipse-image-card-img { +.eclipse-media-preview-image { max-width: 100%; - max-height: 100%; - width: auto; - height: auto; + max-height: 12rem; object-fit: contain; + border-radius: 0.5rem; + box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); +} + +.eclipse-media-preview-filename { + font-size: 0.75rem; + line-height: 1rem; + color: rgb(107 114 128); +} + +.dark .eclipse-media-preview-filename { + color: rgb(156 163 175); } \ No newline at end of file diff --git a/resources/views/components/media-lightbox.blade.php b/resources/views/components/media-lightbox.blade.php index 628c4a9..6e7e57b 100644 --- a/resources/views/components/media-lightbox.blade.php +++ b/resources/views/components/media-lightbox.blade.php @@ -12,7 +12,7 @@ class="eclipse-image-lightbox-overlay"
@@ -27,11 +27,11 @@ class="eclipse-image-lightbox-image"> diff --git a/resources/views/components/media-preview.blade.php b/resources/views/components/media-preview.blade.php index c8a2147..a339059 100644 --- a/resources/views/components/media-preview.blade.php +++ b/resources/views/components/media-preview.blade.php @@ -1,8 +1,8 @@ -
+
{{ $filename }} -

{{ $filename }}

+

{{ $filename }}

\ No newline at end of file diff --git a/resources/views/filament/forms/components/media-gallery.blade.php b/resources/views/filament/forms/components/media-gallery.blade.php index 83b667d..64c4882 100644 --- a/resources/views/filament/forms/components/media-gallery.blade.php +++ b/resources/views/filament/forms/components/media-gallery.blade.php @@ -5,32 +5,35 @@ $gridStyle = $getGridStyle(); $thumbnailHeight = $getThumbnailHeight(); $statePath = $getStatePath(); + $componentKey = $getKey(); $gridId = 'media-gallery-grid-' . str_replace(['.', '[', ']'], '-', $statePath); @endphp +@assets(['eclipse-common::media-gallery-styles', 'eclipse-common::media-gallery-scripts']) +
$wire.activeLocale || 'en', }), - + selectedImages: [], - + bulkActionsOpen: false, - + draggedIndex: null, - + get hasSelection() { return this.selectedImages.length > 0; }, - + get selectedCount() { return this.selectedImages.length; }, - + get totalCount() { return this.state ? this.state.length : 0; }, - + get allSelected() { return this.totalCount > 0 && this.selectedImages.length === this.totalCount; }, - + get someSelected() { return this.selectedImages.length > 0 && this.selectedImages.length < this.totalCount; }, - + toggleSelectAll() { if (this.allSelected) { this.selectedImages = []; @@ -39,7 +42,7 @@ } this.updateBulkActionsVisibility(); }, - + toggleImageSelection(uuid) { const index = this.selectedImages.indexOf(uuid); if (index > -1) { @@ -49,44 +52,42 @@ } this.updateBulkActionsVisibility(); }, - + updateBulkActionsVisibility() { this.bulkActionsOpen = this.hasSelection; }, - + clearSelection() { this.selectedImages = []; this.bulkActionsOpen = false; }, - + async bulkDelete() { if (this.selectedImages.length === 0) return; - + try { - await $wire.mountFormComponentAction('{{ $statePath }}', 'bulkDelete', { - arguments: { uuids: this.selectedImages } - }); + await $wire.mountAction('bulkDelete', { uuids: this.selectedImages }, { schemaComponent: '{{ $componentKey }}' }); this.clearSelection(); } catch (error) { // Don't clear selection on error so user can retry } } }" wire:key="media-gallery-{{ str_replace('.', '-', $statePath) }}" - class="eclipse-media-gallery" style="display: flex; flex-direction: column; gap: 1rem;"> -
+ class="eclipse-media-gallery"> +