Skip to content

Commit 8f161af

Browse files
authored
Merge pull request #309 from apsinghdev/perf/pricing-lag
[perf] improve the perf of pricing page
2 parents 0512164 + 053aeab commit 8f161af

3 files changed

Lines changed: 169 additions & 81 deletions

File tree

apps/web/src/app/(main)/(landing)/pricing/page.tsx

Lines changed: 135 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
11
"use client";
2-
import Footer from "@/components/landing-sections/footer";
32
import Header from "@/components/ui/header";
4-
import { ShineBorder } from "@/components/ui/shine-borders";
5-
import { motion } from "framer-motion";
63
import { Check, CornerDownRight, Target, Terminal } from "lucide-react";
74
import Image from "next/image";
85
import Link from "next/link";
96
import React, { useEffect } from "react";
10-
import PrimaryButton from "@/components/ui/custom-button";
11-
import PaymentFlow from "@/components/payment/PaymentFlow";
127
import { ActiveTag } from "@/components/ui/ActiveTag";
138
import { usePathname } from "next/navigation";
9+
import { motion } from "framer-motion";
10+
import { ShineBorder } from "@/components/ui/shine-borders";
11+
import PrimaryButton from "@/components/ui/custom-button";
12+
import dynamic from "next/dynamic";
13+
14+
const Footer = dynamic(
15+
() =>
16+
import("@/components/landing-sections/footer").then((mod) => mod.default),
17+
{
18+
ssr: false,
19+
loading: () => null,
20+
}
21+
);
22+
23+
// lazy load PaymentFlow - it's inside pricing card but can wait
24+
const PaymentFlow = dynamic(
25+
() => import("@/components/payment/PaymentFlow").then((mod) => mod.default),
26+
{
27+
ssr: false,
28+
loading: () => null,
29+
}
30+
);
1431
const opensoxFeatures = [
1532
{
1633
id: 1,
@@ -71,7 +88,7 @@ const whySub = [
7188
},
7289
{
7390
content:
74-
"After the launch, this $49 offer be removed and Opensox Pro will be around ~ $120 for whole year ($10/mo.)",
91+
"After the launch, this $49 offer be removed and Opensox Pro will be around ~ $89 for whole year.",
7592
},
7693
{
7794
content: "The price of the dollar is constantly increasing.",
@@ -114,60 +131,122 @@ const Pricing = () => {
114131
const callbackUrl = `${pathname}#pro-price-card`;
115132

116133
useEffect(() => {
117-
if (window.location.hash === "#pro-price-card") {
118-
const element = document.getElementById("pro-price-card");
119-
if (element) {
120-
setTimeout(() => {
134+
const handleHashScroll = () => {
135+
if (window.location.hash === "#pro-price-card") {
136+
const element = document.getElementById("pro-price-card");
137+
if (element) {
121138
element.scrollIntoView({ behavior: "smooth", block: "start" });
122-
}, 100);
139+
}
123140
}
124-
}
125-
if (window.location.hash === "#testimonials") {
126-
const element = document.getElementById("testimonials");
127-
if (element) {
128-
setTimeout(() => {
141+
if (window.location.hash === "#testimonials") {
142+
const element = document.getElementById("testimonials");
143+
if (element) {
129144
element.scrollIntoView({ behavior: "smooth", block: "start" });
130-
}, 100);
145+
}
131146
}
147+
};
148+
149+
if ("requestIdleCallback" in window) {
150+
requestIdleCallback(handleHashScroll, { timeout: 2000 });
151+
} else {
152+
setTimeout(handleHashScroll, 100);
132153
}
133154
}, []);
134155

135156
return (
136157
<>
158+
<style
159+
dangerouslySetInnerHTML={{
160+
__html: `
161+
/* critical css for LCP element - inline for fastest rendering */
162+
/* font-family matches Tailwind's font-mono class exactly to ensure consistent fallbacks */
163+
.lcp-feature-item { display: flex; flex-direction: column; gap: 1rem; width: 100%; flex: 1; }
164+
.lcp-feature-content { display: flex; flex-direction: column; gap: 0.5rem; width: 100%; }
165+
.lcp-feature-header { display: flex; gap: 1rem; align-items: center; }
166+
.lcp-feature-number { font-size: 3.75rem; font-family: var(--font-dm-mono), Menlo, Monaco, "Courier New", monospace; font-weight: 600; background: linear-gradient(to bottom, #a472ea, #341e7b); -webkit-background-clip: text; background-clip: text; color: transparent; }
167+
.lcp-feature-title { font-size: 1.5rem; font-weight: 500; }
168+
.lcp-feature-description { font-weight: 500; }
169+
`,
170+
}}
171+
/>
137172
<main className="w-full overflow-hidden flex flex-col items-center justify-center relative">
138173
<Header title="We are working on Opensox 2.0" />
139-
<div className="flex flex-col bg-[#151515]/20 backdrop-blur-xl relative w-full ">
174+
<div className="flex flex-col bg-[#151515]/20 relative w-full ">
140175
<div className="h-full pv relative">
141176
<div className=" py-8 border-b border-[#252525]">
142-
<motion.h2
143-
initial={{ opacity: 0, y: 30, filter: "blur(10px)" }}
144-
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
145-
transition={{
146-
duration: 0.6,
147-
ease: "easeOut",
148-
type: "spring",
149-
delay: 0.4,
150-
}}
151-
className="text-center text-3xl tracking-tight font-medium"
152-
>
177+
<h2 className="text-center text-3xl tracking-tight font-medium">
153178
What is Opensox 2.0?
154-
</motion.h2>
179+
</h2>
155180
</div>
156181
<div className=" w-full h-full flex flex-col gap-6 border-b border-[#252525]">
157182
<ul className="flex flex-col lg:flex-row [&>li]:w-full [&>li]:p-6 divide-y lg:divide-y-0 lg:divide-x divide-[#252525] h-full ">
158183
{opensoxFeatures.map((feature, index) => {
184+
// render first item (LCP element) immediately without animation
185+
const isLCPElement = index === 0;
186+
187+
if (isLCPElement) {
188+
return (
189+
<li key={index} className="lcp-feature-item">
190+
<div className="lcp-feature-content">
191+
<div className="lcp-feature-header">
192+
<div className="lcp-feature-number">
193+
{index + 1}
194+
</div>
195+
<div className="flex items-center gap-2">
196+
<h3 className="lcp-feature-title">
197+
{feature.title}
198+
</h3>
199+
{feature.title === "OX Newsletter" && (
200+
<ActiveTag text="completed" />
201+
)}
202+
</div>
203+
</div>
204+
{Array.isArray(feature.description) ? (
205+
<div className="font-medium">
206+
{feature.description.map(
207+
(sentence, sentenceIndex) => (
208+
<p key={sentenceIndex} className="mb-2">
209+
{sentence}
210+
</p>
211+
)
212+
)}
213+
</div>
214+
) : (
215+
<p className="lcp-feature-description">
216+
{feature.description}
217+
</p>
218+
)}
219+
</div>
220+
<div className="flex flex-col gap-2 w-full h-full">
221+
<ul className="flex flex-col gap-3 w-full h-full pb-8">
222+
{feature.features.map((feature, featureIndex) => {
223+
return (
224+
<li
225+
key={featureIndex}
226+
className="text-sm flex items-center gap-4"
227+
>
228+
<CornerDownRight className="size-4 flex-shrink-0 text-[#a472ea]" />
229+
{feature}
230+
</li>
231+
);
232+
})}
233+
</ul>
234+
</div>
235+
</li>
236+
);
237+
}
238+
159239
return (
160240
<motion.li
161-
initial={{ opacity: 0, y: 30, filter: "blur(10px)" }}
162-
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
241+
initial={{ opacity: 0, y: 20 }}
242+
animate={{ opacity: 1, y: 0 }}
163243
transition={{
164-
duration: 0.6,
244+
duration: 0.3,
165245
ease: "easeOut",
166-
type: "spring",
167-
delay: 0.5 + index * 0.1,
246+
delay: 0.2 + (index - 1) * 0.05,
168247
}}
169248
key={index}
170-
className="flex flex-col gap-4 w-full flex-1 "
249+
className="flex flex-col gap-4 w-full flex-1"
171250
>
172251
<div className="flex flex-col gap-2 w-full">
173252
<div className="flex gap-4 items-center">
@@ -199,10 +278,10 @@ const Pricing = () => {
199278
</div>
200279
<div className="flex flex-col gap-2 w-full h-full">
201280
<ul className="flex flex-col gap-3 w-full h-full pb-8">
202-
{feature.features.map((feature, index) => {
281+
{feature.features.map((feature, featureIndex) => {
203282
return (
204283
<li
205-
key={index}
284+
key={featureIndex}
206285
className="font- text-sm flex items-center gap-4"
207286
>
208287
<CornerDownRight className="size-4 flex-shrink-0 text-[#a472ea]" />
@@ -221,13 +300,12 @@ const Pricing = () => {
221300
<div className="h-full relative ">
222301
<div className="py-8 border-b border-[#252525]">
223302
<motion.h2
224-
initial={{ opacity: 0, y: 30, filter: "blur(10px)" }}
225-
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
303+
initial={{ opacity: 0, y: 20 }}
304+
animate={{ opacity: 1, y: 0 }}
226305
transition={{
227-
duration: 0.6,
306+
duration: 0.3,
228307
ease: "easeOut",
229-
type: "spring",
230-
delay: 0.8,
308+
delay: 0.15,
231309
}}
232310
className="text-center text-3xl tracking-tight font-medium"
233311
>
@@ -239,13 +317,12 @@ const Pricing = () => {
239317
{whySub.map((sub, index) => {
240318
return (
241319
<motion.p
242-
initial={{ opacity: 0, y: 30, filter: "blur(10px)" }}
243-
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
320+
initial={{ opacity: 0, y: 20 }}
321+
animate={{ opacity: 1, y: 0 }}
244322
transition={{
245-
duration: 0.6,
323+
duration: 0.3,
246324
ease: "easeOut",
247-
type: "spring",
248-
delay: 0.9 + index * 0.1,
325+
delay: 0.2 + index * 0.05,
249326
}}
250327
key={index}
251328
className="flex items-center gap-4"
@@ -265,6 +342,7 @@ const Pricing = () => {
265342
src="/assets/layer1.svg"
266343
alt="background"
267344
fill
345+
loading="lazy"
268346
className=" w-full h-full -z-10 opacity-90"
269347
/>
270348
</div>
@@ -299,11 +377,11 @@ const PricingCard = () => {
299377
<div className=" border-border-primary w-full mx-auto flex h-full">
300378
<div className="border-dashed border-border-primary w-full lg:w-max mx-auto relative h-full">
301379
<div className="w-full h-full lg:w-[500px] relative overflow-hidden mx-auto py-10 pb-14 flex flex-col rounded-3xl">
302-
<ShineBorder shineColor={["#7150E7", "#C89BFF", "#432BA0"]} />
303380
<Image
304381
src="/assets/card_bg.svg"
305382
alt="background"
306383
fill
384+
loading="lazy"
307385
className="object-cover object-bottom w-full h-full absolute -z-10"
308386
/>
309387
<div className="w-full border-dashed border-border-primary px-6 lg:px-10 pb-4">
@@ -312,10 +390,12 @@ const PricingCard = () => {
312390
src="/assets/logo_var2.svg"
313391
alt="background"
314392
fill
393+
loading="lazy"
315394
className="object-cover size-full"
316395
/>
317396
</div>
318397
</div>
398+
<ShineBorder shineColor={["#7150E7", "#C89BFF", "#432BA0"]} />
319399

320400
<div className="w-full border-dashed border-border-primary px-6 lg:px-10 py-4">
321401
<h2 className="text-6xl lg:text-[90px] lg:leading-[82px] tracking-tight font-semibold">
@@ -362,7 +442,7 @@ const PricingCard = () => {
362442
})}
363443
</div>
364444
</div>
365-
<div className="bg-white mix-blend-plus-lighter absolute h-[100px] w-full blur-[50px] right-0 -bottom-20"></div>
445+
<div className="bg-white mix-blend-plus-lighter absolute h-[120px] w-full blur-[60px] right-0 -bottom-20 opacity-80"></div>
366446
</div>
367447
</div>
368448
</div>
@@ -380,11 +460,11 @@ const SecondaryPricingCard = ({ callbackUrl }: { callbackUrl: string }) => {
380460
<div className=" border-border-primary w-full mx-auto flex h-full">
381461
<div className="border-dashed border-border-primary w-full lg:w-max mx-auto relative h-full">
382462
<div className=" w-full lg:w-[500px] relative overflow-hidden mx-auto py-10 pb-14 flex flex-col h-full rounded-3xl">
383-
<ShineBorder shineColor={["#7150E7", "#C89BFF", "#432BA0"]} />
384463
<Image
385464
src="/assets/card_bg.svg"
386465
alt="background"
387466
fill
467+
loading="lazy"
388468
className="object-cover object-bottom w-full h-full absolute -z-10"
389469
/>
390470
<div className="w-full border-dashed border-border-primary px-6 lg:px-10 pb-4">
@@ -393,10 +473,12 @@ const SecondaryPricingCard = ({ callbackUrl }: { callbackUrl: string }) => {
393473
src="/assets/logo_var2.svg"
394474
alt="background"
395475
fill
476+
loading="lazy"
396477
className="object-cover size-full"
397478
/>
398479
</div>
399480
</div>
481+
<ShineBorder shineColor={["#7150E7", "#C89BFF", "#432BA0"]} />
400482

401483
<div
402484
id="pro-price-card"
@@ -406,7 +488,7 @@ const SecondaryPricingCard = ({ callbackUrl }: { callbackUrl: string }) => {
406488
<h2 className="text-6xl lg:text-[90px] lg:leading-[82px] tracking-tight font-semibold">
407489
$49{" "}
408490
<span className="text-3xl lg:text-4xl text-white-400 line-through decoration-2">
409-
$69
491+
$89
410492
</span>{" "}
411493
<span className="text-4xl">/ year</span>
412494
</h2>
@@ -470,7 +552,7 @@ const SecondaryPricingCard = ({ callbackUrl }: { callbackUrl: string }) => {
470552
})}
471553
</div>
472554
</div>
473-
<div className="bg-white mix-blend-plus-lighter absolute h-[100px] w-full blur-[50px] right-0 -bottom-20"></div>
555+
<div className="bg-white mix-blend-plus-lighter absolute h-[120px] w-full blur-[60px] right-0 -bottom-20 opacity-80"></div>
474556
</div>
475557
</div>
476558
</div>

apps/web/src/app/layout.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ const dmMono = localFont({
2626
},
2727
],
2828
variable: "--font-dm-mono",
29-
display: "swap",
29+
display: "optional",
30+
preload: true,
3031
});
3132

3233
// Geist Sans - Primary font for body text and UI

0 commit comments

Comments
 (0)