diff --git a/README.md b/README.md
index a934a3c..6596562 100644
--- a/README.md
+++ b/README.md
@@ -14,10 +14,9 @@ A searchable catalog of video games where users can browse, filter and rate game
3. [Functionality](#functionality)
4. [Design](#design)
5. [Architecture](#architecture)
-6. [Folder structure](#folder-structure)
-7. [Accessibility](#accessibility)
-8. [Sustainability](#sustainability)
-9. [Development process and AI use](#development-process-and-ai-use)
+6. [Accessibility](#accessibility)
+7. [Sustainability](#sustainability)
+8. [Development process and AI use](#development-process-and-ai-use)
---
diff --git a/frontend/index.html b/frontend/index.html
index 7b51410..d4263e3 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -2,7 +2,7 @@
-
+
it2810-t33-p2
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 6299a8a..0263763 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -13,6 +13,7 @@
"graphql": "^17.0.2",
"react": "^19.2.8",
"react-bootstrap": "^2.10.10",
+ "react-bootstrap-icons": "^1.11.6",
"react-dom": "^19.2.8",
"rxjs": "^7.8.2"
},
@@ -2999,6 +3000,18 @@
}
}
},
+ "node_modules/react-bootstrap-icons": {
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/react-bootstrap-icons/-/react-bootstrap-icons-1.11.6.tgz",
+ "integrity": "sha512-ycXiyeSyzbS1C4+MlPTYe0riB+UlZ7LV7YZQYqlERV2cxDiKtntI0huHmP/3VVvzPt4tGxqK0K+Y6g7We3U6tQ==",
+ "license": "MIT",
+ "dependencies": {
+ "prop-types": "^15.7.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.6"
+ }
+ },
"node_modules/react-dom": {
"version": "19.3.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 8938b16..99447be 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -15,6 +15,7 @@
"graphql": "^17.0.2",
"react": "^19.2.8",
"react-bootstrap": "^2.10.10",
+ "react-bootstrap-icons": "^1.11.6",
"react-dom": "^19.2.8",
"rxjs": "^7.8.2"
},
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 f90339d..0000000
--- a/frontend/src/App.css
+++ /dev/null
@@ -1,184 +0,0 @@
-.counter {
- font-size: 16px;
- padding: 5px 10px;
- border-radius: 5px;
- color: var(--accent);
- background: var(--accent-bg);
- border: 2px solid transparent;
- transition: border-color 0.3s;
- margin-bottom: 24px;
-
- &:hover {
- border-color: var(--accent-border);
- }
- &:focus-visible {
- outline: 2px solid var(--accent);
- outline-offset: 2px;
- }
-}
-
-.hero {
- position: relative;
-
- .base,
- .framework,
- .vite {
- inset-inline: 0;
- margin: 0 auto;
- }
-
- .base {
- width: 170px;
- position: relative;
- z-index: 0;
- }
-
- .framework,
- .vite {
- position: absolute;
- }
-
- .framework {
- z-index: 1;
- top: 34px;
- height: 28px;
- transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg)
- scale(1.4);
- }
-
- .vite {
- z-index: 0;
- top: 107px;
- height: 26px;
- width: auto;
- transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg)
- scale(0.8);
- }
-}
-
-#center {
- display: flex;
- flex-direction: column;
- gap: 25px;
- place-content: center;
- place-items: center;
- flex-grow: 1;
-
- @media (max-width: 1024px) {
- padding: 32px 20px 24px;
- gap: 18px;
- }
-}
-
-#next-steps {
- display: flex;
- border-top: 1px solid var(--border);
- text-align: left;
-
- & > div {
- flex: 1 1 0;
- padding: 32px;
- @media (max-width: 1024px) {
- padding: 24px 20px;
- }
- }
-
- .icon {
- margin-bottom: 16px;
- width: 22px;
- height: 22px;
- }
-
- @media (max-width: 1024px) {
- flex-direction: column;
- text-align: center;
- }
-}
-
-#docs {
- border-right: 1px solid var(--border);
-
- @media (max-width: 1024px) {
- border-right: none;
- border-bottom: 1px solid var(--border);
- }
-}
-
-#next-steps ul {
- list-style: none;
- padding: 0;
- display: flex;
- gap: 8px;
- margin: 32px 0 0;
-
- .logo {
- height: 18px;
- }
-
- a {
- color: var(--text-h);
- font-size: 16px;
- border-radius: 6px;
- background: var(--social-bg);
- display: flex;
- padding: 6px 12px;
- align-items: center;
- gap: 8px;
- text-decoration: none;
- transition: box-shadow 0.3s;
-
- &:hover {
- box-shadow: var(--shadow);
- }
- .button-icon {
- height: 18px;
- width: 18px;
- }
- }
-
- @media (max-width: 1024px) {
- margin-top: 20px;
- flex-wrap: wrap;
- justify-content: center;
-
- li {
- flex: 1 1 calc(50% - 8px);
- }
-
- a {
- width: 100%;
- justify-content: center;
- box-sizing: border-box;
- }
- }
-}
-
-#spacer {
- height: 88px;
- border-top: 1px solid var(--border);
- @media (max-width: 1024px) {
- height: 48px;
- }
-}
-
-.ticks {
- position: relative;
- width: 100%;
-
- &::before,
- &::after {
- content: '';
- position: absolute;
- top: -4.5px;
- border: 5px solid transparent;
- }
-
- &::before {
- left: 0;
- border-left-color: var(--border);
- }
- &::after {
- right: 0;
- border-right-color: var(--border);
- }
-}
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 9ca8e8d..235f3d9 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,122 +1,8 @@
-import { useState } from 'react'
-import heroImg from './assets/hero.png'
-import reactLogo from './assets/react.svg'
-import viteLogo from './assets/vite.svg'
-import './App.css'
+import "bootstrap/dist/css/bootstrap.min.css";
+import GamesGrid from "./pages/GamesGrid/GamesGrid";
function App() {
- const [count, setCount] = useState(0)
-
- return (
- <>
-
-
-
-
Get started
-
- Edit src/App.tsx and save to test HMR
-
-
- setCount((count) => count + 1)}
- >
- Count is {count}
-
-
-
-
-
-
-
-
-
-
-
Documentation
-
Your questions, answered
-
-
-
-
-
-
-
Connect with us
-
Join the Vite community
-
-
-
-
-
-
- >
- )
+ return ;
}
-export default App
+export default App;
diff --git a/frontend/src/assets/hero.png b/frontend/src/assets/hero.png
deleted file mode 100644
index 02251f4..0000000
Binary files a/frontend/src/assets/hero.png and /dev/null differ
diff --git a/frontend/src/assets/react.svg b/frontend/src/assets/react.svg
deleted file mode 100644
index 6c87de9..0000000
--- a/frontend/src/assets/react.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/frontend/src/assets/vite.svg b/frontend/src/assets/vite.svg
deleted file mode 100644
index 5101b67..0000000
--- a/frontend/src/assets/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-Vite
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}
+
{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
new file mode 100644
index 0000000..b846e7f
--- /dev/null
+++ b/frontend/src/components/Header/Header.tsx
@@ -0,0 +1,27 @@
+import { Button, Form, InputGroup } from "react-bootstrap";
+import { Search } from "react-bootstrap-icons";
+import styles from "./Header.module.css";
+
+export default function Header() {
+ return (
+
+ );
+}
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 (
+
+
+
+ Filter by
+
+
+
+
+ Page 1
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/index.css b/frontend/src/index.css
index 5fb3313..8082bd9 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -1,111 +1,34 @@
:root {
- --text: #6b6375;
- --text-h: #08060d;
- --bg: #fff;
- --border: #e5e4e7;
- --code-bg: #f4f3ec;
- --accent: #aa3bff;
- --accent-bg: rgba(170, 59, 255, 0.1);
- --accent-border: rgba(170, 59, 255, 0.5);
- --social-bg: rgba(244, 243, 236, 0.5);
- --shadow:
- rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px;
-
- --sans: system-ui, 'Segoe UI', Roboto, sans-serif;
- --heading: system-ui, 'Segoe UI', Roboto, sans-serif;
- --mono: ui-monospace, Consolas, monospace;
-
- font: 18px/145% var(--sans);
- letter-spacing: 0.18px;
- color-scheme: light dark;
- color: var(--text);
- background: var(--bg);
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-
- @media (max-width: 1024px) {
- font-size: 16px;
- }
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --text: #9ca3af;
- --text-h: #f3f4f6;
- --bg: #16171d;
- --border: #2e303a;
- --code-bg: #1f2028;
- --accent: #c084fc;
- --accent-bg: rgba(192, 132, 252, 0.15);
- --accent-border: rgba(192, 132, 252, 0.5);
- --social-bg: rgba(47, 48, 58, 0.5);
- --shadow:
- rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px;
- }
-
- #social .button-icon {
- filter: invert(1) brightness(2);
- }
-}
-
-#root {
- width: 1126px;
- max-width: 100%;
- margin: 0 auto;
- text-align: center;
- border-inline: 1px solid var(--border);
- min-height: 100svh;
- display: flex;
- flex-direction: column;
+ /* 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;
-}
-
-h1,
-h2 {
- font-family: var(--heading);
- font-weight: 500;
- color: var(--text-h);
-}
-
-h1 {
- font-size: 56px;
- letter-spacing: -1.68px;
- margin: 32px 0;
- @media (max-width: 1024px) {
- font-size: 36px;
- margin: 20px 0;
- }
-}
-h2 {
- font-size: 24px;
- line-height: 118%;
- letter-spacing: -0.24px;
- margin: 0 0 8px;
- @media (max-width: 1024px) {
- font-size: 20px;
- }
-}
-p {
- margin: 0;
-}
-
-code,
-.counter {
- font-family: var(--mono);
- display: inline-flex;
- border-radius: 4px;
- color: var(--text-h);
-}
-
-code {
- font-size: 15px;
- line-height: 135%;
- padding: 4px 8px;
- background: var(--code-bg);
+ 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 bef5202..15753af 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -1,10 +1,10 @@
-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 "./index.css";
+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
new file mode 100644
index 0000000..3415488
--- /dev/null
+++ b/frontend/src/pages/GameDetails/GameDetails.tsx
@@ -0,0 +1,32 @@
+import { Container, Image } from "react-bootstrap";
+import Header from "../../components/Header/Header";
+
+export default function GameDetails() {
+ return (
+ <>
+
+
+ Release year | Age rating
+ Game Title
+
+
+
+
NTNU Rating:
+
Your Rating:
+
+
+ Tags:
+ Developer(s):
+ Publisher(s):
+ Platform(s):
+ Description
+
+ >
+ );
+}
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
new file mode 100644
index 0000000..93c6aff
--- /dev/null
+++ b/frontend/src/pages/GamesGrid/GamesGrid.tsx
@@ -0,0 +1,63 @@
+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 (
+ <>
+
+
+
+
+ {games.map((game, index) => (
+
+ ))}
+
+
+ >
+ );
+}
diff --git a/frontend/src/pages/MyRatings/MyRatings.tsx b/frontend/src/pages/MyRatings/MyRatings.tsx
new file mode 100644
index 0000000..aede895
--- /dev/null
+++ b/frontend/src/pages/MyRatings/MyRatings.tsx
@@ -0,0 +1,9 @@
+import Header from "../../components/Header/Header";
+
+export default function MyRatings() {
+ return (
+ <>
+
+ >
+ );
+}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..5d533f7
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,78 @@
+{
+ "name": "T33-Project-2",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "react-bootstrap-icons": "^1.11.6"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "license": "MIT"
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.3.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz",
+ "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-bootstrap-icons": {
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/react-bootstrap-icons/-/react-bootstrap-icons-1.11.6.tgz",
+ "integrity": "sha512-ycXiyeSyzbS1C4+MlPTYe0riB+UlZ7LV7YZQYqlERV2cxDiKtntI0huHmP/3VVvzPt4tGxqK0K+Y6g7We3U6tQ==",
+ "license": "MIT",
+ "dependencies": {
+ "prop-types": "^15.7.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.6"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT"
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..112c08d
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "react-bootstrap-icons": "^1.11.6"
+ }
+}
Connect with us
-Join the Vite community
---
-
-
- GitHub
-
-
- -
-
-
- Discord
-
-
- -
-
-
- X.com
-
-
- -
-
-
- Bluesky
-
-
-
-