added Context

This commit is contained in:
Gavin McDonald
2025-06-25 17:04:18 -04:00
parent 59aa904c5a
commit e7ebb0223b
6 changed files with 75 additions and 16 deletions

18
app/AppContext.tsx Normal file
View File

@@ -0,0 +1,18 @@
'use client';
import { createContext, useContext, useState, ReactNode } from 'react';
import type { AppContext, Tilt } from '@/types';
const AppContext = createContext<AppContext | undefined>(undefined);
export function AppProvider({ children }: { children: ReactNode }) {
const [tilts, setTilts] = useState<Tilt[]>([]);
return <AppContext.Provider value={{ tilts, setTilts }}>{children}</AppContext.Provider>;
}
export function useAppContext(): AppContext {
const context = useContext(AppContext);
if (!context) throw new Error('useAppContext must be used within AppProvider');
return context;
}

View File

@@ -1,5 +1,6 @@
import type { Metadata } from 'next';
import { Pirata_One, Eagle_Lake, Cinzel_Decorative } from 'next/font/google';
import { AppProvider } from '@/app/AppContext';
import './globals.css';
const pirataOne = Pirata_One({
@@ -40,7 +41,9 @@ export default function RootLayout({
lang="en"
className={`${pirataOne.variable} ${eagleLake.variable} ${cinzel.variable} antialiased`}
>
<body className={`${eagleLake.className} antialiased`}>{children}</body>
<body className={`${eagleLake.className} antialiased`}>
<AppProvider>{children}</AppProvider>
</body>
</html>
);
}

View File

@@ -60,10 +60,11 @@ export default function Card({
<ToolTip content={tooltip || getTooltip()}>
<TiltCard
className={`h-[21vh] w-[15vh] relative perspective transition-transform duration-200 z-0 hover:z-10 hover:scale-150 ${dm ? 'cursor-pointer' : ''} `}
onClick={handleClick}
cardID={position.id}
>
<div
className={`absolute inset-0 transition-transform duration-500 transform-style-preserve-3d ${flipped ? 'rotate-y-180' : ''}`}
onClick={handleClick}
>
<div className="absolute inset-0 group backface-hidden">
{dm && (

View File

@@ -1,18 +1,39 @@
import { useRef } from 'react';
import { useEffect, useRef } from 'react';
import { useAppContext } from '@/app/AppContext';
export default function TiltCard({
children,
cardID,
className = '',
onClick = () => {},
}: {
children: React.ReactNode;
cardID: string;
className?: string;
onClick: (event: React.MouseEvent) => void;
}) {
const cardRef = useRef<HTMLDivElement>(null);
const { tilts, setTilts } = useAppContext();
const card = cardRef.current;
useEffect(() => {
if (!card) return;
const tilt = tilts.find((tilt) => tilt.cardID === cardID);
if (!tilt) {
card.style.transform = `rotateX(0deg) rotateY(0deg)`;
return;
}
const { rotateX, rotateY } = tilt;
if (rotateX || rotateY) {
card.style.transform = `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
} else {
card.style.transform = `rotateX(0deg) rotateY(0deg)`;
}
}, [tilts]);
const handleMouseMove = (e: React.MouseEvent) => {
const card = cardRef.current;
if (!card) return;
const rect = card.getBoundingClientRect();
@@ -24,22 +45,17 @@ export default function TiltCard({
const rotateX = ((y - centerY) / centerY) * -20;
const rotateY = ((x - centerX) / centerX) * 20;
card.style.transform = `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
setTilts([...tilts.filter((tilt) => tilt.cardID !== cardID), { cardID, rotateX, rotateY }]);
};
const handleMouseLeave = () => {
const card = cardRef.current;
if (!card) return;
card.style.transform = `rotateX(0deg) rotateY(0deg)`;
setTilts(tilts.filter((tilt) => tilt.cardID !== cardID));
};
return (
<div
className={`${className}`}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
onClick={onClick}
>
<div className={`${className}`} onMouseMove={handleMouseMove} onMouseLeave={handleMouseLeave}>
<div ref={cardRef} className={`h-full w-full transition-transform duration-0`}>
{children}
</div>

View File

@@ -4,7 +4,7 @@ import { Server as SocketIOServer, type Socket } from 'socket.io';
import GameStore from '@/lib/GameStore';
import omit from '@/tools/omit';
import type { ClientUpdate, GameUpdate } from '@/types';
import type { ClientUpdate, GameUpdate, Tilt } from '@/types';
const dev = process.env.NODE_ENV !== 'production';
const hostname = '0.0.0.0';
@@ -119,6 +119,16 @@ app.prepare().then(() => {
}
});
socket.on('tilt', ({ gameID, tilt }: { gameID: string; tilt: Tilt }) => {
try {
const gameState = gameStore.getGame(gameID);
broadcast('tilt', gameState);
} catch (e) {
const error = e instanceof Error ? e.message : e;
console.error(Date.now(), 'Error[tilt]', error);
}
});
socket.on('disconnect', () => {
try {
const game = gameStore.playerExit(socket.id);

View File

@@ -103,3 +103,14 @@ export interface Layout {
name: string;
text: string;
}
export interface Tilt {
cardID: string;
rotateX: number;
rotateY: number;
}
export interface AppContext {
tilts: Tilt[];
setTilts: (tilts: Tilt[]) => void;
}