Redesign homepage: editorial layout with current focus + featured work
Replaced the dense mini-CV homepage with an editorial landing page:
- Hero: punchy one-liner ("Researcher & builder. HRI at BU, motorsports
software at Riverhead.") instead of a paragraph bio
- Currently building: Riverhead Raceway mobile app (racehub-app) and
Hotlap (Go monorepo race event management platform)
- Featured work: Honors thesis, IEEE RO-MAN 2025, Riverhead Raceway site,
beenvoice — each with description, tags, and a direct action button
- Education: compact 2-col grid (BU + Bucknell) replaces the full card layout
- Explore: same 3-col nav to Projects / Publications / CV
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+309
-299
@@ -1,16 +1,15 @@
|
||||
import {
|
||||
ArrowUpRight,
|
||||
Award,
|
||||
BookOpen,
|
||||
Building,
|
||||
Code,
|
||||
ExternalLink,
|
||||
FlaskConical,
|
||||
FileText,
|
||||
Flag,
|
||||
Globe,
|
||||
GraduationCap,
|
||||
Mail,
|
||||
MapPin,
|
||||
School,
|
||||
Users
|
||||
Smartphone,
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
@@ -22,60 +21,56 @@ import {
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "~/components/ui/card";
|
||||
import { awards, educationList, experiences, researchInterests } from "~/lib/data";
|
||||
import { educationList } from "~/lib/data";
|
||||
|
||||
function SectionLabel({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<h2 className="text-xs font-semibold uppercase tracking-widest text-muted-foreground">
|
||||
{children}
|
||||
</h2>
|
||||
);
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
const researchExperience = experiences.filter(
|
||||
(exp) => exp.type === "research",
|
||||
);
|
||||
const teachingExperience = experiences.filter(
|
||||
(exp) => exp.type === "teaching",
|
||||
);
|
||||
const professionalExperience = experiences.filter(
|
||||
(exp) => exp.type === "professional",
|
||||
);
|
||||
const leadershipExperience = experiences.filter(
|
||||
(exp) => exp.type === "leadership",
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="space-y-12">
|
||||
{/* Hero Section */}
|
||||
<section className="animate-fade-in-up space-y-6">
|
||||
<div className="space-y-16">
|
||||
|
||||
{/* Hero */}
|
||||
<section className="animate-fade-in-up space-y-5 pt-2">
|
||||
<div className="space-y-4">
|
||||
<h1 className="animate-fade-in-up-delay-1 text-3xl font-bold">
|
||||
<h1 className="animate-fade-in-up-delay-1 text-4xl font-bold tracking-tight">
|
||||
Sean O'Connor
|
||||
</h1>
|
||||
<p className="animate-fade-in-up-delay-2 text-xl text-muted-foreground">
|
||||
Computer Science and Engineering graduate pursuing a Master's
|
||||
at Boston University. Research interests in human-robot interaction
|
||||
and developing technologies that make robots better collaborators
|
||||
with humans.
|
||||
<p className="animate-fade-in-up-delay-2 max-w-lg text-lg text-muted-foreground">
|
||||
Researcher & builder. HRI at BU, motorsports software at Riverhead.
|
||||
</p>
|
||||
<div className="animate-fade-in-up-delay-3 flex flex-wrap gap-4 text-sm text-muted-foreground">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Mail className="h-4 w-4" />
|
||||
<a href="mailto:sean@soconnor.dev" className="hover:text-primary">
|
||||
<a
|
||||
href="mailto:sean@soconnor.dev"
|
||||
className="transition-colors hover:text-foreground"
|
||||
>
|
||||
sean@soconnor.dev
|
||||
</a>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<GraduationCap className="h-4 w-4" />
|
||||
Boston University
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<MapPin className="h-4 w-4" />
|
||||
Boston, MA
|
||||
</div>
|
||||
</div>
|
||||
<div className="animate-fade-in-up-delay-4 flex gap-3">
|
||||
<Button variant="outline" asChild className="button-hover">
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/cv">
|
||||
<ExternalLink className="mr-2 h-4 w-4" />
|
||||
View CV
|
||||
CV
|
||||
</Link>
|
||||
</Button>
|
||||
<Button variant="outline" asChild className="button-hover">
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/publications">
|
||||
<BookOpen className="mr-2 h-4 w-4" />
|
||||
Publications
|
||||
@@ -85,330 +80,344 @@ export default function HomePage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Research Interests */}
|
||||
<section className="animate-fade-in-up space-y-6">
|
||||
<h2 className="text-2xl font-bold">Research Interests</h2>
|
||||
<div className="animate-fade-in-up-delay-1">
|
||||
<Card className="card-hover">
|
||||
<CardContent>
|
||||
<p className="leading-relaxed text-muted-foreground">
|
||||
{researchInterests}
|
||||
{/* Currently Building */}
|
||||
<section className="animate-fade-in-up space-y-4">
|
||||
<SectionLabel>Currently building</SectionLabel>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="rounded-xl bg-primary/10 p-2.5">
|
||||
<Smartphone className="h-5 w-5 text-primary" />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<CardTitle>Riverhead Raceway Mobile App</CardTitle>
|
||||
<CardDescription>racehub-app · React Native</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<div className="flex h-full flex-col gap-3">
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
Native mobile companion for Riverhead Raceway — race-day
|
||||
results, live standings, and event info for fans and
|
||||
competitors on the track.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{["React Native", "TypeScript", "tRPC"].map((t) => (
|
||||
<Badge key={t} variant="secondary">
|
||||
{t}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="rounded-xl bg-primary/10 p-2.5">
|
||||
<Flag className="h-5 w-5 text-primary" />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<CardTitle>Hotlap</CardTitle>
|
||||
<CardDescription>
|
||||
Race event management · Go monorepo
|
||||
</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<div className="flex h-full flex-col gap-3">
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
Full-stack race event management platform in Go.
|
||||
Server-rendered public pages, a Solid.js SPA for track ops,
|
||||
and a custom Go-native bundler powering the whole thing.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{["Go", "Solid.js", "PostgreSQL", "TypeScript"].map((t) => (
|
||||
<Badge key={t} variant="secondary">
|
||||
{t}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Featured Work */}
|
||||
<section className="animate-fade-in-up space-y-4">
|
||||
<SectionLabel>Featured work</SectionLabel>
|
||||
<div className="grid-equal-height grid gap-4 md:grid-cols-2">
|
||||
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0">
|
||||
<CardTitle>Honors Thesis</CardTitle>
|
||||
<CardDescription>
|
||||
Bucknell University · 2026
|
||||
</CardDescription>
|
||||
</div>
|
||||
<FileText className="h-5 w-5 flex-shrink-0 text-muted-foreground" />
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<div className="flex h-full flex-col gap-3">
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
A web-based Wizard-of-Oz platform for accessible, reproducible
|
||||
HRI research. Pilot study showed higher design fidelity and
|
||||
usability than Choregraphe across all six sessions.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{["HRI", "Wizard-of-Oz", "React", "ROS2"].map((t) => (
|
||||
<Badge key={t} variant="outline">
|
||||
{t}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
asChild
|
||||
className="mt-auto w-full"
|
||||
>
|
||||
<Link href="/publications">
|
||||
Read thesis
|
||||
<ArrowUpRight className="ml-1.5 h-3.5 w-3.5" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0">
|
||||
<CardTitle>IEEE RO-MAN 2025</CardTitle>
|
||||
<CardDescription>
|
||||
Eindhoven · First author
|
||||
</CardDescription>
|
||||
</div>
|
||||
<BookOpen className="h-5 w-5 flex-shrink-0 text-muted-foreground" />
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<div className="flex h-full flex-col gap-3">
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
Collaborative and Reproducible HRI Research Through a
|
||||
Web-Based Wizard-of-Oz Platform. 34th IEEE International
|
||||
Conference on Robot and Human Interactive Communication.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{["IEEE", "HRI", "Research"].map((t) => (
|
||||
<Badge key={t} variant="outline">
|
||||
{t}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
asChild
|
||||
className="mt-auto w-full"
|
||||
>
|
||||
<Link href="/publications">
|
||||
View paper
|
||||
<ArrowUpRight className="ml-1.5 h-3.5 w-3.5" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0">
|
||||
<CardTitle>Riverhead Raceway</CardTitle>
|
||||
<CardDescription>
|
||||
Production · 250k+ monthly users
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Globe className="h-5 w-5 flex-shrink-0 text-muted-foreground" />
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<div className="flex h-full flex-col gap-3">
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
Official website and CMS for Riverhead Raceway, NY.
|
||||
Real-time race data, event management, standings, and a full
|
||||
admin interface with 97+ granular permissions.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{["Next.js", "PostgreSQL", "tRPC"].map((t) => (
|
||||
<Badge key={t} variant="outline">
|
||||
{t}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
asChild
|
||||
className="mt-auto w-full"
|
||||
>
|
||||
<a
|
||||
href="https://riverheadraceway.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Visit site
|
||||
<ArrowUpRight className="ml-1.5 h-3.5 w-3.5" />
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0">
|
||||
<CardTitle>beenvoice</CardTitle>
|
||||
<CardDescription>Invoicing for freelancers</CardDescription>
|
||||
</div>
|
||||
<Code className="h-5 w-5 flex-shrink-0 text-muted-foreground" />
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<div className="flex h-full flex-col gap-3">
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
Professional invoicing: client management, PDF generation,
|
||||
email delivery, timesheet view, and CSV import. Built with
|
||||
tRPC and Drizzle ORM on Next.js 16.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{["Next.js", "tRPC", "Drizzle"].map((t) => (
|
||||
<Badge key={t} variant="outline">
|
||||
{t}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
asChild
|
||||
className="mt-auto w-full"
|
||||
>
|
||||
<a
|
||||
href="https://beenvoice.soconnor.dev"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Try it
|
||||
<ArrowUpRight className="ml-1.5 h-3.5 w-3.5" />
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Education */}
|
||||
<section className="animate-fade-in-up space-y-6">
|
||||
<h2 className="text-2xl font-bold">Education</h2>
|
||||
<div className="space-y-4">
|
||||
{educationList.map((edu, index) => (
|
||||
<div key={index} className={`animate-fade-in-up-delay-${index + 1}`}>
|
||||
<Card className="card-hover">
|
||||
<section className="animate-fade-in-up space-y-4">
|
||||
<SectionLabel>Education</SectionLabel>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
{educationList.map((edu, i) => (
|
||||
<Card key={i} className="card-hover">
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<CardTitle className="mb-1">{edu.institution}</CardTitle>
|
||||
<CardDescription>{edu.location}</CardDescription>
|
||||
</div>
|
||||
<School className="h-5 w-5 text-muted-foreground" />
|
||||
</div>
|
||||
<CardTitle>{edu.institution}</CardTitle>
|
||||
<CardDescription>{edu.degree}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<div>
|
||||
<p className="font-medium">{edu.degree}</p>
|
||||
<CardContent>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{edu.graduated ? "" : "Expected "}{edu.expectedGraduation}
|
||||
{edu.graduated ? "" : "Expected "}
|
||||
{edu.expectedGraduation} · {edu.location}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{edu.engineeringGpa ? (
|
||||
<>
|
||||
<Badge variant="secondary">Eng. GPA: {edu.engineeringGpa}</Badge>
|
||||
<Badge variant="outline">Overall GPA: {edu.gpa}</Badge>
|
||||
</>
|
||||
) : (
|
||||
<Badge variant="secondary">GPA: {edu.gpa}</Badge>
|
||||
)}
|
||||
{edu.deansListSemesters.length > 0 && (
|
||||
<Badge variant="outline">
|
||||
Dean's List: {edu.deansListSemesters.length} semesters
|
||||
{edu.engineeringGpa && (
|
||||
<div className="mt-2 flex flex-wrap gap-1.5">
|
||||
<Badge variant="secondary">
|
||||
Eng. GPA {edu.engineeringGpa}
|
||||
</Badge>
|
||||
<Badge variant="outline">Overall {edu.gpa}</Badge>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Research Experience */}
|
||||
<section className="animate-fade-in-up space-y-6">
|
||||
<h2 className="text-2xl font-bold">Research Experience</h2>
|
||||
<div className="space-y-6">
|
||||
{researchExperience.map((exp, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`animate-fade-in-up-delay-${index + 1}`}
|
||||
>
|
||||
<Card className="card-hover">
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<CardTitle className="mb-1">{exp.title}</CardTitle>
|
||||
<CardDescription>{exp.organization}</CardDescription>
|
||||
<CardDescription className="text-xs">
|
||||
{exp.location} • {exp.period}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<FlaskConical className="h-5 w-5 text-muted-foreground" />
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-muted-foreground">
|
||||
{exp.description.map((item, itemIndex) => (
|
||||
<li key={itemIndex} className="flex items-start gap-2">
|
||||
<span className="mt-2 h-1 w-1 flex-shrink-0 rounded-full bg-muted-foreground" />
|
||||
{item}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
{/* Explore */}
|
||||
<section className="animate-fade-in-up space-y-4">
|
||||
<SectionLabel>Explore</SectionLabel>
|
||||
<div className="grid-equal-height grid gap-4 md:grid-cols-3">
|
||||
|
||||
{/* Professional Experience Highlights */}
|
||||
<section className="animate-fade-in-up space-y-6">
|
||||
<h2 className="text-2xl font-bold">
|
||||
Professional Experience Highlights
|
||||
</h2>
|
||||
<div className="space-y-6">
|
||||
{professionalExperience.slice(0, 2).map((exp, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`animate-fade-in-up-delay-${index + 1}`}
|
||||
>
|
||||
<Card className="card-hover">
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<CardTitle className="mb-1">{exp.title}</CardTitle>
|
||||
<CardDescription>{exp.organization}</CardDescription>
|
||||
<CardDescription className="text-xs">
|
||||
{exp.location} • {exp.period}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Building className="h-5 w-5 text-muted-foreground" />
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-muted-foreground">
|
||||
{exp.description.slice(0, 3).map((item, itemIndex) => (
|
||||
<li key={itemIndex} className="flex items-start gap-2">
|
||||
<span className="mt-2 h-1 w-1 flex-shrink-0 rounded-full bg-muted-foreground" />
|
||||
{item}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Teaching Experience */}
|
||||
<section className="animate-fade-in-up space-y-6">
|
||||
<h2 className="text-2xl font-bold">Teaching Experience</h2>
|
||||
<div className="grid-equal-height grid gap-6 md:grid-cols-2">
|
||||
{teachingExperience.slice(0, 4).map((exp, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`animate-fade-in-up-delay-${index + 1}`}
|
||||
>
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
<GraduationCap className="h-5 w-5 flex-shrink-0" />
|
||||
<div className="min-w-0">
|
||||
<CardTitle className="mb-1 break-words text-base leading-tight">
|
||||
{exp.title}
|
||||
</CardTitle>
|
||||
<CardDescription className="break-words text-xs">
|
||||
{exp.organization}
|
||||
</CardDescription>
|
||||
<CardDescription className="text-xs">
|
||||
{exp.period}
|
||||
</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
{exp.description[0]}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Leadership & Activities */}
|
||||
<section className="animate-fade-in-up space-y-6">
|
||||
<h2 className="text-2xl font-bold">Leadership & Activities</h2>
|
||||
<div className="grid-equal-height grid gap-6 md:grid-cols-2">
|
||||
{leadershipExperience.map((exp, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`animate-fade-in-up-delay-${index + 1}`}
|
||||
>
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
<Users className="h-5 w-5 flex-shrink-0" />
|
||||
<div className="min-w-0">
|
||||
<CardTitle className="mb-1 break-words text-base leading-tight">
|
||||
{exp.title}
|
||||
</CardTitle>
|
||||
<CardDescription className="break-words text-xs">
|
||||
{exp.organization}
|
||||
</CardDescription>
|
||||
<CardDescription className="text-xs">
|
||||
{exp.period}
|
||||
</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<ul className="space-y-1 text-sm text-muted-foreground">
|
||||
{exp.description.slice(0, 2).map((item, itemIndex) => (
|
||||
<li key={itemIndex} className="flex items-start gap-2">
|
||||
<span className="mt-2 h-1 w-1 flex-shrink-0 rounded-full bg-muted-foreground" />
|
||||
<span className="break-words">{item}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Recent Awards & Recognition */}
|
||||
<section className="animate-fade-in-up space-y-6">
|
||||
<h2 className="text-2xl font-bold">Recent Awards & Recognition</h2>
|
||||
<div className="grid-equal-height grid gap-4 md:grid-cols-2">
|
||||
{awards.map((award, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`animate-fade-in-up-delay-${index + 1}`}
|
||||
>
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
<Award className="h-5 w-5 flex-shrink-0" />
|
||||
<div className="min-w-0">
|
||||
<CardTitle className="mb-1 break-words text-base leading-tight">
|
||||
{award.title}
|
||||
</CardTitle>
|
||||
{award.organization && (
|
||||
<CardDescription className="break-words">
|
||||
{award.organization} • {award.year}
|
||||
</CardDescription>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
{award.description && (
|
||||
<CardContent className="card-content-stretch">
|
||||
<p className="break-words text-sm leading-relaxed text-muted-foreground">
|
||||
{award.description}
|
||||
</p>
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Quick Links */}
|
||||
<section className="animate-fade-in-up space-y-6">
|
||||
<h2 className="text-2xl font-bold">Explore More</h2>
|
||||
<div className="grid-equal-height grid gap-6 md:grid-cols-3">
|
||||
<div className="animate-fade-in-up-delay-1">
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
<Code className="h-5 w-5 flex-shrink-0" />
|
||||
<CardTitle className="mb-1 break-words">Projects</CardTitle>
|
||||
<CardTitle>Projects</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<div className="flex h-full flex-col">
|
||||
<p className="break-words leading-relaxed text-muted-foreground">
|
||||
Explore my featured projects including HRIStudio, machine
|
||||
learning research, and web applications.
|
||||
<div className="flex h-full flex-col gap-3">
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
HRIStudio, Riverhead Raceway, machine learning, embedded
|
||||
systems, and more.
|
||||
</p>
|
||||
<Button variant="outline" asChild className="mt-auto w-full">
|
||||
<Link href="/projects">
|
||||
View Projects
|
||||
View projects
|
||||
<ArrowUpRight className="ml-2 h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="animate-fade-in-up-delay-2">
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
<BookOpen className="h-5 w-5 flex-shrink-0" />
|
||||
<CardTitle className="mb-1 break-words">
|
||||
Publications
|
||||
</CardTitle>
|
||||
<CardTitle>Publications</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<div className="flex h-full flex-col">
|
||||
<p className="break-words leading-relaxed text-muted-foreground">
|
||||
Read my peer-reviewed publications in human-robot
|
||||
interaction research.
|
||||
<div className="flex h-full flex-col gap-3">
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
Peer-reviewed work in human-robot interaction research.
|
||||
</p>
|
||||
<Button variant="outline" asChild className="mt-auto w-full">
|
||||
<Link href="/publications">
|
||||
View Publications
|
||||
View publications
|
||||
<ArrowUpRight className="ml-2 h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="animate-fade-in-up-delay-3">
|
||||
<Card className="card-hover card-full-height">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
<ExternalLink className="h-5 w-5 flex-shrink-0" />
|
||||
<CardTitle className="mb-1 break-words">
|
||||
Complete CV
|
||||
</CardTitle>
|
||||
<CardTitle>CV</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="card-content-stretch">
|
||||
<div className="flex h-full flex-col">
|
||||
<p className="break-words leading-relaxed text-muted-foreground">
|
||||
View my complete academic and professional curriculum vitae.
|
||||
<div className="flex h-full flex-col gap-3">
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
Complete academic and professional curriculum vitae.
|
||||
</p>
|
||||
<Button variant="outline" asChild className="mt-auto w-full">
|
||||
<Link href="/cv">
|
||||
@@ -419,9 +428,10 @@ export default function HomePage() {
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user