more refactoring

This commit is contained in:
Gavin McDonald
2025-06-26 15:30:03 -04:00
parent 2c2e93649c
commit a0e4f54ed9
6 changed files with 61 additions and 71 deletions

View File

@@ -23,6 +23,7 @@ export interface AppContext {
gameData: GameUpdate; gameData: GameUpdate;
noGame: boolean; noGame: boolean;
tilts: Tilt[]; tilts: Tilt[];
selectCardIndex: number;
flipCard: (cardIndex: number) => void; flipCard: (cardIndex: number) => void;
handleSettings: (gameData: GameUpdate) => void; handleSettings: (gameData: GameUpdate) => void;
redraw: (cardIndex: number) => void; redraw: (cardIndex: number) => void;
@@ -55,6 +56,7 @@ export function AppProvider({ children }: { children: ReactNode }) {
gameData, gameData,
noGame, noGame,
tilts, tilts,
selectCardIndex,
flipCard, flipCard,
handleSettings, handleSettings,
redraw, redraw,

View File

@@ -1,29 +1,20 @@
'use client'; 'use client';
import { useEffect, useState } from 'react'; import { useEffect } from 'react';
import { useParams } from 'next/navigation'; import { useParams } from 'next/navigation';
import { useAppContext } from '@/app/AppContext';
import { Eye } from 'lucide-react';
import { useAppContext } from '@/app/AppContext';
import CardSelect from '@/components/CardSelect'; import CardSelect from '@/components/CardSelect';
import CopyButton from '@/components/CopyButton';
import Notes from '@/components/Notes'; import Notes from '@/components/Notes';
import NotFound from '@/components/NotFound'; import NotFound from '@/components/NotFound';
import Settings from '@/components/Settings'; import Settings from '@/components/Settings';
import { SpectatorLink } from '@/components/SpectatorLink';
import TarokkaGrid from '@/components/TarokkaGrid'; import TarokkaGrid from '@/components/TarokkaGrid';
import type { Deck } from '@/types';
export default function GamePage() { export default function GamePage() {
const { gameData, noGame, handleSettings, select, setGameID } = useAppContext(); const { noGame, setGameID } = useAppContext();
const { gameID } = useParams(); const { gameID } = useParams();
const [selectCard, setSelectCard] = useState(-1);
const { dmID, cards, settings } = gameData;
const isDM = !!dmID;
const selectDeck: Deck | null = selectCard >= 0 ? cards[selectCard].deck : null;
useEffect(() => { useEffect(() => {
if (gameID) { if (gameID) {
setGameID(Array.isArray(gameID) ? gameID[0] : gameID); setGameID(Array.isArray(gameID) ? gameID[0] : gameID);
@@ -32,28 +23,13 @@ export default function GamePage() {
return noGame ? ( return noGame ? (
<NotFound /> <NotFound />
) : cards ? ( ) : (
<main className="min-h-screen flex flex-col items-center justify-center gap-4 bg-[url('/img/table3.png')] bg-cover bg-center"> <main className="min-h-screen flex flex-col items-center justify-center gap-4 bg-[url('/img/table3.png')] bg-cover bg-center">
{isDM && ( <SpectatorLink />
<CopyButton <Settings />
copy={`${location.origin}/${gameData.spectatorID}`}
tooltip={`Spectator link: ${location.origin}/${gameData.spectatorID}`}
Icon={Eye}
className={`fixed top-3 left-3 p-2 z-25 transition-all duration-250 text-yellow-400 hover:text-yellow-300 hover:drop-shadow-[0_0_3px_#ffd700] cursor-pointer`}
size={24}
/>
)}
{isDM && <Settings gameData={gameData} changeAction={handleSettings} />}
<TarokkaGrid /> <TarokkaGrid />
<Notes gameData={gameData} show={cards.every(({ flipped }) => flipped)} /> <Notes />
<CardSelect <CardSelect />
show={selectDeck}
hand={cards}
settings={settings}
closeAction={() => setSelectCard(-1)}
selectAction={select}
/>
</main> </main>
) : null; );
} }

View File

@@ -1,41 +1,36 @@
'use client'; 'use client';
import { CircleX } from 'lucide-react'; import { CircleX } from 'lucide-react';
import { useAppContext } from '@/app/AppContext';
import TarokkaDeck from '@/lib/TarokkaDeck'; import TarokkaDeck from '@/lib/TarokkaDeck';
import getURL from '@/tools/getURL'; import getURL from '@/tools/getURL';
import { Deck, Settings, TarokkaGameCard } from '@/types'; import { Deck } from '@/types';
const tarokkaDeck = new TarokkaDeck(); const tarokkaDeck = new TarokkaDeck();
type CardSelectProps = { type CardSelectProps = {
closeAction: () => void;
selectAction: (cardID: string) => void;
hand: TarokkaGameCard[];
settings: Settings;
show: Deck | null;
className?: string; className?: string;
}; };
export default function CardSelect({ export default function CardSelect({ className = '' }: CardSelectProps) {
closeAction, const { gameData, select, selectCardIndex, setSelectCardIndex } = useAppContext();
selectAction, const { cards: hand, settings } = gameData;
hand,
settings,
show,
className = '',
}: CardSelectProps) {
const handIDs = hand.map(({ id }) => id); const handIDs = hand.map(({ id }) => id);
const selectDeck: Deck | null = selectCardIndex >= 0 ? hand[selectCardIndex].deck : null;
const close = () => setSelectCardIndex(-1);
const handleClose = (event: React.MouseEvent<HTMLElement>) => { const handleClose = (event: React.MouseEvent<HTMLElement>) => {
if (event.target === event.currentTarget) { if (event.target === event.currentTarget) {
closeAction(); close();
} }
}; };
if (!show) return null; if (!selectDeck) return null;
const cards = show === 'high' ? tarokkaDeck.getHigh() : tarokkaDeck.getLow(); const cards = selectDeck === 'high' ? tarokkaDeck.getHigh() : tarokkaDeck.getLow();
return ( return (
<div <div
@@ -44,7 +39,7 @@ export default function CardSelect({
> >
<button <button
className={`fixed top-4 right-4 p-2 transition-all duration-250 text-yellow-400 hover:text-yellow-300 hover:drop-shadow-[0_0_3px_#ffd700] cursor-pointer`} className={`fixed top-4 right-4 p-2 transition-all duration-250 text-yellow-400 hover:text-yellow-300 hover:drop-shadow-[0_0_3px_#ffd700] cursor-pointer`}
onClick={closeAction} onClick={close}
> >
<CircleX className="w-6 h-6" /> <CircleX className="w-6 h-6" />
</button> </button>
@@ -58,7 +53,7 @@ export default function CardSelect({
<div <div
key={card.id} key={card.id}
className={`relative h-[21vh] w-[15vh] perspective transition-transform duration-200 hover:scale-150 z-0 hover:z-10`} className={`relative h-[21vh] w-[15vh] perspective transition-transform duration-200 hover:scale-150 z-0 hover:z-10`}
onClick={() => selectAction(card.id)} onClick={() => select(card.id)}
> >
<img <img
src={getURL(card, settings)} src={getURL(card, settings)}

View File

@@ -3,20 +3,18 @@
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { ScrollText } from 'lucide-react'; import { ScrollText } from 'lucide-react';
import { useAppContext } from '@/app/AppContext';
import CopyButton from '@/components/CopyButton'; import CopyButton from '@/components/CopyButton';
import Scrim from '@/components/Scrim'; import Scrim from '@/components/Scrim';
import getCardInfo from '@/tools/getCardInfo'; import getCardInfo from '@/tools/getCardInfo';
import { cardMap, layout } from '@/constants/tarokka'; import { cardMap, layout } from '@/constants/tarokka';
import { GameUpdate } from '@/types'; export default function Notes() {
const { gameData } = useAppContext();
const { dmID, cards, settings } = gameData;
type NotesProps = {
gameData: GameUpdate;
show: boolean;
};
export default function Notes({ gameData: { dmID, cards, settings }, show }: NotesProps) {
const isDM = !!dmID; const isDM = !!dmID;
const show = cards.every(({ flipped }) => flipped);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);

View File

@@ -4,12 +4,13 @@ import { useState } from 'react';
import { Settings as Gear } from 'lucide-react'; import { Settings as Gear } from 'lucide-react';
import { Cinzel_Decorative } from 'next/font/google'; import { Cinzel_Decorative } from 'next/font/google';
import { useAppContext } from '@/app/AppContext';
import BuyMeACoffee from '@/components/BuyMeACoffee'; import BuyMeACoffee from '@/components/BuyMeACoffee';
import CopyButton from '@/components/CopyButton'; import CopyButton from '@/components/CopyButton';
import GitHubButton from '@/components/GitHubButton'; import GitHubButton from '@/components/GitHubButton';
import Scrim from '@/components/Scrim'; import Scrim from '@/components/Scrim';
import Switch from '@/components/Switch'; import Switch from '@/components/Switch';
import { CardStyle, GameUpdate } from '@/types'; import { CardStyle } from '@/types';
const cinzel = Cinzel_Decorative({ const cinzel = Cinzel_Decorative({
variable: '--font-cinzel', variable: '--font-cinzel',
@@ -17,18 +18,17 @@ const cinzel = Cinzel_Decorative({
weight: '400', weight: '400',
}); });
type SettingsProps = {
gameData: GameUpdate;
changeAction: (updatedSettings: GameUpdate) => void;
};
const cardStyleOptions: CardStyle[] = ['standard', 'color', 'grayscale']; const cardStyleOptions: CardStyle[] = ['standard', 'color', 'grayscale'];
export default function Settings({ gameData, changeAction }: SettingsProps) { export default function Settings() {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const { gameData, handleSettings } = useAppContext();
const { dmID } = gameData;
const isDM = !!dmID;
const togglePermission = (key: string) => { const togglePermission = (key: string) => {
changeAction({ handleSettings({
...gameData, ...gameData,
settings: { settings: {
...gameData.settings, ...gameData.settings,
@@ -38,7 +38,7 @@ export default function Settings({ gameData, changeAction }: SettingsProps) {
}; };
const tuneRadio = (cardStyle: CardStyle) => { const tuneRadio = (cardStyle: CardStyle) => {
changeAction({ handleSettings({
...gameData, ...gameData,
settings: { settings: {
...gameData.settings, ...gameData.settings,
@@ -104,7 +104,7 @@ export default function Settings({ gameData, changeAction }: SettingsProps) {
</fieldset> </fieldset>
); );
return ( return isDM ? (
<div className={`fixed top-4 right-4 z-25 ${cinzel.className}`}> <div className={`fixed top-4 right-4 z-25 ${cinzel.className}`}>
<Scrim <Scrim
clickAction={() => setOpen((prev) => !prev)} clickAction={() => setOpen((prev) => !prev)}
@@ -129,5 +129,5 @@ export default function Settings({ gameData, changeAction }: SettingsProps) {
<Gear className="w-5 h-5" /> <Gear className="w-5 h-5" />
</button> </button>
</div> </div>
); ) : null;
} }

View File

@@ -0,0 +1,19 @@
'use client';
import { Eye } from 'lucide-react';
import { useAppContext } from '@/app/AppContext';
import CopyButton from '@/components/CopyButton';
export function SpectatorLink() {
const { gameData } = useAppContext();
return (
<CopyButton
copy={`${location.origin}/${gameData.spectatorID}`}
tooltip={`Spectator link: ${location.origin}/${gameData.spectatorID}`}
Icon={Eye}
className={`fixed top-3 left-3 p-2 z-25 transition-all duration-250 text-yellow-400 hover:text-yellow-300 hover:drop-shadow-[0_0_3px_#ffd700] cursor-pointer`}
size={24}
/>
);
}