messages implemented
This commit is contained in:
@@ -1,6 +1,16 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@section('content')
|
||||
@php
|
||||
$contentTypes = $contentTypes ?? collect([
|
||||
(object) [
|
||||
'name' => 'Categories',
|
||||
'description' => null,
|
||||
'roots' => $categories ?? collect(),
|
||||
],
|
||||
]);
|
||||
$subgroups = $subgroups ?? collect();
|
||||
@endphp
|
||||
<div class="container-fluid legacy-page">
|
||||
<div class="effect2 page-header-wrap">
|
||||
<header class="page-heading">
|
||||
|
||||
@@ -2,81 +2,23 @@
|
||||
|
||||
@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>
|
||||
{{-- Inline props for the React component --}}
|
||||
<script id="latest-comments-props" type="application/json">
|
||||
{!! json_encode($props, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP) !!}
|
||||
</script>
|
||||
|
||||
<div id="latest-comments-root" class="min-h-screen">
|
||||
{{-- SSR skeleton replaced on React hydration --}}
|
||||
<div class="px-4 pt-10 pb-20 sm:px-6 lg:px-8 max-w-5xl mx-auto">
|
||||
<div class="mb-8">
|
||||
<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">{{ $page_title }}</h1>
|
||||
<p class="mt-1 text-sm text-white/50">Most recent artwork comments from the community.</p>
|
||||
</div>
|
||||
<div class="h-8 w-8 animate-spin rounded-full border-4 border-nova-500 border-t-transparent mx-auto mt-20"></div>
|
||||
</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 = ($comment->commenter_username ?? null) ? '/@' . $comment->commenter_username : '/profile/' . (int)($comment->commenter_id ?? 0);
|
||||
$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>
|
||||
@vite(['resources/js/Pages/Community/LatestCommentsPage.jsx'])
|
||||
|
||||
@endsection
|
||||
|
||||
88
resources/views/web/creators/rising.blade.php
Normal file
88
resources/views/web/creators/rising.blade.php
Normal file
@@ -0,0 +1,88 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@section('content')
|
||||
|
||||
<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">Creators</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight flex items-center gap-3">
|
||||
<i class="fa-solid fa-arrow-trend-up text-sky-400 text-2xl"></i>
|
||||
Rising Creators
|
||||
</h1>
|
||||
<p class="mt-1 text-sm text-white/50">Creators gaining momentum with the most views over the last 90 days.</p>
|
||||
</div>
|
||||
<a href="{{ route('creators.top') }}"
|
||||
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">
|
||||
<i class="fa-solid fa-star text-xs"></i>
|
||||
Top Creators
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-6 pb-16 md:px-10">
|
||||
@php $offset = ($creators->currentPage() - 1) * $creators->perPage(); @endphp
|
||||
|
||||
@if ($creators->isNotEmpty())
|
||||
<div class="rounded-xl border border-white/[0.06] overflow-hidden">
|
||||
<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">Creator</span>
|
||||
<span class="text-xs font-semibold uppercase tracking-widest text-white/30 text-right">Recent Views</span>
|
||||
</div>
|
||||
|
||||
<div class="divide-y divide-white/[0.04]">
|
||||
@foreach ($creators as $i => $creator)
|
||||
@php
|
||||
$rank = $offset + $i + 1;
|
||||
$profileUrl = ($creator->username ?? null)
|
||||
? '/@' . $creator->username
|
||||
: '/profile/' . (int) $creator->user_id;
|
||||
$avatarUrl = \App\Support\AvatarUrl::forUser((int) $creator->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">
|
||||
|
||||
<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>
|
||||
|
||||
<a href="{{ $profileUrl }}" class="flex items-center gap-3 min-w-0 hover:opacity-90 transition-opacity">
|
||||
<img src="{{ $avatarUrl }}" alt="{{ $creator->uname }}"
|
||||
class="w-9 h-9 rounded-full object-cover ring-1 ring-white/10 shrink-0"
|
||||
onerror="this.src='https://files.skinbase.org/avatars/default.webp'" />
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-medium text-white truncate">{{ $creator->uname }}</p>
|
||||
@if($creator->username ?? null)
|
||||
<p class="text-xs text-white/40 truncate">@{{ $creator->username }}</p>
|
||||
@endif
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div class="text-right">
|
||||
<span class="text-sm font-semibold text-white/80">{{ number_format($creator->total) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 flex justify-center">
|
||||
{{ $creators->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 rising creators found yet. Check back soon!</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
73
resources/views/web/discover/index.blade.php
Normal file
73
resources/views/web/discover/index.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">Discover</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight flex items-center gap-3">
|
||||
<i class="fa-solid {{ $icon ?? 'fa-compass' }} text-sky-400 text-2xl"></i>
|
||||
{{ $page_title ?? 'Discover' }}
|
||||
</h1>
|
||||
@isset($description)
|
||||
<p class="mt-1 text-sm text-white/50">{{ $description }}</p>
|
||||
@endisset
|
||||
</div>
|
||||
|
||||
{{-- Section switcher pills --}}
|
||||
<div class="flex flex-wrap items-center gap-2 text-sm">
|
||||
@php
|
||||
$sections = [
|
||||
'trending' => ['label' => 'Trending', 'icon' => 'fa-fire'],
|
||||
'fresh' => ['label' => 'Fresh', 'icon' => 'fa-bolt'],
|
||||
'top-rated' => ['label' => 'Top Rated', 'icon' => 'fa-medal'],
|
||||
'most-downloaded' => ['label' => 'Most Downloaded', 'icon' => 'fa-download'],
|
||||
'on-this-day' => ['label' => 'On This Day', 'icon' => 'fa-calendar-day'],
|
||||
];
|
||||
$active = $section ?? '';
|
||||
@endphp
|
||||
@foreach($sections as $slug => $meta)
|
||||
<a href="{{ route('discover.' . $slug) }}"
|
||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium transition-colors
|
||||
{{ $active === $slug ? 'bg-sky-600 text-white' : 'bg-white/[0.05] text-white/60 hover:bg-white/[0.1] hover:text-white' }}">
|
||||
<i class="fa-solid {{ $meta['icon'] }} text-xs"></i>
|
||||
{{ $meta['label'] }}
|
||||
</a>
|
||||
@endforeach
|
||||
</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 for this section yet.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
40
resources/views/web/tags/index.blade.php
Normal file
40
resources/views/web/tags/index.blade.php
Normal file
@@ -0,0 +1,40 @@
|
||||
@extends('layouts.nova')
|
||||
|
||||
@section('content')
|
||||
|
||||
<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">Browse</p>
|
||||
<h1 class="text-3xl font-bold text-white leading-tight flex items-center gap-3">
|
||||
<i class="fa-solid fa-tags text-sky-400 text-2xl"></i>
|
||||
Tags
|
||||
</h1>
|
||||
<p class="mt-1 text-sm text-white/50">Browse all artwork tags on Skinbase.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-6 pb-16 md:px-10">
|
||||
@if($tags->isNotEmpty())
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@foreach($tags as $tag)
|
||||
<a href="{{ route('tags.show', $tag->slug) }}"
|
||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-white/[0.05] border border-white/[0.07]
|
||||
text-sm text-white/70 hover:bg-white/[0.1] hover:text-white transition-colors">
|
||||
<i class="fa-solid fa-hashtag text-xs text-sky-400/70"></i>
|
||||
{{ $tag->name }}
|
||||
<span class="text-xs text-white/30 ml-1">{{ number_format($tag->artworks_count) }}</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="mt-10 flex justify-center">
|
||||
{{ $tags->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 tags found.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
Reference in New Issue
Block a user