Skip to content

Commit 497da72

Browse files
authored
Merge pull request #400 from kathy-ai-art/feat/redesign-landing-features
refactor(design): redesign landing page features from card grid to bento layout
2 parents 90e0648 + b4e5436 commit 497da72

2 files changed

Lines changed: 107 additions & 6 deletions

File tree

app/__tests__/page.test.tsx

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* eslint-disable react/display-name, @typescript-eslint/no-explicit-any */
2+
import React from 'react';
3+
import { render, screen } from '@testing-library/react';
4+
import LandingPage from '@/app/page';
5+
6+
// Mock translations
7+
jest.mock('@/lib/i18n/useAppTranslation', () => ({
8+
useAppTranslation: () => ({
9+
t: (key: string) => {
10+
const translations: Record<string, string> = {
11+
'landing.badge': 'Now live on Soroban Testnet',
12+
'landing.headline': 'Settle Globally.',
13+
'landing.headlineAccent': 'Instantly & Non-Custodial.',
14+
'landing.description': 'The next-generation merchant payment platform for African businesses.',
15+
'landing.primaryCta': 'Start Accepting Crypto',
16+
'landing.secondaryCta': 'Explore Features',
17+
'landing.featuresTitle': 'Powered by Stellar & Soroban',
18+
'landing.featuresDescription': 'Enterprise-grade payment infrastructure designed for speed, low fees, and perfect transparency.',
19+
'landing.features.settlement.title': 'Instant Settlement',
20+
'landing.features.settlement.description': 'Transactions settle in 3-5 seconds.',
21+
'landing.features.offRamps.title': 'SEP-24 Fiat Off-Ramps',
22+
'landing.features.offRamps.description': 'Automated routing to Stellar Anchors.',
23+
'landing.features.fees.title': 'Smart Fee Splits',
24+
'landing.features.fees.description': 'Soroban contracts automatically calculate and route platform fees.',
25+
};
26+
return translations[key] || key;
27+
},
28+
}),
29+
}));
30+
31+
// Mock next/link
32+
jest.mock('next/link', () => {
33+
return ({ children, href }: any) => {
34+
return <a href={href}>{children}</a>;
35+
};
36+
});
37+
38+
// Mock Header and Footer to isolate the page test
39+
jest.mock('@/components/layout', () => {
40+
return function MockLayout() {
41+
return <div data-testid="layout-component" />;
42+
};
43+
});
44+
45+
describe('Landing Page Integration Tests', () => {
46+
beforeEach(() => {
47+
jest.clearAllMocks();
48+
});
49+
50+
it('renders the main hero section with correct text', () => {
51+
render(<LandingPage />);
52+
expect(screen.getByText('Settle Globally.')).toBeInTheDocument();
53+
expect(screen.getByText('Instantly & Non-Custodial.')).toBeInTheDocument();
54+
});
55+
56+
it('renders the "Powered by Stellar & Soroban" headline as required', () => {
57+
render(<LandingPage />);
58+
expect(screen.getByText('Powered by Stellar & Soroban')).toBeInTheDocument();
59+
});
60+
61+
it('renders all three feature cards with translations', () => {
62+
render(<LandingPage />);
63+
64+
// Feature 1
65+
expect(screen.getByText('Instant Settlement')).toBeInTheDocument();
66+
expect(screen.getByText('Transactions settle in 3-5 seconds.')).toBeInTheDocument();
67+
68+
// Feature 2
69+
expect(screen.getByText('SEP-24 Fiat Off-Ramps')).toBeInTheDocument();
70+
expect(screen.getByText('Automated routing to Stellar Anchors.')).toBeInTheDocument();
71+
72+
// Feature 3
73+
expect(screen.getByText('Smart Fee Splits')).toBeInTheDocument();
74+
expect(screen.getByText('Soroban contracts automatically calculate and route platform fees.')).toBeInTheDocument();
75+
});
76+
77+
it('renders feature elements within a list structure', () => {
78+
render(<LandingPage />);
79+
// The grid div has role="list"
80+
const list = screen.getByRole('list');
81+
expect(list).toBeInTheDocument();
82+
83+
// Features are in listitems
84+
const listitems = screen.getAllByRole('listitem');
85+
expect(listitems).toHaveLength(3);
86+
});
87+
});

app/page.tsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,32 @@ export default function LandingPage() {
8181
</p>
8282
</div>
8383

84-
<div className="grid md:grid-cols-3 gap-6" role="list">
84+
<div className="grid grid-cols-1 md:grid-cols-12 gap-6" role="list">
8585
{features.map((feature, i) => (
8686
<div
8787
key={i}
88-
className="p-8 rounded-2xl bg-card border border-border hover:border-primary/40 hover:shadow-md transition-all duration-200"
88+
className={`group relative overflow-hidden p-8 rounded-3xl bg-card border border-border hover:border-primary/40 hover:shadow-lg transition-all duration-300 ${
89+
i === 0 ? "md:col-span-8 md:row-span-2 flex flex-col justify-center min-h-[400px]" : "md:col-span-4"
90+
}`}
8991
role="listitem"
9092
>
91-
<div className="w-11 h-11 rounded-xl bg-primary/10 border border-primary/20 flex items-center justify-center mb-6" aria-hidden="true">
92-
<feature.icon className="w-5 h-5 text-primary" />
93+
{/* Subtle background decoration for the primary card */}
94+
{i === 0 && (
95+
<div className="absolute right-0 top-0 -mt-8 -mr-8 w-64 h-64 bg-primary/5 rounded-full blur-3xl group-hover:bg-primary/10 transition-colors duration-500" aria-hidden="true" />
96+
)}
97+
98+
<div className={`relative z-10 w-12 h-12 rounded-xl bg-primary/10 border border-primary/20 flex items-center justify-center mb-6 ${i === 0 ? 'w-16 h-16 mb-8' : ''}`} aria-hidden="true">
99+
<feature.icon className={`text-primary ${i === 0 ? 'w-8 h-8' : 'w-6 h-6'}`} />
100+
</div>
101+
102+
<div className="relative z-10">
103+
<h3 className={`font-bold mb-3 text-foreground ${i === 0 ? 'text-3xl lg:text-4xl' : 'text-xl'}`}>
104+
{t(`landing.features.${feature.key}.title`)}
105+
</h3>
106+
<p className={`text-muted-foreground leading-relaxed ${i === 0 ? 'text-lg max-w-xl' : 'text-base'}`}>
107+
{t(`landing.features.${feature.key}.description`)}
108+
</p>
93109
</div>
94-
<h3 className="text-lg font-semibold mb-3 text-foreground">{t(`landing.features.${feature.key}.title`)}</h3>
95-
<p className="text-muted-foreground leading-relaxed text-sm">{t(`landing.features.${feature.key}.description`)}</p>
96110
</div>
97111
))}
98112
</div>

0 commit comments

Comments
 (0)