From 5e912e5b515d938c5bea98911f6ec98075ec8e45 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 25 Nov 2024 13:58:52 -0600 Subject: [PATCH] feat: better placing --- .../components/TierList/DropOff/constants.ts | 1 - .../src/components/TierList/DropOff/index.css | 9 -- .../src/components/TierList/DropOff/index.tsx | 42 ------- .../website/src/components/TierList/Row.tsx | 40 +++--- .../components/TierList/Table/constants.ts | 5 + .../website/src/components/TierList/Tile.tsx | 114 ++++++++++++------ .../website/src/components/TierList/Tiles.tsx | 2 +- 7 files changed, 109 insertions(+), 104 deletions(-) delete mode 100644 packages/website/src/components/TierList/DropOff/constants.ts delete mode 100644 packages/website/src/components/TierList/DropOff/index.css delete mode 100644 packages/website/src/components/TierList/DropOff/index.tsx diff --git a/packages/website/src/components/TierList/DropOff/constants.ts b/packages/website/src/components/TierList/DropOff/constants.ts deleted file mode 100644 index 553dd2dc8..000000000 --- a/packages/website/src/components/TierList/DropOff/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const tierListDropOffs = new Set(); diff --git a/packages/website/src/components/TierList/DropOff/index.css b/packages/website/src/components/TierList/DropOff/index.css deleted file mode 100644 index f1feff18d..000000000 --- a/packages/website/src/components/TierList/DropOff/index.css +++ /dev/null @@ -1,9 +0,0 @@ -.drop-off { - width: 0.125rem; - height: 100%; - border-radius: var(--radius-1); -} - -.drop-off[data-dragging='true'] { - background-color: var(--accent-indicator); -} diff --git a/packages/website/src/components/TierList/DropOff/index.tsx b/packages/website/src/components/TierList/DropOff/index.tsx deleted file mode 100644 index 46d23994c..000000000 --- a/packages/website/src/components/TierList/DropOff/index.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Box } from '@radix-ui/themes'; -import { useEffect, useRef } from 'react'; -import { TierList } from '../../../stores/tierList'; -import { tierListDropOffs } from './constants'; -import './index.css'; - -interface DropOffProps { - row: number; - index: number; -} - -export function DropOff({ row, index }: DropOffProps) { - const tierListStore = TierList.useStore(); - const ref = useRef(null); - - useEffect(() => { - const unsubscribe = tierListStore.subscribe( - (state) => state.dragging, - (dragging) => { - if (!ref.current) return; - ref.current.dataset.dragging = `${dragging}`; - }, - ); - - tierListDropOffs.add(ref.current!); - - return () => { - unsubscribe(); - tierListDropOffs.delete(ref.current!); - }; - }, []); - - return ( - - ); -} diff --git a/packages/website/src/components/TierList/Row.tsx b/packages/website/src/components/TierList/Row.tsx index 7879ef2a0..52eea6978 100644 --- a/packages/website/src/components/TierList/Row.tsx +++ b/packages/website/src/components/TierList/Row.tsx @@ -1,10 +1,9 @@ import { fetchTankDefinitions } from '@blitzkit/core'; import { Flex, Heading, Table } from '@radix-ui/themes'; -import { Fragment } from 'react'; +import { useEffect, useRef } from 'react'; import { Var } from '../../core/radix/var'; import { TierList } from '../../stores/tierList'; -import { DropOff } from './DropOff'; -import { tierListRows } from './Table/constants'; +import { tierListRowElements, tierListRows } from './Table/constants'; import { TierListTile } from './Tile'; interface TierListRowProps { @@ -14,30 +13,43 @@ interface TierListRowProps { const tankDefinitions = await fetchTankDefinitions(); export function TierListRow({ index }: TierListRowProps) { - const row = tierListRows[index]; + const rowStyle = tierListRows[index]; const tanks = TierList.use((state) => state.tanks[index]); + const row = useRef(null); + + useEffect(() => { + if (!row.current) return; + + tierListRowElements.add(row.current); + + return () => { + if (!row.current) return; + + tierListRowElements.delete(row.current); + }; + }); return ( - + - {row.name} + {rowStyle.name} - - {tanks.map((id, tankIndex) => { const tank = tankDefinitions.tanks[id]; - return ( - - - - + ); })} diff --git a/packages/website/src/components/TierList/Table/constants.ts b/packages/website/src/components/TierList/Table/constants.ts index 1faa6e6a1..c90423b36 100644 --- a/packages/website/src/components/TierList/Table/constants.ts +++ b/packages/website/src/components/TierList/Table/constants.ts @@ -10,3 +10,8 @@ export const tierListRows: { { name: 'C', color: 'green-9' }, { name: 'D', color: 'blue-9' }, ]; + +export const tierListRowElements = new Set(); +export const tierListCardElements = tierListRows.map( + () => new Set(), +); diff --git a/packages/website/src/components/TierList/Tile.tsx b/packages/website/src/components/TierList/Tile.tsx index 3ee0ddf5a..6b4a22447 100644 --- a/packages/website/src/components/TierList/Tile.tsx +++ b/packages/website/src/components/TierList/Tile.tsx @@ -1,18 +1,28 @@ import type { TankDefinition } from '@blitzkit/core'; import { useCallback, + useEffect, useRef, type PointerEvent as ReactPointerEvent, } from 'react'; import { TierList } from '../../stores/tierList'; import { TankCard } from '../TankCard'; -import { tierListDropOffs } from './DropOff/constants'; +import { tierListCardElements, tierListRowElements } from './Table/constants'; -interface TierListTileProps { +type TierListTileProps = { tank: TankDefinition; -} +} & ( + | { + isPlaced?: false; + } + | { + isPlaced: true; + rowIndex: number; + tileIndex: number; + } +); -export function TierListTile({ tank }: TierListTileProps) { +export function TierListTile(props: TierListTileProps) { const card = useRef(null); const mutateTierList = TierList.useMutation(); const lastPosition = useRef({ x: 0, y: 0 }); @@ -58,43 +68,59 @@ export function TierListTile({ tank }: TierListTileProps) { const handlePointerUp = useCallback((event: PointerEvent) => { if (!card.current) return; - const rect = card.current.getBoundingClientRect(); - let dropOff: { row: number; index: number; distance: number }; + const cardRect = card.current.getBoundingClientRect(); + const cardX = (cardRect.left + cardRect.right) / 2; + const cardY = (cardRect.top + cardRect.bottom) / 2; - tierListDropOffs.forEach((element) => { - const thisRect = element.getBoundingClientRect(); - const thisX = (thisRect.left + thisRect.right) / 2; - const thisY = (thisRect.top + thisRect.bottom) / 2; - let distance = 0; + rowLoop: for (const row of tierListRowElements) { + const rowRect = row.getBoundingClientRect(); + const isWithinRow = + cardX >= rowRect.left && + cardX <= rowRect.right && + cardY >= rowRect.top && + cardY <= rowRect.bottom; - if ( - (thisX < rect.left || thisX > rect.right) && - (thisY < rect.top || thisY > rect.bottom) - ) { - const rectX = (rect.left + rect.right) / 2; - const rectY = (rect.top + rect.bottom) / 2; - distance = Math.sqrt((thisX - rectX) ** 2 + (thisY - rectY) ** 2); + if (!isWithinRow) continue; + + const rowIndex = Number(row.dataset.index); + + for (const tile of tierListCardElements[rowIndex]) { + const tileId = Number(tile.dataset.tileId); + + if (tileId === props.tank.id) continue; + + const tileRect = tile.getBoundingClientRect(); + const isWithinTile = + cardX >= tileRect.left && + cardX <= tileRect.right && + cardY >= tileRect.top && + cardY <= tileRect.bottom; + + if (!isWithinTile) continue; + + const tileIndex = Number(tile.dataset.tileIndex); + + mutateTierList((draft) => { + draft.dragging = false; + draft.tanks = draft.tanks.map((row) => + row.filter((tankId) => tankId !== props.tank.id), + ); + draft.tanks[rowIndex].splice(tileIndex, 0, props.tank.id); + }); + + break rowLoop; } - if (dropOff === undefined || dropOff.distance > distance) { - dropOff = { - row: Number(element.dataset.row), - index: Number(element.dataset.index), - distance, - }; - } - }); + mutateTierList((draft) => { + draft.dragging = false; + draft.tanks = draft.tanks.map((row) => + row.filter((tankId) => tankId !== props.tank.id), + ); + draft.tanks[rowIndex].push(props.tank.id); + }); - mutateTierList((draft) => { - draft.dragging = false; - draft.tanks = draft.tanks.map((tanks) => - tanks.filter((id) => id !== tank.id), - ); - - if (dropOff) { - draft.tanks[dropOff.row].splice(dropOff.index, 0, tank.id); - } - }); + break; + } card.current.style.position = 'static'; card.current.style.zIndex = 'unset'; @@ -104,11 +130,25 @@ export function TierListTile({ tank }: TierListTileProps) { window.removeEventListener('pointerup', handlePointerUp); }, []); + useEffect(() => { + if (!props.isPlaced || !card.current) return; + + tierListCardElements[props.rowIndex].add(card.current); + + return () => { + if (!card.current) return; + + tierListCardElements[props.rowIndex].delete(card.current); + }; + }, []); + return ( diff --git a/packages/website/src/components/TierList/Tiles.tsx b/packages/website/src/components/TierList/Tiles.tsx index a033ce4e3..d766e9ef1 100644 --- a/packages/website/src/components/TierList/Tiles.tsx +++ b/packages/website/src/components/TierList/Tiles.tsx @@ -15,7 +15,7 @@ export function TierListTiles() { {tanks .filter((tank) => filterTank(filters, tank)) - .map((tank) => ( + .map((tank, tileIndex) => ( ))}