Improve page loading performance by deferring off-screen content
Implement lazy loading for lower sections of the homepage to optimize initial render and improve user experience. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 1f7e7e89-a520-4970-9645-37daadc466dc Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 97dab47f-9107-41f0-9b7a-5900b3b486e6 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/1f7e7e89-a520-4970-9645-37daadc466dc/ZApZ5Qi Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
970c395184
commit
9a81e63740
@ -15,7 +15,7 @@ import { RecipeWidget } from "@/components/recipe-widget";
|
||||
import { NewsWidget } from "@/components/news-widget";
|
||||
import { SidebarWeatherWidget } from "@/components/weather-widget";
|
||||
import { BreakingNewsWidget } from "@/components/breaking-news-widget";
|
||||
import { useState, useEffect, useCallback, useRef, useMemo } from "react";
|
||||
import { useState, useEffect, useCallback, useRef, useMemo, lazy, Suspense } from "react";
|
||||
|
||||
function useFocalPoints() {
|
||||
const { data } = useQuery<Record<string, { x: number; y: number }>>({
|
||||
@ -466,6 +466,33 @@ function FeaturedCarousel({ articles, popular, galleryImages, focalPoints }: { a
|
||||
);
|
||||
}
|
||||
|
||||
function LazySection({ children, minHeight = "200px" }: { children: JSX.Element; minHeight?: string }) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
const obs = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
setVisible(true);
|
||||
obs.disconnect();
|
||||
}
|
||||
},
|
||||
{ rootMargin: "300px" }
|
||||
);
|
||||
obs.observe(el);
|
||||
return () => obs.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={ref} style={{ minHeight: visible ? undefined : minHeight }}>
|
||||
{visible ? children : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BentoSkeleton() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
@ -663,41 +690,47 @@ export default function Home() {
|
||||
</div>
|
||||
|
||||
{gridRows.map((row, ri) => (
|
||||
<div key={`row-group-${ri}`}>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{row.map((item) =>
|
||||
item.type === "widget"
|
||||
? <div key={item.key}>{item.widget!.el}</div>
|
||||
: item.type === "ad"
|
||||
? <div key={item.key} className="h-full" data-testid={`ad-grid-${item.key}`}><ArticleCardAd /></div>
|
||||
: item.article
|
||||
? <MediumCard key={item.key} article={item.article} focalPoints={focalPoints} />
|
||||
: null
|
||||
)}
|
||||
{ri === gridRows.length - 1 && widePickedArticles.length > 0 && (
|
||||
<div className="sm:col-span-2 lg:col-span-4 grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<WideCardClassic article={widePickedArticles[0]} focalPoints={focalPoints} />
|
||||
{widePickedArticles[1] && <WideCardClassic article={widePickedArticles[1]} focalPoints={focalPoints} />}
|
||||
</div>
|
||||
)}
|
||||
<LazySection key={`row-group-${ri}`} minHeight="280px">
|
||||
<div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{row.map((item) =>
|
||||
item.type === "widget"
|
||||
? <div key={item.key}>{item.widget!.el}</div>
|
||||
: item.type === "ad"
|
||||
? <div key={item.key} className="h-full" data-testid={`ad-grid-${item.key}`}><ArticleCardAd /></div>
|
||||
: item.article
|
||||
? <MediumCard key={item.key} article={item.article} focalPoints={focalPoints} />
|
||||
: null
|
||||
)}
|
||||
{ri === gridRows.length - 1 && widePickedArticles.length > 0 && (
|
||||
<div className="sm:col-span-2 lg:col-span-4 grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<WideCardClassic article={widePickedArticles[0]} focalPoints={focalPoints} />
|
||||
{widePickedArticles[1] && <WideCardClassic article={widePickedArticles[1]} focalPoints={focalPoints} />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</LazySection>
|
||||
))}
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{bottomSection.map((item, i) => (
|
||||
<div key={`bottom-${i}`}>
|
||||
{item.el}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<LazySection minHeight="280px">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{bottomSection.map((item, i) => (
|
||||
<div key={`bottom-${i}`}>
|
||||
{item.el}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</LazySection>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<PhotoGalleryWidget key="extra-gallery" />
|
||||
<NewsWidget key="extra-news" />
|
||||
<RecipeWidget key="extra-recipe" />
|
||||
<div className="h-full"><ArticleCardAd /></div>
|
||||
</div>
|
||||
<LazySection minHeight="280px">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<PhotoGalleryWidget key="extra-gallery" />
|
||||
<NewsWidget key="extra-news" />
|
||||
<RecipeWidget key="extra-recipe" />
|
||||
<div className="h-full"><ArticleCardAd /></div>
|
||||
</div>
|
||||
</LazySection>
|
||||
|
||||
</main>
|
||||
<Footer />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user