Save workspace changes
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
import React, { lazy, Suspense } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
|
||||
// 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 HomeMedalHighlights = lazy(() => import('./HomeMedalHighlights'))
|
||||
const HomeRising = lazy(() => import('./HomeRising'))
|
||||
const HomeFresh = lazy(() => import('./HomeFresh'))
|
||||
const HomeCollections = lazy(() => import('./HomeCollections'))
|
||||
const HomeGroups = lazy(() => import('./HomeGroups'))
|
||||
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 cx(...parts) {
|
||||
return parts.filter(Boolean).join(' ')
|
||||
}
|
||||
|
||||
function SectionFallback({ variant = 'gallery' }) {
|
||||
if (variant === 'welcome') {
|
||||
return (
|
||||
<div className="mt-10 px-4 sm:px-6 lg:px-8" aria-hidden="true">
|
||||
<div className="h-20 animate-pulse rounded-[28px] border border-white/10 bg-nova-800/70" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (variant === 'tags') {
|
||||
return (
|
||||
<section className="mt-14 px-4 sm:px-6 lg:px-8" aria-hidden="true">
|
||||
<div className="mb-5 h-8 w-48 animate-pulse rounded-xl bg-nova-800/70" />
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{Array.from({ length: 12 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="h-9 animate-pulse rounded-full bg-nova-800/70"
|
||||
style={{ width: `${88 + (index % 4) * 16}px` }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
if (variant === 'cta') {
|
||||
return (
|
||||
<section className="mt-14 px-4 sm:px-6 lg:px-8" aria-hidden="true">
|
||||
<div className="h-40 animate-pulse rounded-[28px] border border-white/10 bg-nova-800/70" />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
const cardClassName = variant === 'categories'
|
||||
? 'h-28 rounded-2xl'
|
||||
: variant === 'news'
|
||||
? 'h-24 rounded-2xl'
|
||||
: variant === 'creators'
|
||||
? 'h-64 rounded-2xl'
|
||||
: variant === 'collections'
|
||||
? 'h-80 rounded-[28px]'
|
||||
: variant === 'groups'
|
||||
? 'h-80 rounded-[28px]'
|
||||
: 'aspect-[4/3] rounded-2xl'
|
||||
const gridClassName = variant === 'creators'
|
||||
? 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-6'
|
||||
: variant === 'news'
|
||||
? 'grid-cols-1'
|
||||
: variant === 'categories'
|
||||
? 'grid-cols-2 lg:grid-cols-4'
|
||||
: variant === 'collections'
|
||||
? 'grid-cols-1 lg:grid-cols-2 xl:grid-cols-3'
|
||||
: variant === 'groups'
|
||||
? 'grid-cols-1 sm:grid-cols-2 xl:grid-cols-4'
|
||||
: 'grid-cols-2 xl:grid-cols-4'
|
||||
const cardCount = variant === 'creators' ? 6 : variant === 'news' ? 4 : 4
|
||||
|
||||
return (
|
||||
<section className="mt-14 px-4 sm:px-6 lg:px-8" aria-hidden="true">
|
||||
<div className="mb-5 flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<div className="h-8 w-48 animate-pulse rounded-xl bg-nova-800/70" />
|
||||
{(variant === 'collections' || variant === 'groups' || variant === 'news') && (
|
||||
<div className="mt-3 h-4 w-80 max-w-full animate-pulse rounded bg-nova-800/60" />
|
||||
)}
|
||||
</div>
|
||||
<div className="hidden h-5 w-24 animate-pulse rounded bg-nova-800/60 sm:block" />
|
||||
</div>
|
||||
<div className={cx('grid gap-4', gridClassName)}>
|
||||
{Array.from({ length: cardCount }).map((_, index) => (
|
||||
<div key={index} className={cx('animate-pulse bg-nova-800/70', cardClassName)} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function GuestHomePage(props) {
|
||||
const { rising, trending, community_favorites, hall_of_fame, fresh, tags, creators, news, collections_featured, collections_trending, collections_editorial, collections_community, groups } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeRising items={rising} />
|
||||
</Suspense>
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeTrending items={trending} />
|
||||
</Suspense>
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeMedalHighlights
|
||||
title="Community Favorites"
|
||||
href="/explore/top-rated"
|
||||
description="Recent medal momentum from the community. This rail highlights the strongest 30-day medal signal."
|
||||
items={community_favorites}
|
||||
/>
|
||||
</Suspense>
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeMedalHighlights
|
||||
title="Hall of Fame"
|
||||
href="/explore/best"
|
||||
description="All-time medal standouts that keep being remembered long after publication."
|
||||
items={hall_of_fame}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
{/* 3. Fresh Uploads */}
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeFresh items={fresh} />
|
||||
</Suspense>
|
||||
|
||||
<Suspense fallback={<SectionFallback variant="collections" />}>
|
||||
<HomeCollections
|
||||
featured={collections_featured}
|
||||
trending={collections_trending}
|
||||
editorial={collections_editorial}
|
||||
community={collections_community}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
<Suspense fallback={<SectionFallback variant="groups" />}>
|
||||
<HomeGroups groups={groups} />
|
||||
</Suspense>
|
||||
|
||||
{/* 4. Explore Categories */}
|
||||
<Suspense fallback={<SectionFallback variant="categories" />}>
|
||||
<HomeCategories />
|
||||
</Suspense>
|
||||
|
||||
{/* 5. Popular Tags */}
|
||||
<Suspense fallback={<SectionFallback variant="tags" />}>
|
||||
<HomeTags tags={tags} />
|
||||
</Suspense>
|
||||
|
||||
{/* 6. Top Creators */}
|
||||
<Suspense fallback={<SectionFallback variant="creators" />}>
|
||||
<HomeCreators creators={creators} />
|
||||
</Suspense>
|
||||
|
||||
{/* 7. News */}
|
||||
<Suspense fallback={<SectionFallback variant="news" />}>
|
||||
<HomeNews items={news} />
|
||||
</Suspense>
|
||||
|
||||
{/* 8. CTA Upload */}
|
||||
<Suspense fallback={<SectionFallback variant="cta" />}>
|
||||
<HomeCTA isLoggedIn={false} />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function AuthHomePage(props) {
|
||||
const {
|
||||
user_data,
|
||||
for_you,
|
||||
from_following,
|
||||
rising,
|
||||
trending,
|
||||
community_favorites,
|
||||
hall_of_fame,
|
||||
fresh,
|
||||
collections_featured,
|
||||
collections_recent,
|
||||
collections_trending,
|
||||
collections_editorial,
|
||||
collections_community,
|
||||
groups,
|
||||
by_categories,
|
||||
suggested_creators,
|
||||
tags,
|
||||
creators,
|
||||
news,
|
||||
preferences,
|
||||
} = props
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* P0. Welcome/status row — below hero so featured image sits at 0px */}
|
||||
<Suspense fallback={<SectionFallback variant="welcome" />}>
|
||||
<HomeWelcomeRow user_data={user_data} />
|
||||
</Suspense>
|
||||
|
||||
{/* P2. From Creators You Follow */}
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeFromFollowing items={from_following} />
|
||||
</Suspense>
|
||||
|
||||
{/* P3. Personalized For You preview */}
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeTrendingForYou items={for_you} preferences={preferences} />
|
||||
</Suspense>
|
||||
|
||||
{/* Rising Now */}
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeRising items={rising} />
|
||||
</Suspense>
|
||||
|
||||
{/* 2. Global Trending Now */}
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeTrending items={trending} />
|
||||
</Suspense>
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeMedalHighlights
|
||||
title="Community Favorites"
|
||||
href="/explore/top-rated"
|
||||
description="Recent medal momentum from the community. This rail highlights the strongest 30-day medal signal."
|
||||
items={community_favorites}
|
||||
/>
|
||||
</Suspense>
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeMedalHighlights
|
||||
title="Hall of Fame"
|
||||
href="/explore/best"
|
||||
description="All-time medal standouts that keep being remembered long after publication."
|
||||
items={hall_of_fame}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
{/* P4. Because You Like {top tag} — uses by_categories for variety */}
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeBecauseYouLike items={by_categories} preferences={preferences} />
|
||||
</Suspense>
|
||||
|
||||
{/* 3. Fresh Uploads */}
|
||||
<Suspense fallback={<SectionFallback variant="gallery" />}>
|
||||
<HomeFresh items={fresh} />
|
||||
</Suspense>
|
||||
|
||||
<Suspense fallback={<SectionFallback variant="collections" />}>
|
||||
<HomeCollections
|
||||
featured={collections_featured}
|
||||
recent={collections_recent}
|
||||
trending={collections_trending}
|
||||
editorial={collections_editorial}
|
||||
community={collections_community}
|
||||
isLoggedIn
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
<Suspense fallback={<SectionFallback variant="groups" />}>
|
||||
<HomeGroups groups={groups} />
|
||||
</Suspense>
|
||||
|
||||
{/* 4. Explore Categories */}
|
||||
<Suspense fallback={<SectionFallback variant="categories" />}>
|
||||
<HomeCategories />
|
||||
</Suspense>
|
||||
|
||||
{/* P5. Suggested Creators */}
|
||||
<Suspense fallback={<SectionFallback variant="creators" />}>
|
||||
<HomeSuggestedCreators creators={suggested_creators} />
|
||||
</Suspense>
|
||||
|
||||
{/* 5. Popular Tags */}
|
||||
<Suspense fallback={<SectionFallback variant="tags" />}>
|
||||
<HomeTags tags={tags} />
|
||||
</Suspense>
|
||||
|
||||
{/* 6. Top Creators */}
|
||||
<Suspense fallback={<SectionFallback variant="creators" />}>
|
||||
<HomeCreators creators={creators} />
|
||||
</Suspense>
|
||||
|
||||
{/* 7. News */}
|
||||
<Suspense fallback={<SectionFallback variant="news" />}>
|
||||
<HomeNews items={news} />
|
||||
</Suspense>
|
||||
|
||||
{/* 8. CTA Upload */}
|
||||
<Suspense fallback={<SectionFallback variant="cta" />}>
|
||||
<HomeCTA isLoggedIn />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function HomePage(props) {
|
||||
return (
|
||||
<div className="pb-24">
|
||||
{props.is_logged_in
|
||||
? <AuthHomePage {...props} />
|
||||
: <GuestHomePage {...props} />
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Auto-mount when the Blade view provides #homepage-root
|
||||
const mountEl = document.getElementById('homepage-root')
|
||||
if (mountEl) {
|
||||
let props = {}
|
||||
try {
|
||||
const propsEl = document.getElementById('homepage-props')
|
||||
props = propsEl ? JSON.parse(propsEl.textContent || '{}') : {}
|
||||
} catch {
|
||||
props = {}
|
||||
}
|
||||
|
||||
createRoot(mountEl).render(<HomePage {...props} />)
|
||||
}
|
||||
|
||||
export default HomePage
|
||||
Reference in New Issue
Block a user