refactor: unify artwork card rendering

This commit is contained in:
2026-03-17 14:49:20 +01:00
parent 78151aabfe
commit 980a15f66e
30 changed files with 1145 additions and 656 deletions

View File

@@ -3,10 +3,14 @@
<div class="thumb-card effect2">
@php
$t = \App\Services\ThumbnailPresenter::present($upload, 'md');
$card = [
'id' => $t['id'] ?? null,
'title' => $t['title'] ?? 'Artwork',
'thumb' => $t['url'] ?? null,
'thumb_srcset' => $t['srcset'] ?? null,
];
@endphp
<a href="/art/{{ $t['id'] }}/{{ Str::slug($t['title'] ?: 'artwork') }}" title="{{ $t['title'] }}" class="thumb-link">
<img src="{{ $t['url'] }}" @if(!empty($t['srcset'])) srcset="{{ $t['srcset'] }}" @endif alt="{{ $t['title'] }}" class="img-responsive">
</a>
<x-artwork-card :art="$card" />
</div>
@endforeach
</div> <!-- end .gallery-grid -->

View File

@@ -14,18 +14,7 @@
<div class="gallery-grid">
@if($artworks)
@foreach($artworks as $art)
<div class="thumb-card effect2">
@if (!empty($art->category_name))
<div class="ribbon gid_{{ $art->gid_num ?? 0 }}" title="{{ $art->category_name }}"><span>{{ $art->category_name }}</span></div>
@endif
<a href="/art/{{ $art->id }}/{{ Str::slug($art->name ?? '') }}" class="thumb-link" title="{{ $art->name }}">
<img src="{{ $art->thumb_url ?? 'https://files.skinbase.org/default/missing_md.webp' }}" @if(!empty($art->thumb_srcset)) srcset="{{ $art->thumb_srcset }}" @endif alt="{{ $art->name }}" class="img-responsive" loading="lazy" decoding="async">
</a>
<div class="thumb-meta">
<div class="thumb-title">{{ $art->name }}</div>
<div class="thumb-author text-muted">by {{ $art->uname ?? 'Unknown' }}</div>
</div>
</div>
<x-artwork-card :art="$art" />
@endforeach
@else
<p class="text-muted">No artworks found.</p>

View File

@@ -1,55 +1,79 @@
@extends('layouts.nova')
@php
$headerBreadcrumbs = collect([
(object) ['name' => $page_title ?? 'Today in History', 'url' => route('legacy.today_in_history')],
]);
$galleryArtworks = collect(method_exists($artworks, 'items') ? $artworks->items() : [])->map(fn ($art) => [
'id' => $art->id ?? null,
'name' => $art->name ?? null,
'slug' => $art->slug ?? null,
'url' => $art->url ?? $art->art_url ?? null,
'thumb' => $art->thumb_url ?? null,
'thumb_url' => $art->thumb_url ?? null,
'thumb_srcset' => $art->thumb_srcset ?? null,
'uname' => $art->uname ?? '',
'username' => $art->username ?? $art->uname ?? '',
'avatar_url' => $art->avatar_url ?? null,
'content_type_name' => $art->content_type_name ?? '',
'content_type_slug' => $art->content_type_slug ?? '',
'category_name' => $art->category_name ?? '',
'category_slug' => $art->category_slug ?? '',
'width' => $art->width ?? null,
'height' => $art->height ?? null,
])->values();
$galleryNextPageUrl = method_exists($artworks, 'nextPageUrl') ? $artworks->nextPageUrl() : null;
@endphp
@section('content')
<x-nova-page-header
section="History"
:title="$page_title ?? 'Today in History'"
icon="fa-calendar-days"
:breadcrumbs="$headerBreadcrumbs"
:description="'Featured artworks uploaded on <span class=&quot;text-white/80 font-medium&quot;>' . e($todayLabel ?? now()->format('F j')) . '</span> in past years.'"
headerClass="pb-6"
/>
{{-- ── Hero header ── --}}
<div class="px-6 pt-10 pb-6 md:px-10">
<div>
<p class="text-xs font-semibold uppercase tracking-widest text-white/30 mb-1">History</p>
<h1 class="text-3xl font-bold text-white leading-tight">{{ $page_title ?? 'Today in History' }}</h1>
<p class="mt-1 text-sm text-white/50">
Featured artworks uploaded on
<span class="text-white/80 font-medium">{{ $todayLabel ?? now()->format('F j') }}</span>
in past years.
</p>
</div>
</div>
{{-- ── Gallery ── --}}
<div class="px-6 pb-16 md:px-10">
@if($artworks && $artworks->count())
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-3">
@foreach($artworks as $ar)
<a href="{{ $ar->art_url ?? ('/art/' . $ar->id) }}"
class="group relative block overflow-hidden rounded-xl ring-1 ring-white/5 bg-black/20 shadow-md transition-all duration-200 hover:-translate-y-0.5">
<div class="relative aspect-square overflow-hidden bg-neutral-900">
<img src="{{ $ar->thumb_url ?? 'https://files.skinbase.org/default/missing_md.webp' }}"
alt="{{ $ar->name ?? '' }}"
loading="lazy"
decoding="async"
class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-[1.06]"
onerror="this.src='https://files.skinbase.org/default/missing_md.webp'">
{{-- Title overlay on hover --}}
<div class="pointer-events-none absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent px-2 py-2
opacity-0 transition-opacity duration-200 group-hover:opacity-100">
<p class="truncate text-xs font-medium text-white">{{ $ar->name ?? 'Untitled' }}</p>
</div>
</div>
</a>
@endforeach
</div>
{{-- Pagination --}}
<div class="mt-10 flex justify-center">
{{ $artworks->withQueryString()->links('pagination::bootstrap-4') }}
</div>
<section class="px-6 pt-8 md:px-10">
@if ($artworks && $artworks->count())
<div
data-react-masonry-gallery
data-artworks="{{ json_encode($galleryArtworks) }}"
data-gallery-type="today-in-history"
@if ($galleryNextPageUrl) data-next-page-url="{{ $galleryNextPageUrl }}" @endif
data-limit="36"
class="min-h-32"
></div>
@else
<div class="rounded-xl border border-white/[0.06] bg-white/[0.02] px-8 py-16 text-center">
<p class="text-4xl mb-4">📅</p>
<p class="text-white/60 text-sm">No featured artworks found for this day in history.</p>
<p class="text-white/30 text-xs mt-1">Check back tomorrow!</p>
<div class="rounded-xl border border-white/[0.06] bg-white/[0.02] px-8 py-12 text-center">
<p class="text-white/40 text-sm">No featured artworks were found for {{ $todayLabel ?? now()->format('F j') }}.</p>
<p class="text-white/25 text-xs mt-1">When historical features exist for this date, they will appear here.</p>
</div>
@endif
</div>
</section>
@endsection
@push('styles')
<style>
@media (min-width: 1024px) {
[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)); }
}
@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)); }
}
@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)); }
}
</style>
@endpush
@push('scripts')
@vite('resources/js/entry-masonry-gallery.jsx')
@endpush

View File

@@ -1,32 +1,79 @@
@extends('layouts.nova')
@php
$headerBreadcrumbs = collect([
(object) ['name' => $page_title, 'url' => route('legacy.top_favourites')],
]);
$galleryArtworks = collect(method_exists($artworks, 'items') ? $artworks->items() : [])->map(fn ($art) => [
'id' => $art->id ?? null,
'name' => $art->name ?? null,
'slug' => $art->slug ?? null,
'url' => $art->url ?? null,
'thumb' => $art->thumb_url ?? $art->thumb ?? null,
'thumb_url' => $art->thumb_url ?? $art->thumb ?? null,
'thumb_srcset' => $art->thumb_srcset ?? null,
'uname' => $art->uname ?? '',
'username' => $art->username ?? $art->uname ?? '',
'avatar_url' => $art->avatar_url ?? null,
'content_type_name' => $art->content_type_name ?? '',
'content_type_slug' => $art->content_type_slug ?? '',
'category_name' => $art->category_name ?? '',
'category_slug' => $art->category_slug ?? '',
'width' => $art->width ?? null,
'height' => $art->height ?? null,
'favourites' => (int) ($art->favourites ?? $art->num ?? 0),
])->values();
$galleryNextPageUrl = method_exists($artworks, 'nextPageUrl') ? $artworks->nextPageUrl() : null;
@endphp
@section('content')
<div class="container-fluid legacy-page">
<div class="effect2 page-header-wrap">
<header class="page-heading">
<h1 class="page-header">{{ $page_title }}</h1>
<p>Most popular artworks which users added in their favourites</p>
</header>
</div>
<x-nova-page-header
section="Favourites"
:title="$page_title"
icon="fa-heart"
:breadcrumbs="$headerBreadcrumbs"
description="Most popular artworks which users added in their favourites."
headerClass="pb-6"
/>
<section class="px-6 pt-8 md:px-10">
@if ($artworks && $artworks->count())
<div class="container_photo gallery_box">
<div class="grid-sizer"></div>
@foreach ($artworks as $art)
@include('legacy::_artwork_card', ['art' => $art])
@endforeach
</div>
<div class="paginationMenu text-center">
{{ $artworks->withQueryString()->links('pagination::bootstrap-4') }}
</div>
<div
data-react-masonry-gallery
data-artworks="{{ json_encode($galleryArtworks) }}"
data-gallery-type="top-favourites"
@if ($galleryNextPageUrl) data-next-page-url="{{ $galleryNextPageUrl }}" @endif
data-limit="21"
class="min-h-32"
></div>
@else
<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 class="rounded-xl border border-white/[0.06] bg-white/[0.02] px-8 py-12 text-center">
<p class="text-white/40 text-sm">No artworks have been favourited yet.</p>
<p class="text-white/25 text-xs mt-1">Once members start saving artworks, they will appear here.</p>
</div>
@endif
</div>
</section>
@endsection
@push('styles')
<style>
@media (min-width: 1024px) {
[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)); }
}
@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)); }
}
@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)); }
}
</style>
@endpush
@push('scripts')
@vite('resources/js/entry-masonry-gallery.jsx')
@endpush