HEX
Server: LiteSpeed
System: Linux us-phx-web629.main-hosting.eu 5.14.0-503.23.2.el9_5.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Feb 12 05:52:18 EST 2025 x86_64
User: u756937133 (756937133)
PHP: 8.2.27
Disabled: passthru,chgrp
Upload Files
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 &quot;Add Images&quot; 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