246 lines
17 KiB
PHP
246 lines
17 KiB
PHP
@extends('layouts.nova')
|
|
|
|
<?php $useUnifiedSeo = true; ?>
|
|
|
|
@section('main-class', '')
|
|
|
|
@section('content')
|
|
<?php
|
|
$initialPayload = $initialPayload ?? [
|
|
'data' => [],
|
|
'meta' => ['current_page' => 1, 'last_page' => 1, 'per_page' => 24, 'total' => 0],
|
|
'summary' => ['total_categories' => 0, 'total_artworks' => 0],
|
|
'popular_categories' => [],
|
|
'request' => ['query' => '', 'sort' => 'popular', 'page' => 1, 'per_page' => 24],
|
|
];
|
|
|
|
$categories = $initialPayload['data'] ?? [];
|
|
$meta = $initialPayload['meta'] ?? ['current_page' => 1, 'last_page' => 1, 'per_page' => 24, 'total' => 0];
|
|
$summary = $initialPayload['summary'] ?? ['total_categories' => 0, 'total_artworks' => 0];
|
|
$popularCategories = $initialPayload['popular_categories'] ?? [];
|
|
$requestState = $initialPayload['request'] ?? ['query' => '', 'sort' => 'popular', 'page' => 1, 'per_page' => 24];
|
|
|
|
$query = (string) ($requestState['query'] ?? '');
|
|
$sort = (string) ($requestState['sort'] ?? 'popular');
|
|
$currentPage = (int) ($meta['current_page'] ?? 1);
|
|
$lastPage = (int) ($meta['last_page'] ?? 1);
|
|
|
|
$buildCategoriesUrl = function (int $page) use ($query, $sort): string {
|
|
$params = [];
|
|
|
|
if ($page > 1) {
|
|
$params['page'] = $page;
|
|
}
|
|
|
|
if ($sort !== 'popular') {
|
|
$params['sort'] = $sort;
|
|
}
|
|
|
|
if ($query !== '') {
|
|
$params['q'] = $query;
|
|
}
|
|
|
|
$queryString = http_build_query($params);
|
|
|
|
return $queryString === ''
|
|
? url('/categories')
|
|
: url('/categories') . '?' . $queryString;
|
|
};
|
|
|
|
$categoryStyles = [
|
|
'wallpapers' => ['badge' => 'from-cyan-400/90 to-sky-500/90', 'overlay' => 'from-sky-950/10 via-slate-950/12 to-slate-950/92'],
|
|
'skins' => ['badge' => 'from-orange-400/90 to-amber-500/90', 'overlay' => 'from-orange-950/10 via-slate-950/12 to-slate-950/92'],
|
|
'photography' => ['badge' => 'from-emerald-400/90 to-teal-500/90', 'overlay' => 'from-emerald-950/10 via-slate-950/12 to-slate-950/92'],
|
|
'other' => ['badge' => 'from-fuchsia-400/90 to-rose-500/90', 'overlay' => 'from-rose-950/10 via-slate-950/12 to-slate-950/92'],
|
|
'default' => ['badge' => 'from-cyan-400/90 to-orange-400/90', 'overlay' => 'from-slate-900/10 via-slate-950/12 to-slate-950/92'],
|
|
];
|
|
?>
|
|
|
|
<script id="categories-page-props" type="application/json">
|
|
{!! json_encode([
|
|
'apiUrl' => route('api.categories.index'),
|
|
'pageTitle' => $page_title ?? 'Categories',
|
|
'pageDescription' => $page_meta_description ?? null,
|
|
'initialData' => $initialPayload,
|
|
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP) !!}
|
|
</script>
|
|
|
|
<div id="categories-page-root" class="min-h-screen bg-[radial-gradient(circle_at_top,rgba(34,211,238,0.14),transparent_28%),radial-gradient(circle_at_80%_20%,rgba(249,115,22,0.16),transparent_30%),linear-gradient(180deg,#050b13_0%,#09111c_42%,#050913_100%)]">
|
|
<div class="pb-24 text-white">
|
|
<section class="relative overflow-hidden">
|
|
<div class="absolute inset-x-0 top-0 h-[28rem] bg-[radial-gradient(circle_at_top_left,rgba(34,211,238,0.12),transparent_38%),radial-gradient(circle_at_top_right,rgba(249,115,22,0.14),transparent_34%)]"></div>
|
|
<div class="relative w-full px-6 pb-8 pt-14 sm:px-8 sm:pt-20 xl:px-10 2xl:px-14 lg:pt-24">
|
|
<div class="grid gap-8 lg:grid-cols-[minmax(0,1.2fr)_20rem] lg:items-end">
|
|
<div>
|
|
<div class="inline-flex rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-xs font-semibold uppercase tracking-[0.24em] text-white/50 backdrop-blur-sm">
|
|
Category directory
|
|
</div>
|
|
<h1 class="mt-5 max-w-4xl text-4xl font-semibold tracking-[-0.05em] text-white sm:text-5xl lg:text-6xl">
|
|
{{ $page_title ?? 'Categories' }}
|
|
</h1>
|
|
<p class="mt-5 max-w-2xl text-base leading-8 text-white/62 sm:text-lg">
|
|
{{ $page_meta_description ?? 'Browse all wallpapers, skins, themes and digital art categories' }}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="grid gap-4 sm:grid-cols-3 lg:grid-cols-1">
|
|
<div class="rounded-[24px] border border-white/10 bg-black/22 p-5 backdrop-blur-md shadow-[0_24px_60px_rgba(0,0,0,0.24)]">
|
|
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-white/40">Categories</p>
|
|
<p class="mt-3 text-3xl font-semibold tracking-[-0.04em] text-white">{{ number_format((int) ($summary['total_categories'] ?? 0)) }}</p>
|
|
</div>
|
|
<div class="rounded-[24px] border border-white/10 bg-black/22 p-5 backdrop-blur-md shadow-[0_24px_60px_rgba(0,0,0,0.24)]">
|
|
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-white/40">Artworks indexed</p>
|
|
<p class="mt-3 text-3xl font-semibold tracking-[-0.04em] text-white">{{ number_format((int) ($summary['total_artworks'] ?? 0)) }}</p>
|
|
</div>
|
|
<div class="rounded-[24px] border border-white/10 bg-black/22 p-5 backdrop-blur-md shadow-[0_24px_60px_rgba(0,0,0,0.24)]">
|
|
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-white/40">View</p>
|
|
<p class="mt-3 text-3xl font-semibold tracking-[-0.04em] text-white">Grid</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<form method="GET" action="{{ url('/categories') }}" class="mt-10 rounded-[30px] border border-white/10 bg-black/25 p-4 shadow-[0_30px_80px_rgba(0,0,0,0.25)] backdrop-blur-xl sm:p-5">
|
|
<div class="grid gap-4 lg:grid-cols-[minmax(0,1fr)_16rem] lg:items-center">
|
|
<label class="relative block">
|
|
<span class="pointer-events-none absolute left-4 top-1/2 -translate-y-1/2 text-white/35">
|
|
<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="h-5 w-5">
|
|
<path fill-rule="evenodd" d="M8.5 3a5.5 5.5 0 1 0 3.473 9.765l3.63 3.63a.75.75 0 1 0 1.06-1.06l-3.63-3.63A5.5 5.5 0 0 0 8.5 3Zm-4 5.5a4 4 0 1 1 8 0 4 4 0 0 1-8 0Z" clip-rule="evenodd" />
|
|
</svg>
|
|
</span>
|
|
<input
|
|
type="search"
|
|
name="q"
|
|
value="{{ $query }}"
|
|
placeholder="Search categories"
|
|
aria-label="Search categories"
|
|
class="h-14 w-full rounded-2xl border border-white/10 bg-white/[0.04] pl-12 pr-4 text-sm text-white placeholder:text-white/28 focus:border-cyan-300/45 focus:outline-none focus:ring-2 focus:ring-cyan-300/15"
|
|
/>
|
|
</label>
|
|
|
|
<label class="block">
|
|
<span class="mb-2 block text-xs font-semibold uppercase tracking-[0.2em] text-white/38">Sort by</span>
|
|
<select name="sort" aria-label="Sort categories" class="h-14 w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 text-sm text-white focus:border-orange-300/45 focus:outline-none focus:ring-2 focus:ring-orange-300/12">
|
|
<option value="popular" @selected($sort === 'popular') class="bg-slate-950 text-white">Popular</option>
|
|
<option value="az" @selected($sort === 'az') class="bg-slate-950 text-white">A-Z</option>
|
|
<option value="artworks" @selected($sort === 'artworks') class="bg-slate-950 text-white">Most artworks</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="w-full px-6 sm:px-8 xl:px-10 2xl:px-14">
|
|
@if ($query === '' && count($popularCategories) > 0)
|
|
<div class="mb-10 rounded-[28px] border border-white/10 bg-white/[0.03] p-5 shadow-[0_24px_60px_rgba(0,0,0,0.18)] backdrop-blur-sm">
|
|
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
|
<div>
|
|
<p class="text-xs font-semibold uppercase tracking-[0.22em] text-white/38">Popular categories</p>
|
|
<h2 class="mt-2 text-2xl font-semibold tracking-[-0.04em] text-white">Start with the busiest destinations</h2>
|
|
</div>
|
|
<div class="flex flex-wrap gap-3">
|
|
@foreach ($popularCategories as $category)
|
|
<a href="{{ $category['url'] }}" class="inline-flex items-center gap-2 rounded-full border border-white/10 bg-black/20 px-4 py-2 text-sm text-white/72 transition hover:border-white/20 hover:bg-white/[0.05] hover:text-white">
|
|
<span>{{ $category['name'] }}</span>
|
|
<span class="text-white/38">{{ number_format((int) ($category['artwork_count'] ?? 0)) }}</span>
|
|
</a>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="mb-6 flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
|
|
<div>
|
|
<p class="text-xs font-semibold uppercase tracking-[0.22em] text-white/38">Directory results</p>
|
|
<h2 class="mt-2 text-2xl font-semibold tracking-[-0.04em] text-white">{{ number_format((int) ($meta['total'] ?? 0)) }} categories visible</h2>
|
|
</div>
|
|
<p class="text-sm text-white/52">
|
|
@if ((int) ($meta['total'] ?? 0) > 0)
|
|
Showing {{ number_format($categories === [] ? 0 : 1) }} to {{ number_format(count($categories)) }} of {{ number_format((int) ($meta['total'] ?? 0)) }} categories.
|
|
@else
|
|
Browse all wallpapers, skins, themes and digital art categories.
|
|
@endif
|
|
</p>
|
|
</div>
|
|
|
|
@if ((int) ($meta['total'] ?? 0) === 0)
|
|
<div class="rounded-[28px] border border-dashed border-white/14 bg-black/20 px-6 py-14 text-center backdrop-blur-sm">
|
|
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-white/35">No matching categories</p>
|
|
<h2 class="mt-3 text-2xl font-semibold tracking-[-0.03em] text-white">Nothing matched "{{ $query }}"</h2>
|
|
<p class="mx-auto mt-3 max-w-xl text-sm leading-7 text-white/58">
|
|
Try a shorter term or switch sorting to browse the full category directory again.
|
|
</p>
|
|
</div>
|
|
@else
|
|
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
|
|
@foreach ($categories as $index => $category)
|
|
@php
|
|
$contentTypeSlug = $category['content_type']['slug'] ?? 'default';
|
|
$contentTypeName = $category['content_type']['name'] ?? 'Category';
|
|
$style = $categoryStyles[$contentTypeSlug] ?? $categoryStyles['default'];
|
|
@endphp
|
|
<a
|
|
href="{{ $category['url'] }}"
|
|
aria-label="Browse {{ $category['name'] }} category"
|
|
class="group relative block cursor-pointer overflow-hidden rounded-2xl transition duration-300 ease-out hover:-translate-y-1 hover:scale-[1.01] hover:shadow-[0_0_28px_rgba(125,211,252,0.16)]"
|
|
>
|
|
<div class="relative aspect-[4/5] overflow-hidden rounded-2xl border border-white/10 bg-slate-950/80">
|
|
<img
|
|
src="{{ $category['cover_image'] }}"
|
|
alt="Cover artwork for {{ $category['name'] }}"
|
|
loading="lazy"
|
|
class="h-full w-full object-cover transition duration-500 group-hover:scale-110"
|
|
/>
|
|
|
|
<div class="absolute inset-0 bg-gradient-to-b {{ $style['overlay'] }} transition duration-500 group-hover:from-black/20 group-hover:to-black/90"></div>
|
|
<div class="absolute inset-0 bg-[radial-gradient(circle_at_top,rgba(255,255,255,0.22),transparent_42%)] opacity-0 transition duration-500 group-hover:opacity-100"></div>
|
|
<div class="absolute inset-x-0 top-0 flex items-center justify-between gap-3 p-4">
|
|
<span class="inline-flex rounded-full bg-gradient-to-r {{ $style['badge'] }} px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-950 shadow-[0_10px_24px_rgba(0,0,0,0.24)]">
|
|
{{ $contentTypeName }}
|
|
</span>
|
|
<span class="rounded-full border border-white/15 bg-black/25 px-3 py-1 text-[11px] font-medium uppercase tracking-[0.18em] text-white/78 backdrop-blur">
|
|
{{ number_format((int) ($category['artwork_count'] ?? 0)) }} artworks
|
|
</span>
|
|
</div>
|
|
|
|
<div class="absolute inset-x-0 bottom-0 p-4 sm:p-5">
|
|
<div class="rounded-[22px] border border-white/10 bg-black/30 p-4 backdrop-blur-md transition duration-300 group-hover:border-white/20 group-hover:bg-black/42">
|
|
<div class="mb-3 h-px w-14 bg-gradient-to-r from-white/70 to-transparent transition duration-300 group-hover:w-24"></div>
|
|
<h3 class="text-lg font-semibold tracking-[-0.02em] text-white sm:text-xl">{{ $category['name'] }}</h3>
|
|
<p class="mt-2 text-sm leading-6 text-white/65">
|
|
Explore {{ $category['name'] }} across wallpapers, skins, themes, and digital art collections.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
@endforeach
|
|
</div>
|
|
|
|
<div class="mt-10 flex flex-col items-center justify-center gap-3 rounded-[24px] border border-white/8 bg-black/18 px-4 py-5 backdrop-blur-sm">
|
|
<p class="text-sm text-white/46">
|
|
Loaded through page {{ number_format($currentPage) }} of {{ number_format($lastPage) }}
|
|
</p>
|
|
<div class="flex flex-wrap items-center justify-center gap-2">
|
|
@if ($currentPage > 1)
|
|
<a href="{{ $buildCategoriesUrl($currentPage - 1) }}" class="inline-flex items-center justify-center rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-sm text-white/72 transition hover:border-white/20 hover:bg-white/[0.08] hover:text-white">Previous</a>
|
|
@endif
|
|
|
|
<span class="inline-flex items-center justify-center rounded-full border border-white/10 bg-black/25 px-4 py-2 text-sm text-white/72">
|
|
Page {{ number_format($currentPage) }} / {{ number_format($lastPage) }}
|
|
</span>
|
|
|
|
@if ($currentPage < $lastPage)
|
|
<a href="{{ $buildCategoriesUrl($currentPage + 1) }}" class="inline-flex items-center justify-center rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-sm text-white/72 transition hover:border-white/20 hover:bg-white/[0.08] hover:text-white">Next</a>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</section>
|
|
</div>
|
|
</div>
|
|
|
|
@vite(['resources/js/Pages/CategoriesPage.jsx'])
|
|
@endsection
|