diff --git a/web/package-lock.json b/web/package-lock.json index 2cc7803f..c6632523 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "web", - "version": "0.10.2", + "version": "0.11.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "web", - "version": "0.10.2", + "version": "0.11.1", "dependencies": { "@base-ui/react": "^1.6.0", "@codemirror/lang-json": "^6.0.2", diff --git a/web/public/goal_ping.ogg b/web/public/goal_ping.ogg new file mode 100644 index 00000000..7fa299c3 Binary files /dev/null and b/web/public/goal_ping.ogg differ diff --git a/web/src/app/(main)/legal/credits/page.tsx b/web/src/app/(main)/legal/credits/page.tsx new file mode 100644 index 00000000..fa020da0 --- /dev/null +++ b/web/src/app/(main)/legal/credits/page.tsx @@ -0,0 +1,73 @@ +import { GitHub } from '@mui/icons-material'; +import { Box, Container, Typography } from '@mui/material'; +import Link from 'next/link'; + +const contributors = [ + { + name: 'cjs07', + github: 'https://github.com/cjs8487', + }, + { + name: 'Floha258', + github: 'https://github.com/floha258', + }, + { + name: 'lepelog', + github: 'https://github.com/lepelog', + }, + { + name: 'tricksnl', + github: 'https://github.com/devbeoservice', + }, +]; + +export default function Credits() { + return ( + + + Credits + + + PlayBingo would not be possible without the contributions our + community. + + + {contributors.map((contributor) => ( + + {contributor.name} + + + + + + + ))} + + + + An additional, special rhanks to all the community members + who have helped make PlayBingo better by providing feedback, + finding bugs, and working with us to make PlayBingo the best + it can be. + + + + + PlayBingo makes use of parts of the following works made + available under the Creative Commons license. + + + Sound Effects + + + + UI Sound Effects by lolurio (CC BY 4.0) + + + + + ); +} diff --git a/web/src/components/board/Cell.tsx b/web/src/components/board/Cell.tsx index c6a2ebd8..e82cc87d 100644 --- a/web/src/components/board/Cell.tsx +++ b/web/src/components/board/Cell.tsx @@ -57,6 +57,7 @@ radial-gradient(circle at 40% 30%, rgba(147, 137, 137, 0.13) 0%, rgba(0,0,0,0) 9 pointerEvents: 'none', }, }; + interface BoardCellProps { goal?: Goal; completedPlayers: string[]; diff --git a/web/src/components/footer/Footer.tsx b/web/src/components/footer/Footer.tsx index c64d80c3..b9ec2a2e 100644 --- a/web/src/components/footer/Footer.tsx +++ b/web/src/components/footer/Footer.tsx @@ -85,6 +85,10 @@ function LargeFooter() { | All Rights Reserved |{' '} Privacy Policy + {' '} + |{' '} + + Credits diff --git a/web/src/context/RoomContext.tsx b/web/src/context/RoomContext.tsx index c2d707f3..f5fe0d65 100644 --- a/web/src/context/RoomContext.tsx +++ b/web/src/context/RoomContext.tsx @@ -42,6 +42,8 @@ export enum ConnectionStatus { CLOSED, // connection was manually closed, and the user is completely disconnected } +const notificationSound = new Audio('/goal_ping.ogg'); + interface CardRegenerateOptions { seed?: number; generationMode?: string; @@ -264,7 +266,28 @@ export function RoomContextProvider({ !payload.cell ) return; - onCellUpdate(payload.row, payload.col, payload.cell); + if (!board.hidden) { + const newMarks = + payload.cell.completedPlayers.filter( + (player) => + !board.board[payload.row][ + payload.col + ].completedPlayers.includes(player), + ); + if ( + newMarks.length > 0 && + (newMarks.length > 1 || + newMarks[0] !== connectedPlayer?.id) + ) { + notificationSound.play(); + } + + onCellUpdate( + payload.row, + payload.col, + payload.cell, + ); + } break; case 'syncBoard': if (!payload.board) return;