Files
softclick-landing/src/sections/Cases.tsx
Zotov Ivan Yuryevich 4ab369957b chore: minor improvements
2026-07-21 13:09:02 +03:00

108 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ArrowRight } from 'lucide-react'
import { toComponent } from '../lib/cms/icon'
import { toElevatedGradient, toTextColor } from '../lib/cms/color'
import type { Enum_Componentsharedcolor_Value, Enum_Componentsharedicon_Value } from '../graphql/graphql'
import type { Maybe } from '../lib/types'
export interface CaseCardCms {
id: string
title?: Maybe<string>
description?: Maybe<string>
pretitle?: Maybe<string>
badge?: Maybe<string>
footnote?: Maybe<string>
color?: Maybe<{ value?: Maybe<Enum_Componentsharedcolor_Value> }>
icon?: Maybe<{ value?: Maybe<Enum_Componentsharedicon_Value> }>
}
export interface CasesCmsData {
title?: Maybe<string>
description?: Maybe<string>
cards?: Maybe<Array<Maybe<CaseCardCms>>>
}
interface CasesProps {
data?: Maybe<CasesCmsData>
}
export function Cases({ data }: CasesProps) {
const title = data?.title ?? ''
const description = data?.description ?? ''
const cards = (data?.cards ?? []).filter((c): c is CaseCardCms => Boolean(c))
if (!title && !description && cards.length === 0) {
return null
}
return (
<section className="py-4 bg-white">
<div className="max-w-400 mx-auto px-6 xl:px-12 2xl:px-16">
<div className="mb-16">
<p className="text-sm uppercase tracking-wider text-gray-500 mb-4">Кейсы</p>
{title ? <h2 className="text-4xl lg:text-5xl text-gray-900 mb-6">{title}</h2> : null}
{description ? <p className="text-xl text-gray-600">{description}</p> : null}
</div>
<div className="grid lg:grid-cols-3 gap-8">
{cards.map((caseItem, index) => {
const Icon = toComponent(caseItem.icon?.value)
const gradient = toElevatedGradient(caseItem.color?.value)
const iconColorClass = toTextColor(caseItem.color?.value)
const floatClass =
index === 0 ? 'animate-float' : index === 1 ? 'animate-float-delay-1' : 'animate-float-delay-2'
return (
<div
key={caseItem.id}
className="group bg-white rounded-2xl overflow-hidden border border-gray-100 hover:border-blue-200 hover:shadow-xl transition-all duration-300 cursor-pointer flex flex-col"
>
<div
className={`relative h-64 overflow-hidden bg-linear-to-br ${gradient} flex items-center justify-center`}
>
<div
className={`w-24 h-24 bg-white rounded-2xl flex items-center justify-center group-hover:scale-110 transition-transform duration-300 shadow-md ${floatClass}`}
>
<Icon className={`w-12 h-12 ${iconColorClass}`} />
</div>
{caseItem.badge ? (
<div className="absolute top-4 left-4">
<span className="px-3 py-1 bg-white/90 backdrop-blur-sm text-gray-900 rounded-full border border-gray-200 text-sm">
{caseItem.badge}
</span>
</div>
) : null}
</div>
<div className="p-6 flex flex-col flex-1">
{caseItem.pretitle ? <div className="text-sm text-blue-600 mb-2">{caseItem.pretitle}</div> : null}
{caseItem.title ? <h3 className="text-xl text-gray-900 mb-3">{caseItem.title}</h3> : null}
{caseItem.description ? (
<p className="text-gray-600 mb-4 leading-relaxed flex-1">{caseItem.description}</p>
) : null}
<div className="pt-4 border-t border-gray-100 flex items-center justify-between">
<span className="text-gray-900">{caseItem.footnote ?? ''}</span>
<ArrowRight className="w-5 h-5 text-gray-400 group-hover:text-blue-600 group-hover:translate-x-1 transition-all" />
</div>
</div>
</div>
)
})}
</div>
<div className="text-center mt-12">
<button
type="button"
className="px-8 py-4 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all shadow-md hover:shadow-lg inline-flex items-center gap-2"
>
Все кейсы
<ArrowRight className="w-5 h-5" />
</button>
</div>
</div>
</section>
)
}