Skip to content

Commit e58e705

Browse files
committed
Merge branch 'main' of https://github.com/codersforcauses/game-dev into issue-47-Add_explosions_to_committee_page
2 parents f8e6222 + e86cb79 commit e58e705

20 files changed

Lines changed: 292 additions & 105 deletions

client/src/components/main/MemberProfile.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export type MemberProfileData = {
2020
link: string;
2121
socialMediaUserName: string;
2222
}[];
23+
pk: number;
2324
};
2425

2526
type MemberProfileProps = {
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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ type ApiGame = {
2424
itchEmbedID: string;
2525
thumbnail: string | null;
2626
event: number | null;
27+
itchGameEmbedID: string;
28+
itchGameWidth: number;
29+
itchGameHeight: number;
2730
contributors: Contributor[];
2831
};
2932

client/src/hooks/useMember.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type ApiMember = {
1111
link: string;
1212
socialMediaUserName: string;
1313
}[];
14+
pk: number;
1415
};
1516

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

client/src/pages/_app.tsx

Lines changed: 1 addition & 4 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
import { ExplosionProvider } from "@/contexts/ExplosionContext";
1110

@@ -35,9 +34,7 @@ export default function App({ Component, pageProps }: AppProps) {
3534
<ReactQueryDevtools initialIsOpen={false} />
3635
<ExplosionProvider>
3736
<main
38-
className={
39-
`font-sans ` + fonts.map((font) => font.variable).join(" ")
40-
}
37+
className={`font-sans ` + fonts.map((font) => font.variable).join(" ")}
4138
>
4239
<Navbar />
4340
<Component {...pageProps} />

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="relative 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>

client/src/pages/games/[id].tsx

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useRouter } from "next/router";
33
import React from "react";
44
import { SocialIcon } from "react-social-icons";
55

6+
import { GameEmbed } from "@/components/ui/GameEmbed";
67
import { ItchEmbed } from "@/components/ui/ItchEmbed";
78
import { useGame } from "@/hooks/useGames";
89

@@ -51,6 +52,9 @@ export default function IndividualGamePage() {
5152
const gameTitle = game.name;
5253
const gameCover = game.gameCover;
5354
const gameDescription = game.description.split("\n");
55+
const gameEmbedID = game.itchGameEmbedID;
56+
const gameWidth = game.itchGameWidth;
57+
const gameHeight = game.itchGameHeight;
5458

5559
const completionLabels: Record<number, string> = {
5660
1: "WIP",
@@ -83,16 +87,27 @@ export default function IndividualGamePage() {
8387
return (
8488
<div className="min-h-screen bg-background font-sans text-foreground">
8589
<main>
86-
<section className="w-full bg-popover">
87-
<div className="mx-auto max-w-7xl p-0 sm:p-8">
88-
<Image
89-
src={gameCover}
90-
alt="Game Cover"
91-
width={800}
92-
height={800}
93-
className="max-h-[60vh] w-full object-cover sm:mx-auto sm:h-auto sm:max-h-[60vh] sm:rounded-2xl sm:object-contain"
94-
priority
95-
/>
90+
<section className="w-full items-center justify-center bg-popover">
91+
<div className="mx-auto flex max-w-7xl justify-center p-0 sm:p-8">
92+
{gameEmbedID != "0" ? (
93+
<div className="m-auto flex overflow-auto">
94+
<GameEmbed
95+
embedID={gameEmbedID}
96+
gameWidth={gameWidth}
97+
gameHeight={gameHeight}
98+
gameImage={gameCover}
99+
/>
100+
</div>
101+
) : (
102+
<Image
103+
src={gameCover}
104+
alt="Game Cover"
105+
width={800}
106+
height={800}
107+
className="max-h-[60vh] w-full object-cover sm:mx-auto sm:h-auto sm:max-h-[60vh] sm:rounded-2xl sm:object-contain"
108+
priority
109+
/>
110+
)}
96111
</div>
97112
</section>
98113

@@ -171,9 +186,8 @@ export default function IndividualGamePage() {
171186
</section>
172187

173188
<section className="mt-8 flex w-full flex-col items-center gap-6">
174-
{game.itchEmbedID && (
175-
<ItchEmbed embedID={game.itchEmbedID} name={gameTitle} />
176-
)}
189+
<ItchEmbed embedID={game.itchEmbedID} name={gameTitle} />
190+
177191
<h2 className="font-jersey10 text-5xl text-primary">ARTWORK</h2>
178192

179193
<div className="mx-auto mb-6 flex h-auto w-full max-w-4xl flex-col items-center gap-4 px-4 sm:flex-row sm:justify-center sm:gap-6 sm:px-6 md:h-60">

client/src/pages/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export default function Landing() {
130130
width={600}
131131
height={430}
132132
alt="placeholder"
133-
className="min-w-80 border-[26px] border-accent [clip-path:polygon(20px_20px,calc(100%-20px)_20px,100%_32px,100%_30%,calc(100%-20px)_45%,calc(100%-20px)_calc(100%-8px),80%_calc(100%-8px),75%_calc(100%-20px),20px_calc(100%-20px),0%_60%,0%_30%,20px_25%)]"
133+
className="retroBorder min-w-80"
134134
/>
135135
<Image
136136
src="/bomb.png"

0 commit comments

Comments
 (0)