feat: redesign pricing section with card grid, featured unlimited plan

- Subscription cards in responsive grid (1/2/3 cols)
- Popular badge with sparkle floating above first card
- Unlimited plan as featured card with glitter border and crown icon
- Rental items as individual rounded cards
- Rules in numbered card layout

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 19:58:43 +03:00
parent f2b840416d
commit 8fbbc94024

View File

@@ -1,7 +1,7 @@
"use client";
import { useState } from "react";
import { CreditCard, Building2, ScrollText } from "lucide-react";
import { CreditCard, Building2, ScrollText, Crown, Sparkles } from "lucide-react";
import { siteContent } from "@/data/content";
import { SectionHeading } from "@/components/ui/SectionHeading";
import { Reveal } from "@/components/ui/Reveal";
@@ -18,6 +18,10 @@ export function Pricing() {
{ id: "rules", label: "Правила", icon: <ScrollText size={16} /> },
];
// Split items: regular + unlimited (last item)
const regularItems = pricing.items.slice(0, -1);
const unlimitedItem = pricing.items[pricing.items.length - 1];
return (
<section id="pricing" className="section-glow relative section-padding bg-neutral-50 dark:bg-[#050505]">
<div className="section-divider absolute top-0 left-0 right-0" />
@@ -33,7 +37,7 @@ export function Pricing() {
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`inline-flex items-center gap-2 rounded-full px-6 py-2.5 text-sm font-medium transition-all duration-300 ${
className={`inline-flex items-center gap-2 rounded-full px-6 py-2.5 text-sm font-medium transition-all duration-300 cursor-pointer ${
activeTab === tab.id
? "bg-[#c9a96e] text-black shadow-lg shadow-[#c9a96e]/25"
: "bg-neutral-100 text-neutral-600 hover:bg-neutral-200 dark:bg-white/[0.06] dark:text-neutral-300 dark:hover:bg-white/[0.1]"
@@ -49,44 +53,80 @@ export function Pricing() {
{/* Prices tab */}
{activeTab === "prices" && (
<Reveal>
<div className="mx-auto mt-10 max-w-2xl">
<div className="mx-auto mt-10 max-w-4xl">
<p className="mb-8 text-center text-sm text-neutral-500 dark:text-neutral-400">
{pricing.subtitle}
</p>
<div className="overflow-hidden rounded-2xl border border-neutral-200 dark:border-white/[0.06]">
{pricing.items.map((item, i) => {
{/* Cards grid */}
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
{regularItems.map((item, i) => {
const isPopular = i === 0;
return (
<div
key={i}
className={`group flex items-center justify-between gap-4 px-6 py-5 transition-colors hover:bg-neutral-50 dark:hover:bg-white/[0.03] ${
i > 0 ? "border-t border-neutral-100 dark:border-white/[0.04]" : ""
} ${isPopular ? "bg-[#c9a96e]/[0.04] dark:bg-[#c9a96e]/[0.03]" : ""}`}
className={`group relative rounded-2xl border p-5 transition-all duration-300 ${
isPopular
? "border-[#c9a96e]/40 bg-gradient-to-br from-[#c9a96e]/10 via-transparent to-[#c9a96e]/5 dark:from-[#c9a96e]/[0.07] dark:to-[#c9a96e]/[0.02] shadow-lg shadow-[#c9a96e]/10"
: "border-neutral-200 bg-white hover:border-neutral-300 dark:border-white/[0.06] dark:bg-[#0a0a0a] dark:hover:border-white/[0.12]"
}`}
>
<div>
<div className="flex items-center gap-2">
<p className="font-medium text-neutral-900 dark:text-white">
{item.name}
</p>
{isPopular && (
<span className="rounded-full bg-[#c9a96e]/15 px-2.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-[#a08050] dark:text-[#d4b87a]">
Популярный
</span>
)}
{/* Popular badge */}
{isPopular && (
<div className="absolute -top-3 left-1/2 -translate-x-1/2">
<span className="inline-flex items-center gap-1 rounded-full bg-[#c9a96e] px-3 py-1 text-[10px] font-bold uppercase tracking-wider text-black shadow-md shadow-[#c9a96e]/30">
<Sparkles size={10} />
Популярный
</span>
</div>
)}
<div className={isPopular ? "mt-1" : ""}>
{/* Name */}
<p className={`text-sm font-medium ${isPopular ? "text-[#a08050] dark:text-[#d4b87a]" : "text-neutral-700 dark:text-neutral-300"}`}>
{item.name}
</p>
{/* Note */}
{item.note && (
<p className="mt-0.5 text-sm text-neutral-500 dark:text-neutral-400">
<p className="mt-1 text-xs text-neutral-400 dark:text-neutral-500">
{item.note}
</p>
)}
{/* Price */}
<p className={`mt-3 font-display text-2xl font-bold ${isPopular ? "text-[#c9a96e]" : "text-neutral-900 dark:text-white"}`}>
{item.price}
</p>
</div>
<span className="shrink-0 font-display text-xl font-bold text-[#a08050] dark:text-[#d4b87a]">
{item.price}
</span>
</div>
);
})}
</div>
{/* Unlimited — featured card */}
{unlimitedItem && (
<div className="mt-6 team-card-glitter rounded-2xl border border-[#c9a96e]/30 bg-gradient-to-r from-[#c9a96e]/10 via-[#c9a96e]/5 to-[#c9a96e]/10 dark:from-[#c9a96e]/[0.06] dark:via-transparent dark:to-[#c9a96e]/[0.06] p-6 sm:p-8">
<div className="flex flex-col items-center gap-4 sm:flex-row sm:justify-between">
<div className="text-center sm:text-left">
<div className="flex items-center justify-center gap-2 sm:justify-start">
<Crown size={18} className="text-[#c9a96e]" />
<p className="text-lg font-bold text-neutral-900 dark:text-white">
{unlimitedItem.name}
</p>
</div>
{unlimitedItem.note && (
<p className="mt-1 text-sm text-neutral-500 dark:text-neutral-400">
{unlimitedItem.note}
</p>
)}
</div>
<p className="shrink-0 font-display text-3xl font-bold text-[#c9a96e]">
{unlimitedItem.price}
</p>
</div>
</div>
)}
</div>
</Reveal>
)}
@@ -94,31 +134,27 @@ export function Pricing() {
{/* Rental tab */}
{activeTab === "rental" && (
<Reveal>
<div className="mx-auto mt-10 max-w-2xl">
<div className="overflow-hidden rounded-2xl border border-neutral-200 dark:border-white/[0.06]">
{pricing.rentalItems.map((item, i) => (
<div
key={i}
className={`group flex items-center justify-between gap-4 px-6 py-5 transition-colors hover:bg-neutral-50 dark:hover:bg-white/[0.03] ${
i > 0 ? "border-t border-neutral-100 dark:border-white/[0.04]" : ""
}`}
>
<div>
<p className="font-medium text-neutral-900 dark:text-white">
{item.name}
<div className="mx-auto mt-10 max-w-2xl space-y-3">
{pricing.rentalItems.map((item, i) => (
<div
key={i}
className="flex items-center justify-between gap-4 rounded-2xl border border-neutral-200 bg-white px-6 py-5 transition-colors hover:border-neutral-300 dark:border-white/[0.06] dark:bg-[#0a0a0a] dark:hover:border-white/[0.12]"
>
<div>
<p className="font-medium text-neutral-900 dark:text-white">
{item.name}
</p>
{item.note && (
<p className="mt-0.5 text-sm text-neutral-500 dark:text-neutral-400">
{item.note}
</p>
{item.note && (
<p className="mt-0.5 text-sm text-neutral-500 dark:text-neutral-400">
{item.note}
</p>
)}
</div>
<span className="shrink-0 font-display text-xl font-bold text-[#a08050] dark:text-[#d4b87a]">
{item.price}
</span>
)}
</div>
))}
</div>
<span className="shrink-0 font-display text-xl font-bold text-[#a08050] dark:text-[#d4b87a]">
{item.price}
</span>
</div>
))}
</div>
</Reveal>
)}
@@ -126,16 +162,16 @@ export function Pricing() {
{/* Rules tab */}
{activeTab === "rules" && (
<Reveal>
<div className="mx-auto mt-10 max-w-2xl space-y-4">
<div className="mx-auto mt-10 max-w-2xl space-y-3">
{pricing.rules.map((rule, i) => (
<div
key={i}
className="flex gap-4"
className="flex gap-4 rounded-2xl border border-neutral-200 bg-white px-5 py-4 dark:border-white/[0.06] dark:bg-[#0a0a0a]"
>
<span className="mt-1 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-[#c9a96e]/10 text-xs font-bold text-[#a08050] dark:bg-[#c9a96e]/10 dark:text-[#d4b87a]">
<span className="mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-[#c9a96e]/10 text-xs font-bold text-[#a08050] dark:bg-[#c9a96e]/10 dark:text-[#d4b87a]">
{i + 1}
</span>
<p className="text-sm leading-relaxed text-neutral-700 dark:text-neutral-300 sm:text-base">
<p className="text-sm leading-relaxed text-neutral-700 dark:text-neutral-300">
{rule}
</p>
</div>