Files
template-resume/src/pages/Index.tsx
T

417 lines
22 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState, useEffect } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Progress } from "@/components/ui/progress";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import {
Menu, ArrowRight, Mail, Linkedin, Github, Twitter, Download,
ExternalLink, MapPin, Calendar, Briefcase, GraduationCap, Award,
Figma, Globe, Database, Terminal, Layers, Cpu, Send, CheckCircle
} from "lucide-react";
import { ThemeToggle } from "@/components/ThemeToggle";
import { useSaasMutation } from "@/hooks/use-tygarun";
export default function ResumePage() {
const { mutate: createLead, loading: sending } = useSaasMutation("crm", "/leads");
const [mobileOpen, setMobileOpen] = useState(false);
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 20);
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, []);
const navLinks = [
{ label: "Experience", href: "#experience" },
{ label: "Education", href: "#education" },
{ label: "Skills", href: "#skills" },
{ label: "Contact", href: "#contact" },
];
const certifications = [
{ name: "AWS Solutions Architect", issuer: "Amazon Web Services", year: "2024" },
{ name: "Google Cloud Professional", issuer: "Google Cloud", year: "2023" },
{ name: "PMP Certified", issuer: "Project Management Institute", year: "2022" },
];
const experience = [
{
company: "Stripe", role: "Senior Software Engineer", dates: "2022 Present",
bullets: ["Led the redesign of the merchant dashboard serving 2M+ users, improving task completion by 35%.", "Architected a real-time analytics pipeline processing 500K events per second.", "Mentored a team of 6 engineers and established code review best practices."],
},
{
company: "Vercel", role: "Software Engineer", dates: "2020 2022",
bullets: ["Built core deployment infrastructure handling 10M+ builds per month.", "Shipped the Edge Functions runtime adopted by 50K+ projects in first quarter."],
},
{
company: "Airbnb", role: "Frontend Engineer", dates: "2018 2020",
bullets: ["Developed the new search experience increasing booking conversion by 18%.", "Created a shared component library used across 12 product teams."],
},
{
company: "Freelance", role: "Web Developer", dates: "2016 2018",
bullets: ["Delivered 30+ client projects ranging from e-commerce to SaaS dashboards.", "Achieved a 100% on-time delivery rate with 5-star average client rating."],
},
];
const projects = [
{ title: "FinTrack Dashboard", desc: "Real-time financial analytics platform with interactive charts and alerts.", tags: ["React", "TypeScript", "D3.js"], gradient: "from-violet-500 to-indigo-600" },
{ title: "MedConnect", desc: "Telemedicine platform connecting patients with specialists worldwide.", tags: ["Next.js", "Prisma", "WebRTC"], gradient: "from-rose-500 to-orange-500" },
{ title: "EcoShop", desc: "Sustainable e-commerce marketplace with carbon-neutral shipping tracker.", tags: ["Remix", "Stripe", "PostgreSQL"], gradient: "from-emerald-500 to-teal-500" },
];
const technicalSkills = [
{ name: "React / Next.js", value: 95 },
{ name: "TypeScript", value: 90 },
{ name: "Node.js", value: 85 },
{ name: "Python", value: 88 },
{ name: "PostgreSQL", value: 80 },
{ name: "AWS / Cloud", value: 75 },
];
const tools = [
{ icon: Figma, label: "Figma" },
{ icon: Globe, label: "Vercel" },
{ icon: Database, label: "Supabase" },
{ icon: Terminal, label: "Docker" },
{ icon: Layers, label: "Terraform" },
{ icon: Cpu, label: "GitHub" },
];
return (
<div className="min-h-screen bg-background text-foreground antialiased">
{/* ── HEADER ── */}
<header
className={`fixed top-0 inset-x-0 z-50 transition-all duration-300 ${
scrolled
? "bg-background/95 backdrop-blur-lg border-b shadow-sm"
: "bg-transparent"
}`}
>
<div className="mx-auto max-w-5xl flex items-center justify-between px-6 py-4">
<a href="/" className="text-lg font-bold tracking-tight">
Taylor Morgan
</a>
<div className="hidden md:flex items-center gap-8">
<nav className="flex items-center gap-8">
{navLinks.map((l) => (
<a
key={l.href}
href={l.href}
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
>
{l.label}
</a>
))}
</nav>
<ThemeToggle />
</div>
<Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
<SheetTrigger asChild className="md:hidden">
<Button variant="ghost" size="icon"><Menu className="h-5 w-5" /></Button>
</SheetTrigger>
<SheetContent side="right" className="w-72">
<nav className="mt-8 flex flex-col gap-4">
{navLinks.map((l) => (
<a key={l.href} href={l.href} className="text-lg font-medium" onClick={() => setMobileOpen(false)}>
{l.label}
</a>
))}
<ThemeToggle />
</nav>
</SheetContent>
</Sheet>
</div>
</header>
{/* ── HERO ── */}
<section className="relative pt-32 pb-24 overflow-hidden">
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-1/4 right-1/4 w-80 h-80 rounded-full bg-primary/8 blur-[100px]" />
<div className="absolute bottom-0 left-1/3 w-64 h-64 rounded-full bg-violet-500/6 blur-[80px]" />
</div>
<div className="relative z-10 mx-auto max-w-5xl px-6">
<div className="flex flex-col sm:flex-row items-center sm:items-start gap-8 animate-fade-up">
<div className="relative w-32 h-32 shrink-0">
<div className="absolute inset-0 rounded-full bg-gradient-to-br from-primary via-violet-500 to-rose-500 shadow-xl ring-4 ring-primary/20 animate-pulse" />
<div className="absolute inset-0 rounded-full opacity-20" style={{ backgroundImage: "radial-gradient(circle, currentColor 1px, transparent 1px)", backgroundSize: "8px 8px" }} />
<div className="absolute bottom-2 right-2 w-4 h-4 rounded-full bg-emerald-500 ring-2 ring-background" />
<div className="absolute -bottom-1 -left-1 w-3 h-3 rounded-full bg-violet-400 border-2 border-background" />
</div>
<div className="text-center sm:text-left">
<h1 className="text-5xl md:text-7xl font-black tracking-tighter leading-[1.05]">
Taylor Morgan
</h1>
<p className="mt-3 text-xl text-muted-foreground leading-relaxed">Senior Full-Stack Engineer</p>
<p className="mt-4 text-muted-foreground leading-relaxed max-w-lg">
Passionate engineer with 8+ years building scalable web applications. I love clean architecture, great UX, and shipping products that make a difference.
</p>
<div className="mt-6 flex flex-wrap items-center justify-center sm:justify-start gap-3">
<Button variant="outline" size="icon" asChild className="hover:text-primary hover:scale-110 transition-all">
<a href="mailto:taylor@example.com"><Mail className="h-4 w-4" /></a>
</Button>
<Button variant="outline" size="icon" asChild className="hover:text-primary hover:scale-110 transition-all">
<a href="#"><Linkedin className="h-4 w-4" /></a>
</Button>
<Button variant="outline" size="icon" asChild className="hover:text-primary hover:scale-110 transition-all">
<a href="#"><Github className="h-4 w-4" /></a>
</Button>
<Button className="ml-2">
<Download className="mr-2 h-4 w-4" /> Download CV
</Button>
</div>
</div>
</div>
</div>
</section>
{/* ── EXPERIENCE ── */}
<section id="experience" className="py-24">
<div className="mx-auto max-w-5xl px-6">
<div className="flex items-center gap-3 mb-12 animate-fade-up">
<Briefcase className="h-6 w-6 text-primary" />
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight">Experience</h2>
</div>
<div className="relative border-l-2 border-primary/20 ml-4">
{experience.map((job, i) => (
<div
key={i}
className={`relative pl-8 pb-12 last:pb-0 rounded-lg hover:bg-muted/50 transition-colors ${i % 2 === 1 ? "bg-muted/30 -ml-4 pl-12 py-8 rounded-r-xl" : ""}`}
>
<div className="absolute -left-[9px] top-1 w-4 h-4 rounded-full bg-primary ring-4 ring-primary/20 border-2 border-background" />
<div className="flex flex-wrap items-center gap-3 mb-2">
<h3 className="font-semibold text-lg">{job.company}</h3>
<Badge variant="outline" className="text-xs">{job.dates}</Badge>
</div>
<p className="text-primary font-medium text-sm mb-3">{job.role}</p>
<ul className="space-y-1.5 border-l-2 border-primary/10 pl-3">
{job.bullets.map((b, j) => (
<li key={j} className="text-sm text-muted-foreground flex items-start gap-2">
<span className="mt-1.5 w-1.5 h-1.5 rounded-full bg-primary/40 shrink-0" />
{b}
</li>
))}
</ul>
</div>
))}
</div>
</div>
</section>
{/* ── PROJECTS ── */}
<section className="py-24 bg-muted/30">
<div className="mx-auto max-w-5xl px-6">
<div className="flex items-center gap-3 mb-12 animate-fade-up">
<Layers className="h-6 w-6 text-primary" />
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight">Featured Projects</h2>
</div>
<div className="grid md:grid-cols-3 gap-6 stagger">
{projects.map((p, i) => (
<Card key={i} className="group overflow-hidden hover-lift hover:shadow-lg transition-all duration-300 backdrop-blur-sm bg-card/80 border-border/50">
<div className={`aspect-video bg-gradient-to-br ${p.gradient} rounded-t-xl flex items-center justify-center relative overflow-hidden`}>
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-24 h-24 rounded-full bg-white/10 blur-2xl" />
<div className="w-12 h-12 rounded-xl bg-white/20 backdrop-blur group-hover:scale-110 transition-transform relative z-10" />
</div>
<CardHeader className="pb-2">
<CardTitle className="text-base">{p.title}</CardTitle>
</CardHeader>
<CardContent>
<CardDescription className="text-sm leading-relaxed mb-3">{p.desc}</CardDescription>
<div className="flex flex-wrap gap-1.5 mb-3">
{p.tags.map((tag, j) => (
<Badge key={j} variant="secondary" className="text-xs">{tag}</Badge>
))}
</div>
<a href="#" className="inline-flex items-center gap-1.5 text-sm font-medium text-primary hover:gap-3 transition-all">
View Project <ArrowRight className="h-3.5 w-3.5" />
</a>
</CardContent>
</Card>
))}
</div>
</div>
</section>
{/* ── EDUCATION ── */}
<section id="education" className="py-24">
<div className="mx-auto max-w-5xl px-6">
<div className="flex items-center gap-3 mb-12 animate-fade-up">
<GraduationCap className="h-6 w-6 text-primary" />
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight">Education</h2>
</div>
<div className="grid sm:grid-cols-2 gap-6 mb-10">
<Card className="hover-lift hover:shadow-md transition-shadow backdrop-blur-sm bg-card/80">
<CardHeader>
<CardTitle className="text-base flex items-center gap-2">
<GraduationCap className="h-4 w-4 text-primary" /> Stanford University
</CardTitle>
<CardDescription className="text-muted-foreground leading-relaxed">M.S. Computer Science</CardDescription>
</CardHeader>
<CardContent className="flex flex-wrap items-center gap-2">
<Badge variant="outline" className="text-xs">2014 2016</Badge>
<Badge className="text-xs">With Distinction</Badge>
</CardContent>
</Card>
<Card className="hover-lift hover:shadow-md transition-shadow backdrop-blur-sm bg-card/80">
<CardHeader>
<CardTitle className="text-base flex items-center gap-2">
<GraduationCap className="h-4 w-4 text-primary" /> UC Berkeley
</CardTitle>
<CardDescription className="text-muted-foreground leading-relaxed">B.S. Computer Science</CardDescription>
</CardHeader>
<CardContent className="flex flex-wrap items-center gap-2">
<Badge variant="outline" className="text-xs">2010 2014</Badge>
<Badge className="text-xs">Magna Cum Laude</Badge>
</CardContent>
</Card>
</div>
<div>
<h3 className="font-semibold mb-3 flex items-center gap-2">
<Award className="h-5 w-5 text-primary" /> Certifications
</h3>
<div className="flex flex-wrap gap-2">
{["AWS Solutions Architect", "Google Cloud Professional", "PMP Certified"].map((cert, i) => (
<Badge key={i} variant="secondary" className="px-3 py-1">{cert}</Badge>
))}
</div>
</div>
</div>
</section>
{/* ── SKILLS ── */}
<section id="skills" className="py-24 bg-muted/30">
<div className="mx-auto max-w-5xl px-6">
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight mb-12 animate-fade-up">Skills & Tools</h2>
<div className="grid lg:grid-cols-3 gap-12">
{/* Technical */}
<div className="lg:col-span-1">
<h3 className="font-semibold mb-6 flex items-center gap-2 text-sm uppercase tracking-wider text-muted-foreground">
<Terminal className="h-4 w-4 text-primary" /> Development
</h3>
<div className="space-y-5">
{technicalSkills.map((s, i) => (
<div key={i}>
<div className="flex justify-between mb-1.5">
<span className="text-sm font-medium">{s.name}</span>
<span className="text-xs text-muted-foreground tabular-nums">{s.value}%</span>
</div>
<div className="h-2 rounded-full bg-muted overflow-hidden">
<div className="h-full rounded-full bg-gradient-to-r from-primary via-violet-500 to-rose-500 transition-all duration-500" style={{ width: `${s.value}%` }} />
</div>
</div>
))}
</div>
</div>
{/* Soft Skills + Tools */}
<div className="lg:col-span-2 space-y-10">
<div>
<h3 className="font-semibold mb-4 flex items-center gap-2 text-sm uppercase tracking-wider text-muted-foreground">
<Figma className="h-4 w-4 text-primary" /> Design & Soft Skills
</h3>
<div className="flex flex-wrap gap-2">
{["Leadership", "Communication", "Problem Solving", "Mentoring"].map((s, i) => (
<Badge key={i} variant="outline" className="px-4 py-1.5 text-sm">{s}</Badge>
))}
</div>
</div>
<div>
<h3 className="font-semibold mb-4 text-sm uppercase tracking-wider text-muted-foreground">Tools & Platforms</h3>
<div className="grid grid-cols-3 sm:grid-cols-6 gap-4 stagger">
{tools.map((t, i) => (
<div key={i} className="flex flex-col items-center gap-2 p-3 rounded-xl bg-background border hover:border-primary/40 hover:shadow-sm transition-all">
<t.icon className="h-5 w-5 text-muted-foreground" />
<span className="text-xs font-medium text-center">{t.label}</span>
</div>
))}
</div>
</div>
</div>
</div>
</div>
</section>
{/* ── CERTIFICATIONS ── */}
<section className="py-24">
<div className="mx-auto max-w-5xl px-6">
<div className="flex items-center gap-3 mb-12 animate-fade-up">
<Award className="h-6 w-6 text-primary" />
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight">Certifications & Awards</h2>
</div>
<div className="grid sm:grid-cols-3 gap-6 stagger">
{certifications.map((c, i) => (
<Card key={i} className="hover-lift hover:shadow-lg hover:shadow-primary/5 transition-all backdrop-blur-sm bg-card/80 border-border/50">
<CardHeader className="flex flex-row items-start gap-4">
<div className="w-12 h-12 rounded-xl bg-gradient-to-br from-primary/20 to-violet-500/20 flex items-center justify-center shrink-0">
<Award className="h-6 w-6 text-primary" />
</div>
<div>
<CardTitle className="text-base flex items-center gap-1.5">
{c.name} <CheckCircle className="h-4 w-4 text-emerald-500" />
</CardTitle>
<CardDescription className="text-muted-foreground leading-relaxed">{c.issuer}</CardDescription>
</div>
</CardHeader>
<CardContent>
<Badge variant="outline" className="text-xs">{c.year}</Badge>
</CardContent>
</Card>
))}
</div>
</div>
</section>
{/* ── CONTACT ── */}
<section id="contact" className="py-24">
<div className="mx-auto max-w-xl px-6 text-center">
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight mb-2 animate-fade-up">Let's Connect</h2>
<p className="text-muted-foreground leading-relaxed mb-2">Have a project in mind? Id love to hear from you.</p>
<a href="mailto:taylor@example.com" className="inline-flex items-center gap-2 text-primary font-medium hover:underline">
<Mail className="h-4 w-4 shadow-lg shadow-primary/10" /> taylor@example.com
</a>
<Card className="mt-8 backdrop-blur-sm bg-card/80 border-border/50">
<CardContent className="pt-6">
<form onSubmit={async (e) => {
e.preventDefault();
const form = e.currentTarget;
const fd = new FormData(form);
try {
await createLead({ name: fd.get("name"), email: fd.get("email"), message: fd.get("message") });
toast.success("Message sent! I'll get back to you within 24 hours.");
form.reset();
} catch (err) {
toast.error("Something went wrong. Please try again.");
}
}} className="text-left space-y-4">
<Input name="name" placeholder="Your Name" className="h-11" required />
<Input name="email" placeholder="Your Email" type="email" className="h-11" required />
<Textarea name="message" placeholder="Your message..." className="min-h-[120px] resize-none" required />
<Button type="submit" disabled={sending} className="w-full h-11 active:scale-[0.97] transition-transform">
<Send className="mr-2 h-4 w-4" /> {sending ? "Sending..." : "Send Message"}
</Button>
<p className="text-xs text-muted-foreground text-center">Typically responds within 24 hours</p>
</form>
</CardContent>
</Card>
</div>
</section>
{/* ── FOOTER ── */}
<footer className="py-12 border-t">
<div className="mx-auto max-w-5xl px-6 text-center">
<p className="text-muted-foreground mb-4">Let's build something great together.</p>
<div className="flex justify-center gap-2 mb-6">
{[Github, Linkedin, Twitter, Mail].map((Icon, i) => (
<Button key={i} variant="ghost" size="icon" className="h-9 w-9 text-muted-foreground hover:text-foreground">
<Icon className="h-4 w-4" />
</Button>
))}
</div>
<p className="text-sm text-muted-foreground">© 2026 Taylor Morgan. All rights reserved.</p>
</div>
</footer>
</div>
);
}