Skip to content

Commit 27735fb

Browse files
committed
feat: improve prcing section styles
1 parent ef41af0 commit 27735fb

5 files changed

Lines changed: 42 additions & 38 deletions

File tree

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@payloadcms/plugin-seo": "3.86.0",
4242
"@payloadcms/richtext-lexical": "3.86.0",
4343
"@tabler/icons-react": "3.41.1",
44+
"border-beam": "^1.3.0",
4445
"class-variance-authority": "^0.7.1",
4546
"clsx": "^2.1.1",
4647
"graphql": "^16.14.2",

src/components/PageBlockRenderer.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ const pageBlockRenderers: Partial<Record<PageBlock["blockType"], BlockRenderer>>
198198
content={block as Extract<PageBlock, { blockType: "smallPricing" }>}
199199
locale={options.locale ?? "en"}
200200
packages={config.packages}
201-
paymentPeriod={config.paymentPeriod}
202201
/>
203202
)
204203
},

src/components/sections/PricingSection.tsx

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { AppLocale } from "@/lib/i18n"
1010
import { cn } from "@/lib/utils"
1111
import NumberFlow from "@number-flow/react"
1212
import { IconCheck, IconX } from "@tabler/icons-react"
13+
import { BorderBeam } from "border-beam"
1314
import { useState } from "react"
1415

1516
type PricingPeriod = "monthly" | "quarterly" | "yearly"
@@ -32,9 +33,9 @@ export function PricingSection({ content, locale, packages, paymentPeriod }: Pri
3233
{ value: "yearly", label: paymentPeriod.yearlyText },
3334
] as const
3435
const periodSuffix = {
35-
monthly: paymentPeriod.monthlyPeriodSuffix,
36-
quarterly: paymentPeriod.quarterlyPeriodSuffix,
37-
yearly: paymentPeriod.yearlyPeriodSuffix,
36+
monthly: "/mo",
37+
quarterly: "/qtr",
38+
yearly: "/yr",
3839
}[selectedPeriod]
3940
const pricingPackages = [
4041
{
@@ -96,18 +97,14 @@ export function PricingSection({ content, locale, packages, paymentPeriod }: Pri
9697
? Math.max(0, Math.round((1 - pricingPackage.price / (pricingPackage.monthlyPrice * periodMonths)) * 100))
9798
: 0
9899

99-
return (
100+
const card = (
100101
<StaggerItem
101102
key={pricingPackage.key}
102103
y={14}
103104
duration={0.42}
104-
className={cn(
105-
"relative flex h-full min-w-0 flex-col overflow-hidden rounded-3xl border border-white/5 bg-[linear-gradient(160deg,rgba(255,255,255,0.08),rgba(255,255,255,0.02)_28%,rgba(8,10,20,0.6)_100%)] p-6 md:p-8",
106-
highlighted &&
107-
"z-10 border-brand/40 bg-[linear-gradient(160deg,rgba(145,232,120,0.14),rgba(255,255,255,0.04)_32%,rgba(8,10,20,0.72)_100%)] transition-[scale] duration-300 md:scale-[1.025] lg:scale-[1.05]"
108-
)}
105+
className="relative flex h-full min-w-0 flex-col overflow-hidden rounded-3xl border border-white/5 bg-[linear-gradient(160deg,rgba(255,255,255,0.08),rgba(255,255,255,0.02)_28%,rgba(8,10,20,0.6)_100%)] p-6 md:p-8"
109106
>
110-
<div className={cn("pointer-events-none absolute inset-x-0 top-0 h-px bg-linear-to-r from-transparent via-white/30 to-transparent", highlighted && "via-brand")} />
107+
<div className="pointer-events-none absolute inset-x-0 top-0 h-px bg-linear-to-r from-transparent via-white/30 to-transparent" />
111108
{discount > 0 && (
112109
<StableBadge
113110
border
@@ -117,24 +114,24 @@ export function PricingSection({ content, locale, packages, paymentPeriod }: Pri
117114
</StableBadge>
118115
)}
119116
<h3 className={cn("relative z-10 text-2xl font-semibold text-white", discount > 0 && "pr-20")}>{pricingPackage.title}</h3>
120-
{pricingPackage.description && <p className="relative z-10 mt-3 leading-6 text-secondary">{pricingPackage.description}</p>}
121117

122118
{pricingPackage.price !== null && (
123-
<div className="relative z-10 mt-6">
119+
<div className="relative z-10 mt-2">
124120
<div className="flex flex-wrap items-center gap-2">
125121
<NumberFlow
126122
value={pricingPackage.price}
127123
locales={locale === "de" ? "de-DE" : "en-US"}
128124
format={{ style: "currency", currency: "EUR", trailingZeroDisplay: "stripIfInteger" }}
129125
className="text-4xl font-semibold text-white"
130126
/>
127+
<span className="text-lg font-semibold text-tertiary">{periodSuffix}</span>
131128
</div>
132-
{periodSuffix && <p className="mt-1 text-sm text-tertiary">{periodSuffix}</p>}
133129
</div>
134130
)}
131+
{pricingPackage.description && <p className="relative z-10 leading-6 text-secondary">{pricingPackage.description}</p>}
135132

136133
{(features.length > 0 || missingFeatures.length > 0) && (
137-
<ul className="relative z-10 mt-8 flex flex-col gap-3">
134+
<ul className="relative z-10 mt-8 flex flex-col gap-2">
138135
{features.map((feature, featureIndex) => (
139136
<li key={feature.id ?? `feature-${featureIndex}`} className="flex items-start gap-3 text-sm text-white">
140137
<IconCheck size={18} className="mt-0.5 shrink-0 text-brand" />
@@ -163,6 +160,14 @@ export function PricingSection({ content, locale, packages, paymentPeriod }: Pri
163160
)}
164161
</StaggerItem>
165162
)
163+
164+
return highlighted ? (
165+
<BorderBeam key={pricingPackage.key} size="pulse-inner" colorVariant="colorful" strength={0.7} className="h-full">
166+
{card}
167+
</BorderBeam>
168+
) : (
169+
card
170+
)
166171
})}
167172
</StaggerContainer>
168173
</Section>

src/components/sections/SmallPricingSection.tsx

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,17 @@ interface SmallPricingSectionProps {
1717
content?: SmallPricingLayoutBlock | null
1818
locale: AppLocale
1919
packages: SubscriptionConfigData["packages"]
20-
paymentPeriod: SubscriptionConfigData["paymentPeriod"]
2120
}
2221

23-
export function SmallPricingSection({ content, locale, packages, paymentPeriod }: SmallPricingSectionProps) {
22+
export function SmallPricingSection({ content, locale, packages }: SmallPricingSectionProps) {
2423
if (!content) return null
2524

2625
const selectedPeriod = content.pricingPeriod
2726
const periodMonths = selectedPeriod === "quarterly" ? 3 : selectedPeriod === "yearly" ? 12 : 1
2827
const periodSuffix = {
29-
monthly: paymentPeriod.monthlyPeriodSuffix,
30-
quarterly: paymentPeriod.quarterlyPeriodSuffix,
31-
yearly: paymentPeriod.yearlyPeriodSuffix,
28+
monthly: "/mo",
29+
quarterly: "/qtr",
30+
yearly: "/yr",
3231
}[selectedPeriod]
3332
const pricingPackages = [
3433
{
@@ -72,13 +71,7 @@ export function SmallPricingSection({ content, locale, packages, paymentPeriod }
7271
funnelType={content.sectionLayout ?? "center"}
7372
animation={{ preset: "none" }}
7473
>
75-
<Card
76-
size="lg"
77-
variant="light"
78-
radialGradient={content.gradient}
79-
gradientDirection={content.gradientDirection}
80-
className="mx-auto w-full max-w-5xl p-2!"
81-
>
74+
<Card size="lg" variant="light" radialGradient={content.gradient} gradientDirection={content.gradientDirection} className="mx-auto w-full max-w-5xl p-2!">
8275
<StaggerContainer className="relative z-10 grid grid-cols-1 md:grid-cols-3" delayChildren={0.04} staggerChildren={0.08}>
8376
{pricingPackages.map((pricingPackage) => {
8477
const features = pricingPackage.content?.features?.filter((feature) => Boolean(feature.text)) ?? []
@@ -91,36 +84,31 @@ export function SmallPricingSection({ content, locale, packages, paymentPeriod }
9184
: 0
9285

9386
return (
94-
<StaggerItem
95-
key={pricingPackage.key}
96-
y={10}
97-
duration={0.36}
98-
className="flex min-w-0 flex-col p-5 sm:p-6"
99-
>
100-
<div className="flex items-start justify-between gap-3">
87+
<StaggerItem key={pricingPackage.key} y={10} duration={0.36} className="flex min-w-0 flex-col p-5 sm:p-6">
88+
<div className="flex items-start justify-between gap-2">
10189
<h3 className="text-xl font-semibold text-white">{pricingPackage.title}</h3>
10290
{discount > 0 && (
10391
<StableBadge border className="shrink-0 border-brand/25! bg-brand/15! px-2 py-1 text-xs font-semibold tracking-wider text-brand!">
10492
-{discount}%
10593
</StableBadge>
10694
)}
10795
</div>
108-
{pricingPackage.description && <p className="mt-2 text-sm leading-5 text-secondary">{pricingPackage.description}</p>}
10996

11097
{pricingPackage.price !== null && (
111-
<div className="mt-5">
98+
<div className="mt-2 flex items-baseline gap-1">
11299
<NumberFlow
113100
value={pricingPackage.price}
114101
locales={locale === "de" ? "de-DE" : "en-US"}
115102
format={{ style: "currency", currency: "EUR", trailingZeroDisplay: "stripIfInteger" }}
116103
className="text-3xl font-semibold text-white"
117104
/>
118-
{periodSuffix && <p className="mt-1 text-xs text-tertiary">{periodSuffix}</p>}
105+
<span className="text-lg font-semibold text-tertiary">{periodSuffix}</span>
119106
</div>
120107
)}
108+
{pricingPackage.description && <p className="text-sm leading-5 text-secondary">{pricingPackage.description}</p>}
121109

122110
{(features.length > 0 || missingFeatures.length > 0) && (
123-
<ul className="mt-6 flex flex-col gap-2.5">
111+
<ul className="mt-6 flex flex-col gap-1.5">
124112
{features.map((feature, featureIndex) => (
125113
<li key={feature.id ?? `feature-${featureIndex}`} className="flex items-start gap-2 text-sm text-white">
126114
<IconCheck size={16} className="mt-0.5 shrink-0 text-brand" />

0 commit comments

Comments
 (0)