Skip to content

Commit 7fda7cd

Browse files
committed
refactor: loading state using next/dynamic ssr false
remove usage of `const mounted`
1 parent 65469ee commit 7fda7cd

File tree

6 files changed

+153
-162
lines changed

6 files changed

+153
-162
lines changed

app/[locale]/page.tsx

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Fragment } from "react"
2+
import dynamic from "next/dynamic"
23
import { notFound } from "next/navigation"
34
import { getTranslations, setRequestLocale } from "next-intl/server"
45
import { FaDiscord, FaGithub } from "react-icons/fa6"
@@ -15,11 +16,9 @@ import BannerNotification from "@/components/Banners/BannerNotification"
1516
import { ChevronNext } from "@/components/Chevron"
1617
import HomeHero from "@/components/Hero/HomeHero"
1718
import BentoCard from "@/components/Homepage/BentoCard"
18-
import BentoCardSwiper from "@/components/Homepage/BentoCardSwiper"
1919
import CodeExamples from "@/components/Homepage/CodeExamples"
20-
import RecentPostsSwiper from "@/components/Homepage/RecentPostsSwiper"
2120
import { getBentoBoxItems } from "@/components/Homepage/utils"
22-
import ValuesMarquee from "@/components/Homepage/ValuesMarquee"
21+
import ValuesMarqueeFallback from "@/components/Homepage/ValuesMarquee/Fallback"
2322
import BlockHeap from "@/components/icons/block-heap.svg"
2423
import BuildAppsIcon from "@/components/icons/build-apps.svg"
2524
import Calendar from "@/components/icons/calendar.svg"
@@ -53,6 +52,7 @@ import {
5352
SectionHeader,
5453
SectionTag,
5554
} from "@/components/ui/section"
55+
import { Skeleton, SkeletonCardGrid } from "@/components/ui/skeleton"
5656
import WindowBox from "@/components/WindowBox"
5757

5858
import { cn } from "@/lib/utils/cn"
@@ -96,6 +96,41 @@ import ActivityImage from "@/public/images/heroes/layer-2-hub-hero.jpg"
9696
import LearnImage from "@/public/images/heroes/learn-hub-hero.png"
9797
import CommunityImage from "@/public/images/heroes/quizzes-hub-hero.png"
9898
import Hero from "@/public/images/home/hero.png"
99+
100+
const BentoCardSwiper = dynamic(
101+
() => import("@/components/Homepage/BentoCardSwiper"),
102+
{
103+
ssr: false,
104+
loading: () => (
105+
<div className="flex flex-col items-center gap-4">
106+
<Skeleton className="mx-auto mt-4 h-[476px] w-[512px] max-w-128 rounded-2xl border-primary/10 bg-background bg-gradient-to-b from-primary/10 from-20% to-primary/5 to-60% p-4 opacity-50 shadow-card-hover lg:hidden dark:from-primary/20 dark:to-primary/10" />
107+
<Skeleton className="h-6 w-[12rem] rounded-full" />
108+
</div>
109+
),
110+
}
111+
)
112+
113+
const RecentPostsSwiper = dynamic(
114+
() => import("@/components/Homepage/RecentPostsSwiper"),
115+
{
116+
ssr: false,
117+
loading: () => (
118+
<div className="flex flex-col items-center gap-4">
119+
<SkeletonCardGrid className="mt-4 w-full md:mt-16" />
120+
<Skeleton className="h-4 w-20 rounded-full" />
121+
</div>
122+
),
123+
}
124+
)
125+
126+
const ValuesMarquee = dynamic(
127+
() => import("@/components/Homepage/ValuesMarquee"),
128+
{
129+
ssr: false,
130+
loading: () => <ValuesMarqueeFallback />,
131+
}
132+
)
133+
99134
const fetchXmlBlogFeeds = async () => {
100135
const xmlUrls = BLOG_FEEDS.filter((feed) => ![ATTESTANT_BLOG].includes(feed))
101136
return await fetchRSS(xmlUrls)
@@ -472,7 +507,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
472507
</h2>
473508
</div>
474509

475-
{/* Mobile - CLIENT SIDE */}
510+
{/* Mobile - dynamic / lazy loaded */}
476511
<BentoCardSwiper
477512
bentoItems={bentoItems}
478513
eventCategory={eventCategory}
@@ -597,7 +632,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
597632
</p>
598633
</SectionContent>
599634

600-
{/* CLIENT SIDE */}
635+
{/* dynamic / lazy loaded */}
601636
<ValuesMarquee
602637
pairings={valuesPairings}
603638
eventCategory={eventCategory}
@@ -788,7 +823,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
788823
</h3>
789824
<p>{t("page-index-posts-subtitle")}</p>
790825

791-
{/* CLIENT SIDE */}
826+
{/* dynamic / lazy loaded */}
792827
<RecentPostsSwiper
793828
className="mt-4 md:mt-16"
794829
rssItems={rssItems}

src/components/Homepage/BentoCardSwiper.tsx

Lines changed: 33 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@ import { SwiperSlide } from "swiper/react"
55
import { cn } from "@/lib/utils/cn"
66
import { trackCustomEvent } from "@/lib/utils/matomo"
77

8-
import { Skeleton } from "../ui/skeleton"
98
import { Swiper, SwiperContainer, SwiperNavigation } from "../ui/swiper"
109

1110
import BentoCard from "./BentoCard"
1211
import { BentoItem } from "./utils"
1312

14-
import { useIsClient } from "@/hooks/useIsClient"
15-
1613
type BentoCardSwiperProps = {
1714
bentoItems: BentoItem[]
1815
eventCategory: string
@@ -21,52 +18,40 @@ type BentoCardSwiperProps = {
2118
const BentoCardSwiper = ({
2219
bentoItems,
2320
eventCategory,
24-
}: BentoCardSwiperProps) => {
25-
const mounted = useIsClient()
26-
27-
if (!mounted)
28-
return (
29-
<div className="flex flex-col items-center">
30-
<Skeleton className="mx-auto mt-4 h-[476px] w-[512px] max-w-128 rounded-2xl border-primary/10 bg-background bg-gradient-to-b from-primary/10 from-20% to-primary/5 to-60% p-4 opacity-50 shadow-card-hover lg:hidden dark:from-primary/20 dark:to-primary/10" />
31-
<Skeleton className="h-6 w-[12rem] rounded-full" />
32-
</div>
33-
)
34-
35-
return (
36-
<SwiperContainer
37-
className={cn(
38-
"lg:hidden", // Mobile only
39-
"[&_.swiper-slide]:overflow-visible [&_.swiper-slide]:rounded-2xl [&_.swiper-slide]:shadow-card-hover",
40-
"[&_.swiper-slide-shadow]:!bg-transparent",
41-
"[&_.swiper]:mx-auto [&_.swiper]:mt-4 [&_.swiper]:!flex [&_.swiper]:h-fit [&_.swiper]:max-w-128 [&_.swiper]:flex-col [&_.swiper]:items-center"
42-
)}
21+
}: BentoCardSwiperProps) => (
22+
<SwiperContainer
23+
className={cn(
24+
"lg:hidden", // Mobile only
25+
"[&_.swiper-slide]:overflow-visible [&_.swiper-slide]:rounded-2xl [&_.swiper-slide]:shadow-card-hover",
26+
"[&_.swiper-slide-shadow]:!bg-transparent",
27+
"[&_.swiper]:mx-auto [&_.swiper]:mt-4 [&_.swiper]:!flex [&_.swiper]:h-fit [&_.swiper]:max-w-128 [&_.swiper]:flex-col [&_.swiper]:items-center"
28+
)}
29+
>
30+
<Swiper
31+
effect="cards"
32+
onSlideChange={({ activeIndex }) => {
33+
trackCustomEvent({
34+
eventCategory,
35+
eventAction: "mobile use cases",
36+
eventName: `swipe to card ${activeIndex + 1}`,
37+
})
38+
}}
4339
>
44-
<Swiper
45-
effect="cards"
46-
onSlideChange={({ activeIndex }) => {
47-
trackCustomEvent({
48-
eventCategory,
49-
eventAction: "mobile use cases",
50-
eventName: `swipe to card ${activeIndex + 1}`,
51-
})
52-
}}
53-
>
54-
{bentoItems.map(({ className, ...item }) => (
55-
<SwiperSlide key={item.title}>
56-
<BentoCard
57-
imgHeight={220}
58-
{...item}
59-
className={cn(className, "bg-background text-body")}
60-
imgWidth={undefined} // Intentionally last to override box
61-
eventCategory={eventCategory}
62-
/>
63-
</SwiperSlide>
64-
))}
65-
<SwiperNavigation />
66-
</Swiper>
67-
</SwiperContainer>
68-
)
69-
}
40+
{bentoItems.map(({ className, ...item }) => (
41+
<SwiperSlide key={item.title}>
42+
<BentoCard
43+
imgHeight={220}
44+
{...item}
45+
className={cn(className, "bg-background text-body")}
46+
imgWidth={undefined} // Intentionally last to override box
47+
eventCategory={eventCategory}
48+
/>
49+
</SwiperSlide>
50+
))}
51+
<SwiperNavigation />
52+
</Swiper>
53+
</SwiperContainer>
54+
)
7055

7156
BentoCardSwiper.displayName = "BentoCardSwiper"
7257

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
"use client"
2+
3+
import type { RSSItem } from "@/lib/types"
4+
5+
import { isValidDate } from "@/lib/utils/date"
6+
import { breakpointAsNumber } from "@/lib/utils/screen"
7+
8+
import CardImage from "../Image/CardImage"
9+
import {
10+
Card,
11+
CardBanner,
12+
CardContent,
13+
CardHighlight,
14+
CardSubTitle,
15+
CardTitle,
16+
} from "../ui/card"
17+
import {
18+
Swiper,
19+
SwiperContainer,
20+
SwiperNavigation,
21+
SwiperSlide,
22+
} from "../ui/swiper"
23+
24+
type RecentPostsSwiperProps = {
25+
rssItems: RSSItem[]
26+
eventCategory: string
27+
className?: string
28+
}
29+
30+
const RecentPostsSwiper = ({
31+
rssItems,
32+
eventCategory,
33+
className,
34+
}: RecentPostsSwiperProps) => (
35+
<SwiperContainer className={className}>
36+
<Swiper
37+
spaceBetween={32}
38+
breakpoints={{
39+
[breakpointAsNumber.sm]: {
40+
slidesPerView: 2,
41+
slidesPerGroup: 2,
42+
},
43+
[breakpointAsNumber.lg]: {
44+
slidesPerView: 3,
45+
slidesPerGroup: 3,
46+
},
47+
}}
48+
slidesPerView={1}
49+
slidesPerGroup={1}
50+
>
51+
{rssItems.map(({ pubDate, title, source, link, imgSrc }) => (
52+
<SwiperSlide key={title}>
53+
<Card
54+
href={link}
55+
customEventOptions={{
56+
eventCategory,
57+
eventAction: "blogs_posts",
58+
eventName: source,
59+
}}
60+
>
61+
<CardBanner>
62+
<CardImage src={imgSrc} />
63+
</CardBanner>
64+
<CardContent>
65+
<CardTitle>{title}</CardTitle>
66+
{isValidDate(pubDate) && <CardSubTitle>{pubDate}</CardSubTitle>}
67+
<CardHighlight>{source}</CardHighlight>
68+
</CardContent>
69+
</Card>
70+
</SwiperSlide>
71+
))}
72+
<SwiperNavigation />
73+
</Swiper>
74+
</SwiperContainer>
75+
)
76+
77+
RecentPostsSwiper.displayName = "RecentPostsSwiper"
78+
79+
export default RecentPostsSwiper

src/components/Homepage/RecentPostsSwiper/Fallback.tsx

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/components/Homepage/RecentPostsSwiper/index.tsx

Lines changed: 0 additions & 89 deletions
This file was deleted.

0 commit comments

Comments
 (0)