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
23 changes: 15 additions & 8 deletions T04-Project-2/backend/src/graphql/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ const sortColumns = {
playtime: games.playtime,
};

const platformsForGame = (game: { id: number }) => db.select({
id: platforms.id,
name: platforms.name,
description: platforms.description,
})
.from(game_platforms)
.innerJoin(platforms, eq(game_platforms.platform_id, platforms.id))
.where(eq(game_platforms.game_id, game.id));

export const resolvers = {
Query: {
games: async () => {
Expand Down Expand Up @@ -170,6 +179,7 @@ export const resolvers = {
released: games.released,
background_image: games.background_image,
description: games.description,
rating: games.rating,
})
.from(games)
.where(inArray(games.id, gameIds));
Expand Down Expand Up @@ -199,6 +209,7 @@ export const resolvers = {
released: games.released,
background_image: games.background_image,
description: games.description,
rating: games.rating,
})
.from(games)
.where(inArray(games.rawg_id, gameIds));
Expand Down Expand Up @@ -363,13 +374,9 @@ export const resolvers = {
.from(game_publishers)
.innerJoin(publishers, eq(game_publishers.publisher_id, publishers.id))
.where(eq(game_publishers.game_id, game.id)),
platforms: (game: { id: number }) => db.select({
id: platforms.id,
name: platforms.name,
description: platforms.description,
})
.from(game_platforms)
.innerJoin(platforms, eq(game_platforms.platform_id, platforms.id))
.where(eq(game_platforms.game_id, game.id)),
platforms: platformsForGame
},
GameSummary: {
platforms: platformsForGame,
},
};
2 changes: 2 additions & 0 deletions T04-Project-2/backend/src/graphql/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export const typeDefs = /* GraphQL */ `
released: String
background_image: String
description: String
rating: Float
platforms: [Platform!]!
}
type Developer {
Expand Down
10 changes: 10 additions & 0 deletions T04-Project-2/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions T04-Project-2/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"embla-carousel-wheel-gestures": "^8.1.0",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-icons": "^5.7.0",
"react-router-dom": "^7.18.4"
},
"devDependencies": {
Expand Down
6 changes: 3 additions & 3 deletions T04-Project-2/frontend/src/api/games.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { Game } from "../typeDefs";
import type { Game, Platform } from "../typeDefs";
import { infiniteQueryOptions, queryOptions } from "@tanstack/react-query";
import type { GameSearchOptions } from "./filters";

export type GameSearchResult = Pick<Game, "id" | "name" | "released" | "rating" | "background_image" | "ratings_count" | "slug" | "playtime">;
export type GameCardSummary = Pick<Game, "id" | "name" | "released" | "background_image">;
export type FeaturedGameSummary = GameCardSummary & Pick<Game, "description">;
export type FeaturedGameSummary = GameCardSummary & Pick<Game, "description" | "rating"> & {platforms: Pick<Platform, "id" | "name">[];};

export type GameReview = {
id: string;
Expand Down Expand Up @@ -370,7 +370,7 @@ export function fetchGamesByIds(ids: readonly string[]): Promise<GameCardSummary
}

export function fetchFeaturedGamesByIds(ids: readonly string[]): Promise<FeaturedGameSummary[]> {
return fetchGameSummariesByIds<FeaturedGameSummary>(ids, "id name released background_image description");
return fetchGameSummariesByIds<FeaturedGameSummary>(ids, "id name released background_image description rating platforms { id name }");
}

const GAME_QUERY_STALE_TIME = 5 * 60 * 1000;
Expand Down
71 changes: 61 additions & 10 deletions T04-Project-2/frontend/src/components/FeaturedCarousel.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
.featured-favorite {
position: absolute;
z-index: 2;
top: 0.75rem;
right: 0.75rem;
top: 1.5rem;
right: 1.2rem;
display: grid;
width: 2.75rem;
aspect-ratio: 1;
Expand All @@ -47,9 +47,9 @@

.image-info-container {
display: grid;
grid-template-columns: minmax(0, 1.8fr) minmax(0, 1fr);
grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
width: 100%;
min-height: clamp(24rem, 36vw, 32rem);
min-height: clamp(24rem, 32vw, 32rem);
min-width: 0;
box-sizing: border-box;
border-radius: var(--border-radius);
Expand All @@ -65,38 +65,65 @@

.game-info {
min-width: 0;
height: 100%;
box-sizing: border-box;
background-color: var(--secondary-bg);
gap: 0.75rem;
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(1.25rem, 3vw, 3rem);
}

.game-title {
margin: 0;
line-height: 1.15;
font-size: clamp(1.3rem, 3vw, 2rem);
font-size: clamp(1.3rem, 2.8vw, 3rem);
overflow-wrap: anywhere;

color: var(--primary-color);
}
.release-rating-container {
display: flex;
gap: 1.5rem;
color: var(--subtext);
}

.game-release-info {
color: var(--subtext);
margin: 0;
display: flex;
align-items: center;
gap: 0.3rem;
}

.featured-rating {
font-size: 1rem;
margin: 0;
font-weight: bold;
display: flex;
gap: 0.3rem;
color: var(--text);
}

.featured-star {
color: var(--primary-color);
font-size: 1.2rem;
}

.game-info-description {
display: -webkit-box;
max-width: 42ch;
overflow: hidden;
margin: 0.5rem 0 0;
color: var(--subtext);
font-size: 1rem;
line-height: 1.5;
line-height: 1.6;
-webkit-box-orient: vertical;
-webkit-line-clamp: 7;
line-clamp: 7;
-webkit-line-clamp: 5;
line-clamp: 5;
}

.featured-platforms {
font-size: clamp(1rem, 2vw, 1.5rem);
}

.games-container {
Expand All @@ -113,6 +140,20 @@
height: 100%;
object-fit: cover;
}

.info-button-container {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
}

.featured-button {
background-color: var(--primary-color);
margin-top: 1rem;
font-size: clamp(1rem, 1.4vw, 1.15rem);
color: var(--dark-text);
}
.featured-image[data-role = 'hidden'] {
display: none;
}
Expand Down Expand Up @@ -199,6 +240,16 @@
}
}

@media (max-width: 768px) {
.game-info-description {
-webkit-line-clamp: 4;
line-clamp: 4;
}
.release-rating-container {
gap: 0.8rem;
}
}

@media (prefers-reduced-motion: reduce) {
.featured-image[data-role = 'current'][data-direction] {
animation: fade-in 0.4s ease both;
Expand Down
32 changes: 27 additions & 5 deletions T04-Project-2/frontend/src/components/FeaturedCarousel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import './FeaturedCarousel.css'
import { CaretLeftIcon, CaretRightIcon, Star } from "@phosphor-icons/react"
import { CaretLeftIcon, CaretRightIcon, Star, CalendarBlankIcon } from "@phosphor-icons/react"
import { Button } from "./Button"
import { useCallback, useEffect, useState } from "react"
import { useQuery } from "@tanstack/react-query"
Expand All @@ -8,6 +8,9 @@ import { gameQueryOptions } from "../api/games"
import { Link } from "react-router-dom"
import { useFavorites } from "./useFavorites"
import { GameLoading } from "./GameLoading"
import { PlatformDisplay } from './PlatformDisplay'
import { ButtonContent } from './ButtonContent'
import { StarIcon } from '@phosphor-icons/react/dist/ssr'

type FeaturedCarouselProps = {
gameIds: readonly string[];
Expand Down Expand Up @@ -103,10 +106,29 @@ export const FeaturedCarousel = ({gameIds}: FeaturedCarouselProps) => {
</div>
<div className="game-info">
<h3 className="game-title">{currentGameData.name}</h3>
<p className="game-release-info">{currentGameData.released ? `Released ${currentGameData.released}` : 'Release date unknown'}</p>
<p className="game-info-description">
{description || 'No description is available for this game yet.'}
</p>
<PlatformDisplay className='featured-platforms' platforms={currentGameData.platforms}/>
<div className='release-rating-container'>
<p className="game-release-info">
<CalendarBlankIcon size={24}/>
{currentGameData.released ? `Released ${currentGameData.released}` : 'Release date unknown'}
</p>
<span>|</span>
<p className='featured-rating'>
{currentGameData.rating ? Math.round(currentGameData.rating * 10) /10 : "No ratings"}
<StarIcon className='featured-star' weight='fill'/>
</p>
</div>
<div className='info-button-container'>
<p className="game-info-description">
{description || 'No description is available for this game yet.'}
</p>
<Button
className='link-button featured-button'
content={<ButtonContent
leftIcon={<CaretRightIcon weight='bold'/>}
text='View game'/>}
/>
</div>
</div>
</Link>
{userId && (
Expand Down
4 changes: 2 additions & 2 deletions T04-Project-2/frontend/src/components/FeaturedGames.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
margin-top: -0rem;
}
.featured-games {
position: relative; /* lets ::before be positioned inside the section */
isolation: isolate; /* keeps z-index: -1 inside the section instead of behind the page */
position: relative;
isolation: isolate;
}

.featured-games::before {
Expand Down
2 changes: 1 addition & 1 deletion T04-Project-2/frontend/src/components/FilterDropdown.css
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
font-size: 0.8rem;
}
.filter-dropdown-option:hover {
background-color: rgba(48, 48, 48, 0.346);
background-color: var(--bg-hover);
}

.filter-checkbox {
Expand Down
2 changes: 0 additions & 2 deletions T04-Project-2/frontend/src/components/FilterSection.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* the gap moves into the body so a closed section doesn't leave empty space */
.filter-section-container {
gap: 0;
}
Expand Down Expand Up @@ -43,7 +42,6 @@
display: flex;
flex-direction: column;
gap: 0.5rem;
/* room for the slider thumbs, which stick out past the track */
padding: 0.75rem 0 0.5rem;
}

Expand Down
2 changes: 1 addition & 1 deletion T04-Project-2/frontend/src/components/GameCard.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
width: 100%;
aspect-ratio: 3 / 2;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.14);
border: 1px solid var(--border-color-light);
border-radius: 1.25rem;
background: #21171e;
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.28);
Expand Down
4 changes: 0 additions & 4 deletions T04-Project-2/frontend/src/components/GameSection.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
margin-top: 2rem;
}

.game-category {
margin-left: 1.5rem;
}

.game-section > .heading-container + .game-category {
padding-top: 1rem;
}
Expand Down
15 changes: 10 additions & 5 deletions T04-Project-2/frontend/src/components/GameSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@ import type { GameCategory } from "../data/games"
import { GameCardCarousel } from "./GameCardCarousel"
import './GameSection.css'
import { SectionHeading } from "./SectionHeading"
import { Top5Games } from './Top5Games'

type GameSectionProps = {
gameCategories: readonly GameCategory[],
heading: string,
highlight: string,
}

export const GameSection = ({gameCategories, heading, highlight}: GameSectionProps) => {
export const GameSection = ({gameCategories}: GameSectionProps) => {
return (
<section className="game-section">
<SectionHeading text={heading} headerLine={true} highlight={highlight}></SectionHeading>
{gameCategories.map((category) => (
{gameCategories.slice(0, 2).map((category) => (
<section className="game-category" key={category.name}>
<SectionHeading text={category.name} headerLine={true} highlight={category.highlight}></SectionHeading>
<GameCardCarousel gameIds={category.gameIds}></GameCardCarousel>
</section>
))}
<Top5Games/>
{gameCategories.slice(2, 4).map((category) => (
<section className="game-category" key={category.name}>
<SectionHeading text={category.name} headerLine={true} highlight={category.highlight}></SectionHeading>
<GameCardCarousel gameIds={category.gameIds}></GameCardCarousel>
Expand Down
2 changes: 1 addition & 1 deletion T04-Project-2/frontend/src/components/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function HomePage() {
<>
<Hero />
<FeaturedGames gameIds={featuredGameIds} />
<GameSection gameCategories={gameCategories} heading="Our best picks" highlight="picks" />
<GameSection gameCategories={gameCategories}/>
</>
)
}
Expand Down
Loading