Files
myeasycms-v2/apps/web/app/[locale]/(marketing)/page.tsx
Zaid Marzguioui b26e5aaafa
Some checks failed
Workflow / ʦ TypeScript (push) Failing after 6m20s
Workflow / ⚫️ Test (push) Has been skipped
feat: pre-existing local changes — fischerei, verband, modules, members, packages
Commits all remaining uncommitted local work:

- apps/web: fischerei, verband, modules, members-cms, documents,
  newsletter, meetings, site-builder, courses, bookings, events,
  finance pages and components
- apps/web: marketing page updates, layout, paths config,
  next.config.mjs, styles/makerkit.css
- apps/web/i18n: documents, fischerei, marketing, verband (de+en)
- packages/features: finance, fischerei, member-management,
  module-builder, newsletter, sitzungsprotokolle, verbandsverwaltung
  server APIs and components
- packages/ui: button.tsx updates
- pnpm-lock.yaml
2026-04-02 01:19:54 +02:00

545 lines
19 KiB
TypeScript

import Image from 'next/image';
import Link from 'next/link';
import {
ArrowRightIcon,
CalendarIcon,
FileTextIcon,
GraduationCapIcon,
LayoutDashboardIcon,
MailIcon,
ShieldCheckIcon,
UsersIcon,
WalletIcon,
BedDoubleIcon,
GlobeIcon,
ZapIcon,
HeadsetIcon,
LockIcon,
SmartphoneIcon,
CheckIcon,
} from 'lucide-react';
import { PricingTable } from '@kit/billing-gateway/marketing';
import {
CtaButton,
EcosystemShowcase,
FeatureShowcase,
FeatureShowcaseIconContainer,
GradientText,
Hero,
Pill,
SecondaryHero,
} from '@kit/ui/marketing';
import { Trans } from '@kit/ui/trans';
import { cn } from '@kit/ui/utils';
import billingConfig from '~/config/billing.config';
import pathsConfig from '~/config/paths.config';
import { AnimateOnScroll } from './_components/animate-on-scroll';
function Home() {
return (
<div className={'mt-4 flex flex-col space-y-24 py-14 lg:space-y-36'}>
{/* Hero Section */}
<div className={'mx-auto'}>
<Hero
pill={
<Pill label={'Neu'}>
<span>
<Trans i18nKey={'marketing.heroPill'} />
</span>
</Pill>
}
title={
<span className="text-secondary-foreground">
<Trans i18nKey={'marketing.heroTitleLine1'} />{' '}
<GradientText className="from-primary to-primary/60">
<Trans i18nKey={'marketing.heroTitleLine2'} />
</GradientText>
</span>
}
subtitle={
<span>
<Trans i18nKey={'marketing.heroSubtitle'} />
</span>
}
cta={<MainCallToActionButton />}
image={
<div className="relative">
<div
className="bg-primary/10 absolute inset-0 -z-10 mx-auto max-w-3xl rounded-full blur-3xl"
aria-hidden="true"
/>
<Image
priority
className={
'dark:border-primary/10 w-full rounded-2xl border border-gray-200 shadow-2xl'
}
width={3558}
height={2222}
src={`/images/dashboard.webp`}
alt={`MyEasyCMS Dashboard`}
/>
</div>
}
/>
</div>
{/* Stats Bar */}
<AnimateOnScroll>
<div className={'container mx-auto'}>
<div className="border-border border-y py-8">
<p className="text-muted-foreground mb-6 text-center text-sm font-medium tracking-widest uppercase">
<Trans i18nKey={'marketing.trustedBy'} />
</p>
<div className="reveal-stagger divide-border flex flex-wrap items-center justify-center divide-x">
<StatItem value="69,000+" labelKey="marketing.statMembers" />
<StatItem value="90+" labelKey="marketing.statOrganizations" />
<StatItem value="22" labelKey="marketing.statYears" />
<StatItem value="3" labelKey="marketing.statFederations" />
</div>
</div>
</div>
</AnimateOnScroll>
{/* Core Modules Feature Grid */}
<AnimateOnScroll>
<div className={'container mx-auto'}>
<div className={'py-4 xl:py-8'}>
<FeatureShowcase
heading={
<>
<b className="font-medium tracking-tight dark:text-white">
<Trans i18nKey={'marketing.featuresHeading'} />
</b>
.{' '}
<span className="text-secondary-foreground/70 block font-normal tracking-tight">
<Trans i18nKey={'marketing.featuresSubheading'} />
</span>
</>
}
icon={
<FeatureShowcaseIconContainer>
<LayoutDashboardIcon className="h-4 w-4" />
<span>
<Trans i18nKey={'marketing.featuresLabel'} />
</span>
</FeatureShowcaseIconContainer>
}
>
<div className="reveal-stagger mt-2 grid w-full grid-cols-1 gap-4 md:mt-6 md:grid-cols-2 lg:grid-cols-3">
<IconFeatureCard
icon={UsersIcon}
titleKey="marketing.featureMembersTitle"
descKey="marketing.featureMembersDesc"
/>
<IconFeatureCard
icon={GraduationCapIcon}
titleKey="marketing.featureCoursesTitle"
descKey="marketing.featureCoursesDesc"
accentBg="bg-chart-1/10"
accentText="text-chart-1"
/>
<IconFeatureCard
icon={BedDoubleIcon}
titleKey="marketing.featureBookingsTitle"
descKey="marketing.featureBookingsDesc"
accentBg="bg-chart-2/10"
accentText="text-chart-2"
/>
<IconFeatureCard
icon={CalendarIcon}
titleKey="marketing.featureEventsTitle"
descKey="marketing.featureEventsDesc"
accentBg="bg-chart-3/10"
accentText="text-chart-3"
/>
<IconFeatureCard
icon={WalletIcon}
titleKey="marketing.featureFinanceTitle"
descKey="marketing.featureFinanceDesc"
accentBg="bg-chart-4/10"
accentText="text-chart-4"
/>
<IconFeatureCard
icon={MailIcon}
titleKey="marketing.featureNewsletterTitle"
descKey="marketing.featureNewsletterDesc"
accentBg="bg-chart-5/10"
accentText="text-chart-5"
/>
</div>
</FeatureShowcase>
</div>
</div>
</AnimateOnScroll>
{/* Testimonials */}
<AnimateOnScroll>
<div className="container mx-auto">
<div className="flex flex-col items-center gap-12">
<div className="text-center">
<h2 className="text-3xl font-medium tracking-tight xl:text-5xl dark:text-white">
<Trans i18nKey={'marketing.testimonialsHeading'} />
</h2>
<p className="text-secondary-foreground/70 mx-auto mt-4 max-w-2xl text-xl font-medium tracking-tight">
<Trans i18nKey={'marketing.testimonialsSubheading'} />
</p>
</div>
<div className="reveal-stagger grid w-full grid-cols-1 gap-6 md:grid-cols-3">
<TestimonialCard
quoteKey="marketing.testimonial1Quote"
nameKey="marketing.testimonial1Name"
roleKey="marketing.testimonial1Role"
/>
<TestimonialCard
quoteKey="marketing.testimonial2Quote"
nameKey="marketing.testimonial2Name"
roleKey="marketing.testimonial2Role"
/>
<TestimonialCard
quoteKey="marketing.testimonial3Quote"
nameKey="marketing.testimonial3Name"
roleKey="marketing.testimonial3Role"
/>
</div>
</div>
</div>
</AnimateOnScroll>
{/* Additional Features Row */}
<AnimateOnScroll>
<div className={'container mx-auto'}>
<div className={'py-4 xl:py-8'}>
<FeatureShowcase
heading={
<>
<b className="font-medium tracking-tight dark:text-white">
<Trans i18nKey={'marketing.additionalFeaturesHeading'} />
</b>
.{' '}
<span className="text-secondary-foreground/70 block font-normal tracking-tight">
<Trans i18nKey={'marketing.additionalFeaturesSubheading'} />
</span>
</>
}
icon={
<FeatureShowcaseIconContainer>
<ZapIcon className="h-4 w-4" />
<span>
<Trans i18nKey={'marketing.additionalFeaturesLabel'} />
</span>
</FeatureShowcaseIconContainer>
}
>
<div className="reveal-stagger mt-2 grid w-full grid-cols-1 gap-4 md:mt-6 md:grid-cols-2 lg:grid-cols-3">
<IconFeatureCard
icon={FileTextIcon}
titleKey="marketing.featureDocumentsTitle"
descKey="marketing.featureDocumentsDesc"
accentBg="bg-chart-1/10"
accentText="text-chart-1"
/>
<IconFeatureCard
icon={GlobeIcon}
titleKey="marketing.featureSiteBuilderTitle"
descKey="marketing.featureSiteBuilderDesc"
accentBg="bg-chart-2/10"
accentText="text-chart-2"
/>
<IconFeatureCard
icon={LayoutDashboardIcon}
titleKey="marketing.featureModulesTitle"
descKey="marketing.featureModulesDesc"
accentBg="bg-chart-3/10"
accentText="text-chart-3"
/>
</div>
</FeatureShowcase>
</div>
</div>
</AnimateOnScroll>
{/* Why Choose Us Section */}
<AnimateOnScroll>
<div className={'container mx-auto'}>
<EcosystemShowcase
heading={<Trans i18nKey={'marketing.whyChooseHeading'} />}
description={<Trans i18nKey={'marketing.whyChooseDescription'} />}
textPosition="right"
className="border-primary/10 rounded-xl border"
>
<div className="flex flex-col gap-6">
<WhyItem
icon={SmartphoneIcon}
titleKey="marketing.whyResponsiveTitle"
descKey="marketing.whyResponsiveDesc"
/>
<WhyItem
icon={LockIcon}
titleKey="marketing.whySecureTitle"
descKey="marketing.whySecureDesc"
/>
<WhyItem
icon={HeadsetIcon}
titleKey="marketing.whySupportTitle"
descKey="marketing.whySupportDesc"
/>
<WhyItem
icon={ShieldCheckIcon}
titleKey="marketing.whyGdprTitle"
descKey="marketing.whyGdprDesc"
/>
</div>
</EcosystemShowcase>
</div>
</AnimateOnScroll>
{/* How It Works */}
<AnimateOnScroll>
<div className="container mx-auto">
<div className="flex flex-col items-center gap-12">
<div className="text-center">
<h2 className="text-3xl font-medium tracking-tight xl:text-5xl dark:text-white">
<Trans i18nKey={'marketing.howItWorksHeading'} />
</h2>
<p className="text-secondary-foreground/70 mx-auto mt-4 max-w-2xl text-xl font-medium tracking-tight">
<Trans i18nKey={'marketing.howItWorksSubheading'} />
</p>
</div>
<div className="relative grid w-full grid-cols-1 gap-8 md:grid-cols-3">
<div
className="border-primary/30 absolute top-10 right-[16.67%] left-[16.67%] hidden h-px border-t border-dashed md:block"
aria-hidden="true"
/>
<StepCard
step="01"
titleKey="marketing.howStep1Title"
descKey="marketing.howStep1Desc"
/>
<StepCard
step="02"
titleKey="marketing.howStep2Title"
descKey="marketing.howStep2Desc"
/>
<StepCard
step="03"
titleKey="marketing.howStep3Title"
descKey="marketing.howStep3Desc"
/>
</div>
</div>
</div>
</AnimateOnScroll>
{/* Pricing Section */}
<AnimateOnScroll>
<div className={'container mx-auto'}>
<div
className={
'flex flex-col items-center justify-center space-y-12 py-4 xl:py-8'
}
>
<SecondaryHero
pill={
<Pill label={<Trans i18nKey={'marketing.pricingPillLabel'} />}>
<Trans i18nKey={'marketing.pricingPillText'} />
</Pill>
}
heading={
<GradientText className="from-primary to-primary/60">
<Trans i18nKey={'marketing.pricingHeading'} />
</GradientText>
}
subheading={<Trans i18nKey={'marketing.pricingSubheading'} />}
/>
<div className={'w-full'}>
<PricingTable
config={billingConfig}
paths={{
signUp: pathsConfig.auth.signUp,
return: pathsConfig.app.home,
}}
/>
</div>
</div>
</div>
</AnimateOnScroll>
{/* Final CTA */}
<AnimateOnScroll>
<div className="container mx-auto">
<div className="ring-primary/10 from-primary/10 via-background to-primary/5 flex flex-col items-center gap-8 rounded-2xl border bg-gradient-to-br p-12 text-center ring-1 lg:p-16">
<h2 className="max-w-3xl text-3xl font-medium tracking-tight xl:text-5xl dark:text-white">
<GradientText className="from-primary to-primary/60">
<Trans i18nKey={'marketing.ctaHeading'} />
</GradientText>
</h2>
<p className="text-secondary-foreground/70 max-w-2xl text-lg">
<Trans i18nKey={'marketing.ctaDescription'} />
</p>
<div className="flex flex-col gap-3 sm:flex-row">
<CtaButton className="h-14 px-10 text-lg">
<Link href={'/auth/sign-up'}>
<span className="flex items-center gap-2">
<Trans i18nKey={'marketing.ctaButtonPrimary'} />
<ArrowRightIcon className="h-5 w-5" />
</span>
</Link>
</CtaButton>
<CtaButton variant={'outline'} className="h-14 px-10 text-lg">
<Link href={'/contact'}>
<Trans i18nKey={'marketing.ctaButtonSecondary'} />
</Link>
</CtaButton>
</div>
<p className="text-muted-foreground flex items-center gap-2 text-sm">
<CheckIcon className="h-4 w-4" />
<Trans i18nKey={'marketing.ctaNote'} />
</p>
</div>
</div>
</AnimateOnScroll>
</div>
);
}
export default Home;
function MainCallToActionButton() {
return (
<div className={'flex space-x-2.5'}>
<CtaButton className="h-12 px-8 text-base shadow-lg">
<Link href={'/auth/sign-up'}>
<span className={'flex items-center space-x-0.5'}>
<span>
<Trans i18nKey={'common.getStarted'} />
</span>
<ArrowRightIcon
className={
'animate-in fade-in slide-in-from-left-8 h-4' +
' zoom-in fill-mode-both delay-1000 duration-1000'
}
/>
</span>
</Link>
</CtaButton>
<CtaButton variant={'link'} className="h-12 px-8 text-base">
<Link href={'/pricing'}>
<Trans i18nKey={'common.pricing'} />
</Link>
</CtaButton>
</div>
);
}
function IconFeatureCard(props: {
icon: React.ComponentType<{ className?: string }>;
titleKey: string;
descKey: string;
accentBg?: string;
accentText?: string;
}) {
return (
<div className="reveal bg-muted/50 hover:border-primary/20 flex flex-col gap-3 rounded-xl border border-transparent p-6 transition-all duration-300 hover:-translate-y-1 hover:shadow-md">
<div
className={cn(
'flex h-10 w-10 items-center justify-center rounded-lg',
props.accentBg ?? 'bg-primary/10',
)}
>
<props.icon
className={cn('h-5 w-5', props.accentText ?? 'text-primary')}
/>
</div>
<h4 className="text-lg font-medium">
<Trans i18nKey={props.titleKey} />
</h4>
<p className="text-muted-foreground max-w-xs text-sm">
<Trans i18nKey={props.descKey} />
</p>
</div>
);
}
function StatItem(props: { value: string; labelKey: string }) {
return (
<div className="reveal flex flex-col items-center gap-1 px-6 py-4">
<span className="text-primary text-3xl font-bold tracking-tight lg:text-4xl">
{props.value}
</span>
<span className="text-muted-foreground text-sm font-medium">
<Trans i18nKey={props.labelKey} />
</span>
</div>
);
}
function TestimonialCard(props: {
quoteKey: string;
nameKey: string;
roleKey: string;
}) {
return (
<div className="reveal border-border bg-card flex flex-col gap-4 rounded-xl border p-6 shadow-sm">
<p className="text-secondary-foreground text-sm leading-relaxed italic">
&ldquo;
<Trans i18nKey={props.quoteKey} />
&rdquo;
</p>
<div className="border-border border-t pt-4">
<p className="text-sm font-medium">
<Trans i18nKey={props.nameKey} />
</p>
<p className="text-muted-foreground text-xs">
<Trans i18nKey={props.roleKey} />
</p>
</div>
</div>
);
}
function WhyItem(props: {
icon: React.ComponentType<{ className?: string }>;
titleKey: string;
descKey: string;
}) {
return (
<div className="flex gap-4">
<div className="ring-primary/20 bg-primary/10 flex h-12 w-12 shrink-0 items-center justify-center rounded-xl ring-1">
<props.icon className="text-primary h-5 w-5" />
</div>
<div>
<h4 className="text-secondary-foreground font-medium">
<Trans i18nKey={props.titleKey} />
</h4>
<p className="text-muted-foreground mt-1 text-sm">
<Trans i18nKey={props.descKey} />
</p>
</div>
</div>
);
}
function StepCard(props: { step: string; titleKey: string; descKey: string }) {
return (
<div className="reveal border-border bg-card relative flex flex-col items-center gap-4 rounded-xl border p-8 text-center shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-md">
<div className="bg-primary text-primary-foreground shadow-primary/20 relative z-10 flex h-14 w-14 items-center justify-center rounded-full text-xl font-bold shadow-lg">
{props.step}
</div>
<h3 className="text-secondary-foreground text-xl font-medium">
<Trans i18nKey={props.titleKey} />
</h3>
<p className="text-muted-foreground text-sm">
<Trans i18nKey={props.descKey} />
</p>
</div>
);
}