diff --git a/app/dev/who-we-are/page.tsx b/app/dev/who-we-are/page.tsx
new file mode 100644
index 0000000..b524dee
--- /dev/null
+++ b/app/dev/who-we-are/page.tsx
@@ -0,0 +1,15 @@
+import OurMission from "@/components/OurMission";
+import WhoWeAre from "@/components/WhoWeAre";
+
+
+export default function WhoWeArePage() {
+
+ return (
+ <>
+
+
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/app/globals.css b/app/globals.css
index b5c61c9..f1cd372 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1,3 +1,14 @@
+@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap");
+
@tailwind base;
@tailwind components;
@tailwind utilities;
+
+.hide-scrollbar::-webkit-scrollbar {
+ display: none;
+}
+
+.hide-scrollbar {
+ -ms-overflow-style: none; /* IE and Edge */
+ scrollbar-width: none; /* Firefox */
+}
\ No newline at end of file
diff --git a/app/page.tsx b/app/page.tsx
index 664f909..c424d90 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,5 +1,8 @@
import Button from "@/components/button";
import Hero from "@/components/hero";
+import OurMission from "@/components/OurMission";
+import WhoWeAre from "@/components/WhoWeAre";
+
export default function HomePage() {
return (
@@ -18,6 +21,9 @@ export default function HomePage() {
>
}
/>
+
+
+
);
}
diff --git a/components/FeaturedStatistics.tsx b/components/FeaturedStatistics.tsx
new file mode 100644
index 0000000..8511ed9
--- /dev/null
+++ b/components/FeaturedStatistics.tsx
@@ -0,0 +1,65 @@
+/**
+ * @fileoverview A section that displays a set of large statistics
+ * and statistic descriptions.
+ *
+ * @file FeaturedStatistics.tsx
+ * @date January 5th, 2023
+ * @author Gabriel Sessions
+ *
+ */
+
+import clsx from "clsx"
+
+interface FeaturedStatisticsProps {
+ statistics: Array,
+ className?: string
+}
+
+/**
+ * Displays a set of statistics in a row (or column depending on screen size)
+ *
+ * @param props - An array of statistics to be fed into DisplayStatistic
+ */
+export default function FeaturedStatistics(props: FeaturedStatisticsProps) {
+ return (
+
+ {
+ props.statistics.map((stat, idx) =>
+
+
+
+ )
+ }
+
+ )
+}
+
+interface Statistic {
+ statistic: string,
+ label: string
+}
+
+/**
+ * Displays a bold statistic (e.g. number)
+ * and a short description of the statistic
+ *
+ * @param props - A statistic and a descriptor (label)
+ */
+function DisplayStatistic(props: Statistic) {
+ return (
+ <>
+
+
{props.statistic}
+ {props.label}
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/components/FeaturedTextBlock.tsx b/components/FeaturedTextBlock.tsx
new file mode 100644
index 0000000..cea70dd
--- /dev/null
+++ b/components/FeaturedTextBlock.tsx
@@ -0,0 +1,31 @@
+/**
+ * @fileoverview A simple section with a small title and a block of bolded text
+ *
+ * @file FeaturedTextBlock.tsx
+ * @date January 5th, 2025
+ * @author Gabriel Sessions
+ *
+ */
+
+import { ReactNode } from "react"
+
+interface FeaturedTextBlockProps {
+ title: ReactNode,
+ featuredText: ReactNode
+}
+
+/**
+ * Displays a header and descriptor text below the header.
+ *
+ * @param Takes in a title (header) and featured text (descriptor)
+ */
+export default function FeaturedTextBlock(props: FeaturedTextBlockProps) {
+ return (
+ <>
+
+
{props.title}
+ {props.featuredText}
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/components/ImageCarousel.tsx b/components/ImageCarousel.tsx
new file mode 100644
index 0000000..5cb4e8d
--- /dev/null
+++ b/components/ImageCarousel.tsx
@@ -0,0 +1,120 @@
+/**
+ * @fileoverview A scrollable image carousel which shows a preview of the
+ * next/previous images.
+ *
+ * @file ImageCarousel.tsx
+ * @date January 5th, 2023
+ * @author Gabriel Sessions
+ *
+ * @todo Remove hardcoded width/height values if this component is reused
+ * with different image dimensions.
+ */
+
+"use client"
+
+import { clsx } from 'clsx';
+import Image from "next/image";
+import { useEffect, useRef, useState } from "react";
+
+const IMG_HEIGHT = 389;
+const IMG_WIDTH = 665;
+
+/**
+ * @param path - Local or absolute path to an image asset
+ * @param altText - A text descriptor of the image
+ * @param className - Optional field to add CSS styles
+ */
+interface ImageProps {
+ path: string,
+ altText: string,
+ className?: string
+}
+
+/**
+ * @param images - An array of objects to be fed into the Image component
+ * @param className - Optional field to add CSS styles
+ */
+interface ImageCarouselProps {
+ images: Array,
+ className?: string
+}
+
+/**
+ * An Image Carousel with basic scrolling functionality
+ *
+ * @param props - An array of images
+ * @todo Adjust the useEffect scrolling logic to display an even number
+ * of images properly.
+ */
+export default function ImageCarousel(props: ImageCarouselProps) {
+ const scrollContainerRef = useRef(null);
+
+ // The carousel is hidden from the user while it loads and waits for the
+ // useEffect to scroll the carousel
+ const [isVisible, setIsVisible] = useState(false);
+
+ // Scrolls the carousel to the center when the page loads
+ useEffect(() => {
+ if (scrollContainerRef.current) {
+ const scrollContainer = scrollContainerRef.current;
+ const centerPosition = (scrollContainer.scrollWidth - scrollContainer.clientWidth) / 2;
+ scrollContainer.scrollLeft = centerPosition;
+ setIsVisible(true);
+ }
+ }, []);
+
+ return (
+
+
+ {props.images.map((image, idx) => (
+
+ ))}
+
+
+ )
+}
+
+
+/**
+ * An image container generator. Creates a responsive, rounded box
+ * for images with a max width of 600px.
+ *
+ * @param props - Image path, alt text. Width and height are defined globally.
+ * @returns A React component
+ *
+ * @todo Change width/height to props values if the component needs to be reused
+ * with new image dimensions.
+ */
+function ImageContainer(props: ImageProps) {
+ return (
+
+ )
+}
+
diff --git a/components/OurMission.tsx b/components/OurMission.tsx
new file mode 100644
index 0000000..ad7f702
--- /dev/null
+++ b/components/OurMission.tsx
@@ -0,0 +1,26 @@
+/**
+ * @fileoverview The "Our Mission" section on the JumboCode homepage
+ *
+ * @file OurMission.tsx
+ * @date January 5th, 2025
+ * @author Gabriel Sessions
+ */
+
+import FeaturedTextBlock from "./FeaturedTextBlock"
+
+const ourMissionText = {
+ title: "Our mission",
+ featuredText:
+ <>
+ To strengthen communities by developing custom software solutions that promote change and foster student growth.
+ >
+}
+
+export default function OurMission() {
+
+ return (
+ <>
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/components/WhoWeAre.tsx b/components/WhoWeAre.tsx
new file mode 100644
index 0000000..16f5b8b
--- /dev/null
+++ b/components/WhoWeAre.tsx
@@ -0,0 +1,77 @@
+/**
+ * @fileoverview The "Who We Are" section of the JumboCode homepage.
+ *
+ * @file WhoWeAre.tsx
+ * @date January 5th, 2025
+ * @author Gabriel Sessions
+ */
+
+import FeaturedStatistics from "./FeaturedStatistics";
+import FeaturedTextBlock from "./FeaturedTextBlock";
+import ImageCarousel from "./ImageCarousel";
+
+const whoWeAreText = {
+ title: "Who we are",
+ featuredText:
+ <>
+ JumboCode is a student-run digital agency at Tufts University that provides custom and high-quality software to nonprofits through year-long pro bono projects.
+ >
+}
+
+const whoWeAreImages = [
+ {
+ path: "/homepage/who-we-are-4.png",
+ altText: "Project presentation"
+ },
+ {
+ path: "/homepage/who-we-are-1.png",
+ altText: "A live demo at JumboCode final presentations"
+ },
+ {
+ path: "/homepage/who-we-are-2.png",
+ altText: "JumboCode Team Photo"
+ },
+ {
+ path: "/homepage/who-we-are-3.png",
+ altText: "A team having fun at a JumboCode hack night"
+ },
+ {
+ path: "/homepage/who-we-are-5.png",
+ altText: "JumboHack programmers working on their projects"
+ }
+];
+
+const featuredStatistics = [
+ {
+ statistic: "170+",
+ label: "Annual Members"
+ },
+ {
+ statistic: "80K+",
+ label: "Hours Volunteered"
+ },
+ {
+ statistic: "75+",
+ label: "Shipped Apps"
+ }
+]
+
+export default function WhoWeAre() {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ )
+}
+
diff --git a/public/homepage/who-we-are-1.png b/public/homepage/who-we-are-1.png
new file mode 100644
index 0000000..d0ce221
Binary files /dev/null and b/public/homepage/who-we-are-1.png differ
diff --git a/public/homepage/who-we-are-2.png b/public/homepage/who-we-are-2.png
new file mode 100644
index 0000000..d038a9b
Binary files /dev/null and b/public/homepage/who-we-are-2.png differ
diff --git a/public/homepage/who-we-are-3.png b/public/homepage/who-we-are-3.png
new file mode 100644
index 0000000..450cc0d
Binary files /dev/null and b/public/homepage/who-we-are-3.png differ
diff --git a/public/homepage/who-we-are-4.png b/public/homepage/who-we-are-4.png
new file mode 100644
index 0000000..b32e197
Binary files /dev/null and b/public/homepage/who-we-are-4.png differ
diff --git a/public/homepage/who-we-are-5.png b/public/homepage/who-we-are-5.png
new file mode 100644
index 0000000..89f1035
Binary files /dev/null and b/public/homepage/who-we-are-5.png differ
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 88ab515..57b8a80 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -10,9 +10,14 @@ const config: Config = {
],
theme: {
extend: {
+ fontFamily: {
+ inter: ['Inter', 'sans-serif']
+ },
colors: {
gray: colors.zinc,
brand: "#32C89E",
+ background: "#171719",
+ subtext: "#A1A1A1"
},
},
},