Skip to content

Commit

Permalink
Merge pull request #52 from JollyGrin/feat/hover-preview-v2
Browse files Browse the repository at this point in the history
Feat/hover preview v2
  • Loading branch information
JollyGrin authored Oct 20, 2024
2 parents 171e022 + 842c5f4 commit 49ad807
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 5 deletions.
20 changes: 19 additions & 1 deletion src/components/organisms/GameBoard/Footer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ import { CountersTray } from "./Counters";
/**
* HAND - Drag and Drop tray of all the cards in your hand
* */
export const GameFooter = (props: GameStateActions & PlayerDataProps) => {
export const GameFooter = ({
setHoverCard,
...props
}: GameStateActions &
PlayerDataProps & {
setHoverCard(slug: string): void;
}) => {
const gridIndex = GRIDS.HAND;
const cardsInHand = props.gridItems[gridIndex] ?? [];

Expand Down Expand Up @@ -97,6 +103,7 @@ export const GameFooter = (props: GameStateActions & PlayerDataProps) => {
gridIndex={gridIndex}
cardIndex={index}
gameStateActions={props}
setHoverCard={setHoverCard}
/>
))}
</HStack>
Expand All @@ -112,12 +119,21 @@ const HandCard = ({
gridIndex,
cardIndex: index,
gameStateActions,
...props
}: {
card: GameCard;
gridIndex: number;
cardIndex: number;
gameStateActions: GameStateActions;
setHoverCard(slug?: string): void;
}) => {
function over() {
if (props.setHoverCard) props.setHoverCard(card.img);
}
function out() {
if (props.setHoverCard) props.setHoverCard();
}

const [preview, setPreview] = useState(false);
const deckType = card.type === "site" ? "atlas" : "deck";

Expand All @@ -139,6 +155,8 @@ const HandCard = ({
e.preventDefault();
setPreview(true);
}}
onMouseOver={over}
onMouseOut={out}
style={{
position: "relative",
width: "100%",
Expand Down
63 changes: 59 additions & 4 deletions src/components/organisms/GameBoard/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,76 @@
import { ReactNode } from "react";
import { DragEvent, ReactNode, useState } from "react";
import { Box, Grid } from "styled-system/jsx";
import { grid } from "styled-system/patterns";
import { LAYOUT_HEIGHTS } from "./constants";
import { getCardImage, LAYOUT_HEIGHTS } from "./constants";
import { GameFooter } from "./Footer";
import { GameStateActions } from ".";
import { Auras } from "./Auras";
import { PlayerDataProps } from "@/types/card";
import { GameHeader } from "./Header";
import { useMediaQuery } from "@/utils/hooks/useMediaQuery";

const { nav, body, footer } = LAYOUT_HEIGHTS;

export const GameLayout = (
props: GameStateActions &
PlayerDataProps & { isReversed?: boolean; children: ReactNode },
PlayerDataProps & {
isReversed?: boolean;
activeCardSlug?: string;
setHoverCard(slug: string): void;
children: ReactNode;
},
) => {
const matches = useMediaQuery("(min-width: 1200px)");
const [trans, setTrans] = useState<string>("");

const handleDrag = (e: DragEvent<HTMLDivElement>) => {
e.preventDefault(); // Prevent default drag behavior

if (e.clientX !== 0 && e.clientY !== 0) {
const transform = `translate(${e.clientX - 150}px, ${e.clientY - 150}px)`;
setTrans(transform ?? "");
}
};

return (
<Grid style={{ gridTemplateRows: `${nav} ${body} ${footer}` }} gap={0}>
<Grid
style={{ gridTemplateRows: `${nav} ${body} ${footer}` }}
gap={0}
position="relative"
>
<Box
zIndex={5}
position="absolute"
draggable
onDragStart={(e) => {
const img = new Image();
img.src = "";
e.dataTransfer.setDragImage(img, 0, 0);
}}
onDrag={handleDrag} // Directly update position for smoother dragging
cursor="grab"
style={{
transform: trans,
display: matches ? "block" : "none",
}}
>
{matches && props.activeCardSlug && (
<img
src={getCardImage(props.activeCardSlug)}
alt="card"
style={{ maxWidth: "20rem" }}
/>
)}
{matches && props.activeCardSlug === undefined && (
<Box
w="20rem"
h="26rem"
bg="gray"
borderRadius="1rem"
opacity="0.35"
/>
)}
</Box>
<GameHeader players={props.players} />
<Box position="relative" h="100%" w="100%" maxW="1200px" m="0 auto">
<Auras {...props} />
Expand Down
10 changes: 10 additions & 0 deletions src/components/organisms/GameBoard/SortItemWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ export const SortItemWrapper = ({
gridIndex: number;
cardIndex: number;
amountOfCards?: number;
setHoverImage?(slug?: string): void;
} & GameStateActions) => {
function over() {
if (props.setHoverImage) props.setHoverImage(card.img);
}
function out() {
if (props.setHoverImage) props.setHoverImage();
}

const { query } = useRouter();
const name = query?.name as string;

Expand Down Expand Up @@ -78,6 +86,8 @@ export const SortItemWrapper = ({
e.stopPropagation();
toggleTap();
}}
onMouseOver={over}
onMouseOut={out}
data-testid={"sortable-item-wrapper-" + card.id}
style={{
height: heightCalc() + 7 + "px",
Expand Down
5 changes: 5 additions & 0 deletions src/components/organisms/GameBoard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export const GameBoard = ({
setGridItems,
});

const [hoverCard, setHoverCard] = useState<string>();

const [gridHover, setGridHover] = useState<number | undefined>(undefined);
const { key, ...options } = LOCALSTORAGE_KEYS.SETTINGS.DISPLAY.toggle;
const [isDisplay] = useLocalStorage(key, false, options);
Expand All @@ -47,6 +49,8 @@ export const GameBoard = ({
gridItems={gridItems}
setGridItems={setGridItems}
isReversed={isReversed}
activeCardSlug={hoverCard}
setHoverCard={setHoverCard}
{...playerDataProps}
>
{(isReversed
Expand Down Expand Up @@ -105,6 +109,7 @@ export const GameBoard = ({
<SortItemWrapper
key={card.id}
amountOfCards={cards?.length}
setHoverImage={setHoverCard}
{...{ gridItems, setGridItems }}
{...{ card, gridIndex, cardIndex }}
/>
Expand Down
61 changes: 61 additions & 0 deletions src/utils/hooks/useMediaQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useState } from "react";

import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect";

type UseMediaQueryOptions = {
defaultValue?: boolean;
initializeWithValue?: boolean;
};

const IS_SERVER = typeof window === "undefined";

export function useMediaQuery(
query: string,
{
defaultValue = false,
initializeWithValue = true,
}: UseMediaQueryOptions = {},
): boolean {
const getMatches = (query: string): boolean => {
if (IS_SERVER) {
return defaultValue;
}
return window.matchMedia(query).matches;
};

const [matches, setMatches] = useState<boolean>(() => {
if (initializeWithValue) {
return getMatches(query);
}
return defaultValue;
});

// Handles the change event of the media query.
function handleChange() {
setMatches(getMatches(query));
}

useIsomorphicLayoutEffect(() => {
const matchMedia = window.matchMedia(query);

// Triggered at the first client-side load and if query changes
handleChange();

// Use deprecated `addListener` and `removeListener` to support Safari < 14 (#135)
if (matchMedia.addListener) {
matchMedia.addListener(handleChange);
} else {
matchMedia.addEventListener("change", handleChange);
}

return () => {
if (matchMedia.removeListener) {
matchMedia.removeListener(handleChange);
} else {
matchMedia.removeEventListener("change", handleChange);
}
};
}, [query]);

return matches;
}

0 comments on commit 49ad807

Please sign in to comment.