feat: increase gallery grid from 4 to 5 columns per row on desktopfeat: increase gallery grid from 4 to 5 columns per row on desktop
This commit is contained in:
112
resources/views/web/authors/top.blade.php
Normal file
112
resources/views/web/authors/top.blade.php
Normal file
@@ -0,0 +1,112 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- ── Hero header ── --}}
|
||||
<div class="px-6 pt-10 pb-6 md:px-10">
|
||||
<div class="flex flex-col sm:flex-row sm:items-end sm:justify-between gap-4">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-widest text-white/30 mb-1">Community</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight">Top Authors</h1>
|
||||
<p class="mt-1 text-sm text-white/50">Most popular members ranked by artwork {{ $metric === 'downloads' ? 'downloads' : 'views' }}.</p>
|
||||
</div>
|
||||
|
||||
{{-- Metric switcher --}}
|
||||
<nav class="flex items-center gap-2" aria-label="Ranking metric">
|
||||
<a href="{{ request()->fullUrlWithQuery(['metric' => 'views']) }}"
|
||||
class="inline-flex items-center gap-1.5 rounded-full px-4 py-1.5 text-xs font-medium border transition-colors
|
||||
{{ $metric === 'views' ? 'bg-sky-500/15 text-sky-300 border-sky-500/30' : 'border-white/[0.08] bg-white/[0.04] text-white/55 hover:text-white hover:bg-white/[0.08]' }}">
|
||||
<svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
|
||||
</svg>
|
||||
Views
|
||||
</a>
|
||||
<a href="{{ request()->fullUrlWithQuery(['metric' => 'downloads']) }}"
|
||||
class="inline-flex items-center gap-1.5 rounded-full px-4 py-1.5 text-xs font-medium border transition-colors
|
||||
{{ $metric === 'downloads' ? 'bg-emerald-500/15 text-emerald-300 border-emerald-500/30' : 'border-white/[0.08] bg-white/[0.04] text-white/55 hover:text-white hover:bg-white/[0.08]' }}">
|
||||
<svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
|
||||
</svg>
|
||||
Downloads
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── Leaderboard ── --}}
|
||||
<div class="px-6 pb-16 md:px-10">
|
||||
@php $offset = ($authors->currentPage() - 1) * $authors->perPage(); @endphp
|
||||
|
||||
@if ($authors->isNotEmpty())
|
||||
<div class="rounded-xl border border-white/[0.06] overflow-hidden">
|
||||
|
||||
{{-- Table header --}}
|
||||
<div class="grid grid-cols-[3rem_1fr_auto] items-center gap-4 px-5 py-3 bg-white/[0.03] border-b border-white/[0.06]">
|
||||
<span class="text-xs font-semibold uppercase tracking-widest text-white/30 text-center">#</span>
|
||||
<span class="text-xs font-semibold uppercase tracking-widest text-white/30">Author</span>
|
||||
<span class="text-xs font-semibold uppercase tracking-widest text-white/30 text-right">
|
||||
{{ $metric === 'downloads' ? 'Downloads' : 'Views' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{-- Rows --}}
|
||||
<div class="divide-y divide-white/[0.04]">
|
||||
@foreach ($authors as $i => $author)
|
||||
@php
|
||||
$rank = $offset + $i + 1;
|
||||
$profileUrl = ($author->username ?? null)
|
||||
? '/@' . $author->username
|
||||
: '/profile/' . (int) $author->user_id;
|
||||
$avatarUrl = \App\Support\AvatarUrl::forUser((int) $author->user_id, null, 40);
|
||||
@endphp
|
||||
<div class="grid grid-cols-[3rem_1fr_auto] items-center gap-4 px-5 py-4
|
||||
{{ $rank <= 3 ? 'bg-white/[0.015]' : '' }} hover:bg-white/[0.03] transition-colors">
|
||||
|
||||
{{-- Rank badge --}}
|
||||
<div class="text-center">
|
||||
@if ($rank === 1)
|
||||
<span class="inline-flex items-center justify-center w-7 h-7 rounded-full bg-amber-400/15 text-amber-300 text-xs font-bold ring-1 ring-amber-400/30">1</span>
|
||||
@elseif ($rank === 2)
|
||||
<span class="inline-flex items-center justify-center w-7 h-7 rounded-full bg-slate-400/15 text-slate-300 text-xs font-bold ring-1 ring-slate-400/30">2</span>
|
||||
@elseif ($rank === 3)
|
||||
<span class="inline-flex items-center justify-center w-7 h-7 rounded-full bg-orange-700/20 text-orange-400 text-xs font-bold ring-1 ring-orange-600/30">3</span>
|
||||
@else
|
||||
<span class="text-sm text-white/30 font-medium">{{ $rank }}</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Author info --}}
|
||||
<a href="{{ $profileUrl }}" class="flex items-center gap-3 min-w-0 hover:opacity-90 transition-opacity">
|
||||
<img src="{{ $avatarUrl }}" alt="{{ $author->uname }}"
|
||||
class="w-9 h-9 rounded-full object-cover flex-shrink-0 ring-1 ring-white/[0.08]">
|
||||
<div class="min-w-0">
|
||||
<div class="truncate text-sm font-semibold text-white/90">{{ $author->uname ?? 'Unknown' }}</div>
|
||||
@if (!empty($author->username))
|
||||
<div class="truncate text-xs text-white/35">{{ '@' . $author->username }}</div>
|
||||
@endif
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Metric count --}}
|
||||
<div class="text-right flex-shrink-0">
|
||||
<span class="text-sm font-semibold {{ $metric === 'downloads' ? 'text-emerald-400' : 'text-sky-400' }}">
|
||||
{{ number_format($author->total ?? 0) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 flex justify-center">
|
||||
{{ $authors->withQueryString()->links() }}
|
||||
</div>
|
||||
@else
|
||||
<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 authors found.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
82
resources/views/web/comments/latest.blade.php
Normal file
82
resources/views/web/comments/latest.blade.php
Normal file
@@ -0,0 +1,82 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- ── 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">Community</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight">Latest Comments</h1>
|
||||
<p class="mt-1 text-sm text-white/50">Most recent artwork comments from the community.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── Comment cards grid ── --}}
|
||||
<div class="px-6 pb-16 md:px-10">
|
||||
@if ($comments->isNotEmpty())
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5">
|
||||
@foreach ($comments as $comment)
|
||||
@php
|
||||
$artUrl = '/art/' . (int)($comment->id ?? 0) . '/' . ($comment->artwork_slug ?? 'artwork');
|
||||
$userUrl = '/profile/' . (int)($comment->commenter_id ?? 0) . '/' . rawurlencode($comment->uname ?? 'user');
|
||||
$avatarUrl = \App\Support\AvatarUrl::forUser((int)($comment->commenter_id ?? 0), $comment->icon ?? null, 40);
|
||||
$ago = \Carbon\Carbon::parse($comment->datetime ?? now())->diffForHumans();
|
||||
$snippet = \Illuminate\Support\Str::limit(strip_tags($comment->comment_description ?? ''), 160);
|
||||
@endphp
|
||||
|
||||
<article class="flex flex-col rounded-xl border border-white/[0.06] bg-white/[0.03] hover:border-white/[0.1] hover:bg-white/[0.05] transition-all duration-200 overflow-hidden">
|
||||
|
||||
{{-- Artwork thumbnail --}}
|
||||
@if (!empty($comment->thumb))
|
||||
<a href="{{ $artUrl }}" class="block overflow-hidden bg-neutral-900 flex-shrink-0">
|
||||
<img src="{{ $comment->thumb }}" alt="{{ $comment->name ?? 'Artwork' }}"
|
||||
class="w-full h-36 object-cover transition-transform duration-300 hover:scale-[1.03]"
|
||||
loading="lazy">
|
||||
</a>
|
||||
@endif
|
||||
|
||||
<div class="flex flex-col flex-1 p-4 gap-3">
|
||||
|
||||
{{-- Commenter row --}}
|
||||
<div class="flex items-center gap-2.5">
|
||||
<a href="{{ $userUrl }}" class="flex-shrink-0">
|
||||
<img src="{{ $avatarUrl }}" alt="{{ $comment->uname ?? 'User' }}"
|
||||
class="w-8 h-8 rounded-full object-cover ring-1 ring-white/[0.08]">
|
||||
</a>
|
||||
<div class="min-w-0 flex-1">
|
||||
<a href="{{ $userUrl }}" class="block truncate text-xs font-semibold text-white/85 hover:text-white transition-colors">
|
||||
{{ $comment->uname ?? 'Unknown' }}
|
||||
</a>
|
||||
<span class="text-[10px] text-white/35">{{ $ago }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Comment text --}}
|
||||
<p class="flex-1 text-sm text-white/60 leading-relaxed line-clamp-4">{{ $snippet }}</p>
|
||||
|
||||
{{-- Artwork link footer --}}
|
||||
@if (!empty($comment->name))
|
||||
<a href="{{ $artUrl }}"
|
||||
class="mt-auto inline-flex items-center gap-1.5 text-xs text-sky-400/70 hover:text-sky-300 transition-colors truncate">
|
||||
<svg class="w-3.5 h-3.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
<span class="truncate">{{ $comment->name }}</span>
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</article>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="mt-10 flex justify-center">
|
||||
{{ $comments->withQueryString()->links() }}
|
||||
</div>
|
||||
@else
|
||||
<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 comments found.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
90
resources/views/web/comments/monthly.blade.php
Normal file
90
resources/views/web/comments/monthly.blade.php
Normal file
@@ -0,0 +1,90 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- ── Hero header ── --}}
|
||||
<div class="px-6 pt-10 pb-6 md:px-10">
|
||||
<div class="flex flex-col sm:flex-row sm:items-end sm:justify-between gap-4">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-widest text-white/30 mb-1">Community</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight">Monthly Top Commentators</h1>
|
||||
<p class="mt-1 text-sm text-white/50">Members who posted the most comments in the last 30 days.</p>
|
||||
</div>
|
||||
<span class="flex-shrink-0 inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-medium bg-violet-500/10 text-violet-300 ring-1 ring-violet-500/25">
|
||||
<svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"/>
|
||||
</svg>
|
||||
Last 30 days
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── Leaderboard ── --}}
|
||||
<div class="px-6 pb-16 md:px-10">
|
||||
@php $offset = ($rows->currentPage() - 1) * $rows->perPage(); @endphp
|
||||
|
||||
@if ($rows->isNotEmpty())
|
||||
<div class="rounded-xl border border-white/[0.06] overflow-hidden">
|
||||
|
||||
{{-- Table header --}}
|
||||
<div class="grid grid-cols-[3rem_1fr_auto] items-center gap-4 px-5 py-3 bg-white/[0.03] border-b border-white/[0.06]">
|
||||
<span class="text-xs font-semibold uppercase tracking-widest text-white/30 text-center">#</span>
|
||||
<span class="text-xs font-semibold uppercase tracking-widest text-white/30">Member</span>
|
||||
<span class="text-xs font-semibold uppercase tracking-widest text-white/30 text-right">Comments</span>
|
||||
</div>
|
||||
|
||||
{{-- Rows --}}
|
||||
<div class="divide-y divide-white/[0.04]">
|
||||
@foreach ($rows as $i => $row)
|
||||
@php
|
||||
$rank = $offset + $i + 1;
|
||||
$profileUrl = '/profile/' . (int)($row->user_id ?? 0) . '/' . rawurlencode($row->uname ?? 'user');
|
||||
$avatarUrl = \App\Support\AvatarUrl::forUser((int)($row->user_id ?? 0), null, 40);
|
||||
@endphp
|
||||
<div class="grid grid-cols-[3rem_1fr_auto] items-center gap-4 px-5 py-4
|
||||
{{ $rank <= 3 ? 'bg-white/[0.015]' : '' }} hover:bg-white/[0.03] transition-colors">
|
||||
|
||||
{{-- Rank badge --}}
|
||||
<div class="text-center">
|
||||
@if ($rank === 1)
|
||||
<span class="inline-flex items-center justify-center w-7 h-7 rounded-full bg-amber-400/15 text-amber-300 text-xs font-bold ring-1 ring-amber-400/30">1</span>
|
||||
@elseif ($rank === 2)
|
||||
<span class="inline-flex items-center justify-center w-7 h-7 rounded-full bg-slate-400/15 text-slate-300 text-xs font-bold ring-1 ring-slate-400/30">2</span>
|
||||
@elseif ($rank === 3)
|
||||
<span class="inline-flex items-center justify-center w-7 h-7 rounded-full bg-orange-700/20 text-orange-400 text-xs font-bold ring-1 ring-orange-600/30">3</span>
|
||||
@else
|
||||
<span class="text-sm text-white/30 font-medium">{{ $rank }}</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Member info --}}
|
||||
<a href="{{ $profileUrl }}" class="flex items-center gap-3 min-w-0 hover:opacity-90 transition-opacity">
|
||||
<img src="{{ $avatarUrl }}" alt="{{ $row->uname ?? 'User' }}"
|
||||
class="w-9 h-9 rounded-full object-cover flex-shrink-0 ring-1 ring-white/[0.08]">
|
||||
<div class="min-w-0">
|
||||
<div class="truncate text-sm font-semibold text-white/90">{{ $row->uname ?? 'Unknown' }}</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Comment count --}}
|
||||
<div class="text-right flex-shrink-0">
|
||||
<span class="text-sm font-semibold text-violet-400">
|
||||
{{ number_format((int)($row->num_comments ?? 0)) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 flex justify-center">
|
||||
{{ $rows->withQueryString()->links() }}
|
||||
</div>
|
||||
@else
|
||||
<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 comment activity in the last 30 days.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
@@ -1,47 +1,111 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid legacy-page">
|
||||
<div class="effect2 page-header-wrap">
|
||||
<header class="page-heading">
|
||||
<h1 class="page-header">Daily Uploads</h1>
|
||||
<p>List of all latest uploaded Artworks - <strong>Skins</strong>, <strong>Photography</strong> and <strong>Wallpapers</strong> to Skinbase ordered by upload date.</p>
|
||||
</header>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default uploads-panel effect2">
|
||||
<div class="panel-body">
|
||||
<b>Choose date:</b>
|
||||
<ul id="recentTab">
|
||||
@foreach($dates as $i => $d)
|
||||
<li id="tab-{{ $i+1 }}" data-iso="{{ $d['iso'] }}">{{ $d['label'] }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
|
||||
<div id="myContent">
|
||||
@include('web.partials.daily-uploads-grid', ['arts' => $recent])
|
||||
</div>
|
||||
{{-- ── Hero header ── --}}
|
||||
<div class="px-6 pt-10 pb-6 md:px-10">
|
||||
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-widest text-white/30 mb-1">Skinbase</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight">Daily Uploads</h1>
|
||||
<p class="mt-1 text-sm text-white/50">Browse all artworks uploaded on a specific date.</p>
|
||||
</div>
|
||||
<a href="{{ route('uploads.latest') }}"
|
||||
class="inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium border border-white/[0.08] bg-white/[0.04] text-white/70 hover:bg-white/[0.08] hover:text-white transition-colors">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
Latest Uploads
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── Date strip ── --}}
|
||||
<div class="px-6 md:px-10 pb-5">
|
||||
<div class="flex items-center gap-1.5 overflow-x-auto pb-1 scrollbar-none" id="dateStrip">
|
||||
@foreach($dates as $i => $d)
|
||||
<button type="button"
|
||||
data-iso="{{ $d['iso'] }}"
|
||||
id="tab-{{ $i+1 }}"
|
||||
class="flex-shrink-0 rounded-lg px-3.5 py-1.5 text-xs font-medium border transition-colors
|
||||
{{ $i === 0
|
||||
? 'bg-sky-500/15 text-sky-300 border-sky-500/30 active-date-tab'
|
||||
: 'border-white/[0.08] bg-white/[0.03] text-white/50 hover:text-white hover:bg-white/[0.07]' }}">
|
||||
@if ($i === 0)
|
||||
Today
|
||||
@elseif ($i === 1)
|
||||
Yesterday
|
||||
@else
|
||||
{{ \Carbon\Carbon::parse($d['iso'])->format('M j') }}
|
||||
@endif
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── Active date label ── --}}
|
||||
<div class="px-6 md:px-10 mb-4">
|
||||
<p id="activeDateLabel" class="text-sm text-white/40">
|
||||
Showing uploads from <strong class="text-white/70">{{ $dates[0]['label'] ?? 'today' }}</strong>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{{-- ── Grid container ── --}}
|
||||
<div id="myContent" class="px-6 pb-16 md:px-10 min-h-48">
|
||||
@include('web.partials.daily-uploads-grid', ['arts' => $recent])
|
||||
</div>
|
||||
|
||||
{{-- ── Loading overlay (hidden) ── --}}
|
||||
<template id="loadingTpl">
|
||||
<div class="flex items-center justify-center py-20 text-white/30 text-sm gap-2">
|
||||
<svg class="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
|
||||
</svg>
|
||||
Loading artworks…
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
(function(){
|
||||
function loadDate(iso, tabId){
|
||||
var el = document.getElementById('myContent');
|
||||
fetch('/daily-uploads?ajax=1&datum=' + encodeURIComponent(iso))
|
||||
.then(function(r){ return r.text(); })
|
||||
.then(function(html){ el.innerHTML = html; });
|
||||
}
|
||||
(function () {
|
||||
var endpoint = '/uploads/daily';
|
||||
var strip = document.getElementById('dateStrip');
|
||||
var content = document.getElementById('myContent');
|
||||
var dateLabel = document.getElementById('activeDateLabel');
|
||||
var loadingTpl = document.getElementById('loadingTpl');
|
||||
|
||||
document.getElementById('recentTab').addEventListener('click', function(e){
|
||||
var li = e.target.closest('li');
|
||||
if (!li) return;
|
||||
var iso = li.getAttribute('data-iso');
|
||||
loadDate(iso, li.id);
|
||||
function setActive(btn) {
|
||||
strip.querySelectorAll('button').forEach(function (b) {
|
||||
b.classList.remove('bg-sky-500/15', 'text-sky-300', 'border-sky-500/30', 'active-date-tab');
|
||||
b.classList.add('border-white/[0.08]', 'bg-white/[0.03]', 'text-white/50');
|
||||
});
|
||||
})();
|
||||
btn.classList.add('bg-sky-500/15', 'text-sky-300', 'border-sky-500/30', 'active-date-tab');
|
||||
btn.classList.remove('border-white/[0.08]', 'bg-white/[0.03]', 'text-white/50');
|
||||
}
|
||||
|
||||
function loadDate(iso, label) {
|
||||
content.innerHTML = loadingTpl.innerHTML;
|
||||
dateLabel.innerHTML = 'Showing uploads from <strong class="text-white/70">' + label + '</strong>';
|
||||
|
||||
fetch(endpoint + '?ajax=1&datum=' + encodeURIComponent(iso), {
|
||||
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||||
})
|
||||
.then(function (r) { return r.text(); })
|
||||
.then(function (html) { content.innerHTML = html; })
|
||||
.catch(function () {
|
||||
content.innerHTML = '<p class="text-center text-white/30 py-16 text-sm">Failed to load artworks.</p>';
|
||||
});
|
||||
}
|
||||
|
||||
strip.addEventListener('click', function (e) {
|
||||
var btn = e.target.closest('button[data-iso]');
|
||||
if (!btn || btn.classList.contains('active-date-tab')) return;
|
||||
setActive(btn);
|
||||
var label = btn.textContent.trim();
|
||||
loadDate(btn.getAttribute('data-iso'), label);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
|
||||
73
resources/views/web/downloads/today.blade.php
Normal file
73
resources/views/web/downloads/today.blade.php
Normal file
@@ -0,0 +1,73 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- ── Hero header ── --}}
|
||||
<div class="px-6 pt-10 pb-6 md:px-10">
|
||||
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-widest text-white/30 mb-1">Downloads</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight">Most Downloaded Today</h1>
|
||||
<p class="mt-1 text-sm text-white/50">
|
||||
Artworks downloaded the most on <time datetime="{{ now()->toDateString() }}">{{ now()->format('d F Y') }}</time>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex-shrink-0 flex items-center gap-2">
|
||||
<span class="inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-medium bg-emerald-500/10 text-emerald-300 ring-1 ring-emerald-500/25">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse"></span>
|
||||
Live today
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── Artwork grid ── --}}
|
||||
<div class="px-6 pb-16 md:px-10">
|
||||
@if ($artworks && $artworks->isNotEmpty())
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 gap-4 md:gap-5">
|
||||
@foreach ($artworks as $art)
|
||||
@php
|
||||
$card = (object)[
|
||||
'id' => $art->id ?? null,
|
||||
'name' => $art->name ?? 'Artwork',
|
||||
'thumb' => $art->thumb ?? null,
|
||||
'thumb_srcset' => $art->thumb_srcset ?? null,
|
||||
'uname' => $art->uname ?? '',
|
||||
'category_name' => $art->category_name ?? '',
|
||||
'slug' => $art->slug ?? \Illuminate\Support\Str::slug($art->name ?? 'artwork'),
|
||||
];
|
||||
$downloads = (int) ($art->num_downloads ?? 0);
|
||||
@endphp
|
||||
|
||||
{{-- Wrap card to overlay download badge --}}
|
||||
<div class="relative">
|
||||
<x-artwork-card :art="$card" />
|
||||
@if ($downloads > 0)
|
||||
<div class="absolute top-2 left-2 z-40 pointer-events-none">
|
||||
<span class="inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[10px] font-semibold bg-black/60 text-emerald-300 backdrop-blur-sm ring-1 ring-emerald-500/30">
|
||||
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
|
||||
</svg>
|
||||
{{ number_format($downloads) }}
|
||||
</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="mt-10 flex justify-center">
|
||||
{{ $artworks->withQueryString()->links() }}
|
||||
</div>
|
||||
@else
|
||||
<div class="rounded-xl border border-white/[0.06] bg-white/[0.02] px-8 py-12 text-center">
|
||||
<svg class="mx-auto mb-3 w-10 h-10 text-white/20" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
|
||||
</svg>
|
||||
<p class="text-white/40 text-sm">No downloads recorded today yet.</p>
|
||||
<p class="text-white/25 text-xs mt-1">Check back later as the day progresses.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
@@ -7,7 +7,7 @@
|
||||
@endphp
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid legacy-page">
|
||||
<div class="min-h-screen">
|
||||
@include('web.home.featured')
|
||||
|
||||
@include('web.home.uploads')
|
||||
|
||||
@@ -1,37 +1,46 @@
|
||||
|
||||
{{-- Featured row — use Nova cards for consistent layout with browse/gallery --}}
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
@if(!empty($featured))
|
||||
<div>
|
||||
@include('web.partials._artwork_card', ['art' => $featured])
|
||||
</div>
|
||||
@else
|
||||
<div class="panel panel-default effect2">
|
||||
<div class="panel-heading"><strong>Featured Artwork</strong></div>
|
||||
<div class="panel-body text-neutral-400">No featured artwork set.</div>
|
||||
</div>
|
||||
@endif
|
||||
<section class="px-6 pt-8 pb-6 md:px-10">
|
||||
<div class="flex items-center gap-2 mb-6">
|
||||
<span class="inline-flex items-center justify-center w-7 h-7 rounded-md bg-amber-500/15 text-amber-400">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8"><path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z"/></svg>
|
||||
</span>
|
||||
<h2 class="text-base font-semibold text-white/90 tracking-wide uppercase">Featured</h2>
|
||||
</div>
|
||||
|
||||
@if(!empty($memberFeatured))
|
||||
<div>
|
||||
@include('web.partials._artwork_card', ['art' => $memberFeatured])
|
||||
</div>
|
||||
@else
|
||||
<div class="panel panel-default effect2">
|
||||
<div class="panel-heading"><strong>Member Featured</strong></div>
|
||||
<div class="panel-body text-neutral-400">No member featured artwork.</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
@if(!empty($featured))
|
||||
<div>
|
||||
@include('web.partials._artwork_card', ['art' => $featured])
|
||||
</div>
|
||||
@else
|
||||
<div class="rounded-2xl ring-1 ring-white/5 bg-white/[0.03] p-4">
|
||||
<p class="text-sm text-neutral-400">No featured artwork set.</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div>
|
||||
<div class="group relative block overflow-hidden rounded-2xl ring-1 ring-white/5 bg-black/20 shadow-lg p-4 text-center">
|
||||
<a href="{{ route('register') }}" title="Join Skinbase" class="inline-block mb-3">
|
||||
<img src="/gfx/sb_join.jpg" alt="Join SkinBase Community" class="w-full h-40 object-cover rounded-lg">
|
||||
</a>
|
||||
<div class="text-lg font-semibold text-white/90">Join Skinbase World</div>
|
||||
<p class="mt-2 text-sm text-neutral-400">Join Skinbase and be part of our community. Upload, share and explore curated photography and skins.</p>
|
||||
<a href="{{ route('register') }}" class="mt-3 inline-block px-4 py-2 rounded-md bg-sky-500 text-white">Create an account</a>
|
||||
@if(!empty($memberFeatured))
|
||||
<div>
|
||||
@include('web.partials._artwork_card', ['art' => $memberFeatured])
|
||||
</div>
|
||||
@else
|
||||
<div class="rounded-2xl ring-1 ring-white/5 bg-white/[0.03] p-4">
|
||||
<p class="text-sm text-neutral-400">No member featured artwork.</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div>
|
||||
<div class="group relative flex flex-col overflow-hidden rounded-2xl ring-1 ring-white/5 bg-white/[0.03] shadow-lg h-full">
|
||||
<a href="{{ route('register') }}" title="Join Skinbase" class="block shrink-0">
|
||||
<img src="/gfx/sb_join.jpg" alt="Join SkinBase Community" class="w-full h-48 object-cover">
|
||||
</a>
|
||||
<div class="flex flex-col flex-1 p-5 text-center">
|
||||
<div class="text-lg font-semibold text-white/90">Join Skinbase World</div>
|
||||
<p class="mt-2 text-sm text-neutral-400 flex-1">Join our community — upload, share and explore curated photography and skins.</p>
|
||||
<a href="{{ route('register') }}" class="mt-4 inline-block px-4 py-2 rounded-lg bg-sky-500 hover:bg-sky-400 transition-colors text-white text-sm font-medium">Create an account</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
48
resources/views/web/members/photos.blade.php
Normal file
48
resources/views/web/members/photos.blade.php
Normal file
@@ -0,0 +1,48 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- ── 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">Members</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight">{{ $page_title ?? 'Member Photos' }}</h1>
|
||||
<p class="mt-1 text-sm text-white/50">Artwork submitted by the Skinbase community.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── Artwork grid ── --}}
|
||||
<div class="px-6 pb-16 md:px-10">
|
||||
@php $items = is_object($artworks) && method_exists($artworks, 'toArray') ? $artworks : collect($artworks ?? []); @endphp
|
||||
|
||||
@if (!empty($artworks) && (is_countable($artworks) ? count($artworks) > 0 : true))
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 gap-4 md:gap-5">
|
||||
@foreach ($artworks as $art)
|
||||
@php
|
||||
$card = (object)[
|
||||
'id' => $art->id ?? null,
|
||||
'name' => $art->name ?? $art->title ?? 'Artwork',
|
||||
'thumb' => $art->thumb ?? $art->thumb_url ?? null,
|
||||
'thumb_srcset' => $art->thumb_srcset ?? null,
|
||||
'uname' => $art->uname ?? $art->author ?? '',
|
||||
'category_name' => $art->category_name ?? '',
|
||||
'slug' => $art->slug ?? \Illuminate\Support\Str::slug($art->name ?? 'artwork'),
|
||||
];
|
||||
@endphp
|
||||
<x-artwork-card :art="$card" />
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@if (is_object($artworks) && method_exists($artworks, 'links'))
|
||||
<div class="mt-10 flex justify-center">
|
||||
{{ $artworks->withQueryString()->links() }}
|
||||
</div>
|
||||
@endif
|
||||
@else
|
||||
<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 found.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
@@ -1,14 +1,11 @@
|
||||
@if($arts && count($arts))
|
||||
<div class="container_photo gallery_box">
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 gap-4 md:gap-5">
|
||||
@foreach($arts as $art)
|
||||
<div class="photo_frame">
|
||||
<a href="/art/{{ $art->id }}/{{ \Illuminate\Support\Str::slug($art->name ?? '') }}">
|
||||
<img src="{{ $art->thumb }}" srcset="{{ $art->thumb_srcset }}" loading="lazy" decoding="async" alt="{{ $art->name }}" class="img-responsive">
|
||||
</a>
|
||||
</div>
|
||||
<x-artwork-card :art="$art" />
|
||||
@endforeach
|
||||
</div>
|
||||
<br style="clear:both"><br>
|
||||
@else
|
||||
<p class="text-muted">No uploads for this date.</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 uploads for this date.</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
174
resources/views/web/sections.blade.php
Normal file
174
resources/views/web/sections.blade.php
Normal file
@@ -0,0 +1,174 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@php
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
// One accent colour set per content-type (cycles if more than 4)
|
||||
$accents = [
|
||||
['ring' => 'ring-sky-500/30', 'bg' => 'bg-sky-500/10', 'text' => 'text-sky-400', 'badge' => 'bg-sky-500/15 text-sky-300', 'pill' => 'hover:bg-sky-500/15 hover:text-sky-300', 'dot' => 'bg-sky-400', 'border' => 'border-sky-500/25'],
|
||||
['ring' => 'ring-violet-500/30', 'bg' => 'bg-violet-500/10', 'text' => 'text-violet-400', 'badge' => 'bg-violet-500/15 text-violet-300', 'pill' => 'hover:bg-violet-500/15 hover:text-violet-300', 'dot' => 'bg-violet-400', 'border' => 'border-violet-500/25'],
|
||||
['ring' => 'ring-amber-500/30', 'bg' => 'bg-amber-500/10', 'text' => 'text-amber-400', 'badge' => 'bg-amber-500/15 text-amber-300', 'pill' => 'hover:bg-amber-500/15 hover:text-amber-300', 'dot' => 'bg-amber-400', 'border' => 'border-amber-500/25'],
|
||||
['ring' => 'ring-emerald-500/30', 'bg' => 'bg-emerald-500/10','text' => 'text-emerald-400','badge' => 'bg-emerald-500/15 text-emerald-300','pill' => 'hover:bg-emerald-500/15 hover:text-emerald-300','dot' => 'bg-emerald-400','border' => 'border-emerald-500/25'],
|
||||
];
|
||||
|
||||
// Map content-type slug → icon SVG paths
|
||||
$typeIcons = [
|
||||
'photography' => '<path stroke-linecap="round" stroke-linejoin="round" d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"/>',
|
||||
'wallpapers' => '<path stroke-linecap="round" stroke-linejoin="round" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/>',
|
||||
'skins' => '<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>',
|
||||
'other' => '<path stroke-linecap="round" stroke-linejoin="round" d="M5 3a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V7.414A2 2 0 0020.414 6L15 .586A2 2 0 0013.586 0H5z"/>',
|
||||
];
|
||||
$defaultIcon = '<path stroke-linecap="round" stroke-linejoin="round" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>';
|
||||
@endphp
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- ── Hero header ── --}}
|
||||
<div class="px-6 pt-10 pb-6 md:px-10">
|
||||
<div class="flex flex-col sm:flex-row sm:items-end sm:justify-between gap-4">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-widest text-white/30 mb-1">Skinbase</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight">Browse Sections</h1>
|
||||
<p class="mt-1 text-sm text-white/50">Explore all artwork categories — photography, wallpapers, skins and more.</p>
|
||||
</div>
|
||||
|
||||
{{-- Quick-jump anchor links --}}
|
||||
<nav class="flex flex-wrap gap-2" aria-label="Section jump links">
|
||||
@foreach ($contentTypes as $i => $ct)
|
||||
@php $a = $accents[$i % count($accents)]; @endphp
|
||||
<a href="#section-{{ $ct->slug }}"
|
||||
class="inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-medium border border-white/[0.08] bg-white/[0.04] {{ $a['text'] }} hover:{{ $a['bg'] }} transition-colors">
|
||||
<span class="w-1.5 h-1.5 rounded-full {{ $a['dot'] }}"></span>
|
||||
{{ $ct->name }}
|
||||
</a>
|
||||
@endforeach
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── Content type sections ── --}}
|
||||
<div class="px-6 pb-16 md:px-10 space-y-14">
|
||||
|
||||
@forelse ($contentTypes as $i => $ct)
|
||||
@php
|
||||
$a = $accents[$i % count($accents)];
|
||||
$icon = $typeIcons[strtolower($ct->slug)] ?? $defaultIcon;
|
||||
$totalCount = $artworkCountsByType[$ct->id] ?? 0;
|
||||
$roots = $ct->rootCategories;
|
||||
@endphp
|
||||
|
||||
<section id="section-{{ $ct->slug }}" class="scroll-mt-20">
|
||||
|
||||
{{-- Section heading ── --}}
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="flex-shrink-0 w-10 h-10 rounded-xl {{ $a['bg'] }} {{ $a['text'] }} flex items-center justify-center ring-1 {{ $a['ring'] }}">
|
||||
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75">
|
||||
{!! $icon !!}
|
||||
</svg>
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="flex items-center gap-3 flex-wrap">
|
||||
<h2 class="text-xl font-bold text-white">{{ $ct->name }}</h2>
|
||||
@if ($totalCount > 0)
|
||||
<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium {{ $a['badge'] }}">
|
||||
{{ number_format($totalCount) }} artworks
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@if (!empty($ct->description))
|
||||
<p class="mt-0.5 text-sm text-white/45 leading-snug">{{ $ct->description }}</p>
|
||||
@endif
|
||||
</div>
|
||||
<a href="/{{ strtolower($ct->slug) }}"
|
||||
class="hidden sm:inline-flex flex-shrink-0 items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium border {{ $a['border'] }} {{ $a['text'] }} {{ $a['bg'] }} hover:brightness-110 transition-all">
|
||||
Browse all
|
||||
<svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{-- Separator line --}}
|
||||
<div class="h-px bg-white/[0.06] mb-6"></div>
|
||||
|
||||
@if ($roots->isEmpty())
|
||||
<div class="rounded-xl border border-white/[0.06] bg-white/[0.02] px-6 py-8 text-center text-sm text-white/35">
|
||||
No categories available yet.
|
||||
</div>
|
||||
@else
|
||||
{{-- Root category cards grid --}}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||||
@foreach ($roots as $root)
|
||||
@php $subCats = $root->children; @endphp
|
||||
<div class="group flex flex-col rounded-xl border border-white/[0.06] bg-white/[0.03] hover:border-white/[0.12] hover:bg-white/[0.05] transition-all duration-200 overflow-hidden">
|
||||
|
||||
{{-- Card header --}}
|
||||
<div class="px-4 pt-4 pb-3 border-b border-white/[0.05]">
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<div class="min-w-0">
|
||||
<a href="{{ $root->url }}"
|
||||
class="block text-sm font-semibold text-white/90 group-hover:{{ $a['text'] }} transition-colors leading-snug truncate">
|
||||
{{ $root->name }}
|
||||
</a>
|
||||
@if (!empty($root->description))
|
||||
<p class="mt-1 text-xs text-white/40 leading-relaxed line-clamp-2">{{ $root->description }}</p>
|
||||
@endif
|
||||
</div>
|
||||
@if (($root->artwork_count ?? 0) > 0)
|
||||
<span class="flex-shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium {{ $a['badge'] }} whitespace-nowrap">
|
||||
{{ number_format($root->artwork_count) }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Sub-category pills --}}
|
||||
<div class="px-4 py-3 flex-1">
|
||||
@if ($subCats->isEmpty())
|
||||
<span class="text-xs text-white/25 italic">No subcategories</span>
|
||||
@else
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
@foreach ($subCats as $sub)
|
||||
<a href="{{ $sub->url }}"
|
||||
title="{{ $sub->name }}{{ ($sub->artwork_count ?? 0) > 0 ? ' · ' . number_format($sub->artwork_count) . ' artworks' : '' }}"
|
||||
class="inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs text-white/55 bg-white/[0.04] border border-white/[0.06] transition-colors {{ $a['pill'] }}">
|
||||
{{ $sub->name }}
|
||||
@if (($sub->artwork_count ?? 0) > 0)
|
||||
<span class="text-white/30 text-[10px]">{{ number_format($sub->artwork_count) }}</span>
|
||||
@endif
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Card footer link --}}
|
||||
<div class="px-4 pb-3 pt-1">
|
||||
<a href="{{ $root->url }}"
|
||||
class="text-xs {{ $a['text'] }} opacity-60 hover:opacity-100 transition-opacity inline-flex items-center gap-1">
|
||||
View all
|
||||
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
{{-- Mobile browse-all link --}}
|
||||
<div class="mt-4 sm:hidden text-center">
|
||||
<a href="/{{ strtolower($ct->slug) }}"
|
||||
class="inline-flex items-center gap-1.5 rounded-lg px-4 py-2 text-sm font-medium border {{ $a['border'] }} {{ $a['text'] }} {{ $a['bg'] }}">
|
||||
Browse all {{ $ct->name }}
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</section>
|
||||
@empty
|
||||
<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 sections available.</p>
|
||||
</div>
|
||||
@endforelse
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
55
resources/views/web/uploads/latest.blade.php
Normal file
55
resources/views/web/uploads/latest.blade.php
Normal file
@@ -0,0 +1,55 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- ── Hero header ── --}}
|
||||
<div class="px-6 pt-10 pb-6 md:px-10">
|
||||
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-widest text-white/30 mb-1">Skinbase</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight">Latest Artworks</h1>
|
||||
<p class="mt-1 text-sm text-white/50">Recently uploaded Skins, Photography and Wallpapers.</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<a href="{{ route('uploads.daily') }}"
|
||||
class="inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium border border-white/[0.08] bg-white/[0.04] text-white/70 hover:bg-white/[0.08] hover:text-white transition-colors">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
Daily Uploads
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── Artwork grid ── --}}
|
||||
<div class="px-6 pb-16 md:px-10">
|
||||
@if ($artworks && $artworks->isNotEmpty())
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 gap-4 md:gap-5">
|
||||
@foreach ($artworks as $art)
|
||||
@php
|
||||
$card = (object)[
|
||||
'id' => $art->id,
|
||||
'name' => $art->name,
|
||||
'thumb' => $art->thumb_url ?? $art->thumb ?? null,
|
||||
'thumb_srcset' => $art->thumb_srcset ?? null,
|
||||
'uname' => $art->uname ?? '',
|
||||
'category_name' => $art->category_name ?? '',
|
||||
];
|
||||
@endphp
|
||||
<x-artwork-card :art="$card" />
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
{{-- Pagination --}}
|
||||
<div class="mt-10 flex justify-center">
|
||||
{{ $artworks->withQueryString()->links() }}
|
||||
</div>
|
||||
@else
|
||||
<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 found.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
Reference in New Issue
Block a user