From e317bbe75a46ef3bf853cf85584bcd22ebaacf23 Mon Sep 17 00:00:00 2001 From: realtradam Date: Sat, 29 Jun 2024 00:20:29 -0400 Subject: add games page + rails auth cleanup --- react-frontend/src/components/GameCard.tsx | 43 ++++++++++++++ react-frontend/src/components/Layout.tsx | 23 +++++--- react-frontend/src/index.css | 92 +++++++++++++++++++++++++++++- react-frontend/src/pages/Games.tsx | 28 +++++++++ react-frontend/src/routes/index.tsx | 2 + 5 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 react-frontend/src/components/GameCard.tsx create mode 100644 react-frontend/src/pages/Games.tsx (limited to 'react-frontend/src') diff --git a/react-frontend/src/components/GameCard.tsx b/react-frontend/src/components/GameCard.tsx new file mode 100644 index 0000000..4367977 --- /dev/null +++ b/react-frontend/src/components/GameCard.tsx @@ -0,0 +1,43 @@ +import { Link } from "react-router-dom"; + +export type ImageRendering = "auto" | "crisp-edges" | "pixelated"; +export type Tag = { + id: number, + tag_type: string, + name: string, +}; +export type GameType = { + id: number, + title: string, + titleSlug: string, + description: string, + github_link: string, + img_rendering: ImageRendering, + status: string, + order: number, + created_at: string, + updated_at: string, + user_id: number, + tags: Tag[], + card_img: string, + char_img: string, + title_img: string, +}; +export type GameCardProps = { link: string, game: GameType }; + +export default function GameCard ({ link, game }: GameCardProps) +{ + return ( + <> + +
+
+ +
+ + +
+ + + ); +} diff --git a/react-frontend/src/components/Layout.tsx b/react-frontend/src/components/Layout.tsx index db31b55..274e579 100644 --- a/react-frontend/src/components/Layout.tsx +++ b/react-frontend/src/components/Layout.tsx @@ -1,5 +1,5 @@ import { Dispatch } from 'react'; -import { Outlet, useNavigate } from "react-router-dom"; +import { Outlet, Link, useNavigate } from "react-router-dom"; import { IconButton, Button, ButtonGroup } from 'rsuite'; import { Icon } from '@rsuite/icons'; import { FaUser } from "react-icons/fa6"; @@ -28,22 +28,31 @@ export default function Layout(prop : { userData: userData, setUserData : Dispat const loggedout_element = }>Log In; - const loggedin_element = ; + const loggedin_element = ; console.log(prop); return( <>
-
+
-
- { prop.userData.name ? loggedin_element : loggedout_element } +
+ { prop.userData.name ? loggedin_element : loggedout_element } +
+ +
+
-
+
+ Game Holster +
+
- }>Browse Games + + }>Browse Games + }>Upload Game
diff --git a/react-frontend/src/index.css b/react-frontend/src/index.css index ac216f5..382c958 100644 --- a/react-frontend/src/index.css +++ b/react-frontend/src/index.css @@ -2,7 +2,97 @@ @tailwind components; @tailwind utilities; +/* debug class */ * { - /*border: 1px solid red;*/ + border: 1px solid red; } +@layer components { + .gameCard { + aspect-ratio: 5/7; + width: 18.75em; /*300px;*/ + perspective: 2500px; + + @apply relative flex justify-center items-end; + } + + .gameCardCoverImg { + + @apply w-full h-full object-cover rounded-md; + } + + .gameCardWrapper { + transition: all 0.5s; + z-index: -1; + box-shadow: -15px 15px 32px -8px rgba(0, 0, 0, 0.75); + + @apply absolute w-full h-full rounded-md; + } + + .gameCard:hover .gameCardWrapper { + transform: perspective(900px) translateY(-5%) rotateX(25deg) translateZ(0); + box-shadow: -10px 35px 32px -8px rgba(0, 0, 0, 0.75); + } + + .gameCardWrapper::before, + .gameCardWrapper::after { + content: ""; + transition: all 0.5s; + + @apply opacity-0 w-full h-20 absolute left-0 rounded-md; + } + + .gameCardWrapper::before { + background-image: linear-gradient( + to top, + transparent 46%, + rgba(12, 13, 19, 0.5) 68%, + rgba(12, 13, 19) 97% + ); + + @apply top-0 h-full rounded-md; + } + + .gameCardWrapper::after { + background-image: linear-gradient( + to bottom, + transparent 46%, + rgba(12, 13, 19, 0.5) 68%, + rgba(12, 13, 19) 97% + ); + + @apply bottom-0 opacity-100 rounded-md; + } + + .gameCard:hover .gameCardWrapper::before, + .gameCardWrapper::after { + + @apply opacity-100; + } + + .gameTitleImg { + padding: 5%; + transition: transform 0.5s; + + @apply w-full max-h-40 object-contain; + } + + .gameCard:hover .gameTitleImg { + transform: translate3d(0%, -50px, 100px); + } + + .gameCharacterImg { + transition: all 0.5s; + z-index: -1; + + @apply w-full max-h-80 object-contain opacity-0 absolute; + } + + .gameCard:hover .gameCharacterImg { + transform: translate3d(0%, -30%, 100px); + + @apply opacity-100; + } +} + + diff --git a/react-frontend/src/pages/Games.tsx b/react-frontend/src/pages/Games.tsx new file mode 100644 index 0000000..2a9b23a --- /dev/null +++ b/react-frontend/src/pages/Games.tsx @@ -0,0 +1,28 @@ +import { useState, useEffect } from "react"; +import GameCard from "../components/GameCard"; + +export default function Games () { + const [games, setGames] = useState([]); + + useEffect(() => { + const url = `${import.meta.env.VITE_API_TITLE}/api/v1/games`; + fetch(url).then((response) => { + if (response.ok) { + return response.json(); + } + throw new Error("Network response was not ok."); + }).then((response) => setGames(response)); //.catch(() => navigate("/")); + }, []); + + const allGames = games.map((game) => ( + + )); + + return ( + <> +
+ { allGames } +
+ + ); +} diff --git a/react-frontend/src/routes/index.tsx b/react-frontend/src/routes/index.tsx index 6876ce5..9b3d599 100644 --- a/react-frontend/src/routes/index.tsx +++ b/react-frontend/src/routes/index.tsx @@ -1,6 +1,7 @@ import { useState, useEffect } from "react"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import Home from "../pages/Home"; +import Games from "../pages/Games"; import Layout from "../components/Layout"; import CloseWindow from "../pages/CloseWindow"; @@ -34,6 +35,7 @@ export default function Index() }> } /> + } /> } /> -- cgit v1.2.3