Marketing Website
This commit is contained in:
73
frontend/src/marketing/components/CTASection.tsx
Normal file
73
frontend/src/marketing/components/CTASection.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import React from "react";
|
||||
interface CTASectionProps {
|
||||
title: string;
|
||||
description: string;
|
||||
primaryCta: { label: string; href: string };
|
||||
secondaryCta?: { label: string; href: string };
|
||||
}
|
||||
|
||||
const CTASection: React.FC<CTASectionProps> = ({
|
||||
title,
|
||||
description,
|
||||
primaryCta,
|
||||
secondaryCta,
|
||||
}) => {
|
||||
const renderAnchor = (label: string, href: string, className: string) => {
|
||||
const isExternal = href.startsWith("http");
|
||||
|
||||
if (isExternal) {
|
||||
return (
|
||||
<a
|
||||
key={href}
|
||||
href={href}
|
||||
className={className}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<a key={href} href={href} className={className}>
|
||||
{label}
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="py-24">
|
||||
<div className="max-w-5xl mx-auto px-6">
|
||||
<div className="relative overflow-hidden rounded-3xl border border-white/10 bg-gradient-to-br from-brand-500/30 via-brand-600/20 to-transparent p-10 md:p-14">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top_left,_rgba(255,255,255,0.12),_transparent_60%)] pointer-events-none" />
|
||||
<div className="relative flex flex-col gap-6">
|
||||
<h3 className="text-3xl md:text-4xl font-semibold text-white leading-tight">
|
||||
{title}
|
||||
</h3>
|
||||
<p className="text-white/70 text-base md:text-lg max-w-2xl">
|
||||
{description}
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4">
|
||||
{renderAnchor(
|
||||
primaryCta.label,
|
||||
primaryCta.href,
|
||||
"inline-flex items-center justify-center rounded-full bg-white text-slate-950 px-6 py-3 text-sm md:text-base font-semibold hover:bg-brand-100 transition"
|
||||
)}
|
||||
{secondaryCta && (
|
||||
renderAnchor(
|
||||
secondaryCta.label,
|
||||
secondaryCta.href,
|
||||
"inline-flex items-center justify-center rounded-full border border-white/40 px-6 py-3 text-sm md:text-base font-semibold text-white hover:border-white/60 transition"
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default CTASection;
|
||||
|
||||
49
frontend/src/marketing/components/FeatureGrid.tsx
Normal file
49
frontend/src/marketing/components/FeatureGrid.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from "react";
|
||||
import { ArrowUpRightIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
interface FeatureItem {
|
||||
title: string;
|
||||
description: string;
|
||||
icon: React.ReactNode;
|
||||
link?: { label: string; href: string };
|
||||
}
|
||||
|
||||
interface FeatureGridProps {
|
||||
features: FeatureItem[];
|
||||
}
|
||||
|
||||
const FeatureGrid: React.FC<FeatureGridProps> = ({ features }) => {
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto px-6 py-24">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{features.map((feature) => (
|
||||
<div
|
||||
key={feature.title}
|
||||
className="relative rounded-3xl border border-white/10 bg-gradient-to-br from-white/8 via-transparent to-white/0 p-8 flex flex-col gap-4 group hover:border-brand-400/40 transition"
|
||||
>
|
||||
<div className="size-12 rounded-2xl bg-brand-500/10 border border-brand-500/30 flex items-center justify-center text-brand-200">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-white">{feature.title}</h3>
|
||||
<p className="text-sm text-white/60 leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
{feature.link && (
|
||||
<a
|
||||
href={feature.link.href}
|
||||
className="inline-flex items-center gap-2 text-sm font-semibold text-brand-200 hover:text-brand-100"
|
||||
>
|
||||
{feature.link.label}
|
||||
<ArrowUpRightIcon className="h-4 w-4" />
|
||||
</a>
|
||||
)}
|
||||
<div className="absolute inset-0 rounded-3xl border border-white/0 group-hover:border-brand-500/30 transition" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeatureGrid;
|
||||
|
||||
74
frontend/src/marketing/components/HeroSection.tsx
Normal file
74
frontend/src/marketing/components/HeroSection.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
interface HeroSectionProps {
|
||||
image: string;
|
||||
headline: string;
|
||||
subheadline: string;
|
||||
primaryCta: { label: string; href: string };
|
||||
secondaryCta?: { label: string; href: string };
|
||||
}
|
||||
|
||||
const HeroSection: React.FC<HeroSectionProps> = ({
|
||||
image,
|
||||
headline,
|
||||
subheadline,
|
||||
primaryCta,
|
||||
secondaryCta,
|
||||
}) => {
|
||||
return (
|
||||
<section className="relative overflow-hidden">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top,_rgba(66,133,244,0.25),_rgba(9,14,26,0.9))]" />
|
||||
<div className="relative max-w-6xl mx-auto px-6 py-24 md:py-32 flex flex-col lg:flex-row gap-16 items-center">
|
||||
<div className="flex-1 flex flex-col gap-6">
|
||||
<span className="inline-flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.28em] text-brand-200">
|
||||
AI + SEO PLATFORM
|
||||
</span>
|
||||
<h1 className="text-4xl md:text-6xl font-semibold leading-tight text-white">
|
||||
{headline}
|
||||
</h1>
|
||||
<p className="text-lg md:text-xl text-white/70 leading-relaxed max-w-xl">
|
||||
{subheadline}
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4">
|
||||
<Link
|
||||
to={primaryCta.href}
|
||||
className="inline-flex items-center justify-center rounded-full bg-brand-500 hover:bg-brand-400 px-6 py-3 text-sm md:text-base font-semibold transition"
|
||||
>
|
||||
{primaryCta.label}
|
||||
</Link>
|
||||
{secondaryCta && (
|
||||
<Link
|
||||
to={secondaryCta.href}
|
||||
className="inline-flex items-center justify-center rounded-full border border-white/20 px-6 py-3 text-sm md:text-base font-semibold text-white/80 hover:text-white hover:border-white/40 transition"
|
||||
>
|
||||
{secondaryCta.label}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 w-full">
|
||||
<div className="relative rounded-3xl border border-white/10 bg-white/5 shadow-[0_0_60px_rgba(88,166,255,0.1)]">
|
||||
<div className="absolute inset-0 rounded-3xl bg-gradient-to-br from-white/10 via-transparent to-white/0 pointer-events-none" />
|
||||
<img
|
||||
src={`/marketing/images/${image}`}
|
||||
alt="Igny8 dashboard preview"
|
||||
className="w-full h-full object-cover rounded-3xl"
|
||||
/>
|
||||
<div className="absolute bottom-6 left-6 bg-slate-950/70 backdrop-blur-lg border border-white/10 rounded-2xl px-6 py-4 flex flex-col gap-1">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-white/50">
|
||||
End-to-end automation
|
||||
</span>
|
||||
<span className="text-lg font-semibold text-white">
|
||||
Keywords ➝ Ideas ➝ Tasks ➝ Content ➝ Images
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeroSection;
|
||||
|
||||
15
frontend/src/marketing/components/LoadingPage.tsx
Normal file
15
frontend/src/marketing/components/LoadingPage.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
|
||||
const LoadingPage: React.FC = () => {
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col items-center justify-center bg-slate-950 text-white">
|
||||
<div className="flex items-center gap-3 text-lg font-semibold tracking-wide uppercase">
|
||||
<span className="h-3 w-3 rounded-full bg-brand-500 animate-pulse" />
|
||||
Loading experience…
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadingPage;
|
||||
|
||||
39
frontend/src/marketing/components/LogoCloud.tsx
Normal file
39
frontend/src/marketing/components/LogoCloud.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import React from "react";
|
||||
|
||||
const logos = [
|
||||
"launchpad",
|
||||
"northbeam",
|
||||
"scaleops",
|
||||
"pathfinder",
|
||||
"catalyst",
|
||||
"orbit",
|
||||
];
|
||||
|
||||
const LogoCloud: React.FC = () => {
|
||||
return (
|
||||
<section className="py-16 bg-slate-950/70 border-y border-white/5">
|
||||
<div className="max-w-5xl mx-auto px-6 flex flex-col gap-6 items-center">
|
||||
<span className="text-xs uppercase tracking-[0.28em] text-white/40">
|
||||
Trusted by modern SEO + content teams
|
||||
</span>
|
||||
<div className="flex flex-wrap justify-center gap-8 md:gap-12">
|
||||
{logos.map((name) => (
|
||||
<div
|
||||
key={name}
|
||||
className="h-8 md:h-10 opacity-70 hover:opacity-100 transition"
|
||||
>
|
||||
<img
|
||||
src={`/marketing/images/logo-${name}.svg`}
|
||||
alt={`${name} logo`}
|
||||
className="h-full w-auto"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogoCloud;
|
||||
|
||||
30
frontend/src/marketing/components/MetricsBar.tsx
Normal file
30
frontend/src/marketing/components/MetricsBar.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import React from "react";
|
||||
|
||||
interface Metric {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface MetricsBarProps {
|
||||
metrics: Metric[];
|
||||
}
|
||||
|
||||
const MetricsBar: React.FC<MetricsBarProps> = ({ metrics }) => {
|
||||
return (
|
||||
<div className="max-w-5xl mx-auto -mt-12 sm:-mt-16 px-6">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-2xl p-6">
|
||||
{metrics.map((metric) => (
|
||||
<div key={metric.label} className="text-center sm:text-left">
|
||||
<div className="text-3xl font-semibold text-white">{metric.value}</div>
|
||||
<div className="text-sm uppercase tracking-[0.2em] text-white/50 mt-2">
|
||||
{metric.label}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MetricsBar;
|
||||
|
||||
38
frontend/src/marketing/components/SectionHeading.tsx
Normal file
38
frontend/src/marketing/components/SectionHeading.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import React from "react";
|
||||
|
||||
interface SectionHeadingProps {
|
||||
eyebrow?: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
align?: "left" | "center";
|
||||
}
|
||||
|
||||
const SectionHeading: React.FC<SectionHeadingProps> = ({
|
||||
eyebrow,
|
||||
title,
|
||||
description,
|
||||
align = "center",
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={`flex flex-col gap-4 ${align === "center" ? "items-center text-center" : "items-start text-left"}`}
|
||||
>
|
||||
{eyebrow && (
|
||||
<span className="inline-flex items-center rounded-full border border-white/15 bg-white/5 px-4 py-1 text-xs font-semibold uppercase tracking-[0.2em] text-brand-200">
|
||||
{eyebrow}
|
||||
</span>
|
||||
)}
|
||||
<h2 className="text-3xl md:text-4xl font-semibold text-white leading-tight max-w-3xl">
|
||||
{title}
|
||||
</h2>
|
||||
{description && (
|
||||
<p className="text-white/60 max-w-2xl text-base md:text-lg leading-relaxed">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SectionHeading;
|
||||
|
||||
41
frontend/src/marketing/components/TestimonialSlider.tsx
Normal file
41
frontend/src/marketing/components/TestimonialSlider.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import React from "react";
|
||||
import { testimonials } from "../data/testimonials";
|
||||
|
||||
const TestimonialSlider: React.FC = () => {
|
||||
return (
|
||||
<section className="bg-slate-950">
|
||||
<div className="max-w-6xl mx-auto px-6 py-24 space-y-12">
|
||||
<div className="flex flex-col items-center gap-4 text-center">
|
||||
<span className="inline-flex items-center rounded-full border border-white/15 bg-white/5 px-4 py-1 text-xs font-semibold uppercase tracking-[0.2em] text-brand-200">
|
||||
Loved by scaling teams
|
||||
</span>
|
||||
<h2 className="text-3xl md:text-4xl font-semibold text-white leading-tight max-w-2xl">
|
||||
Teams ship more content, capture more demand, and see faster ROI with Igny8.
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{testimonials.map((testimonial) => (
|
||||
<div
|
||||
key={testimonial.name}
|
||||
className="rounded-3xl border border-white/10 bg-white/5 p-8 flex flex-col gap-6 relative overflow-hidden"
|
||||
>
|
||||
<div className="absolute -top-16 left-1/2 -translate-x-1/2 h-32 w-[140%] rounded-[50%] bg-brand-500/10 blur-3xl pointer-events-none" />
|
||||
<p className="text-base text-white/80 leading-relaxed">
|
||||
“{testimonial.quote}”
|
||||
</p>
|
||||
<div className="flex flex-col text-sm text-white/60">
|
||||
<span className="font-semibold text-white">{testimonial.name}</span>
|
||||
<span>
|
||||
{testimonial.title} · {testimonial.company}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default TestimonialSlider;
|
||||
|
||||
38
frontend/src/marketing/components/WorkflowSteps.tsx
Normal file
38
frontend/src/marketing/components/WorkflowSteps.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import React from "react";
|
||||
|
||||
interface WorkflowStep {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
}
|
||||
|
||||
interface WorkflowStepsProps {
|
||||
steps: WorkflowStep[];
|
||||
}
|
||||
|
||||
const WorkflowSteps: React.FC<WorkflowStepsProps> = ({ steps }) => {
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto px-6 py-24">
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
{steps.map((step, index) => (
|
||||
<div
|
||||
key={step.title}
|
||||
className="rounded-3xl border border-white/10 bg-white/5 p-6 flex flex-col gap-4 hover:border-brand-400/40 transition"
|
||||
>
|
||||
<div className="h-12 w-12 rounded-2xl bg-brand-500/10 border border-brand-500/30 flex items-center justify-center font-semibold text-brand-200 text-xl">
|
||||
{index + 1}
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-white leading-snug">
|
||||
{step.title}
|
||||
</h3>
|
||||
<p className="text-sm text-white/60 leading-relaxed">
|
||||
{step.subtitle}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkflowSteps;
|
||||
|
||||
Reference in New Issue
Block a user