Skip to content

Commit 201c5d8

Browse files
Add people page
Created and wired a new People page that pulls data from src/data/people.ts, built a UCLA-HCI inspired grid layout, added route /people, and integrated with existing app. Also added data model and component to display current and alumni members. X-Lovable-Edit-ID: edt-cfc4174e-b78e-4f78-9744-f8ea21bc0e3b
2 parents eac68bf + 66e02cf commit 201c5d8

3 files changed

Lines changed: 380 additions & 0 deletions

File tree

src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
55
import { BrowserRouter, Routes, Route } from "react-router-dom";
66
import Index from "./pages/Index";
77
import Research from "./pages/Research";
8+
import People from "./pages/People";
89
import NotFound from "./pages/NotFound";
910

1011
const queryClient = new QueryClient();
@@ -18,6 +19,7 @@ const App = () => (
1819
<Routes>
1920
<Route path="/" element={<Index />} />
2021
<Route path="/research" element={<Research />} />
22+
<Route path="/people" element={<People />} />
2123
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
2224
<Route path="*" element={<NotFound />} />
2325
</Routes>

src/data/people.ts

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
export type PersonRole =
2+
| "faculty"
3+
| "phd"
4+
| "graduate"
5+
| "undergraduate"
6+
| "alumni";
7+
8+
export interface Person {
9+
name: string;
10+
image: string;
11+
url: string;
12+
role: string;
13+
period: string;
14+
category: "current" | "alumni";
15+
destination?: string;
16+
}
17+
18+
export const people: Person[] = [
19+
// --- Current Members ---
20+
{
21+
name: "qiyu li",
22+
image: "https://www.haojianj.in/lab/qiyuli.gif",
23+
url: "https://qyli00.github.io/",
24+
role: "phd student",
25+
period: "2023 –",
26+
category: "current",
27+
},
28+
{
29+
name: "shao-yu chu",
30+
image: "https://www.haojianj.in/lab/shao-yu-chu.jpg",
31+
url: "https://www.linkedin.com/in/shao-yu-chu/",
32+
role: "phd student",
33+
period: "2024 –",
34+
category: "current",
35+
},
36+
{
37+
name: "xuan liu",
38+
image: "https://www.haojianj.in/lab/xuanliu.jpeg",
39+
url: "https://xuanl17.github.io/",
40+
role: "phd student",
41+
period: "2025 –",
42+
category: "current",
43+
},
44+
{
45+
name: "muchan li",
46+
image: "https://www.haojianj.in/lab/muchanli.jpeg",
47+
url: "https://www.linkedin.com/in/muchan-li-989703227/",
48+
role: "graduate student",
49+
period: "2023 –",
50+
category: "current",
51+
},
52+
{
53+
name: "john driscoll",
54+
image: "https://www.haojianj.in/lab/johndriscoll.jpeg",
55+
url: "https://github.com/jjdrisco",
56+
role: "graduate student",
57+
period: "2025 –",
58+
category: "current",
59+
},
60+
{
61+
name: "lucas chen",
62+
image: "https://www.haojianj.in/lab/yulinchen.jpeg",
63+
url: "https://www.linkedin.com/in/yulin-chen-1503512a5/",
64+
role: "undergraduate",
65+
period: "2025 –",
66+
category: "current",
67+
},
68+
{
69+
name: "viki shi",
70+
image: "https://www.haojianj.in/lab/vikishi.jpeg",
71+
url: "https://www.linkedin.com/in/viki-shi/",
72+
role: "undergraduate",
73+
period: "2025 –",
74+
category: "current",
75+
},
76+
{
77+
name: "peter shamoun",
78+
image: "https://www.haojianj.in/lab/petershamoun.jpeg",
79+
url: "https://www.linkedin.com/in/peter-shamoun/",
80+
role: "undergraduate",
81+
period: "2025 –",
82+
category: "current",
83+
},
84+
{
85+
name: "izak vucharatavintara",
86+
image: "https://www.haojianj.in/lab/lzakvucharatavintara.jpeg",
87+
url: "https://www.linkedin.com/in/izak-vuch/",
88+
role: "undergraduate",
89+
period: "2025 –",
90+
category: "current",
91+
},
92+
93+
// --- Alumni ---
94+
{
95+
name: "max wong",
96+
image: "https://www.haojianj.in/lab/maxwong.jpeg",
97+
url: "https://www.linkedin.com/in/wys6299/",
98+
role: "undergraduate",
99+
period: "2024 – 2025",
100+
category: "alumni",
101+
},
102+
{
103+
name: "chris wong",
104+
image: "https://www.haojianj.in/lab/chriswong.jpeg",
105+
url: "https://www.linkedin.com/in/ykw001/",
106+
role: "undergraduate",
107+
period: "2024 – 2025",
108+
category: "alumni",
109+
},
110+
{
111+
name: "jinhe wen",
112+
image: "https://www.haojianj.in/lab/jinhewen.jpeg",
113+
url: "https://jinhewen.owlstown.net/",
114+
role: "ucsd ms (2023 – 2024)",
115+
period: "2023 – 2024",
116+
category: "alumni",
117+
destination: "hkust phd",
118+
},
119+
{
120+
name: "longxuan yu",
121+
image: "https://www.haojianj.in/lab/longxuanyu.jpg",
122+
url: "https://fengsxy.github.io/",
123+
role: "ucsd ms",
124+
period: "2024",
125+
category: "alumni",
126+
destination: "ucr phd",
127+
},
128+
{
129+
name: "jason dai",
130+
image: "https://www.haojianj.in/lab/jasondai.jpeg",
131+
url: "https://www.linkedin.com/in/jason-dai9/",
132+
role: "undergraduate",
133+
period: "2024",
134+
category: "alumni",
135+
destination: "upenn ms",
136+
},
137+
{
138+
name: "yuxuan liu",
139+
image: "https://www.haojianj.in/lab/yuxuanliu.jpeg",
140+
url: "https://www.linkedin.com/in/arrie-yuxuan/",
141+
role: "undergraduate",
142+
period: "2024",
143+
category: "alumni",
144+
destination: "columbia ms",
145+
},
146+
{
147+
name: "yuhe tian",
148+
image: "https://www.haojianj.in/lab/yuhe-tian.jpeg",
149+
url: "https://www.linkedin.com/in/yuhe-tian-07244b242/",
150+
role: "undergraduate",
151+
period: "2024",
152+
category: "alumni",
153+
destination: "ucsd ms",
154+
},
155+
{
156+
name: "trista xu",
157+
image: "https://www.haojianj.in/lab/tristaxu.jpeg",
158+
url: "https://www.linkedin.com/in/tristaxu01/",
159+
role: "undergraduate",
160+
period: "2024",
161+
category: "alumni",
162+
destination: "umich ms",
163+
},
164+
{
165+
name: "elijah zhao",
166+
image: "https://www.haojianj.in/lab/elijahzhao.jpeg",
167+
url: "https://www.linkedin.com/in/yunpeng-elijah-zhao/",
168+
role: "undergraduate",
169+
period: "2024",
170+
category: "alumni",
171+
destination: "cmu ms",
172+
},
173+
{
174+
name: "andrew zhao",
175+
image: "https://www.haojianj.in/lab/andrewzhao.jpeg",
176+
url: "https://www.linkedin.com/in/andrew-zhao-609aa6205/",
177+
role: "undergraduate",
178+
period: "2024",
179+
category: "alumni",
180+
destination: "harvard ms",
181+
},
182+
{
183+
name: "tony li",
184+
image: "https://www.haojianj.in/lab/tonyli.jpg",
185+
url: "https://tonyli1.github.io/",
186+
role: "phd collaborator",
187+
period: "2023 – 2024",
188+
category: "alumni",
189+
},
190+
{
191+
name: "peiran wang",
192+
image: "https://www.haojianj.in/lab/peiranwang.png",
193+
url: "https://whilebug.github.io/p",
194+
role: "remote intern",
195+
period: "2023",
196+
category: "alumni",
197+
destination: "ucla phd",
198+
},
199+
{
200+
name: "arshia arya",
201+
image: "https://www.haojianj.in/lab/arshia.jpeg",
202+
url: "https://arshiaarya.github.io/",
203+
role: "rotation phd",
204+
period: "2023 fall",
205+
category: "alumni",
206+
},
207+
{
208+
name: "joanne pon",
209+
image: "https://www.haojianj.in/lab/joannepon.jpeg",
210+
url: "https://www.linkedin.com/in/joanne-pon-9bb87b231/",
211+
role: "undergraduate",
212+
period: "2023",
213+
category: "alumni",
214+
destination: "cmu ms",
215+
},
216+
{
217+
name: "yuwei xiao",
218+
image: "https://www.haojianj.in/lab/yuweixiao.jpeg",
219+
url: "https://xavier-shaw.github.io/",
220+
role: "undergraduate",
221+
period: "2023",
222+
category: "alumni",
223+
destination: "ucla phd",
224+
},
225+
{
226+
name: "yaqing yang",
227+
image: "https://www.haojianj.in/lab/yaqingyang.png",
228+
url: "https://yyqbeatrice.github.io/yaqing/",
229+
role: "undergraduate",
230+
period: "2023",
231+
category: "alumni",
232+
destination: "cmu phd",
233+
},
234+
{
235+
name: "zirui cheng",
236+
image: "https://www.haojianj.in/lab/ziruicheng.png",
237+
url: "https://chengzr01.github.io/",
238+
role: "undergraduate",
239+
period: "2023",
240+
category: "alumni",
241+
destination: "uiuc ms",
242+
},
243+
{
244+
name: "jingfei xu",
245+
image: "https://www.haojianj.in/lab/jingfeixu.jpeg",
246+
url: "https://www.linkedin.com/in/jingfei-xu-220774207/",
247+
role: "undergraduate",
248+
period: "2023",
249+
category: "alumni",
250+
destination: "cmu ms",
251+
},
252+
{
253+
name: "xiyan shao",
254+
image: "https://www.haojianj.in/lab/xiyanshao.png",
255+
url: "https://www.xiyan.dev/about/",
256+
role: "undergraduate",
257+
period: "2023",
258+
category: "alumni",
259+
destination: "duolingo",
260+
},
261+
{
262+
name: "gram liu",
263+
image: "https://www.haojianj.in/lab/gramliu.webp",
264+
url: "https://gramliu.com/",
265+
role: "undergraduate",
266+
period: "2022",
267+
category: "alumni",
268+
destination: "stripe",
269+
},
270+
{
271+
name: "david ethan hwang",
272+
image: "https://www.haojianj.in/lab/davidhwang.jpeg",
273+
url: "https://www.linkedin.com/in/h-davidethan",
274+
role: "undergraduate",
275+
period: "2022",
276+
category: "alumni",
277+
},
278+
];

src/pages/People.tsx

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { people } from "@/data/people";
2+
import { ArrowLeft, ExternalLink } from "lucide-react";
3+
import { Link } from "react-router-dom";
4+
5+
const currentMembers = people.filter((p) => p.category === "current");
6+
const alumni = people.filter((p) => p.category === "alumni");
7+
8+
const People = () => {
9+
return (
10+
<div className="light-research min-h-screen bg-background text-foreground">
11+
{/* header */}
12+
<header className="sticky top-0 z-20 bg-background/95 backdrop-blur-sm">
13+
<div className="mx-auto max-w-[1200px] px-8 py-5 flex items-center justify-between">
14+
<Link
15+
to="/"
16+
className="flex items-center gap-1.5 text-sm text-muted-foreground transition-colors hover:text-foreground"
17+
>
18+
<ArrowLeft className="h-3.5 w-3.5" />
19+
home
20+
</Link>
21+
<nav className="flex items-center gap-6">
22+
<Link
23+
to="/research"
24+
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
25+
>
26+
research
27+
</Link>
28+
</nav>
29+
</div>
30+
</header>
31+
32+
<main className="mx-auto max-w-[1200px] px-8 pb-20">
33+
{/* current members */}
34+
<section className="pt-8 pb-16">
35+
<h2 className="mb-10 text-sm font-medium tracking-widest text-muted-foreground">
36+
current members
37+
</h2>
38+
<div className="grid grid-cols-2 gap-x-8 gap-y-10 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5">
39+
{currentMembers.map((person) => (
40+
<PersonCard key={person.name} person={person} />
41+
))}
42+
</div>
43+
</section>
44+
45+
{/* alumni */}
46+
<section className="pb-16">
47+
<h2 className="mb-10 text-sm font-medium tracking-widest text-muted-foreground">
48+
alumni
49+
</h2>
50+
<div className="grid grid-cols-2 gap-x-8 gap-y-10 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5">
51+
{alumni.map((person) => (
52+
<PersonCard key={person.name} person={person} />
53+
))}
54+
</div>
55+
</section>
56+
</main>
57+
</div>
58+
);
59+
};
60+
61+
function PersonCard({ person }: { person: (typeof people)[number] }) {
62+
return (
63+
<a
64+
href={person.url}
65+
target="_blank"
66+
rel="noopener noreferrer"
67+
className="group flex flex-col items-center text-center"
68+
>
69+
{/* circular avatar */}
70+
<div className="mb-3 h-28 w-28 overflow-hidden rounded-full bg-muted">
71+
<img
72+
src={person.image}
73+
alt={person.name}
74+
loading="lazy"
75+
className="h-full w-full object-cover grayscale transition-[filter] duration-300 group-hover:grayscale-0"
76+
/>
77+
</div>
78+
79+
{/* name */}
80+
<h3 className="text-sm font-semibold text-foreground group-hover:underline underline-offset-2">
81+
{person.name}
82+
</h3>
83+
84+
{/* role */}
85+
<p className="mt-0.5 text-xs text-muted-foreground">{person.role}</p>
86+
87+
{/* period */}
88+
<p className="text-xs text-muted-foreground/60">{person.period}</p>
89+
90+
{/* destination for alumni */}
91+
{person.destination && (
92+
<p className="mt-0.5 text-xs text-muted-foreground/80">
93+
{person.destination}
94+
</p>
95+
)}
96+
</a>
97+
);
98+
}
99+
100+
export default People;

0 commit comments

Comments
 (0)