Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 69 additions & 50 deletions frontend/src/pages/LandingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import {
Image,
Merge,
ArrowRight,
Layers,
Upload,
Wand2,
Download,
Gem,
Pen,
FileOutput,
} from 'lucide-react'
import heroImage from '../assets/hero.png'

const tools = [
{ icon: Merge, name: 'Merge', desc: 'Combine multiple documents into one' },
Expand Down Expand Up @@ -68,8 +68,8 @@ export default function LandingPage() {

/* Crystal prism */
.prism {
width: 340px;
height: 340px;
width: min(72vw, 340px);
height: min(72vw, 340px);
position: relative;
}
.prism::before {
Expand Down Expand Up @@ -129,6 +129,15 @@ export default function LandingPage() {
transparent 12px
);
}

@media (prefers-reduced-motion: reduce) {
.anim-reveal,
.anim-fade,
.prism::before,
.prism::after {
animation: none;
}
}
`}</style>

{/* ── Ambient glow ───────────────────────────────────── */}
Expand All @@ -142,88 +151,98 @@ export default function LandingPage() {
{/* ── Nav ────────────────────────────────────────────── */}
<nav className="sticky top-0 z-50 backdrop-blur-xl border-b border-white/[.04]"
style={{ background: 'rgba(5,14,24,.75)' }}>
<div className="max-w-6xl mx-auto flex items-center justify-between px-6 h-16">
<Link to="/" className="flex items-center gap-2.5 group">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-brand-500 to-blue-400 flex items-center justify-center
<div className="max-w-6xl mx-auto flex items-center justify-between gap-3 px-4 sm:px-6 h-14 sm:h-16">
<Link to="/" className="flex min-w-0 items-center gap-2 sm:gap-2.5 group">
<div className="w-7 h-7 sm:w-8 sm:h-8 rounded-lg bg-gradient-to-br from-brand-500 to-blue-400 flex shrink-0 items-center justify-center
shadow-lg shadow-brand-500/20 group-hover:shadow-brand-500/40 transition-shadow">
<Gem size={14} className="text-white" />
</div>
<span className="font-display text-lg font-semibold tracking-tight text-white">
<span className="font-display text-base sm:text-lg font-semibold text-white">
Crystal<span className="text-blue-400">PDF</span>
</span>
</Link>
<div className="flex items-center gap-2">
<div className="flex shrink-0 items-center gap-1.5 sm:gap-2">
<Link to="/login"
className="text-sm text-slate-400 hover:text-white px-4 py-2 transition-colors">
className="whitespace-nowrap text-xs sm:text-sm text-slate-400 hover:text-white px-2.5 sm:px-4 py-2 transition-colors">
Sign in
</Link>
<Link to="/register"
className="text-sm font-medium text-blue-300 bg-brand-500/15 hover:bg-brand-500/25
className="whitespace-nowrap text-xs sm:text-sm font-medium text-blue-300 bg-brand-500/15 hover:bg-brand-500/25
border border-brand-500/25 hover:border-brand-500/40
px-4 py-2 rounded-lg transition-all">
px-3 sm:px-4 py-2 rounded-lg transition-all">
Get started
</Link>
</div>
</div>
</nav>

{/* ── Hero ───────────────────────────────────────────── */}
<section className="relative z-10 max-w-6xl mx-auto px-6
pt-20 pb-24 md:pt-32 md:pb-36
grid md:grid-cols-[1fr,auto] items-center gap-12">
<section className="relative z-10 max-w-6xl mx-auto px-4 sm:px-6
pt-12 pb-16 sm:pt-16 sm:pb-20 lg:pt-28 lg:pb-32
grid lg:grid-cols-[minmax(0,1fr),auto] items-center gap-8 lg:gap-12">
{/* Text column */}
<div className="max-w-2xl">
<h1 className="font-display font-semibold tracking-tight leading-[1.1]
text-[clamp(2.2rem,5.5vw,4.8rem)] text-white anim-reveal">
<h1 className="font-display font-semibold leading-[1.08]
text-4xl sm:text-5xl lg:text-7xl text-white anim-reveal">
Every<br className="hidden sm:block" /> PDF tool<br className="hidden sm:block" /> you'll ever{' '}
<em className="not-italic text-blue-400">need.</em>
</h1>

<p className="mt-7 text-[clamp(1rem,1.8vw,1.2rem)] leading-relaxed
<p className="mt-5 sm:mt-7 text-base sm:text-lg leading-relaxed
text-slate-400 max-w-md anim-reveal anim-d2">
Merge, split, compress, protect, convert, and annotate&nbsp;&mdash;
from one elegant workspace. No subscriptions, no upload limits.
</p>

<div className="mt-10 flex flex-wrap gap-3 anim-reveal anim-d3">
<div className="mt-7 sm:mt-10 flex flex-col sm:flex-row sm:flex-wrap gap-3 anim-reveal anim-d3">
<Link to="/register"
className="inline-flex items-center gap-2 px-6 py-3.5 rounded-xl text-[15px] font-medium
className="inline-flex w-full sm:w-auto items-center justify-center gap-2 px-6 py-3.5 rounded-xl text-[15px] font-medium
text-white bg-gradient-to-b from-brand-500 to-brand-600
shadow-[0_2px_24px_rgba(45,98,255,.35)]
hover:shadow-[0_4px_32px_rgba(45,98,255,.5)]
hover:-translate-y-px active:translate-y-0 transition-all">
Start for free <ArrowRight size={15} strokeWidth={2.2} />
</Link>
<Link to="/login"
className="inline-flex items-center gap-2 px-6 py-3.5 rounded-xl text-[15px] font-medium
className="inline-flex w-full sm:w-auto items-center justify-center gap-2 px-6 py-3.5 rounded-xl text-[15px] font-medium
text-slate-300 border border-white/10 hover:border-white/20
hover:bg-white/[.03] transition-all">
Sign in to workspace
</Link>
</div>

<div className="mt-8 flex justify-center sm:justify-start lg:hidden anim-fade anim-d4" aria-hidden="true">
<img
src={heroImage}
alt=""
className="w-44 sm:w-56 h-auto drop-shadow-[0_24px_48px_rgba(45,98,255,.22)]"
/>
</div>
</div>

{/* Crystal visual */}
<div className="hidden md:flex items-center justify-center anim-fade anim-d4">
<div className="prism">
{/* Inner facets */}
<div className="absolute inset-0 flex items-center justify-center">
<Layers size={48} className="text-blue-400/30" strokeWidth={1} />
</div>
<div className="hidden lg:flex items-center justify-center anim-fade anim-d4" aria-hidden="true">
<div className="relative flex items-center justify-center">
<div className="prism opacity-80" />
<img
src={heroImage}
alt=""
className="absolute w-72 h-auto drop-shadow-[0_32px_72px_rgba(45,98,255,.24)]"
/>
</div>
</div>
</section>

{/* ── Tools grid ─────────────────────────────────────── */}
<section className="relative z-10 dot-grid">
<div className="max-w-6xl mx-auto px-6 py-24 md:py-32">
<div className="max-w-6xl mx-auto px-4 sm:px-6 py-16 sm:py-24 md:py-28">
{/* Section header */}
<div className="max-w-lg mb-14">
<p className="text-xs font-medium tracking-[.15em] uppercase text-brand-400 mb-4">
<div className="max-w-lg mb-10 sm:mb-14">
<p className="text-xs font-medium uppercase text-brand-400 mb-4">
Toolkit
</p>
<h2 className="font-display text-[clamp(2rem,4.5vw,3.5rem)] font-semibold
tracking-tight leading-[1.05] text-white">
<h2 className="font-display text-3xl sm:text-4xl lg:text-5xl font-semibold
leading-[1.05] text-white">
Everything in<br className="hidden sm:block" /> one workspace
</h2>
<p className="mt-4 text-slate-500 leading-relaxed text-[15px]">
Expand All @@ -232,16 +251,16 @@ export default function LandingPage() {
</div>

{/* Grid */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
<div className="grid grid-cols-1 min-[420px]:grid-cols-2 lg:grid-cols-4 gap-3">
{tools.map((t) => (
<div key={t.name} className="tool-card rounded-2xl p-5 cursor-default group">
<div className="w-10 h-10 rounded-xl bg-blue-400/[.08] border border-blue-400/[.12]
<div key={t.name} className="tool-card rounded-lg p-5 cursor-default group">
<div className="w-10 h-10 rounded-lg bg-blue-400/[.08] border border-blue-400/[.12]
flex items-center justify-center mb-4
group-hover:bg-blue-400/[.12] group-hover:border-blue-400/[.2]
transition-colors">
<t.icon size={18} className="text-blue-400" strokeWidth={1.8} />
</div>
<p className="text-[15px] font-semibold text-white tracking-tight mb-1">
<p className="text-[15px] font-semibold text-white mb-1">
{t.name}
</p>
<p className="text-[13px] text-slate-500 leading-snug">
Expand All @@ -255,13 +274,13 @@ export default function LandingPage() {

{/* ── How it works ───────────────────────────────────── */}
<section className="relative z-10 border-t border-white/[.04]">
<div className="max-w-3xl mx-auto px-6 py-24 md:py-32">
<div className="text-center max-w-lg mx-auto mb-16">
<p className="text-xs font-medium tracking-[.15em] uppercase text-brand-400 mb-4">
<div className="max-w-3xl mx-auto px-4 sm:px-6 py-16 sm:py-24 md:py-28">
<div className="text-center max-w-lg mx-auto mb-12 sm:mb-16">
<p className="text-xs font-medium uppercase text-brand-400 mb-4">
How it works
</p>
<h2 className="font-display text-[clamp(2rem,4.5vw,3.5rem)] font-semibold
tracking-tight leading-[1.05] text-white">
<h2 className="font-display text-3xl sm:text-4xl lg:text-5xl font-semibold
leading-[1.05] text-white">
Three steps, that's it
</h2>
</div>
Expand All @@ -273,18 +292,18 @@ export default function LandingPage() {
<div className="flex items-start gap-5">
{/* Left: number + icon */}
<div className="flex flex-col items-center">
<div className="w-12 h-12 rounded-xl flex items-center justify-center
<div className="w-12 h-12 rounded-lg flex items-center justify-center
bg-brand-500/10 border border-brand-500/20 shrink-0">
<s.icon size={20} className="text-blue-400" strokeWidth={1.6} />
</div>
</div>

{/* Right: text */}
<div className="pt-1">
<p className="text-xs font-medium text-brand-400/60 tracking-wider mb-1">
<p className="text-xs font-medium text-brand-400/60 mb-1">
Step {s.num}
</p>
<h3 className="text-base font-semibold text-white tracking-tight mb-1.5">
<h3 className="text-base font-semibold text-white mb-1.5">
{s.title}
</h3>
<p className="text-sm text-slate-500 leading-relaxed max-w-sm">
Expand All @@ -309,30 +328,30 @@ export default function LandingPage() {

{/* ── CTA ────────────────────────────────────────────── */}
<section className="relative z-10 border-t border-white/[.04]">
<div className="max-w-6xl mx-auto px-6 py-28 md:py-36 text-center">
<div className="max-w-6xl mx-auto px-4 sm:px-6 py-20 sm:py-28 md:py-32 text-center">
{/* Soft top glow */}
<div className="absolute inset-x-0 top-0 h-64 pointer-events-none"
style={{ background: 'radial-gradient(ellipse 50% 100% at 50% 0%, rgba(45,98,255,.06), transparent)' }} />

<p className="text-sm text-slate-500 mb-4 relative">
Free to use. No credit card required.
</p>
<h2 className="font-display text-[clamp(2.4rem,5.5vw,4.5rem)] font-semibold
tracking-tight leading-[.95] text-white mb-10 relative">
<h2 className="font-display text-4xl sm:text-5xl lg:text-6xl font-semibold
leading-none text-white mb-8 sm:mb-10 relative">
Start working with<br />
your PDFs today.
</h2>
<div className="relative flex flex-wrap justify-center gap-3">
<div className="relative flex flex-col sm:flex-row sm:flex-wrap justify-center gap-3">
<Link to="/register"
className="inline-flex items-center gap-2 px-7 py-3.5 rounded-xl text-[15px] font-medium
className="inline-flex w-full sm:w-auto items-center justify-center gap-2 px-7 py-3.5 rounded-xl text-[15px] font-medium
text-white bg-gradient-to-b from-brand-500 to-brand-600
shadow-[0_2px_24px_rgba(45,98,255,.35)]
hover:shadow-[0_4px_32px_rgba(45,98,255,.5)]
hover:-translate-y-px transition-all">
Create free account <ArrowRight size={15} strokeWidth={2.2} />
</Link>
<Link to="/login"
className="inline-flex items-center gap-2 px-7 py-3.5 rounded-xl text-[15px] font-medium
className="inline-flex w-full sm:w-auto items-center justify-center gap-2 px-7 py-3.5 rounded-xl text-[15px] font-medium
text-slate-400 hover:text-slate-200 transition-colors">
or sign in
</Link>
Expand All @@ -342,7 +361,7 @@ export default function LandingPage() {

{/* ── Footer ─────────────────────────────────────────── */}
<footer className="relative z-10 border-t border-white/[.04]">
<div className="max-w-6xl mx-auto px-6 py-8 flex items-center justify-between flex-wrap gap-4">
<div className="max-w-6xl mx-auto px-4 sm:px-6 py-8 flex flex-col sm:flex-row items-center justify-between gap-3 sm:gap-4 text-center sm:text-left">
<span className="font-display text-sm font-semibold text-slate-600">
Crystal<span className="text-blue-400/50">PDF</span>
</span>
Expand Down