added Context
This commit is contained in:
18
app/AppContext.tsx
Normal file
18
app/AppContext.tsx
Normal 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;
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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>
|
||||
|
||||
12
server.ts
12
server.ts
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user