Files
SkinbaseNova/resources/js/Pages/Home/HomeWelcomeRow.jsx
Gregor Klevze 4f9b43bbba feat(homepage): Nova homepage layout — guest/auth split, mascot category tiles, 5-col artwork grids
- HomeController: is_logged_in now lives inside props JSON (not separate view var)
- HomepageService: allForUser() adds user_data, fresh, suggested_creators; auth
  payload includes is_logged_in:true; guest payload merged with is_logged_in:false
- getTrending/getFreshUploads/getFollowingFeed: limit 12→10 (2 clean rows of 5)
- New getUserData() — unread messages + notifications counts via DB
- New getSuggestedCreators() — top followed-count creators not yet followed, cached 5 min

React — new components:
- HomeWelcomeRow: greeting bar with avatar, unread message/notification badges, upload CTA
- HomeFromFollowing: art grid from followed creators with empty-state
- HomeTrendingForYou: personalized grid adapts heading/link to user's top tag
- HomeBecauseYouLike: secondary personalized section keyed on top tag
- HomeSuggestedCreators: 4-col creator cards with avatar, stats, View Profile link
- HomeCTA: gradient upload banner; guest sees Create Account second CTA
- HomeCategories: 5-tile static category grid with mascot images

React — updated:
- HomePage: split into GuestHomePage + AuthHomePage; routes on is_logged_in prop
- HomeHero: isLoggedIn prop; upload href gates on auth; CTA → /discover/trending
- HomeTrending: see-all → /discover/trending; grid 4→5 cols; slice to multiple of 5
- HomeFresh: see-all → /discover/fresh; grid 4→5 cols; slice to multiple of 5
- HomeFromFollowing/TrendingForYou/BecauseYouLike: 5-col grid, slice to multiple of 5
- HomeCategories: mascots per category (wallpapers/photography/skins/other), smaller tiles
2026-02-27 10:48:35 +01:00

75 lines
3.3 KiB
JavaScript

import React from 'react'
const AVATAR_FALLBACK = 'https://files.skinbase.org/avatars/default.webp'
export default function HomeWelcomeRow({ user_data }) {
if (!user_data) return null
const { name, avatar, messages_unread, notifications_unread, url } = user_data
const firstName = name?.split(' ')[0] || name || 'there'
return (
<section className="border-b border-white/5 bg-nova-900/60 backdrop-blur-sm">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-4">
<div className="flex flex-wrap items-center justify-between gap-3">
{/* Left: greeting */}
<div className="flex items-center gap-3">
<a href={url || '/profile'}>
<img
src={avatar || AVATAR_FALLBACK}
alt={name}
className="h-9 w-9 rounded-full object-cover ring-2 ring-white/10 hover:ring-accent/60 transition"
onError={(e) => { e.currentTarget.src = AVATAR_FALLBACK }}
/>
</a>
<div>
<p className="text-sm text-soft">Welcome back,</p>
<p className="text-sm font-semibold text-white leading-tight">{firstName}</p>
</div>
</div>
{/* Right: action badges */}
<div className="flex items-center gap-2">
{messages_unread > 0 && (
<a
href="/messages"
className="inline-flex items-center gap-1.5 rounded-lg bg-nova-800 px-3 py-1.5 text-xs font-medium text-white ring-1 ring-white/10 hover:bg-nova-700 transition"
>
<svg className="h-3.5 w-3.5 text-accent shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
{messages_unread} new
</a>
)}
{notifications_unread > 0 && (
<a
href="/notifications"
className="inline-flex items-center gap-1.5 rounded-lg bg-nova-800 px-3 py-1.5 text-xs font-medium text-white ring-1 ring-white/10 hover:bg-nova-700 transition"
>
<svg className="h-3.5 w-3.5 text-yellow-400 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
</svg>
{notifications_unread}
</a>
)}
<a
href="/upload"
className="inline-flex items-center gap-1.5 rounded-lg bg-accent px-3 py-1.5 text-xs font-semibold text-white shadow hover:brightness-110 transition"
>
<svg className="h-3.5 w-3.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
</svg>
Upload
</a>
</div>
</div>
</div>
</section>
)
}