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
This commit is contained in:
@@ -1,14 +1,22 @@
|
||||
import React, { lazy, Suspense } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
|
||||
// Sub-section components — lazy-loaded so only the hero blocks the initial bundle
|
||||
// Above-fold — eager
|
||||
import HomeHero from './HomeHero'
|
||||
|
||||
const HomeTrending = lazy(() => import('./HomeTrending'))
|
||||
const HomeFresh = lazy(() => import('./HomeFresh'))
|
||||
const HomeTags = lazy(() => import('./HomeTags'))
|
||||
const HomeCreators = lazy(() => import('./HomeCreators'))
|
||||
const HomeNews = lazy(() => import('./HomeNews'))
|
||||
// Below-fold — lazy-loaded to keep initial bundle small
|
||||
const HomeWelcomeRow = lazy(() => import('./HomeWelcomeRow'))
|
||||
const HomeFromFollowing = lazy(() => import('./HomeFromFollowing'))
|
||||
const HomeTrendingForYou = lazy(() => import('./HomeTrendingForYou'))
|
||||
const HomeBecauseYouLike = lazy(() => import('./HomeBecauseYouLike'))
|
||||
const HomeSuggestedCreators = lazy(() => import('./HomeSuggestedCreators'))
|
||||
const HomeTrending = lazy(() => import('./HomeTrending'))
|
||||
const HomeFresh = lazy(() => import('./HomeFresh'))
|
||||
const HomeCategories = lazy(() => import('./HomeCategories'))
|
||||
const HomeTags = lazy(() => import('./HomeTags'))
|
||||
const HomeCreators = lazy(() => import('./HomeCreators'))
|
||||
const HomeNews = lazy(() => import('./HomeNews'))
|
||||
const HomeCTA = lazy(() => import('./HomeCTA'))
|
||||
|
||||
function SectionFallback() {
|
||||
return (
|
||||
@@ -16,32 +24,141 @@ function SectionFallback() {
|
||||
)
|
||||
}
|
||||
|
||||
function HomePage({ hero, trending, fresh, tags, creators, news }) {
|
||||
return (
|
||||
<div className="pb-24">
|
||||
{/* Hero — above-fold, eager */}
|
||||
<HomeHero artwork={hero} />
|
||||
function GuestHomePage(props) {
|
||||
const { hero, trending, fresh, tags, creators, news } = props
|
||||
|
||||
{/* Below-fold sections — lazy */}
|
||||
return (
|
||||
<>
|
||||
{/* 1. Hero */}
|
||||
<HomeHero artwork={hero} isLoggedIn={false} />
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeTrending items={trending} />
|
||||
</Suspense>
|
||||
|
||||
{/* 3. Fresh Uploads */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeFresh items={fresh} />
|
||||
</Suspense>
|
||||
|
||||
{/* 4. Explore Categories */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeCategories />
|
||||
</Suspense>
|
||||
|
||||
{/* 5. Popular Tags */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeTags tags={tags} />
|
||||
</Suspense>
|
||||
|
||||
{/* 6. Top Creators */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeCreators creators={creators} />
|
||||
</Suspense>
|
||||
|
||||
{/* 7. News */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeNews items={news} />
|
||||
</Suspense>
|
||||
|
||||
{/* 8. CTA Upload */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeCTA isLoggedIn={false} />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function AuthHomePage(props) {
|
||||
const {
|
||||
user_data,
|
||||
hero,
|
||||
from_following,
|
||||
trending,
|
||||
fresh,
|
||||
by_tags,
|
||||
by_categories,
|
||||
suggested_creators,
|
||||
tags,
|
||||
creators,
|
||||
news,
|
||||
preferences,
|
||||
} = props
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* P0. Welcome/status row */}
|
||||
<Suspense fallback={null}>
|
||||
<HomeWelcomeRow user_data={user_data} />
|
||||
</Suspense>
|
||||
|
||||
{/* 1. Hero */}
|
||||
<HomeHero artwork={hero} isLoggedIn />
|
||||
|
||||
{/* P2. From Creators You Follow */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeFromFollowing items={from_following} />
|
||||
</Suspense>
|
||||
|
||||
{/* P3. Trending For You (by_tags = Meilisearch tag overlap sorted by trending) */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeTrendingForYou items={by_tags} preferences={preferences} />
|
||||
</Suspense>
|
||||
|
||||
{/* 2. Global Trending Now */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeTrending items={trending} />
|
||||
</Suspense>
|
||||
|
||||
{/* P4. Because You Like {top tag} — uses by_categories for variety */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeBecauseYouLike items={by_categories} preferences={preferences} />
|
||||
</Suspense>
|
||||
|
||||
{/* 3. Fresh Uploads */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeFresh items={fresh} />
|
||||
</Suspense>
|
||||
|
||||
{/* 4. Explore Categories */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeCategories />
|
||||
</Suspense>
|
||||
|
||||
{/* P5. Suggested Creators */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeSuggestedCreators creators={suggested_creators} />
|
||||
</Suspense>
|
||||
|
||||
{/* 5. Popular Tags */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeTags tags={tags} />
|
||||
</Suspense>
|
||||
|
||||
{/* 6. Top Creators */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeCreators creators={creators} />
|
||||
</Suspense>
|
||||
|
||||
{/* 7. News */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeNews items={news} />
|
||||
</Suspense>
|
||||
|
||||
{/* 8. CTA Upload */}
|
||||
<Suspense fallback={<SectionFallback />}>
|
||||
<HomeCTA isLoggedIn />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function HomePage(props) {
|
||||
return (
|
||||
<div className="pb-24">
|
||||
{props.is_logged_in
|
||||
? <AuthHomePage {...props} />
|
||||
: <GuestHomePage {...props} />
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user