Files
thrillwiki_laravel/resources/views/livewire/photo-gallery-component.blade.php

299 lines
21 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 mb-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Photo Gallery</h3>
<div class="flex space-x-2">
<button
wire:click="toggleViewMode"
class="inline-flex items-center px-3 py-1.5 bg-gray-100 border border-gray-300 rounded-md font-medium text-xs text-gray-700 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition ease-in-out duration-150 dark:bg-gray-700 dark:border-gray-600 dark:text-gray-200 dark:hover:bg-gray-600"
>
@if ($viewMode === 'grid')
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7" />
</svg>
Carousel View
@else
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
</svg>
Grid View
@endif
</button>
</div>
</div>
@if ($isLoading)
<div class="flex justify-center items-center py-12">
<svg class="animate-spin h-8 w-8 text-blue-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</div>
@elseif ($error)
<div class="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded relative dark:bg-red-900 dark:border-red-800 dark:text-red-200" role="alert">
<span class="block sm:inline">{{ $error }}</span>
</div>
@elseif (count($photos) === 0)
<div class="text-center py-12 text-gray-500 dark:text-gray-400">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<p class="text-lg font-medium">No photos yet</p>
<p class="mt-1">Upload photos to showcase this park.</p>
</div>
@else
@if ($viewMode === 'grid')
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4">
@foreach ($photos as $photo)
<div
wire:key="photo-{{ $photo->id }}"
class="relative group aspect-square overflow-hidden rounded-lg bg-gray-100 dark:bg-gray-700"
>
<img
src="{{ $photo->url }}"
alt="{{ $photo->alt_text ?? $photo->title ?? 'Park photo' }}"
class="w-full h-full object-cover cursor-pointer"
wire:click="selectPhoto({{ $photo->id }})"
>
@if ($photo->is_featured)
<div class="absolute top-2 left-2 bg-yellow-500 text-white text-xs px-2 py-1 rounded-full">
Featured
</div>
@endif
<div class="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-40 transition-all duration-300 flex items-center justify-center opacity-0 group-hover:opacity-100">
<div class="flex space-x-2">
<button
wire:click="selectPhoto({{ $photo->id }})"
class="p-1.5 bg-white rounded-full text-gray-800 hover:bg-blue-500 hover:text-white transition-colors duration-200"
title="View photo"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
</button>
@if (!$photo->is_featured)
<button
wire:click="setFeatured({{ $photo->id }})"
class="p-1.5 bg-white rounded-full text-gray-800 hover:bg-yellow-500 hover:text-white transition-colors duration-200"
title="Set as featured"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
</svg>
</button>
@endif
<button
wire:click="deletePhoto({{ $photo->id }})"
wire:confirm="Are you sure you want to delete this photo? This action cannot be undone."
class="p-1.5 bg-white rounded-full text-gray-800 hover:bg-red-500 hover:text-white transition-colors duration-200"
title="Delete photo"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
</button>
</div>
</div>
</div>
@endforeach
</div>
@else
<div
x-data="{
activeSlide: 0,
totalSlides: {{ count($photos) }},
next() {
this.activeSlide = (this.activeSlide + 1) % this.totalSlides;
},
prev() {
this.activeSlide = (this.activeSlide - 1 + this.totalSlides) % this.totalSlides;
}
}"
class="relative"
>
<div class="relative aspect-video overflow-hidden rounded-lg bg-gray-100 dark:bg-gray-700">
@foreach ($photos as $index => $photo)
<div
x-show="activeSlide === {{ $index }}"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform scale-95"
x-transition:enter-end="opacity-100 transform scale-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 transform scale-100"
x-transition:leave-end="opacity-0 transform scale-95"
class="absolute inset-0"
>
<img
src="{{ $photo->url }}"
alt="{{ $photo->alt_text ?? $photo->title ?? 'Park photo' }}"
class="w-full h-full object-contain"
>
@if ($photo->is_featured)
<div class="absolute top-4 left-4 bg-yellow-500 text-white px-2 py-1 rounded-full text-sm">
Featured
</div>
@endif
<div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-4 text-white">
<h4 class="font-medium">{{ $photo->title ?? 'Untitled Photo' }}</h4>
@if ($photo->description)
<p class="text-sm text-gray-200 mt-1">{{ $photo->description }}</p>
@endif
@if ($photo->credit)
<p class="text-xs text-gray-300 mt-2">Credit: {{ $photo->credit }}</p>
@endif
</div>
</div>
@endforeach
</div>
<button
@click="prev"
class="absolute left-2 top-1/2 -translate-y-1/2 p-1.5 bg-black/50 hover:bg-black/70 rounded-full text-white transition-colors duration-200"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
</button>
<button
@click="next"
class="absolute right-2 top-1/2 -translate-y-1/2 p-1.5 bg-black/50 hover:bg-black/70 rounded-full text-white transition-colors duration-200"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
<div class="flex justify-center mt-4 space-x-2">
@foreach ($photos as $index => $photo)
<button
@click="activeSlide = {{ $index }}"
:class="{'bg-blue-600': activeSlide === {{ $index }}, 'bg-gray-300 dark:bg-gray-600': activeSlide !== {{ $index }}}"
class="w-2.5 h-2.5 rounded-full transition-colors duration-200"
></button>
@endforeach
</div>
</div>
@endif
@endif
</div>
<!-- Photo Detail Modal -->
@if ($selectedPhoto)
<div
class="fixed inset-0 z-50 overflow-y-auto"
x-data="{}"
x-init="$nextTick(() => { document.body.style.overflow = 'hidden'; })"
x-on:keydown.escape.window="$wire.closePhotoDetail(); document.body.style.overflow = '';"
>
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 bg-gray-900 bg-opacity-75 transition-opacity" wire:click="closePhotoDetail"></div>
<div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full">
<div class="absolute top-0 right-0 pt-4 pr-4">
<button
wire:click="closePhotoDetail"
class="bg-white dark:bg-gray-800 rounded-md text-gray-400 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<span class="sr-only">Close</span>
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="p-6">
<div class="flex flex-col md:flex-row gap-6">
<div class="md:w-2/3">
<div class="aspect-video bg-gray-100 dark:bg-gray-700 rounded-lg overflow-hidden">
<img
src="{{ $selectedPhoto->url }}"
alt="{{ $selectedPhoto->alt_text ?? $selectedPhoto->title ?? 'Park photo' }}"
class="w-full h-full object-contain"
>
</div>
</div>
<div class="md:w-1/3">
<h3 class="text-lg font-medium text-gray-900 dark:text-white">
{{ $selectedPhoto->title ?? 'Untitled Photo' }}
</h3>
@if ($selectedPhoto->description)
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
{{ $selectedPhoto->description }}
</p>
@endif
<div class="mt-4 border-t border-gray-200 dark:border-gray-700 pt-4">
<dl class="space-y-3 text-sm">
@if ($selectedPhoto->credit)
<div>
<dt class="font-medium text-gray-500 dark:text-gray-400">Credit:</dt>
<dd class="mt-1 text-gray-900 dark:text-white">{{ $selectedPhoto->credit }}</dd>
</div>
@endif
@if ($selectedPhoto->source_url)
<div>
<dt class="font-medium text-gray-500 dark:text-gray-400">Source:</dt>
<dd class="mt-1 text-blue-600 dark:text-blue-400">
<a href="{{ $selectedPhoto->source_url }}" target="_blank" rel="noopener noreferrer" class="hover:underline">
{{ $selectedPhoto->source_url }}
</a>
</dd>
</div>
@endif
<div>
<dt class="font-medium text-gray-500 dark:text-gray-400">Dimensions:</dt>
<dd class="mt-1 text-gray-900 dark:text-white">{{ $selectedPhoto->width }} × {{ $selectedPhoto->height }}</dd>
</div>
<div>
<dt class="font-medium text-gray-500 dark:text-gray-400">File Size:</dt>
<dd class="mt-1 text-gray-900 dark:text-white">{{ number_format($selectedPhoto->file_size / 1024, 2) }} KB</dd>
</div>
</dl>
</div>
<div class="mt-6 flex space-x-3">
@if (!$selectedPhoto->is_featured)
<button
wire:click="setFeatured({{ $selectedPhoto->id }})"
class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
</svg>
Set as Featured
</button>
@endif
<button
wire:click="deletePhoto({{ $selectedPhoto->id }})"
wire:confirm="Are you sure you want to delete this photo? This action cannot be undone."
class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
Delete Photo
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endif
</div>