Skip to content
Open
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Resources from "./pages/Forms";
import TravelReimbursement from "./pages/TravelReimbursement";
import Donate from "./pages/Donate";
import History from "./pages/History";
import PillarDetail from "./pages/PillarDetail";
import ScrollToTop from "./components/ScrollToTop";
import { CartProvider } from "./lib/CartContext";

Expand Down Expand Up @@ -54,6 +55,7 @@ function App() {
<Route element={<MainLayout />}>
<Route path="/" element={<Home />} />
<Route path="/history" element={<History />} />
<Route path="/pillars/:slug" element={<PillarDetail />} />
<Route path="/mentorship" element={<Mentorship />} />
<Route path="/distinguishedMembers" element={<PointsSystem />} />
<Route path="/leaderboard" element={<Leaderboard />} />
Expand Down
26 changes: 26 additions & 0 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,32 @@ body {

.section {
@apply py-8 md:py-16 flex flex-col justify-center items-center;
position: relative;
}

/* Subtle zebra-striping so consecutive sections read as distinct blocks,
on top of the gradient divider line below. */
.section:nth-of-type(even) {
background-color: rgba(255, 255, 255, 0.025);
}

/* Soft horizontal divider above every section after the first, giving
each homepage section visual separation without heavy hard lines. */
.section + .section::before {
content: "";
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: min(80rem, 92%);
height: 3px;
background: linear-gradient(
to right,
transparent 0%,
rgba(231, 231, 229, 0.35) 50%,
transparent 100%
);
pointer-events: none;
}

.cal-shadow {
Expand Down
53 changes: 19 additions & 34 deletions src/components/Mission.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,34 @@
const perks = [
{
header: "Professional Development",
description:
"SoDA offers boundless opportunities to advance your career. From technical workshops hosted by industry leaders to career fairs and networking events, you’ll gain invaluable experience and connections to kickstart your journey as a software developer.",
imgURL: "/events/amazon-table.webp",
alt: "Amazon table at a SoDA event",
},
{
header: "Community and Support",
description:
"SoDA provides a supportive network of fellow computer science students, offering collaboration, encouragement, and a sense of belonging through regular meetings and events with free food.",
imgURL: "/events/microsoft-resume-review.webp",
alt: "Microsoft resume review at a SoDA event",
},
{
header: "Learning",
description:
"Enhance your skills through a variety of learning opportunities, including coding workshops, bootcamps, and talks from industry professionals. SoDA is committed to your personal and professional growth, ensuring you stay ahead in the fast-paced tech world.",
imgURL: "/events/what-is-soda.webp",
alt: "SoDA members at a meeting",
},
];
import { Link } from "react-router-dom";
import HoverPlayMedia from "./ui/HoverPlayMedia";
import { pillars } from "../data/pillars";

export default function Mission() {
return (
<>
<main className="flex flex-col justify-center items-center" id="mission">
<h1 className="section-header-text">Mission</h1>
<p className="hero-small-text max-w-3xl text-center mb-8 px-6">
SoDA’s mission is to provide an accessible, professional, and fun community for students
interested in building software.
</p>
<section className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{perks.map((perk) => (
<div
key={perk.header}
className="bg-neutral-900 p-4 border-gray-600 rounded-2xl justify-center flex flex-col min-h-[300px] max-w-[300px] w-full"
{pillars.map((pillar) => (
<Link
key={pillar.slug}
to={`/pillars/${pillar.slug}`}
className="bg-neutral-900 p-4 border-gray-600 rounded-2xl justify-center flex flex-col min-h-[300px] max-w-[300px] w-full transition-colors hover:bg-neutral-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-soda-blue"
>
<img
src={perk.imgURL}
<HoverPlayMedia
src={pillar.imgURL}
videoSrc={pillar.videoURL}
alt={pillar.alt}
className="rounded-t-xl object-cover w-full h-48"
alt={perk.alt}
/>
<div className="text-white px-4 py-3 space-y-3 text-left flex-1">
<h4 className="font-semibold text-xl max-md:text-lg">{perk.header}</h4>
{/* <hr className="border-soda-gray opacity-75 my-2 w-[60%]" /> */}
<p className="text-[14px] max-md:text-sm ">{perk.description}</p>
<h4 className="font-semibold text-xl max-md:text-lg">{pillar.header}</h4>
<p className="text-[14px] max-md:text-sm ">{pillar.description}</p>
</div>
</div>
</Link>
))}
</section>
</main>
Expand Down
3 changes: 2 additions & 1 deletion src/components/Stats/Statistics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const statistics = [
// value: 22500, // last updated 2020-01-16 (https://github.com/asusoda/asu-soda-oldsite/commit/0813ac24a21dcc190ecfc44b0829825c27d85718)
// last known value + semesters since * estimated = 22500 + 10 * 3500 = 57500 // last updated 2025-03-29
//Added the number for Spring 2025 updated 2025-08-25: 61276
value: 61276,
// Updated 2026-08-25: 63857.20
value: 63857.2,
steps: 3000,
formatter: (x: number) => <>{dollarFormatter.format(x)}</>,
},
Expand Down
43 changes: 43 additions & 0 deletions src/components/ui/HoverPlayMedia.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useRef } from "react";

interface HoverPlayMediaProps {
src: string;
videoSrc?: string;
alt: string;
className?: string;
}

export default function HoverPlayMedia({ src, videoSrc, alt, className }: HoverPlayMediaProps) {
const videoRef = useRef<HTMLVideoElement>(null);

if (!videoSrc) {
return <img src={src} className={className} alt={alt} />;
}

const play = () => videoRef.current?.play();
const reset = () => {
const video = videoRef.current;
if (!video) return;
video.pause();
video.currentTime = 0;
};

return (
<video
ref={videoRef}
className={className}
poster={src}
src={videoSrc}
muted
loop
playsInline
preload="none"
aria-label={alt}
onMouseEnter={play}
onMouseLeave={reset}
onFocus={play}
onBlur={reset}
tabIndex={0}
/>
);
}
36 changes: 36 additions & 0 deletions src/data/pillars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export interface Pillar {
slug: string;
header: string;
description: string;
imgURL: string;
alt: string;
// Hover-play video, added per pillar once footage is available.
videoURL?: string;
}

export const pillars: Pillar[] = [
{
slug: "professional-development",
header: "Professional Development",
description:
"SoDA offers boundless opportunities to advance your career. From technical workshops hosted by industry leaders to career fairs and networking events, you’ll gain invaluable experience and connections to kickstart your journey as a software developer.",
imgURL: "/events/amazon-table.webp",
alt: "Amazon table at a SoDA event",
},
{
slug: "community",
header: "Community and Support",
description:
"SoDA provides a supportive network of fellow computer science students, offering collaboration, encouragement, and a sense of belonging through regular meetings and events with free food.",
imgURL: "/events/microsoft-resume-review.webp",
alt: "Microsoft resume review at a SoDA event",
},
{
slug: "learning",
header: "Learning",
description:
"Enhance your skills through a variety of learning opportunities, including coding workshops, bootcamps, and talks from industry professionals. SoDA is committed to your personal and professional growth, ensuring you stay ahead in the fast-paced tech world.",
imgURL: "/events/what-is-soda.webp",
alt: "SoDA members at a meeting",
},
];
41 changes: 41 additions & 0 deletions src/pages/PillarDetail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Helmet } from "react-helmet-async";
import { Link, useParams } from "react-router-dom";
import { pillars } from "../data/pillars";

export default function PillarDetail() {
const { slug } = useParams<{ slug: string }>();
const pillar = pillars.find((p) => p.slug === slug);

if (!pillar) {
return (
<div className="max-w-3xl mx-auto p-6 my-28 text-center text-white">
<h1 className="section-header-text">Pillar not found</h1>
<Link to="/#mission" className="text-soda-blue underline">
Back to Mission
</Link>
</div>
);
}

return (
<div className="max-w-3xl mx-auto p-6 my-28">
<Helmet>
<title>SoDA - {pillar.header}</title>
<meta name="description" content={pillar.description} />
</Helmet>

<Link to="/#mission" className="text-soda-blue underline text-sm">
← Back to Mission
</Link>

<img
src={pillar.imgURL}
alt={pillar.alt}
className="rounded-2xl object-cover w-full h-64 md:h-80 mt-4 mb-8"
/>

<h1 className="section-header-text text-left! w-full!">{pillar.header}</h1>
<p className="hero-small-text">{pillar.description}</p>
</div>
);
}