From c70d5afd31017b87fb904d098dff02d31fd8d6cb Mon Sep 17 00:00:00 2001 From: samuelisi Date: Mon, 27 Jul 2026 11:30:14 +0000 Subject: [PATCH 1/4] refactor(frontend): extract FeatureCard/Step/FooterColumn from LandingPage The three feature cards, four how-it-works steps, and three footer sections were each near-identical hand-copied JSX blocks. Extract shared components and drive them from small local data arrays via .map() to remove the duplication and shrink LandingPage.tsx. Co-Authored-By: Claude Sonnet 5 --- frontend/src/components/LandingPage.tsx | 116 ++++++------------ .../__tests__/LandingPage.dataDriven.test.tsx | 45 +++++++ .../src/components/landing/FeatureCard.tsx | 15 +++ .../src/components/landing/FooterColumn.tsx | 37 ++++++ frontend/src/components/landing/Step.tsx | 13 ++ 5 files changed, 148 insertions(+), 78 deletions(-) create mode 100644 frontend/src/components/__tests__/LandingPage.dataDriven.test.tsx create mode 100644 frontend/src/components/landing/FeatureCard.tsx create mode 100644 frontend/src/components/landing/FooterColumn.tsx create mode 100644 frontend/src/components/landing/Step.tsx diff --git a/frontend/src/components/LandingPage.tsx b/frontend/src/components/LandingPage.tsx index 4b76c2ff..200a5e7c 100644 --- a/frontend/src/components/LandingPage.tsx +++ b/frontend/src/components/LandingPage.tsx @@ -6,6 +6,9 @@ import { api } from '../lib/api/client'; import { Statistics } from './Statistics'; import { ErrorBoundary } from './ErrorBoundary'; import { LoadingSpinner } from './LoadingSpinner'; +import { FeatureCard } from './landing/FeatureCard'; +import { Step } from './landing/Step'; +import { FooterColumn } from './landing/FooterColumn'; interface LandingPageProps { className?: string; @@ -61,6 +64,32 @@ export const LandingPage: React.FC = ({ className }) => { } }; + const features = [ + { icon: '/icons/decentralized.svg', title: t('features.decentralized.title'), description: t('features.decentralized.description') }, + { icon: '/icons/secure.svg', title: t('features.secure.title'), description: t('features.secure.description') }, + { icon: '/icons/fast.svg', title: t('features.fast.title'), description: t('features.fast.description') }, + ]; + + const steps = [ + { title: t('howItWorks.step1.title'), description: t('howItWorks.step1.description') }, + { title: t('howItWorks.step2.title'), description: t('howItWorks.step2.description') }, + { title: t('howItWorks.step3.title'), description: t('howItWorks.step3.description') }, + { title: t('howItWorks.step4.title'), description: t('howItWorks.step4.description') }, + ]; + + const footerColumns = [ + { heading: t('footer.title'), headingLevel: 'h2' as const, tagline: t('footer.tagline') }, + { heading: t('footer.linksHeading'), links: [ + { href: '/docs', label: t('footer.documentation') }, + { href: '/github', label: t('footer.github') }, + { href: '/discord', label: t('footer.discord') }, + ] }, + { heading: t('footer.legalHeading'), links: [ + { href: '/privacy', label: t('footer.privacy') }, + { href: '/terms', label: t('footer.terms') }, + ] }, + ]; + return (
{/* Skip to main content link */} @@ -237,47 +266,9 @@ export const LandingPage: React.FC = ({ className }) => {

{t('features.heading')}

-
- -

{t('features.decentralized.title')}

-

- {t('features.decentralized.description')} -

-
- -
- -

{t('features.secure.title')}

-

- {t('features.secure.description')} -

-
- -
- -

{t('features.fast.title')}

-

- {t('features.fast.description')} -

-
+ {features.map((feature) => ( + + ))}
@@ -286,22 +277,9 @@ export const LandingPage: React.FC = ({ className }) => {

{t('howItWorks.heading')}

    -
  1. -

    {t('howItWorks.step1.title')}

    -

    {t('howItWorks.step1.description')}

    -
  2. -
  3. -

    {t('howItWorks.step2.title')}

    -

    {t('howItWorks.step2.description')}

    -
  4. -
  5. -

    {t('howItWorks.step3.title')}

    -

    {t('howItWorks.step3.description')}

    -
  6. -
  7. -

    {t('howItWorks.step4.title')}

    -

    {t('howItWorks.step4.description')}

    -
  8. + {steps.map((step) => ( + + ))}
@@ -320,27 +298,9 @@ export const LandingPage: React.FC = ({ className }) => { {/* Footer */}