Skip to content
Merged
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
99 changes: 99 additions & 0 deletions apps/frontend/app/about/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { AboutCard } from "@/components/about-us-card";
import { PublicPageLayout } from "@/components/public-page-shell";
import type { Metadata } from "next";
import type { ReactNode } from "react";

export const metadata: Metadata = {
title: "About Us",
description:
"Learn about CS + Social Good at UNC Chapel Hill, our mission, and how we build technology for community impact.",
};

type GoalItemProps = {
index: number;
children: ReactNode;
};

function GoalItem({ index, children }: GoalItemProps) {
return (
<div className="grid gap-3 md:grid-cols-[72px_1fr] md:items-start md:gap-10">
<div className="text-(--color-accent) text-3xl font-bold leading-none md:text-5xl">
{index}
</div>
<div className="max-w-4xl text-base leading-8 text-slate-900 md:text-[1.45rem] md:leading-[1.45]">
{children}
</div>
</div>
);
}

const goals = [
"Complete impactful, technically challenging projects for nonprofit clients, pro bono, to lighten the heavy burden these organizations face.",
"Provide a space for students to learn about the intersection of computer science and social good, and to connect with other students who are interested in this field.",
"Create opportunities for professional development and industry connections for our members, with an emphasis on partners who make a positive impact.",
];

const structureItems = [
{
title: "Projects",
icon: "</>",
description:
"The projects team is responsible for building projects benefiting nonprofits in the Chapel Hill area and beyond.",
},
{
title: "Education",
icon: "Edu",
description:
"The education team is responsible for running semester-long classes to teach members the technical skills required for membership on a project team.",
},
{
title: "Engagement",
icon: "Com",
description:
"The engagement team is responsible for organizing events, performing marketing, and hosting workshops for our members.",
},
{
title: "Strategy",
icon: "Plan",
description:
"The strategy team is responsible for developing and executing the long-term vision and strategy for CS+SG.",
},
];

export default function AboutPage() {
return (
<PublicPageLayout>
<section className="rounded-4xl bg-white/92 border border-cyan-100/15 px-6 py-10 text-slate-900 shadow-[0_25px_90px_rgba(4,18,33,0.22)] md:px-12 md:py-14">
<h1 className="font-mono text-2xl font-bold tracking-tight md:text-3xl">Our Goals</h1>

<div className="mt-10 space-y-8 md:space-y-10">
{goals.map((goal, index) => (
<GoalItem key={goal} index={index + 1}>
{goal}
</GoalItem>
))}
</div>
</section>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reuse: The numbered goal block is a repeated structure. Consider a small GoalItem (or generic numbered content block) that takes index and children so the page stays thin and the pattern is reusable.

<div className="mx-auto my-8 h-10 w-full max-w-6xl rounded-full bg-[linear-gradient(90deg,#173654_0%,#245c83_50%,#173654_100%)] opacity-95" />

<section className="rounded-4xl bg-white/92 border border-cyan-100/15 px-6 py-10 text-slate-900 shadow-[0_25px_90px_rgba(4,18,33,0.22)] md:px-12 md:py-14">
<h2 className="font-mono text-2xl font-bold tracking-tight md:text-3xl">Our Structure</h2>
<p className="mt-4 max-w-3xl text-sm text-slate-500 md:text-lg">
CS+SG is comprised of a variety of components, each with a unique focus.
</p>

<div className="mt-12 grid gap-8 md:grid-cols-2 xl:grid-cols-4">
{structureItems.map((item) => (
<AboutCard
key={item.title}
title={item.title}
icon={item.icon}
description={item.description}
/>
))}
</div>
</section>
</PublicPageLayout>
);
}
95 changes: 95 additions & 0 deletions apps/frontend/app/contact/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { PublicInfoCard } from "@/components/public-info-card";
import { PublicPageLayout } from "@/components/public-page-shell";
import type { Metadata } from "next";
import Link from "next/link";

export const metadata: Metadata = {
title: "Contact Us",
description:
"Contact CS + Social Good at UNC Chapel Hill for general questions, partnerships, and collaboration opportunities.",
};

const socialLinks = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Data vs presentation: socialLinks embeds JSX in the array, which mixes data and presentation. Consider a SocialLink component that accepts name, href, and icon (e.g. ReactNode) and keep the data array to plain objects; pass icons via a separate map or render them inside the component so props are clear.

{
name: "GitHub",
href: "https://github.com/cssgunc",
icon: (
<svg viewBox="0 0 24 24" aria-hidden="true" className="h-5 w-5 fill-current">
<path d="M12 1.5a10.5 10.5 0 0 0-3.32 20.46c.53.1.72-.23.72-.51v-1.79c-2.93.64-3.55-1.25-3.55-1.25-.48-1.22-1.17-1.54-1.17-1.54-.96-.65.07-.64.07-.64 1.07.07 1.63 1.1 1.63 1.1.94 1.62 2.47 1.15 3.07.88.1-.68.37-1.15.67-1.42-2.34-.27-4.81-1.17-4.81-5.22 0-1.15.41-2.08 1.08-2.82-.11-.27-.47-1.38.1-2.88 0 0 .88-.28 2.88 1.08a9.97 9.97 0 0 1 5.24 0c2-1.36 2.88-1.08 2.88-1.08.57 1.5.21 2.61.1 2.88.67.74 1.08 1.67 1.08 2.82 0 4.06-2.48 4.95-4.84 5.21.38.33.72.97.72 1.96v2.91c0 .28.19.62.73.51A10.5 10.5 0 0 0 12 1.5Z" />
</svg>
),
},
{
name: "LinkedIn",
href: "https://www.linkedin.com/company/unc-cs-social-good/",
icon: (
<svg viewBox="0 0 24 24" aria-hidden="true" className="h-5 w-5 fill-current">
<path d="M6.94 8.5H3.56V20h3.38V8.5Zm.22-3.56C7.15 3.83 6.28 3 5.25 3S3.34 3.83 3.34 4.94c0 1.1.85 1.94 1.88 1.94h.03c1.04 0 1.91-.84 1.91-1.94ZM20.66 13.08c0-3.47-1.85-5.08-4.33-5.08-2 0-2.89 1.1-3.39 1.88V8.5H9.56c.04.91 0 11.5 0 11.5h3.38v-6.42c0-.34.02-.67.12-.91.27-.67.89-1.36 1.93-1.36 1.36 0 1.91 1.03 1.91 2.54V20H20.3v-6.92c0-.37.01-.73.01-1Z" />
</svg>
),
},
{
name: "Instagram",
href: "https://www.instagram.com/unc_cssg/",
icon: (
<svg
viewBox="0 0 24 24"
aria-hidden="true"
className="h-5 w-5 fill-none stroke-current stroke-[1.8]"
>
<rect x="3.5" y="3.5" width="17" height="17" rx="4.5" />
<circle cx="12" cy="12" r="4.2" />
<circle cx="17.4" cy="6.6" r="1" fill="currentColor" stroke="none" />
</svg>
),
},
];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reuse: Same page shell as About and Projects (gradient + overlay). Consider using a shared PublicPageLayout component so this isn’t duplicated in three files.


export default function ContactPage() {
return (
<PublicPageLayout>
<h1 className="text-3xl font-bold text-[#63e8c7] md:text-4xl">Contact Us</h1>
<p className="mt-4 max-w-3xl text-base leading-7 text-white/85 md:text-lg">
Interested in partnering with CS + Social Good or joining our team? Reach out and we can
connect you with the right people.
</p>

<section className="mt-12 grid gap-6 md:grid-cols-2">
<PublicInfoCard title="General Inquiries">
<p>
For questions about meetings, membership, or events, email us and we will reply as soon
as possible.
</p>

<Link
href="mailto:cssgunc@gmail.com"
className="mt-4 inline-block text-sm font-medium text-[#63e8c7] underline-offset-4 transition hover:underline"
>
cssgunc@gmail.com
</Link>
</PublicInfoCard>

<PublicInfoCard title="Socials">
<p>
Follow CS + Social Good online for updates on projects, events, and campus activity.
</p>

<div className="mt-5 space-y-3">
{socialLinks.map((link) => (
<Link
key={link.name}
href={link.href}
target="_blank"
rel="noreferrer"
className="flex items-center gap-3 rounded-xl border border-cyan-100/10 bg-white/5 px-4 py-3 text-sm font-medium text-white/90 transition hover:border-cyan-300/40 hover:text-[#63e8c7]"
>
<span className="text-[#63e8c7]">{link.icon}</span>
<span>{link.name}</span>
</Link>
))}
</div>
</PublicInfoCard>
</section>
</PublicPageLayout>
);
}
48 changes: 36 additions & 12 deletions apps/frontend/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,26 +1,50 @@
@import "tailwindcss";

:root {
--background: #ffffff;
--foreground: #171717;
--color-surface-950: #081c2e;
--color-surface-900: #0b2031;
--color-surface-700: #184566;
--color-accent: #63e8c7;
--color-accent-strong: #7ff2d6;
--color-text-primary: #f4fbff;
--color-text-muted: rgba(244, 251, 255, 0.82);
--color-border-soft: rgba(186, 232, 255, 0.2);
--navbar-height: 72px;
}

@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-background: var(--color-surface-950);
--color-foreground: var(--color-text-primary);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}

@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
* {
box-sizing: border-box;
}

html,
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
min-height: 100%;
}

body {
margin: 0;
background: var(--color-surface-950);
color: var(--color-text-primary);
font-family:
var(--font-geist-sans),
ui-sans-serif,
system-ui,
-apple-system,
sans-serif;
line-height: 1.5;
}

a {
color: inherit;
}

main {
min-height: calc(100vh - var(--navbar-height));
}
14 changes: 11 additions & 3 deletions apps/frontend/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { PublicNavbar } from "../components/public-navbar";
import "./globals.css";

const geistSans = Geist({
Expand All @@ -13,8 +14,12 @@ const geistMono = Geist_Mono({
});

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: {
default: "CSSG UNC",
template: "%s | CSSG UNC",
},
description:
"CS + Social Good at UNC Chapel Hill builds technology solutions for organizations creating social impact.",
};

export default function RootLayout({
Expand All @@ -24,7 +29,10 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>{children}</body>
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
<PublicNavbar />
<main>{children}</main>
</body>
</html>
);
}
Loading
Loading