Skip to content

Commit bc0912c

Browse files
committed
feat: redesign Features section
1 parent b8dbed1 commit bc0912c

13 files changed

+302
-119
lines changed

components/FeatureCard.tsx

Lines changed: 73 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,91 @@
1-
import React from 'react';
2-
import { LucideIcon, ExternalLink } from 'lucide-react';
1+
import React, { CSSProperties, ReactNode, forwardRef } from 'react';
32
import Link from 'next/link';
43

54
interface FeatureCardProps {
6-
icon: LucideIcon;
7-
title: string;
8-
description: string;
5+
title: ReactNode;
6+
description: ReactNode;
7+
ctaHref: string;
8+
ctaText: string;
9+
media: ReactNode;
910
className?: string;
10-
link?: string;
11+
isSlideChanging?: boolean;
12+
leftWrapperStyle?: CSSProperties;
13+
leftContentStyle?: CSSProperties;
14+
leftContentRef?: React.Ref<HTMLDivElement>;
15+
children?: ReactNode;
1116
}
1217

13-
const DEFAULT_DOCS_URL = 'https://opsimate.vercel.app/docs/';
14-
15-
const FeatureCard: React.FC<FeatureCardProps> = ({
16-
icon: Icon,
18+
const FeatureCard = forwardRef<HTMLDivElement, FeatureCardProps>(({
1719
title,
1820
description,
21+
ctaHref,
22+
ctaText,
23+
media,
1924
className = '',
20-
link,
21-
}) => {
22-
const resolvedLink = link ?? DEFAULT_DOCS_URL;
25+
isSlideChanging = false,
26+
leftWrapperStyle,
27+
leftContentStyle,
28+
leftContentRef,
29+
children,
30+
}, ref) => {
31+
const isExternal = /^https?:\/\//.test(ctaHref);
2332

2433
return (
25-
<div className={`feature-card group hover:scale-105 transition-all duration-300 ${className}`}>
26-
<div className="flex items-center mb-3">
27-
<div className="bg-surface-200 dark:bg-surface-700 p-2 rounded-lg group-hover:bg-surface-300 dark:group-hover:bg-surface-600 transition-colors duration-300">
28-
<Icon className="h-5 w-5 text-surface-600 dark:text-surface-400" />
34+
<div
35+
ref={ref}
36+
className={`relative isolate overflow-hidden border-2 border-surface-900 dark:border-white/20 bg-[#fdfbf7] dark:bg-surface-900 text-surface-900 dark:text-surface-50 shadow-[12px_12px_0_rgba(15,15,15,0.08)] p-6 md:p-10 lg:p-14 pb-28 md:pb-32 md:h-[520px] lg:h-[560px] ${className}`}
37+
>
38+
<div
39+
aria-hidden
40+
className="pointer-events-none absolute inset-0 opacity-30 mix-blend-multiply"
41+
style={{
42+
backgroundImage: 'linear-gradient(90deg, rgba(15,15,15,0.08) 1px, transparent 1px), linear-gradient(rgba(15,15,15,0.08) 1px, transparent 1px)',
43+
backgroundSize: '48px 48px',
44+
}}
45+
/>
46+
<div className="absolute -right-16 -top-16 h-32 w-32 border-2 border-surface-900 dark:border-white/30 bg-[#0a5ad4] opacity-30 rotate-[25deg]" aria-hidden />
47+
<div className="relative grid grid-cols-1 lg:grid-cols-12 gap-10 lg:gap-14 items-start">
48+
<div className="lg:col-span-5 overflow-hidden">
49+
<div className="flex items-center gap-4 text-[11px] tracking-[0.45em] uppercase text-[#0a5ad4] dark:text-[#7cc6ff]">
50+
<span className="h-px flex-1 bg-[#0a5ad4]/60 dark:bg-[#7cc6ff]/60" aria-hidden />
51+
<span>O P S I M A T E</span>
52+
</div>
53+
<div
54+
className={`mt-6 transition-all duration-500 will-change-transform ease-[cubic-bezier(0.22,0.61,0.36,1)] ${isSlideChanging ? 'opacity-0 -translate-x-8 blur-sm' : 'opacity-100 translate-x-0 blur-0'}`}
55+
style={leftWrapperStyle}
56+
>
57+
<div
58+
ref={leftContentRef}
59+
style={leftContentStyle}
60+
>
61+
<h2 className="text-[32px] sm:text-5xl md:text-6xl font-black font-sans uppercase tracking-[0.08em] text-surface-900 dark:text-white leading-[1.05]">
62+
{title}
63+
</h2>
64+
<p className="mt-6 text-base sm:text-lg leading-relaxed tracking-wide text-surface-600 dark:text-surface-200 max-w-md font-source-sans">
65+
<span className="inline">{description}</span>
66+
<Link
67+
href={ctaHref}
68+
className="ml-3 inline-flex items-center gap-2 text-[11px] uppercase tracking-[0.3em] font-semibold text-[#0a5ad4] dark:text-[#7cc6ff] border-b-2 border-current pb-0.5"
69+
{...(isExternal && { target: '_blank', rel: 'noopener noreferrer' })}
70+
>
71+
<span>{ctaText}</span>
72+
<span aria-hidden className="text-sm leading-none"></span>
73+
</Link>
74+
</p>
75+
</div>
76+
</div>
77+
</div>
78+
79+
<div className="lg:col-span-7 hidden lg:block">
80+
{media}
2981
</div>
3082
</div>
31-
<h3 className="text-lg font-semibold text-surface-900 dark:text-surface-100 mb-2">{title}</h3>
32-
<p className="text-sm text-surface-600 dark:text-surface-400 leading-relaxed">{description}</p>
3383

34-
{resolvedLink && (
35-
<Link
36-
href={resolvedLink}
37-
className="mt-3 inline-flex items-center gap-1 text-blue-600 hover:text-blue-700 text-sm font-medium transition-colors duration-200"
38-
{...(resolvedLink.startsWith('https') && {
39-
target: "_blank",
40-
rel: "noopener noreferrer"
41-
})}
42-
>
43-
Learn more
44-
{resolvedLink.startsWith('https') && <ExternalLink className="h-3 w-3" />}
45-
</Link>
46-
)}
84+
{children}
4785
</div>
4886
);
49-
};
87+
});
88+
89+
FeatureCard.displayName = 'FeatureCard';
5090

5191
export default FeatureCard;

0 commit comments

Comments
 (0)