303 lines
14 KiB
PHP
303 lines
14 KiB
PHP
@extends('layouts.nova')
|
||
|
||
@php
|
||
use App\Banner;
|
||
$gridV2 = request()->query('grid') === 'v2';
|
||
@endphp
|
||
|
||
@php
|
||
$seoPage = max(1, (int) request()->query('page', 1));
|
||
$seoBase = url()->current();
|
||
$seoQ = request()->query(); unset($seoQ['page']);
|
||
$seoUrl = fn(int $p) => $seoBase . ($p > 1
|
||
? '?' . http_build_query(array_merge($seoQ, ['page' => $p]))
|
||
: (count($seoQ) ? '?' . http_build_query($seoQ) : ''));
|
||
$seoPrev = $seoPage > 1 ? $seoUrl($seoPage - 1) : null;
|
||
$seoNext = (isset($artworks) && method_exists($artworks, 'nextPageUrl'))
|
||
? $artworks->nextPageUrl() : null;
|
||
@endphp
|
||
|
||
@push('head')
|
||
<link rel="canonical" href="{{ $seoUrl($seoPage) }}">
|
||
@if($seoPrev)<link rel="prev" href="{{ $seoPrev }}">@endif
|
||
@if($seoNext)<link rel="next" href="{{ $seoNext }}">@endif
|
||
<meta name="robots" content="index,follow">
|
||
@endpush
|
||
|
||
@section('content')
|
||
<div class="container-fluid legacy-page">
|
||
@php Banner::ShowResponsiveAd(); @endphp
|
||
|
||
<div class="pt-0">
|
||
<div class="mx-auto w-full">
|
||
<div class="relative flex min-h-[calc(100vh-64px)]">
|
||
|
||
<button
|
||
id="sidebar-toggle"
|
||
type="button"
|
||
class="hidden md:inline-flex items-center justify-center h-10 w-10 rounded-lg border border-white/10 bg-white/5 text-white/90 hover:bg-white/10 absolute top-3 z-20"
|
||
aria-controls="sidebar"
|
||
aria-expanded="true"
|
||
aria-label="Toggle sidebar"
|
||
style="left:16px;"
|
||
>
|
||
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||
<path d="M4 6h16M4 12h16M4 18h16" />
|
||
</svg>
|
||
</button>
|
||
|
||
<aside id="sidebar" class="hidden md:block w-72 shrink-0 border-r border-neutral-800 bg-nova-900/60 backdrop-blur-sm">
|
||
<div class="p-4">
|
||
<div class="mt-2 text-sm text-neutral-400">
|
||
<div class="font-semibold text-white/80 mb-2">Main Categories:</div>
|
||
<ul class="space-y-2">
|
||
@foreach($mainCategories as $main)
|
||
<li>
|
||
<a class="flex items-center gap-2 hover:text-white" href="{{ $main->url }}"><span class="opacity-70">📁</span> {{ $main->name }}</a>
|
||
</li>
|
||
@endforeach
|
||
</ul>
|
||
|
||
<div class="mt-6 font-semibold text-white/80 mb-2">Browse Subcategories:</div>
|
||
<ul class="space-y-2 pr-2">
|
||
@forelse($subcategories as $sub)
|
||
@php
|
||
$subName = $sub->category_name ?? $sub->name ?? null;
|
||
$subUrl = $sub->url ?? ((isset($sub->slug) && isset($contentType)) ? '/' . $contentType->slug . '/' . $sub->slug : null);
|
||
$isActive = isset($category) && isset($sub->id) && $category && ((int) $sub->id === (int) $category->id);
|
||
@endphp
|
||
<li>
|
||
@if($subUrl)
|
||
<a class="hover:text-white {{ $isActive ? 'font-semibold text-white' : 'text-neutral-400' }}" href="{{ $subUrl }}">{{ $subName }}</a>
|
||
@else
|
||
<span class="text-neutral-400">{{ $subName }}</span>
|
||
@endif
|
||
</li>
|
||
@empty
|
||
<li><span class="text-neutral-500">No subcategories</span></li>
|
||
@endforelse
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<main class="flex-1">
|
||
<div class="relative overflow-hidden nb-hero-radial">
|
||
<div class="absolute inset-0 opacity-35"></div>
|
||
|
||
<div class="relative px-6 py-8 md:px-10 md:py-10">
|
||
<div class="text-sm text-neutral-400">
|
||
@if(($gallery_type ?? null) === 'browse')
|
||
Browse
|
||
@elseif(isset($contentType) && $contentType)
|
||
<a class="hover:text-white" href="/{{ $contentType->slug }}">{{ $contentType->name }}</a>
|
||
@if(($gallery_type ?? null) === 'category')
|
||
@foreach($breadcrumbs as $crumb)
|
||
<span class="opacity-50">›</span>
|
||
<a class="hover:text-white" href="{{ $crumb->url }}">{{ $crumb->name }}</a>
|
||
@endforeach
|
||
@endif
|
||
@endif
|
||
</div>
|
||
|
||
<h1 class="mt-2 text-3xl md:text-4xl font-semibold tracking-tight text-white/95">{{ $hero_title ?? 'Browse Artworks' }}</h1>
|
||
|
||
<section class="mt-5 bg-white/5 border border-white/10 rounded-2xl shadow-lg">
|
||
<div class="p-5 md:p-6">
|
||
<div class="text-lg font-semibold text-white/90">{{ $hero_title ?? 'Browse Artworks' }}</div>
|
||
<p class="mt-2 text-sm leading-6 text-neutral-400">{!! $hero_description ?? '' !!}</p>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="absolute left-0 right-0 bottom-0 h-36 nb-hero-fade pointer-events-none" aria-hidden="true"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<section class="px-6 pb-10 pt-8 md:px-10" data-nova-gallery data-gallery-type="{{ $gallery_type ?? 'browse' }}">
|
||
<div class="{{ $gridV2 ? 'gallery' : 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 force-5' }}" data-gallery-grid>
|
||
@forelse ($artworks as $art)
|
||
<x-artwork-card
|
||
:art="$art"
|
||
:loading="$loop->index < 8 ? 'eager' : 'lazy'"
|
||
:fetchpriority="$loop->index === 0 ? 'high' : null"
|
||
/>
|
||
@empty
|
||
<div class="panel panel-default effect2">
|
||
<div class="panel-heading"><strong>No Artworks Yet</strong></div>
|
||
<div class="panel-body">
|
||
<p>Once uploads arrive they will appear here. Check back soon.</p>
|
||
</div>
|
||
</div>
|
||
@endforelse
|
||
</div>
|
||
|
||
<div class="flex justify-center mt-10" data-gallery-pagination>
|
||
@if ($artworks instanceof \Illuminate\Contracts\Pagination\Paginator || $artworks instanceof \Illuminate\Contracts\Pagination\CursorPaginator)
|
||
{{ method_exists($artworks, 'withQueryString') ? $artworks->withQueryString()->links() : $artworks->links() }}
|
||
@endif
|
||
</div>
|
||
<div class="hidden" data-gallery-skeleton-template aria-hidden="true">
|
||
<x-skeleton.artwork-card />
|
||
</div>
|
||
<div class="hidden mt-8" data-gallery-skeleton></div>
|
||
</section>
|
||
</main>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endsection
|
||
|
||
@push('styles')
|
||
@if(! $gridV2)
|
||
<style>
|
||
[data-nova-gallery].is-enhanced [data-gallery-grid] {
|
||
display: grid;
|
||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||
grid-auto-rows: 8px;
|
||
gap: 1rem;
|
||
}
|
||
@media (min-width: 768px) {
|
||
[data-nova-gallery].is-enhanced [data-gallery-grid] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||
}
|
||
@media (min-width: 1024px) {
|
||
/* Fallback for non-enhanced (no-js) galleries: use 5 columns on desktop */
|
||
[data-nova-gallery] [data-gallery-grid] { grid-template-columns: repeat(5, minmax(0, 1fr)); }
|
||
[data-nova-gallery].is-enhanced [data-gallery-grid] { grid-template-columns: repeat(5, minmax(0, 1fr)); }
|
||
/* High-specificity override for legacy/tailwind classes */
|
||
[data-gallery-grid].force-5 { grid-template-columns: repeat(5, minmax(0, 1fr)) !important; }
|
||
}
|
||
/* Larger desktop screens: 6 columns */
|
||
@media (min-width: 1600px) {
|
||
[data-nova-gallery] [data-gallery-grid] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
|
||
[data-nova-gallery].is-enhanced [data-gallery-grid] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
|
||
[data-gallery-grid].force-5 { grid-template-columns: repeat(6, minmax(0, 1fr)) !important; }
|
||
}
|
||
@media (min-width: 2600px) {
|
||
[data-nova-gallery] [data-gallery-grid] { grid-template-columns: repeat(7, minmax(0, 1fr)); }
|
||
[data-nova-gallery].is-enhanced [data-gallery-grid] { grid-template-columns: repeat(7, minmax(0, 1fr)); }
|
||
[data-gallery-grid].force-5 { grid-template-columns: repeat(7, minmax(0, 1fr)) !important; }
|
||
}
|
||
/* Ensure dashboard gallery shows 5 columns on desktop even when JS hasn't enhanced */
|
||
[data-nova-gallery][data-gallery-type="dashboard"] [data-gallery-grid] {
|
||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||
}
|
||
@media (min-width: 1600px) {
|
||
[data-nova-gallery][data-gallery-type="dashboard"] [data-gallery-grid] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
|
||
}
|
||
[data-nova-gallery].is-enhanced [data-gallery-grid] > .nova-card { margin: 0 !important; }
|
||
/* Keep pagination visible when JS enhances the gallery so users
|
||
have a clear navigation control (numeric links for length-aware
|
||
paginators, prev/next for cursor paginators). Make it compact. */
|
||
[data-nova-gallery].is-enhanced [data-gallery-pagination] {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
margin-top: 1.5rem;
|
||
}
|
||
[data-nova-gallery].is-enhanced [data-gallery-pagination] ul {
|
||
display: inline-flex;
|
||
gap: 0.25rem;
|
||
align-items: center;
|
||
padding: 0;
|
||
margin: 0;
|
||
list-style: none;
|
||
}
|
||
[data-nova-gallery].is-enhanced [data-gallery-pagination] li a,
|
||
[data-nova-gallery].is-enhanced [data-gallery-pagination] li span {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: 2.25rem;
|
||
height: 2.25rem;
|
||
border-radius: 0.5rem;
|
||
padding: 0 0.5rem;
|
||
background: rgba(255,255,255,0.03);
|
||
color: #e6eef8;
|
||
border: 1px solid rgba(255,255,255,0.04);
|
||
text-decoration: none;
|
||
font-size: 0.875rem;
|
||
}
|
||
[data-gallery-skeleton].is-loading { display: grid !important; grid-template-columns: inherit; gap: 1rem; }
|
||
.nova-skeleton-card {
|
||
border-radius: 1rem;
|
||
min-height: 180px;
|
||
background: linear-gradient(110deg, rgba(255,255,255,.06) 8%, rgba(255,255,255,.12) 18%, rgba(255,255,255,.06) 33%);
|
||
background-size: 200% 100%;
|
||
animation: novaShimmer 1.2s linear infinite;
|
||
}
|
||
@keyframes novaShimmer {
|
||
to { background-position-x: -200%; }
|
||
}
|
||
.nb-hero-fade {
|
||
background: linear-gradient(180deg, rgba(17,24,39,0) 0%, rgba(7,10,15,0.9) 60%, rgba(7,10,15,1) 100%);
|
||
}
|
||
</style>
|
||
@endif
|
||
@endpush
|
||
|
||
@push('scripts')
|
||
<script src="/js/legacy-gallery-init.js" defer></script>
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
var toggle = document.getElementById('sidebar-toggle');
|
||
var sidebar = document.getElementById('sidebar');
|
||
if (!toggle || !sidebar) return;
|
||
|
||
var collapsed = false;
|
||
try {
|
||
collapsed = window.localStorage.getItem('gallery.sidebar.collapsed') === '1';
|
||
} catch (e) {
|
||
collapsed = false;
|
||
}
|
||
|
||
function applySidebarState() {
|
||
if (collapsed) {
|
||
sidebar.classList.add('md:hidden');
|
||
toggle.setAttribute('aria-expanded', 'false');
|
||
} else {
|
||
sidebar.classList.remove('md:hidden');
|
||
toggle.setAttribute('aria-expanded', 'true');
|
||
}
|
||
positionToggle();
|
||
}
|
||
|
||
toggle.addEventListener('click', function () {
|
||
collapsed = !collapsed;
|
||
applySidebarState();
|
||
try {
|
||
window.localStorage.setItem('gallery.sidebar.collapsed', collapsed ? '1' : '0');
|
||
} catch (e) {
|
||
// no-op
|
||
}
|
||
});
|
||
|
||
function positionToggle() {
|
||
if (!toggle || !sidebar) return;
|
||
// when sidebar is visible, position toggle just outside its right edge
|
||
if (!collapsed) {
|
||
var rect = sidebar.getBoundingClientRect();
|
||
if (rect && rect.right) {
|
||
toggle.style.left = (rect.right + 8) + 'px';
|
||
toggle.style.transform = '';
|
||
} else {
|
||
// fallback to sidebar width (18rem)
|
||
toggle.style.left = 'calc(18rem + 8px)';
|
||
}
|
||
} else {
|
||
// when collapsed, position toggle near page left edge
|
||
toggle.style.left = '16px';
|
||
toggle.style.transform = '';
|
||
}
|
||
}
|
||
|
||
window.addEventListener('resize', function () { positionToggle(); });
|
||
|
||
applySidebarState();
|
||
// ensure initial position set
|
||
positionToggle();
|
||
});
|
||
</script>
|
||
@endpush
|