Homepage
- Add HomepageService with hero, trending (award-weighted), fresh uploads,
popular tags, creator spotlight (weekly uploads ranking), and news sections
- Add React components: HomePage, HomeHero, HomeTrending, HomeFresh,
HomeTags, HomeCreators, HomeNews (lazy-loaded below the fold)
- Wire home.blade.php with JSON props, SEO meta, JSON-LD, and hero preload
- Add HomePage.jsx to vite.config.js inputs
Profile page
- Hero banner with random user artwork as background + dark gradient overlay
- Favourites section uses real Artwork models + <x-artwork-card> for CDN URLs
- Newest artworks grid: gallery-grid → grid grid-cols-2 gap-4
Edit Profile page (user.blade.php)
- Add hero banner (featured wallpaper/photography via artwork_features,
content_type_id IN [2,3]) sourced in UserController
- Remove bg-deep from outer wrapper; card backgrounds: bg-panel → bg-nova-800
- Remove stray AI-generated tag fragment from template
Author profile links
- Fix all /@username routes in: HomepageService, MonthlyCommentatorsController,
LatestCommentsController, MyBuddiesController and corresponding blade views
Legacy view namespace
- Register View::addNamespace('legacy', resource_path('views/_legacy'))
in AppServiceProvider::boot()
- Convert all view('legacy.x') and @include('legacy.x') calls to legacy::x
- Migrate legacy views to resources/views/_legacy/ with namespace support
73 lines
2.7 KiB
JavaScript
73 lines
2.7 KiB
JavaScript
import React from 'react'
|
|
|
|
const AVATAR_FALLBACK = 'https://files.skinbase.org/avatars/default.webp'
|
|
|
|
function CreatorCard({ creator }) {
|
|
return (
|
|
<article className="group relative flex flex-col items-center gap-3 overflow-hidden rounded-xl bg-panel p-5 shadow-sm text-center transition hover:ring-1 hover:ring-nova-500">
|
|
{/* Background artwork thumbnail */}
|
|
{creator.bg_thumb && (
|
|
<>
|
|
<img
|
|
src={creator.bg_thumb}
|
|
alt=""
|
|
aria-hidden="true"
|
|
className="pointer-events-none absolute inset-0 h-full w-full object-cover opacity-50 transition duration-500 group-hover:opacity-20 group-hover:scale-105"
|
|
loading="lazy"
|
|
decoding="async"
|
|
/>
|
|
<div className="pointer-events-none absolute inset-0 bg-gradient-to-t from-panel via-panel/80 to-panel/60" />
|
|
</>
|
|
)}
|
|
|
|
{/* Content */}
|
|
<a href={creator.url} className="relative block">
|
|
<img
|
|
src={creator.avatar}
|
|
alt={creator.name}
|
|
className="mx-auto h-16 w-16 rounded-full object-cover ring-4 bg-nova-800/80 ring-nova-800"
|
|
loading="lazy"
|
|
decoding="async"
|
|
onError={(e) => { e.currentTarget.src = AVATAR_FALLBACK }}
|
|
/>
|
|
<h3 className="mt-2 text-sm font-semibold text-white">{creator.name}</h3>
|
|
</a>
|
|
<div className="relative flex flex-wrap justify-center gap-3 text-xs text-soft">
|
|
<span title="Total uploads">📁 {creator.uploads}</span>
|
|
{creator.weekly_uploads > 0 && (
|
|
<span title="Uploads this week" className="text-accent font-semibold">↑{creator.weekly_uploads} this week</span>
|
|
)}
|
|
<span title="Views">👁 {creator.views.toLocaleString()}</span>
|
|
{creator.awards > 0 && <span title="Awards">🏆 {creator.awards}</span>}
|
|
</div>
|
|
<a
|
|
href={creator.url}
|
|
className="relative mt-1 rounded-lg bg-nova-700 px-4 py-1.5 text-xs font-semibold text-white transition hover:bg-nova-600"
|
|
>
|
|
View Profile
|
|
</a>
|
|
</article>
|
|
)
|
|
}
|
|
|
|
export default function HomeCreators({ creators }) {
|
|
if (!Array.isArray(creators) || creators.length === 0) return null
|
|
|
|
return (
|
|
<section className="mt-14 px-4 sm:px-6 lg:px-8">
|
|
<div className="mb-5 flex items-center justify-between">
|
|
<h2 className="text-xl font-bold text-white">👤 Creator Spotlight</h2>
|
|
<a href="/members" className="text-sm text-nova-300 hover:text-white transition">
|
|
All creators →
|
|
</a>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-6">
|
|
{creators.map((c) => (
|
|
<CreatorCard key={c.id} creator={c} />
|
|
))}
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|