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
85 changes: 64 additions & 21 deletions frontend/src/pages/LandingPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useState } from 'react'
import { Link } from 'react-router-dom'
import {
Scissors,
Expand All @@ -14,6 +15,8 @@ import {
Gem,
Pen,
FileOutput,
Menu,
X,
} from 'lucide-react'

const tools = [
Expand All @@ -34,8 +37,10 @@ const steps = [
]

export default function LandingPage() {
const [menuOpen, setMenuOpen] = useState(false)

return (
<div className="min-h-screen bg-[#050e18] text-slate-200 relative">
<div className="min-h-screen bg-[#050e18] text-slate-200 relative overflow-x-hidden">
{/* ── CSS ─────────────────────────────────────────────── */}
<style>{`
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;0,700;1,500;1,600&display=swap');
Expand Down Expand Up @@ -68,10 +73,16 @@ export default function LandingPage() {

/* Crystal prism */
.prism {
width: 340px;
height: 340px;
width: min(280px, 70vw);
height: min(280px, 70vw);
position: relative;
}
@media (min-width: 768px) {
.prism {
width: 340px;
height: 340px;
}
}
.prism::before {
content: '';
position: absolute;
Expand Down Expand Up @@ -142,17 +153,19 @@ 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 px-4 sm:px-6 h-14 sm:h-16">
<Link to="/" className="flex items-center gap-2.5 group min-w-0">
<div className="w-8 h-8 shrink-0 rounded-lg bg-gradient-to-br from-brand-500 to-blue-400 flex 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 tracking-tight text-white truncate">
Crystal<span className="text-blue-400">PDF</span>
</span>
</Link>
<div className="flex items-center gap-2">

{/* Desktop actions */}
<div className="hidden sm:flex items-center gap-2">
<Link to="/login"
className="text-sm text-slate-400 hover:text-white px-4 py-2 transition-colors">
Sign in
Expand All @@ -164,13 +177,43 @@ export default function LandingPage() {
Get started
</Link>
</div>

{/* Mobile menu button — 44px touch target */}
<button
type="button"
className="sm:hidden inline-flex items-center justify-center w-11 h-11 rounded-lg
text-slate-300 hover:text-white hover:bg-white/[.06] transition-colors"
aria-label={menuOpen ? 'Close menu' : 'Open menu'}
aria-expanded={menuOpen}
onClick={() => setMenuOpen((v) => !v)}
>
{menuOpen ? <X size={22} /> : <Menu size={22} />}
</button>
</div>

{/* Mobile drawer */}
{menuOpen && (
<div className="sm:hidden border-t border-white/[.06] px-4 py-3 flex flex-col gap-2"
style={{ background: 'rgba(5,14,24,.95)' }}>
<Link to="/login"
onClick={() => setMenuOpen(false)}
className="text-sm text-slate-300 hover:text-white px-4 py-3 rounded-lg hover:bg-white/[.04] transition-colors">
Sign in
</Link>
<Link to="/register"
onClick={() => setMenuOpen(false)}
className="text-sm font-medium text-center text-blue-300 bg-brand-500/15 hover:bg-brand-500/25
border border-brand-500/25 px-4 py-3 rounded-lg transition-all">
Get started
</Link>
</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-20 sm:pb-24 md:pt-32 md:pb-36
grid md:grid-cols-[1fr,auto] items-center gap-8 md:gap-12">
{/* Text column */}
<div className="max-w-2xl">
<h1 className="font-display font-semibold tracking-tight leading-[1.1]
Expand All @@ -185,17 +228,17 @@ export default function LandingPage() {
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-8 sm:mt-10 flex flex-col sm:flex-row flex-wrap gap-3 anim-reveal anim-d3 w-full sm:w-auto">
<Link to="/register"
className="inline-flex items-center gap-2 px-6 py-3.5 rounded-xl text-[15px] font-medium
className="inline-flex items-center justify-center gap-2 w-full sm:w-auto 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 items-center justify-center gap-2 w-full sm:w-auto 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
Expand All @@ -204,7 +247,7 @@ export default function LandingPage() {
</div>

{/* Crystal visual */}
<div className="hidden md:flex items-center justify-center anim-fade anim-d4">
<div className="flex items-center justify-center order-first md:order-none anim-fade anim-d4">
<div className="prism">
{/* Inner facets */}
<div className="absolute inset-0 flex items-center justify-center">
Expand All @@ -216,7 +259,7 @@ export default function LandingPage() {

{/* ── 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-32">
{/* Section header */}
<div className="max-w-lg mb-14">
<p className="text-xs font-medium tracking-[.15em] uppercase text-brand-400 mb-4">
Expand All @@ -232,9 +275,9 @@ export default function LandingPage() {
</div>

{/* Grid */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
<div className="grid grid-cols-1 xs:grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3">
{tools.map((t) => (
<div key={t.name} className="tool-card rounded-2xl p-5 cursor-default group">
<div key={t.name} className="tool-card rounded-2xl p-4 sm:p-5 cursor-default group">
<div className="w-10 h-10 rounded-xl 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]
Expand All @@ -255,7 +298,7 @@ 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="max-w-3xl mx-auto px-4 sm:px-6 py-16 sm: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">
How it works
Expand Down Expand Up @@ -309,7 +352,7 @@ 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-16 sm:py-28 md:py-36 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)' }} />
Expand Down Expand Up @@ -342,7 +385,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-6 sm:py-8 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
<span className="font-display text-sm font-semibold text-slate-600">
Crystal<span className="text-blue-400/50">PDF</span>
</span>
Expand Down