File: /home/u756937133/domains/swingersnest.com/public_html/resources/views/pages/albums/show.blade.php
@extends('layouts.feeds')
@section('title', $album->name . ' - Album - ' . config('app.name'))
@section('content')
<div class="album-page bg-sn-soft dark:bg-transparent rounded-xl">
{{-- Compact header --}}
<div class="flex flex-wrap items-center justify-between gap-3 pb-4 border-b border-sn-divider dark:border-gray-700 mb-4">
<div class="flex items-center gap-2 min-w-0">
<a href="{{ auth()->check() && $isOwnAlbum ? route('user.profile', $user->username ?? $user->id) . '#album' : url()->previous() }}" class="flex-shrink-0 w-9 h-9 rounded-lg border border-sn-divider dark:border-gray-600 flex items-center justify-center text-sn-muted hover:text-sn-heading dark:hover:text-white hover:bg-sn-soft dark:hover:bg-gray-800 transition-colors" title="Back">
<i class="ri-arrow-left-line text-lg"></i>
</a>
<div class="min-w-0">
<h1 class="text-lg font-bold text-sn-heading dark:text-white truncate">{{ $album->name }}</h1>
<p class="text-xs text-sn-muted dark:text-gray-400 mt-0.5">{{ $album->image_count }} {{ $album->image_count === 1 ? 'photo' : 'photos' }}</p>
</div>
@if($album->is_private)
<span class="flex-shrink-0 inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400 text-[10px] font-semibold"><i class="ri-lock-line"></i> Private</span>
@else
<span class="flex-shrink-0 inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-emerald-100 dark:bg-emerald-500/20 text-emerald-700 dark:text-emerald-400 text-[10px] font-semibold"><i class="ri-global-line"></i> Public</span>
@endif
</div>
@if($isOwnAlbum)
<button type="button" onclick="document.getElementById('albumImageInput').click()" class="inline-flex items-center gap-1.5 px-3 py-2 rounded-lg bg-sn-plum text-white text-sm font-semibold hover:opacity-90 transition-opacity">
<i class="ri-add-line text-base"></i>
Add Images
</button>
@endif
</div>
{{-- Images grid (compact) --}}
@if($album->images->count() > 0)
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2 sm:gap-3">
@foreach($album->images as $image)
<div class="relative group rounded-lg border border-sn-divider dark:border-gray-600 bg-white dark:bg-gray-800/50 overflow-hidden">
<img src="{{ asset('storage/' . $image->image_path) }}" alt="Album image" class="w-full aspect-square object-cover cursor-pointer image-modal-trigger" data-src="{{ asset('storage/' . $image->image_path) }}">
@if($isOwnAlbum)
<button type="button" onclick="deleteImage({{ $album->id }}, {{ $image->id }}, this)" class="absolute top-1.5 right-1.5 w-8 h-8 rounded-full bg-red-500 hover:bg-red-600 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity" title="Remove image">
<i class="ri-delete-bin-line text-sm"></i>
</button>
@endif
</div>
@endforeach
</div>
@else
<div class="rounded-xl border border-sn-divider dark:border-gray-600 bg-white dark:bg-gray-800/50 py-10 px-4 text-center">
<i class="ri-image-line text-4xl text-sn-muted dark:text-gray-500 mb-3 block"></i>
<h3 class="text-base font-bold text-sn-heading dark:text-white mb-1">No images yet</h3>
<p class="text-xs text-sn-muted dark:text-gray-400 mb-4">
@if($isOwnAlbum)
Click "Add Images" to upload photos.
@else
This album has no images yet.
@endif
</p>
</div>
@endif
@if($isOwnAlbum)
<input type="file" id="albumImageInput" name="images[]" accept="image/jpeg,image/jpg,image/png,image/gif,image/webp" multiple class="hidden" onchange="handleAlbumImageUpload(this, {{ $album->id }})">
@endif
</div>
{{-- Image modal (compact) --}}
<div id="imageModal" class="fixed inset-0 bg-black/90 z-50 hidden items-center justify-center p-4" onclick="closeImageModal()">
<button type="button" onclick="closeImageModal()" class="absolute top-3 right-3 w-10 h-10 rounded-full bg-white/10 text-white flex items-center justify-center z-10 hover:bg-white/20">
<i class="ri-close-line text-xl"></i>
</button>
<img id="modalImage" src="" alt="Full size" class="max-w-full max-h-[85vh] object-contain rounded-lg" onclick="event.stopPropagation()">
</div>
{{-- Upload progress --}}
<div id="uploadProgressModal" class="fixed inset-0 bg-black/70 z-50 hidden items-center justify-center p-4">
<div class="bg-gray-800 dark:bg-gray-900 rounded-xl shadow-xl max-w-xs w-full p-5" onclick="event.stopPropagation()">
<p class="text-sm font-medium text-white mb-2">Uploading…</p>
<div class="w-full bg-gray-700 rounded-full h-2 overflow-hidden">
<div id="uploadProgressBar" class="bg-sn-plum h-full rounded-full transition-all duration-300" style="width:0%"></div>
</div>
<span id="uploadProgressText" class="text-xs text-gray-400 mt-1 block">0%</span>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.image-modal-trigger').forEach(function(img) {
img.addEventListener('click', function(e) {
e.preventDefault();
openImageModal(this.getAttribute('data-src'));
});
});
});
function openImageModal(src) {
var modal = document.getElementById('imageModal');
document.getElementById('modalImage').src = src;
modal.classList.remove('hidden');
modal.classList.add('flex');
document.body.style.overflow = 'hidden';
}
function closeImageModal() {
var modal = document.getElementById('imageModal');
modal.classList.add('hidden');
modal.classList.remove('flex');
document.body.style.overflow = '';
}
function handleAlbumImageUpload(input, albumId) {
if (!input.files || input.files.length === 0) return;
var formData = new FormData();
Array.from(input.files).forEach(function(file) { formData.append('images[]', file); });
formData.append('_token', document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '{{ csrf_token() }}');
var progressModal = document.getElementById('uploadProgressModal');
var progressBar = document.getElementById('uploadProgressBar');
var progressText = document.getElementById('uploadProgressText');
if (progressModal) { progressModal.classList.remove('hidden'); progressModal.classList.add('flex'); document.body.style.overflow = 'hidden'; }
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable && progressBar) { var p = Math.round((e.loaded / e.total) * 100); progressBar.style.width = p + '%'; if (progressText) progressText.textContent = p + '%'; }
});
xhr.addEventListener('load', function() {
if (xhr.status === 200) {
var r = JSON.parse(xhr.responseText);
if (r.success) { if (progressBar) progressBar.style.width = '100%'; if (progressText) progressText.textContent = '100%'; setTimeout(function() { if (progressModal) { progressModal.classList.add('hidden'); progressModal.classList.remove('flex'); } document.body.style.overflow = ''; location.reload(); }, 400); }
else { if (progressModal) { progressModal.classList.add('hidden'); progressModal.classList.remove('flex'); } document.body.style.overflow = ''; alert(r.message || 'Upload failed'); }
} else { if (progressModal) { progressModal.classList.add('hidden'); progressModal.classList.remove('flex'); } document.body.style.overflow = ''; alert('Upload failed'); }
});
xhr.addEventListener('error', function() { if (progressModal) { progressModal.classList.add('hidden'); progressModal.classList.remove('flex'); } document.body.style.overflow = ''; alert('Upload error'); });
xhr.open('POST', '{{ route("albums.upload-images", ":id") }}'.replace(':id', albumId));
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.send(formData);
input.value = '';
}
function deleteImage(albumId, imageId, btn) {
if (!confirm('Delete this image?')) return;
var formData = new FormData();
formData.append('_token', document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '{{ csrf_token() }}');
formData.append('_method', 'DELETE');
var el = btn.closest('.relative.group');
if (el) { el.style.opacity = '0.5'; el.style.pointerEvents = 'none'; }
fetch('{{ route("albums.delete-image", [":albumId", ":imageId"]) }}'.replace(':albumId', albumId).replace(':imageId', imageId), { method: 'POST', body: formData, headers: { 'X-Requested-With': 'XMLHttpRequest' } })
.then(function(r) { return r.json(); })
.then(function(d) { if (d.success) location.reload(); else { alert(d.message || 'Delete failed'); if (el) { el.style.opacity = ''; el.style.pointerEvents = ''; } } })
.catch(function() { if (el) { el.style.opacity = ''; el.style.pointerEvents = ''; } alert('Error'); });
}
</script>
@endsection