From f4afa74864affcf20e94f9efc7a581282777e65e Mon Sep 17 00:00:00 2001 From: joelte Date: Fri, 9 Oct 2026 16:20:33 +0200 Subject: [PATCH 1/3] refactor: Split frontend into scaling-proof tree Sliit the frontend src-code into a more structured folder setup that will allow for easier implementation in the future --- frontend/src/App.tsx | 6 +++--- frontend/src/{ => components/Header}/Header.tsx | 0 frontend/src/{ => pages/GameDetails}/GameDetails.tsx | 2 +- frontend/src/{ => pages/GamesGrid}/GamesGrid.tsx | 2 +- frontend/src/{ => pages/MyRatings}/MyRatings.tsx | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) rename frontend/src/{ => components/Header}/Header.tsx (100%) rename frontend/src/{ => pages/GameDetails}/GameDetails.tsx (95%) rename frontend/src/{ => pages/GamesGrid}/GamesGrid.tsx (93%) rename frontend/src/{ => pages/MyRatings}/MyRatings.tsx (65%) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index d3db457..57bbd76 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,8 +1,8 @@ import './App.css'; import 'bootstrap/dist/css/bootstrap.min.css'; -import GameDetails from './GameDetails.tsx'; -import Header from './Header.tsx'; -import GamesGrid from './GamesGrid.tsx'; +import GameDetails from './pages/GameDetails/GameDetails.tsx'; +import Header from './components/Header/Header.tsx'; +import GamesGrid from './pages/GamesGrid/GamesGrid.tsx'; function App() { diff --git a/frontend/src/Header.tsx b/frontend/src/components/Header/Header.tsx similarity index 100% rename from frontend/src/Header.tsx rename to frontend/src/components/Header/Header.tsx diff --git a/frontend/src/GameDetails.tsx b/frontend/src/pages/GameDetails/GameDetails.tsx similarity index 95% rename from frontend/src/GameDetails.tsx rename to frontend/src/pages/GameDetails/GameDetails.tsx index 960d866..d5e3d2d 100644 --- a/frontend/src/GameDetails.tsx +++ b/frontend/src/pages/GameDetails/GameDetails.tsx @@ -1,5 +1,5 @@ import { Container, Image } from "react-bootstrap"; -import Header from "./Header"; +import Header from "../../components/Header/Header"; function fetchGameDetails(){ diff --git a/frontend/src/GamesGrid.tsx b/frontend/src/pages/GamesGrid/GamesGrid.tsx similarity index 93% rename from frontend/src/GamesGrid.tsx rename to frontend/src/pages/GamesGrid/GamesGrid.tsx index 288b80b..1e0723c 100644 --- a/frontend/src/GamesGrid.tsx +++ b/frontend/src/pages/GamesGrid/GamesGrid.tsx @@ -1,5 +1,5 @@ import { Container, Image } from "react-bootstrap"; -import Header from "./Header"; +import Header from "../../components/Header/Header"; export default function GamesGrid () { return ( diff --git a/frontend/src/MyRatings.tsx b/frontend/src/pages/MyRatings/MyRatings.tsx similarity index 65% rename from frontend/src/MyRatings.tsx rename to frontend/src/pages/MyRatings/MyRatings.tsx index 0dafea7..e52a5cc 100644 --- a/frontend/src/MyRatings.tsx +++ b/frontend/src/pages/MyRatings/MyRatings.tsx @@ -1,4 +1,4 @@ -import Header from './Header.tsx' +import Header from '../../components/Header/Header.tsx' export default function MyRatings () { return ( From 1eb7e4a3b2d1997f4c681288427e359f03c9c678 Mon Sep 17 00:00:00 2001 From: joelte Date: Fri, 9 Oct 2026 16:26:08 +0200 Subject: [PATCH 2/3] refactor: Remove unecessary unused files and code Cleanup of the current skeleton to allow for easier future implementation --- frontend/public/favicon.svg | 1 - frontend/public/icons.svg | 24 -------- frontend/src/App.css | 0 frontend/src/App.tsx | 16 +---- frontend/src/components/Header/Header.tsx | 37 +++++++----- frontend/src/index.css | 0 frontend/src/main.tsx | 11 ++-- .../src/pages/GameDetails/GameDetails.tsx | 59 ++++++++----------- frontend/src/pages/GamesGrid/GamesGrid.tsx | 43 +++++++------- frontend/src/pages/MyRatings/MyRatings.tsx | 16 ++--- 10 files changed, 81 insertions(+), 126 deletions(-) delete mode 100644 frontend/public/favicon.svg delete mode 100644 frontend/public/icons.svg delete mode 100644 frontend/src/App.css delete mode 100644 frontend/src/index.css diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg deleted file mode 100644 index 6893eb1..0000000 --- a/frontend/public/favicon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/public/icons.svg b/frontend/public/icons.svg deleted file mode 100644 index e952219..0000000 --- a/frontend/public/icons.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/App.css b/frontend/src/App.css deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 57bbd76..235f3d9 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,18 +1,8 @@ -import './App.css'; -import 'bootstrap/dist/css/bootstrap.min.css'; -import GameDetails from './pages/GameDetails/GameDetails.tsx'; -import Header from './components/Header/Header.tsx'; -import GamesGrid from './pages/GamesGrid/GamesGrid.tsx'; +import "bootstrap/dist/css/bootstrap.min.css"; +import GamesGrid from "./pages/GamesGrid/GamesGrid"; function App() { - - return ( - <> - {/*
*/} - {/* */} - - - ) + return ; } export default App; diff --git a/frontend/src/components/Header/Header.tsx b/frontend/src/components/Header/Header.tsx index 95d51fe..e833e68 100644 --- a/frontend/src/components/Header/Header.tsx +++ b/frontend/src/components/Header/Header.tsx @@ -1,23 +1,28 @@ -import { Button, Container, Form, InputGroup, Nav, Navbar } from 'react-bootstrap'; -import { Search } from 'react-bootstrap-icons'; - +import { + Button, + Container, + Form, + InputGroup, + Nav, + Navbar, +} from "react-bootstrap"; +import { Search } from "react-bootstrap-icons"; export default function Header() { - return ( + return ( - - NTNU Game Ratings(WIP) + + NTNU Game Ratings (WIP)
- - - -
+ + + + + My Ratings
- ); -} \ No newline at end of file + ); +} diff --git a/frontend/src/index.css b/frontend/src/index.css deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index bef5202..f8fc6f5 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,10 +1,9 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import './index.css' -import App from './App.tsx' +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import App from "./App"; -createRoot(document.getElementById('root')!).render( +createRoot(document.getElementById("root")!).render( , -) +); diff --git a/frontend/src/pages/GameDetails/GameDetails.tsx b/frontend/src/pages/GameDetails/GameDetails.tsx index d5e3d2d..3415488 100644 --- a/frontend/src/pages/GameDetails/GameDetails.tsx +++ b/frontend/src/pages/GameDetails/GameDetails.tsx @@ -1,43 +1,32 @@ import { Container, Image } from "react-bootstrap"; import Header from "../../components/Header/Header"; -function fetchGameDetails(){ - -} - export default function GameDetails() { return ( <> -
- - - Release year | Age rating - -

- Game Title -

-
- Game Image -
-
NTNU Rating:
-

Your Rating:

-
-
-
Tags:
-
Developer(s):
-
Publisher(s):
-
Platform(s):
-

- Description -

- -
+
+ + Release year | Age rating +

Game Title

+
+ Game Image +
+
NTNU Rating:
+

Your Rating:

+
+
+
Tags:
+
Developer(s):
+
Publisher(s):
+
Platform(s):
+

Description

+
); -} \ No newline at end of file +} diff --git a/frontend/src/pages/GamesGrid/GamesGrid.tsx b/frontend/src/pages/GamesGrid/GamesGrid.tsx index 1e0723c..f2012f7 100644 --- a/frontend/src/pages/GamesGrid/GamesGrid.tsx +++ b/frontend/src/pages/GamesGrid/GamesGrid.tsx @@ -1,26 +1,23 @@ import { Container, Image } from "react-bootstrap"; import Header from "../../components/Header/Header"; -export default function GamesGrid () { - return ( - <> -
- {/* Filtering, paging and sorting */} - {/* Grid itself */} - - Game Image -
-
Game Title
-
Release year
-
Tags
-
Rating
-
- -
- - ); -} \ No newline at end of file +export default function GamesGrid() { + return ( + <> +
+ + Game Image +
+
Game Title
+
Release year
+
Tags
+
Rating
+
+
+ + ); +} diff --git a/frontend/src/pages/MyRatings/MyRatings.tsx b/frontend/src/pages/MyRatings/MyRatings.tsx index e52a5cc..aede895 100644 --- a/frontend/src/pages/MyRatings/MyRatings.tsx +++ b/frontend/src/pages/MyRatings/MyRatings.tsx @@ -1,9 +1,9 @@ -import Header from '../../components/Header/Header.tsx' +import Header from "../../components/Header/Header"; -export default function MyRatings () { - return ( - <> -
- - ); -} \ No newline at end of file +export default function MyRatings() { + return ( + <> +
+ + ); +} From 32794471674bd845f8af370a77ecbc1a0a7dfddb Mon Sep 17 00:00:00 2001 From: joelte Date: Fri, 9 Oct 2026 16:58:55 +0200 Subject: [PATCH 3/3] feat: Implementing static version of main Implemented a full 1st version of the frontpage with each module statically codeded with responsive sizes for the elements --- .../GameListItem/GameListItem.module.css | 34 ++++++++++ .../components/GameListItem/GameListItem.tsx | 31 +++++++++ .../src/components/Header/Header.module.css | 42 ++++++++++++ frontend/src/components/Header/Header.tsx | 43 ++++++------ .../src/components/Layout/Layout.module.css | 5 ++ frontend/src/components/Layout/Layout.tsx | 6 ++ .../src/components/Toolbar/Toolbar.module.css | 33 ++++++++++ frontend/src/components/Toolbar/Toolbar.tsx | 33 ++++++++++ frontend/src/index.css | 34 ++++++++++ frontend/src/main.tsx | 1 + .../src/pages/GamesGrid/GamesGrid.module.css | 6 ++ frontend/src/pages/GamesGrid/GamesGrid.tsx | 66 +++++++++++++++---- 12 files changed, 299 insertions(+), 35 deletions(-) create mode 100644 frontend/src/components/GameListItem/GameListItem.module.css create mode 100644 frontend/src/components/GameListItem/GameListItem.tsx create mode 100644 frontend/src/components/Header/Header.module.css create mode 100644 frontend/src/components/Layout/Layout.module.css create mode 100644 frontend/src/components/Layout/Layout.tsx create mode 100644 frontend/src/components/Toolbar/Toolbar.module.css create mode 100644 frontend/src/components/Toolbar/Toolbar.tsx create mode 100644 frontend/src/index.css create mode 100644 frontend/src/pages/GamesGrid/GamesGrid.module.css diff --git a/frontend/src/components/GameListItem/GameListItem.module.css b/frontend/src/components/GameListItem/GameListItem.module.css new file mode 100644 index 0000000..10da3c9 --- /dev/null +++ b/frontend/src/components/GameListItem/GameListItem.module.css @@ -0,0 +1,34 @@ +.row { + display: flex; + align-items: center; + flex: 1 1 0; + min-height: var(--row-min-height); + gap: 1.5rem; + padding: 0 1.5rem; +} + +.odd { + background-color: var(--color-stripe-odd); +} + +.even { + background-color: var(--color-stripe-even); +} + +.image { + width: 95px; + height: 95px; + object-fit: cover; + background-color: #ddd; + flex-shrink: 0; +} + +.info p { + margin: 0; +} + +.title { + margin: 0 0 0.25rem; + font-size: 1.1rem; + font-weight: 700; +} diff --git a/frontend/src/components/GameListItem/GameListItem.tsx b/frontend/src/components/GameListItem/GameListItem.tsx new file mode 100644 index 0000000..e682427 --- /dev/null +++ b/frontend/src/components/GameListItem/GameListItem.tsx @@ -0,0 +1,31 @@ +import styles from "./GameListItem.module.css"; + +interface GameListItemProps { + title: string; + year: number; + tags: string; + rating: number; + image: string; + striped: boolean; +} + +export default function GameListItem({ + title, + year, + tags, + rating, + image, + striped, +}: GameListItemProps) { + return ( +
+ {title} +
+

{title}

+

{year}

+

{tags}

+

{rating.toFixed(1)}/10

+
+
+ ); +} diff --git a/frontend/src/components/Header/Header.module.css b/frontend/src/components/Header/Header.module.css new file mode 100644 index 0000000..7fde7a7 --- /dev/null +++ b/frontend/src/components/Header/Header.module.css @@ -0,0 +1,42 @@ +.header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + height: var(--header-height); + padding: 0 1.5rem; + background-color: var(--color-brand); +} + +.brand, +.link { + font-weight: 700; + color: var(--color-text); + white-space: nowrap; +} + +.link { + text-decoration: none; +} + +.search { + flex: 1; + max-width: 420px; +} + +.search :global(.input-group) { + border-radius: 999px; + overflow: hidden; +} + +.search :global(.form-control) { + border: none; +} + +.search :global(.form-control:focus) { + box-shadow: none; +} + +.search :global(.btn) { + border: none; +} diff --git a/frontend/src/components/Header/Header.tsx b/frontend/src/components/Header/Header.tsx index e833e68..b846e7f 100644 --- a/frontend/src/components/Header/Header.tsx +++ b/frontend/src/components/Header/Header.tsx @@ -1,28 +1,27 @@ -import { - Button, - Container, - Form, - InputGroup, - Nav, - Navbar, -} from "react-bootstrap"; +import { Button, Form, InputGroup } from "react-bootstrap"; import { Search } from "react-bootstrap-icons"; +import styles from "./Header.module.css"; export default function Header() { return ( - - - NTNU Game Ratings (WIP) -
- - - - -
- My Ratings -
-
+
+ Working Title + +
+ + + + +
+ + + My Ratings + +
); } diff --git a/frontend/src/components/Layout/Layout.module.css b/frontend/src/components/Layout/Layout.module.css new file mode 100644 index 0000000..52611a0 --- /dev/null +++ b/frontend/src/components/Layout/Layout.module.css @@ -0,0 +1,5 @@ +.shell { + width: 100%; + max-width: var(--content-width); + margin: 0 auto; +} diff --git a/frontend/src/components/Layout/Layout.tsx b/frontend/src/components/Layout/Layout.tsx new file mode 100644 index 0000000..ced9683 --- /dev/null +++ b/frontend/src/components/Layout/Layout.tsx @@ -0,0 +1,6 @@ +import type { ReactNode } from "react"; +import styles from "./Layout.module.css"; + +export default function Layout({ children }: { children: ReactNode }) { + return
{children}
; +} diff --git a/frontend/src/components/Toolbar/Toolbar.module.css b/frontend/src/components/Toolbar/Toolbar.module.css new file mode 100644 index 0000000..51f876a --- /dev/null +++ b/frontend/src/components/Toolbar/Toolbar.module.css @@ -0,0 +1,33 @@ +.toolbar { + display: flex; + align-items: center; + justify-content: space-between; + height: var(--toolbar-height); + padding: 0 1.5rem; + background-color: #fff; + border-bottom: 1px solid var(--color-border); + color: var(--color-muted); +} + +.action { + display: inline-flex; + align-items: center; + gap: 0.4rem; + border: none; + background: none; + color: inherit; + font: inherit; + cursor: pointer; +} + +.pagination { + display: inline-flex; + align-items: center; + gap: 0.75rem; +} + +.sort { + display: inline-flex; + align-items: center; + gap: 1rem; +} diff --git a/frontend/src/components/Toolbar/Toolbar.tsx b/frontend/src/components/Toolbar/Toolbar.tsx new file mode 100644 index 0000000..e2eadbb --- /dev/null +++ b/frontend/src/components/Toolbar/Toolbar.tsx @@ -0,0 +1,33 @@ +import { + ArrowDownUp, + ChevronDown, + ChevronLeft, + ChevronRight, + Funnel, +} from "react-bootstrap-icons"; +import styles from "./Toolbar.module.css"; + +export default function Toolbar() { + return ( +
+ + +
+ + Page 1 + +
+ +
+ + +
+
+ ); +} diff --git a/frontend/src/index.css b/frontend/src/index.css new file mode 100644 index 0000000..8082bd9 --- /dev/null +++ b/frontend/src/index.css @@ -0,0 +1,34 @@ +:root { + /* 50% of a 1920px viewport — the grid stays centered at this width until + the viewport can't fit it anymore, then it fills the screen (see Layout). */ + --content-width: 960px; + --header-height: 72px; + --toolbar-height: 56px; + /* Rows grow to fill the list height evenly, split across however many + games are currently rendered, but never shrink below this. Once rows + hit the floor, the list clips instead of squeezing them unreadably + thin (see GamesGrid.module.css and GameListItem.module.css). */ + --row-min-height: 112px; + --color-brand: #a8504f; + --color-text: #1a1a1a; + --color-muted: #495057; + --color-stripe-odd: #f6d9d8; + --color-stripe-even: #fdf6f5; + --color-border: #e9cfce; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + background-color: var(--color-stripe-odd); + color: var(--color-text); + font-family: + system-ui, + -apple-system, + "Segoe UI", + Roboto, + sans-serif; +} diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index f8fc6f5..15753af 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,5 +1,6 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; +import "./index.css"; import App from "./App"; createRoot(document.getElementById("root")!).render( diff --git a/frontend/src/pages/GamesGrid/GamesGrid.module.css b/frontend/src/pages/GamesGrid/GamesGrid.module.css new file mode 100644 index 0000000..4dd75cc --- /dev/null +++ b/frontend/src/pages/GamesGrid/GamesGrid.module.css @@ -0,0 +1,6 @@ +.list { + display: flex; + flex-direction: column; + height: calc(100vh - var(--header-height) - var(--toolbar-height)); + overflow: hidden; +} diff --git a/frontend/src/pages/GamesGrid/GamesGrid.tsx b/frontend/src/pages/GamesGrid/GamesGrid.tsx index f2012f7..93c6aff 100644 --- a/frontend/src/pages/GamesGrid/GamesGrid.tsx +++ b/frontend/src/pages/GamesGrid/GamesGrid.tsx @@ -1,23 +1,63 @@ -import { Container, Image } from "react-bootstrap"; import Header from "../../components/Header/Header"; +import Layout from "../../components/Layout/Layout"; +import Toolbar from "../../components/Toolbar/Toolbar"; +import GameListItem from "../../components/GameListItem/GameListItem"; +import styles from "./GamesGrid.module.css"; + +const games = [ + { + title: "Heroes of Might and Magic: Olden Era", + year: 2026, + tags: "Turn-based strategy", + rating: 9.3, + image: "", + }, + { + title: "Minecraft", + year: 2009, + tags: "Indie, Survival, Adventure, Sandbox", + rating: 9.1, + image: "", + }, + { + title: "Ori and the Blind Forest", + year: 2015, + tags: "Metroidvania", + rating: 8.8, + image: "", + }, + { + title: "Pokémon Legends: Z-A", + year: 2025, + tags: "Action RPG", + rating: 0.1, + image: "", + }, + { + title: "Hades", + year: 2020, + tags: "Roguelike", + rating: 9.4, + image: "", + }, +]; export default function GamesGrid() { return ( <>
- - Game Image -
-
Game Title
-
Release year
-
Tags
-
Rating
+ + +
+ {games.map((game, index) => ( + + ))}
- +
); }