Skip to content

Commit a90681c

Browse files
author
belledw
committed
Merge branch 'main' into issue-94-members_documentation
2 parents a5adc71 + e86cb79 commit a90681c

26 files changed

Lines changed: 519 additions & 138 deletions

client/src/components/main/MemberProfile.tsx

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

33
import Image from "next/image";
4+
import { SocialIcon } from "react-social-icons";
45

56
// unused atm, as the member isnt linked a project on the backend
67
/* export type MemberProfileProject = {
@@ -15,6 +16,11 @@ export type MemberProfileData = {
1516
about: string;
1617
pronouns?: string;
1718
profile_picture?: string;
19+
social_media?: {
20+
link: string;
21+
socialMediaUserName: string;
22+
}[];
23+
pk: number;
1824
};
1925

2026
type MemberProfileProps = {
@@ -66,7 +72,37 @@ export function MemberProfile({ member }: MemberProfileProps) {
6672
<p className="min-w-fit font-jersey10 text-4xl">{member.name}</p>
6773
<hr className="ml-5 hidden w-full self-center border-light_2 lg:flex" />
6874
</div>
69-
<p className="text-lg">{member.pronouns}</p>
75+
<div className="flex items-center gap-2">
76+
{member.social_media && member.social_media.length > 0 && (
77+
<div className="w-full">
78+
<div className="mt-2 flex flex-wrap items-center gap-2">
79+
{member.social_media.map((sm) => (
80+
<span
81+
key={sm.link}
82+
className="ml-2 flex items-center gap-1"
83+
>
84+
<SocialIcon
85+
url={sm.link}
86+
style={{ height: 24, width: 24 }}
87+
/>
88+
<a
89+
href={sm.link}
90+
target="_blank"
91+
rel="noopener noreferrer"
92+
className="font-firaCode text-base underline hover:text-primary"
93+
>
94+
{sm.socialMediaUserName}
95+
</a>
96+
</span>
97+
))}
98+
</div>
99+
</div>
100+
)}
101+
</div>
102+
<div className="flex items-center gap-2">
103+
<p className="text-lg">{member.pronouns}</p>
104+
</div>
105+
70106
<p>{member.about}</p>
71107
</div>
72108
</div>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// notes:
2+
// - width and height don't match itch.io, making games look smaller
3+
// - you can just embed from itch.io, but only the developer can get the embed link as far as i can tell
4+
// - would need to save embed link, width and height to db
5+
// - this method is reliant on itch.io staying up and not changing anything
6+
// - would want a play button so it doesn't autoload (especially for bigger more intense games)
7+
import Image from "next/image";
8+
import React, { useState } from "react";
9+
10+
import { Button } from "./button";
11+
12+
type GameEmbedProps = {
13+
embedID: string;
14+
gameWidth: number;
15+
gameHeight: number;
16+
gameImage: string;
17+
};
18+
19+
export function GameEmbed({
20+
embedID,
21+
gameWidth,
22+
gameHeight,
23+
gameImage,
24+
}: GameEmbedProps) {
25+
const [isPlaying, setIsPlaying] = useState(false);
26+
27+
return (
28+
<div
29+
className={`retroBorder flex items-center justify-center bg-background`}
30+
style={{ width: gameWidth + 26 * 2, height: gameHeight + 26 * 2 }}
31+
>
32+
{!isPlaying ? (
33+
<div>
34+
<Image
35+
src={gameImage}
36+
alt="Game Cover"
37+
width={gameWidth}
38+
height={gameHeight}
39+
className="absolute translate-x-[-50%] translate-y-[calc(-50%)] blur-sm"
40+
style={{ width: "auto", height: gameHeight - 52 }}
41+
/>
42+
<Button
43+
onClick={() => setIsPlaying(!isPlaying)}
44+
size={"lg"}
45+
className="absolute translate-x-[-50%] translate-y-[calc(-50%)] text-3xl"
46+
>
47+
Play
48+
</Button>
49+
</div>
50+
) : (
51+
<div>
52+
<iframe
53+
src={`https://itch.io/embed-upload/${embedID}?color=110e1a`}
54+
width={gameWidth}
55+
height={gameHeight}
56+
></iframe>
57+
</div>
58+
)}
59+
</div>
60+
);
61+
}

client/src/hooks/useCommittee.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ export type ApiMember = {
88
profile_picture: string;
99
pronouns: string;
1010
about: string;
11+
social_media?: {
12+
link: string;
13+
socialMediaUserName: string;
14+
}[];
15+
pk: number;
1116
};
1217

1318
export function useCommittee() {

client/src/hooks/useGames.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ type Contributor = {
77
member_id: number;
88
name: string;
99
role: string;
10+
social_media?: Array<{
11+
socialMediaName: string;
12+
link: string;
13+
socialMediaUserName: string;
14+
}>;
1015
};
1116

1217
type ApiGame = {
@@ -19,6 +24,9 @@ type ApiGame = {
1924
itchEmbedID: string;
2025
thumbnail: string | null;
2126
event: number | null;
27+
itchGameEmbedID: string;
28+
itchGameWidth: number;
29+
itchGameHeight: number;
2230
contributors: Contributor[];
2331
};
2432

client/src/hooks/useGameshowcase.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import api from "@/lib/api";
66
type Contributor = {
77
name: string;
88
role: string;
9+
social_media?: {
10+
socialMediaName: string;
11+
link: string;
12+
socialMediaUserName: string;
13+
}[];
914
};
1015

1116
type ApiShowcaseGame = {

client/src/hooks/useMember.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ type ApiMember = {
77
about: string;
88
pronouns?: string;
99
profile_picture?: string;
10+
social_media?: {
11+
link: string;
12+
socialMediaUserName: string;
13+
}[];
14+
pk: number;
1015
};
1116

1217
// return api member, import id number from router, is not enabled if not a number type

client/src/pages/_app.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
55
import type { AppProps } from "next/app";
66
import { Fira_Code, Inter as FontSans, Jersey_10 } from "next/font/google";
77

8-
import Footer from "@/components/main/Footer";
98
import Navbar from "@/components/main/Navbar";
109

1110
const fontSans = FontSans({
@@ -37,7 +36,6 @@ export default function App({ Component, pageProps }: AppProps) {
3736
>
3837
<Navbar />
3938
<Component {...pageProps} />
40-
<Footer />
4139
</main>
4240
</QueryClientProvider>
4341
);

client/src/pages/about.tsx

Lines changed: 63 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import Image from "next/image";
2+
import Link from "next/link";
23

34
import { ApiMember, useCommittee } from "@/hooks/useCommittee";
45

56
export default function AboutPage() {
67
const { data: committee, isPending, error, isError } = useCommittee();
78

8-
const topRow: ApiMember[] = [];
9-
const bottomRow: ApiMember[] = [];
10-
//lists that will be populated with member objects in the committee
9+
const committeeList: ApiMember[] = [];
10+
//List that will be populated with member objects in the committee
1111
const roleOrder = [
1212
"President",
1313
"Vice President",
@@ -44,9 +44,7 @@ export default function AboutPage() {
4444
<Image
4545
src="/landing_placeholder.png"
4646
alt="/landing_placeholder.png"
47-
width={128}
48-
height={128}
49-
className="h-[90%] w-[90%]"
47+
fill={true}
5048
/>
5149
</div>
5250
</div>
@@ -61,23 +59,63 @@ export default function AboutPage() {
6159
</>
6260
);
6361

62+
function committeeImage(profilePic: string) {
63+
return (
64+
<div className="relative h-[8.75rem] w-[8.25rem] overflow-hidden">
65+
<Image
66+
src={profilePic === null ? "/landing_placeholder.png" : profilePic}
67+
alt="/landing_placeholder.png"
68+
fill
69+
className="object-cover object-center"
70+
/>
71+
</div>
72+
);
73+
}
74+
75+
function committeePortrait(committeeMember: ApiMember, id: number) {
76+
return (
77+
<>
78+
<div className="relative flex h-56 w-56 items-center justify-center bg-[url('/pixel-art-frame.svg')] bg-contain bg-center bg-no-repeat">
79+
{committeeMember.pk === 0 ? (
80+
committeeImage(committeeMember.profile_picture)
81+
) : (
82+
<Link href={`/members/${committeeMember.pk}`}>
83+
{committeeImage(committeeMember.profile_picture)}
84+
</Link>
85+
)}
86+
</div>
87+
<div className="text-md max-w-56 pl-3 text-left font-firaCode leading-tight">
88+
<p className="inline-block text-white">
89+
<text className="inline-block bg-card px-2 py-1">
90+
{committeeMember.pk === 0 ? (
91+
<>{committeeMember.name}</>
92+
) : (
93+
<Link href={`/members/${committeeMember.pk}`}>
94+
{committeeMember.name}
95+
</Link>
96+
)}
97+
</text>
98+
<text className="inline-block bg-card px-2 py-1 empty:hidden">
99+
{committeeMember.pronouns}
100+
</text>
101+
</p>
102+
<p className="inline-block bg-card px-2 py-1 text-primary">
103+
{roleOrder[id]}
104+
</p>
105+
</div>
106+
</>
107+
);
108+
}
109+
64110
if (isPending) {
65111
for (let i = 0; i < 8; i++) {
66-
if (i < 4) {
67-
topRow.push({
68-
name: "Loading...",
69-
pronouns: "",
70-
profile_picture: "/landing_placeholder.png",
71-
about: "",
72-
});
73-
} else {
74-
bottomRow.push({
75-
name: "Loading...",
76-
pronouns: "",
77-
profile_picture: "/landing_placeholder.png",
78-
about: "",
79-
});
80-
}
112+
committeeList.push({
113+
name: "Loading...",
114+
pronouns: "",
115+
profile_picture: "/landing_placeholder.png",
116+
about: "",
117+
pk: 0,
118+
});
81119
}
82120
} else if (isError) {
83121
const errorMessage =
@@ -97,80 +135,23 @@ export default function AboutPage() {
97135
);
98136
} else {
99137
for (let i = 0; i < 8; i++) {
100-
if (i < 4) {
101-
topRow.push(committee[i]);
102-
} else {
103-
bottomRow.push(committee[i]);
104-
}
138+
committeeList.push(committee[i]);
105139
}
106140
}
107141

108142
return (
109143
<main className="min-h-screen bg-background">
110144
{about}
111145
{/* Portraits Section - DARK - Full Width */}
112-
<section className="w-full bg-background px-6 py-10 pt-16 md:px-10">
146+
<section className="w-full bg-background px-6 py-10 pb-20 pt-16 md:px-10">
113147
<div className="mx-auto max-w-6xl">
114-
{/* Top row - 4 Presidents */}
115148
<div className="flex flex-wrap justify-center gap-6 md:gap-10">
116-
{topRow.map((member, idx) => (
149+
{committeeList.map((member, idx) => (
117150
<div
118151
key={`top-${idx}`}
119152
className="flex flex-col items-start gap-0"
120153
>
121-
<div className="relative flex h-[11.25rem] w-[11.25rem] items-center justify-center bg-[url('/pixel-art-frame.svg')] bg-contain bg-center bg-no-repeat">
122-
<Image
123-
src={
124-
member.profile_picture === null
125-
? "/landing_placeholder.png"
126-
: member.profile_picture
127-
}
128-
alt="/landing_placeholder.png"
129-
width={108}
130-
height={108}
131-
className="h-[7.25rem] w-[6.75rem]"
132-
/>
133-
</div>
134-
<div className="w-[11.25rem] pl-3 text-left font-firaCode text-[0.5rem] leading-tight">
135-
<p className="inline-block bg-card px-2 py-1 text-white">
136-
{member.name} {member.pronouns}
137-
</p>
138-
<p className="inline-block bg-card px-2 py-1 text-primary">
139-
{roleOrder[idx]}
140-
</p>
141-
</div>
142-
</div>
143-
))}
144-
</div>
145-
146-
{/* Bottom row - 4 other roles */}
147-
<div className="mt-10 flex flex-wrap justify-center gap-6 md:gap-10">
148-
{bottomRow.map((member, idx) => (
149-
<div
150-
key={`bottom-${idx}`}
151-
className="flex flex-col items-start gap-0"
152-
>
153-
<div className="relative flex h-[11.25rem] w-[11.25rem] items-center justify-center bg-[url('/pixel-art-frame.svg')] bg-contain bg-center bg-no-repeat">
154-
<Image
155-
src={
156-
member.profile_picture === null
157-
? "/landing_placeholder.png"
158-
: member.profile_picture
159-
}
160-
alt="/landing_placeholder.png"
161-
width={108}
162-
height={108}
163-
className="h-[7.25rem] w-[6.75rem]"
164-
/>
165-
</div>
166-
<div className="w-[11.25rem] pl-3 text-left font-firaCode text-[0.5rem] leading-tight">
167-
<p className="inline-block bg-card px-2 py-1 text-white">
168-
{member.name} {member.pronouns}
169-
</p>
170-
<p className="inline-block bg-card px-2 py-1 text-primary">
171-
{roleOrder[4 + idx]}
172-
</p>
173-
</div>
154+
{committeePortrait(member, idx)}
174155
</div>
175156
))}
176157
</div>

0 commit comments

Comments
 (0)