Skip to content

Commit ffd7912

Browse files
author
zz3188
committed
Added team member profiles
2 parents 106527c + 8042477 commit ffd7912

34 files changed

Lines changed: 2332 additions & 776 deletions

.github/workflows/lint.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,28 @@ jobs:
2626
with:
2727
eslint: true
2828
prettier: true
29+
ruff:
30+
name: Ruff (backend)
31+
runs-on: ubuntu-latest
32+
defaults:
33+
run:
34+
working-directory: ./backend
35+
36+
steps:
37+
- name: Check out Git repository
38+
uses: actions/checkout@v5
39+
40+
- name: Install uv
41+
uses: astral-sh/setup-uv@v4
42+
43+
- name: Set up Python
44+
run: uv python install
45+
46+
- name: Install backend dependencies
47+
run: uv sync --group dev
48+
49+
- name: Run Ruff lint check
50+
run: uv run ruff check
51+
52+
- name: Run Ruff format check
53+
run: uv run ruff format --check

app/Content.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export default function Content({
1414
children: ReactNode;
1515
}): React.JSX.Element {
1616
const tabs = [
17+
{ title: 'About', href: '/about' },
1718
{ title: 'Send Mail', href: '/app' },
1819
{ title: 'Scheduled Emails', href: '/scheduled' },
1920
{ title: 'Current Digest', href: '/digest?type=current' },

app/about/page.tsx

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
'use client';
2+
3+
import React from 'react';
4+
5+
import { Heading, majorScale, Pane, Text, useTheme } from 'evergreen-ui';
6+
7+
// --- Helper Components & Data ---
8+
interface member {
9+
name: string;
10+
role: string;
11+
imgSrc: string;
12+
socials: {
13+
linkedin: string;
14+
github: string;
15+
};
16+
}
17+
18+
// Icon for social media links
19+
const SocialIcon = ({
20+
href,
21+
children,
22+
}: {
23+
href: string;
24+
children: React.ReactNode;
25+
}) => (
26+
<a
27+
href={href}
28+
target='_blank'
29+
rel='noopener noreferrer'
30+
className='text-gray-400 transition-colors duration-300'
31+
>
32+
{children}
33+
</a>
34+
);
35+
36+
// SVG components for icons
37+
const LinkedinIcon = () => (
38+
<svg
39+
xmlns='http://www.w3.org/2000/svg'
40+
width='24'
41+
height='24'
42+
viewBox='0 0 24 24'
43+
fill='none'
44+
stroke='currentColor'
45+
strokeWidth='2'
46+
strokeLinecap='round'
47+
strokeLinejoin='round'
48+
>
49+
<path d='M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z' />
50+
<rect x='2' y='9' width='4' height='12' />
51+
<circle cx='4' cy='4' r='2' />
52+
</svg>
53+
);
54+
55+
const GitHubIcon = () => (
56+
<svg
57+
xmlns='http://www.w3.org/2000/svg'
58+
width='24'
59+
height='24'
60+
viewBox='0 0 16 16'
61+
fill='currentColor'
62+
>
63+
<path d='M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8' />
64+
</svg>
65+
);
66+
67+
const teamLeads: member[] = [
68+
{
69+
name: 'Jenny Fan',
70+
role: 'Team Lead',
71+
imgSrc: 'https://i.imgur.com/grwgWFZ.jpeg',
72+
socials: {
73+
linkedin: 'https://www.linkedin.com/in/jennyfan04/',
74+
github: 'https://github.com/jfmath04',
75+
},
76+
},
77+
{
78+
name: 'Zhao Song Zhou',
79+
role: 'Team Lead',
80+
imgSrc: 'https://i.imgur.com/JeUh9dc.jpeg',
81+
socials: {
82+
linkedin: 'https://www.linkedin.com/in/zhao-song-zhou/',
83+
github: 'https://github.com/ZhaoSongZh7',
84+
},
85+
},
86+
{
87+
name: 'Alvin Sze',
88+
role: 'Team Lead',
89+
imgSrc: 'https://i.imgur.com/mZy9kzp.jpeg',
90+
socials: {
91+
linkedin: 'https://www.linkedin.com/in/alvinsze/',
92+
github: 'https://github.com/asze17',
93+
},
94+
},
95+
];
96+
97+
const teamMembers: member[] = [
98+
{
99+
name: 'Chloe Lau',
100+
role: 'Product Manager',
101+
imgSrc: 'https://i.imgur.com/BVrnu64.jpeg',
102+
socials: {
103+
linkedin: 'https://www.linkedin.com/in/chloe-hc-lau/',
104+
github: 'https://github.com/lauechlo',
105+
},
106+
},
107+
{
108+
name: 'Allison Lee',
109+
role: 'Product Manager',
110+
imgSrc: 'https://i.imgur.com/3SPqM7z.jpeg',
111+
socials: {
112+
linkedin: 'https://www.linkedin.com/in/allisonelee/',
113+
github: 'https://github.com/allisonelee',
114+
},
115+
},
116+
{
117+
name: 'Christal Chen',
118+
role: 'Software Engineer',
119+
imgSrc: 'https://i.imgur.com/ZshQ3Fj.jpeg',
120+
socials: {
121+
linkedin: 'https://www.linkedin.com/in/christalchen/',
122+
github: 'https://github.com/12chenec',
123+
},
124+
},
125+
];
126+
127+
/**
128+
* Modern "Meet the Team" page component.
129+
* Features a clean, professional design with interactive cards.
130+
*/
131+
export function App() {
132+
const theme = useTheme();
133+
return (
134+
<div className='min-h-screen font-sans text-slate-800'>
135+
<style
136+
dangerouslySetInnerHTML={{
137+
__html: `.group:hover .group-hover-border { border-color: ${theme.colors.blue300}; }`,
138+
}}
139+
/>
140+
<div className='container mx-auto px-4 sm:px-6 lg:px-8 py-16'>
141+
{/* Header */}
142+
<Pane textAlign='center' marginBottom={majorScale(6)}>
143+
<Heading
144+
size={900}
145+
fontSize='3rem'
146+
fontWeight={700}
147+
marginBottom={majorScale(4)}
148+
>
149+
Meet the{' '}
150+
<Text
151+
size={900}
152+
fontSize='3rem'
153+
color={theme.colors.blue500}
154+
>
155+
HoagieMail
156+
</Text>{' '}
157+
Team
158+
</Heading>
159+
<Text
160+
size={500}
161+
display='block'
162+
maxWidth={900}
163+
marginX='auto'
164+
>
165+
HoagieMail is Princeton&apos;s go-to platform for
166+
campus-wide email communication. Built by students, for
167+
students, it serves as the primary channel through which
168+
clubs, organizations, and student groups reach the
169+
broader Princeton community from event announcements and
170+
recruitment blasts to club updates and campus
171+
initiatives. <br /> <br />
172+
HoagieMail has become an indispensable part of campus
173+
life, ensuring that students stay connected to the
174+
communities and opportunities that matter most to them.
175+
</Text>
176+
</Pane>
177+
178+
{/* Team Leadership Section */}
179+
<section className='mb-16'>
180+
<h2 className='text-3xl font-bold text-slate-900 mb-12 text-center'>
181+
Team Leadership
182+
</h2>
183+
<div className='grid grid-cols-1 lg:grid-cols-2 gap-10 max-w-5xl mx-auto'>
184+
{teamLeads.map((lead) => (
185+
<div
186+
key={lead.name}
187+
className='bg-white rounded-2xl shadow-lg overflow-hidden transform hover:scale-[1.02] transition-transform duration-300 ease-in-out w-full'
188+
>
189+
<div className='p-8 flex flex-col sm:flex-row items-center'>
190+
<Pane
191+
flexShrink={0}
192+
marginBottom={majorScale(3)}
193+
marginRight={majorScale(4)}
194+
width={128}
195+
height={128}
196+
borderRadius='50%'
197+
border={`4px solid ${theme.colors.blue300}`}
198+
boxShadow='0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)'
199+
overflow='hidden'
200+
>
201+
{/* Intentionally using img so direct Imgur URLs work without Next image domain config. */}
202+
{/* eslint-disable-next-line @next/next/no-img-element */}
203+
<img
204+
src={lead.imgSrc}
205+
alt={lead.name}
206+
height={128}
207+
width={128}
208+
style={{ objectFit: 'cover' }}
209+
/>
210+
</Pane>
211+
<div className='text-center sm:text-left'>
212+
<h3 className='text-2xl font-bold text-slate-900'>
213+
{lead.name}
214+
</h3>
215+
<p
216+
className='text-md font-semibold mb-2'
217+
style={{
218+
color: theme.colors.blue500,
219+
}}
220+
>
221+
{lead.role}
222+
</p>
223+
<div className='flex justify-center sm:justify-start space-x-4'>
224+
<SocialIcon href={lead.socials.github}>
225+
<GitHubIcon />
226+
</SocialIcon>
227+
<SocialIcon
228+
href={lead.socials.linkedin}
229+
>
230+
<LinkedinIcon />
231+
</SocialIcon>
232+
</div>
233+
</div>
234+
</div>
235+
</div>
236+
))}
237+
</div>
238+
</section>
239+
240+
{/* Team Members Section */}
241+
<section className='mb-16'>
242+
<h2 className='text-3xl font-bold text-slate-900 mb-12 text-center'>
243+
Contributors
244+
</h2>
245+
<div className='grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-8'>
246+
{teamMembers.map((member) => (
247+
<div
248+
key={member.name}
249+
className='bg-white rounded-xl shadow-md p-6 text-center transform hover:-translate-y-2 transition-transform duration-300 ease-in-out group'
250+
>
251+
{/* Intentionally using img so direct Imgur URLs work without Next image domain config. */}
252+
{/* eslint-disable-next-line @next/next/no-img-element */}
253+
<img
254+
src={member.imgSrc}
255+
alt={member.name}
256+
className='w-24 h-24 rounded-full mx-auto mb-4 border-4 border-slate-200 group-hover-border transition-colors duration-300'
257+
height={128}
258+
width={128}
259+
style={{ objectFit: 'cover' }}
260+
/>
261+
<h4 className='font-bold text-slate-800 text-lg'>
262+
{member.name}
263+
</h4>
264+
<p
265+
className='!text-sm'
266+
style={{ color: theme.colors.blue500 }}
267+
>
268+
{member.role}
269+
</p>
270+
<div className='flex mx-auto w-min mt-2 justify-center sm:justify-start space-x-4'>
271+
<SocialIcon href={member.socials.github}>
272+
<GitHubIcon />
273+
</SocialIcon>
274+
<SocialIcon href={member.socials.linkedin}>
275+
<LinkedinIcon />
276+
</SocialIcon>
277+
</div>
278+
</div>
279+
))}
280+
</div>
281+
</section>
282+
</div>
283+
</div>
284+
);
285+
}
286+
287+
export default App;

app/mail.css

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
@import 'tailwindcss/theme' layer(theme);
2+
@import 'tailwindcss/utilities' layer(utilities);
3+
14
body {
25
background: #ffe3c6;
36
}
@@ -32,6 +35,24 @@ body {
3235
animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards;
3336
}
3437

38+
.template-card {
39+
text-align: center;
40+
cursor: pointer;
41+
transition: transform 0.2s;
42+
}
43+
44+
.template-card:hover {
45+
transform: translateY(-2px);
46+
}
47+
48+
.template-preview-box {
49+
transition: all 0.2s;
50+
}
51+
52+
.template-preview-box:hover {
53+
border-color: #ffcb97;
54+
}
55+
3556
@keyframes stroke {
3657
100% {
3758
stroke-dashoffset: 0;

0 commit comments

Comments
 (0)