From 59772afb04b984a2bbfc9eb05c9e2682c14f750d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 10 Apr 2024 09:40:52 -0500 Subject: [PATCH] feat: drag and drop --- src/app/tools/compare/page.tsx | 147 ++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 3 deletions(-) diff --git a/src/app/tools/compare/page.tsx b/src/app/tools/compare/page.tsx index 9bb27eda0..7e5b89ea5 100644 --- a/src/app/tools/compare/page.tsx +++ b/src/app/tools/compare/page.tsx @@ -21,7 +21,8 @@ import { } from '@radix-ui/themes'; import { times } from 'lodash'; import { usePathname, useRouter, useSearchParams } from 'next/navigation'; -import { use, useCallback, useEffect, useMemo, useState } from 'react'; +import { use, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { Vector2 } from 'three'; import { ConsumablesManager } from '../../../components/ConsumablesManager'; import { CrewSkillManager } from '../../../components/CrewSkillManager'; import { EquipmentManager } from '../../../components/EquipmentManager'; @@ -58,6 +59,8 @@ import { permanentSkills } from '../tankopedia/[id]/components/Characteristics/c import { TankSearch } from '../tankopedia/components/TankSearch'; import { TankControl } from './components/TankControl'; +const insertionMarkers: { element: HTMLDivElement; index: number }[] = []; + export default function Page() { const pathname = usePathname(); const router = useRouter(); @@ -328,8 +331,94 @@ export default function Page() { } function TankCard({ index, tank }: { index: number; tank: TankDefinition }) { + const image = useRef(null); + + useEffect(() => { + const initial = new Vector2(); + const current = new Vector2(); + const delta = new Vector2(); + const marker = new Vector2(); + let initialRect = image.current!.getBoundingClientRect(); + let dropIndex = -1; + + function handlePointerDown(event: PointerEvent) { + event.preventDefault(); + + initialRect = image.current!.getBoundingClientRect(); + + delta.set(0, 0); + current.copy(initial.set(event.clientX, event.clientY)); + window.addEventListener('pointermove', handlePointerMove); + window.addEventListener('pointerup', handlePointerUp); + } + function handlePointerMove(event: PointerEvent) { + event.preventDefault(); + + current.set(event.clientX, event.clientY); + delta.copy(current).sub(initial); + insertionMarkers.forEach(({ element }) => { + element.style.opacity = '0'; + }); + + const distances = insertionMarkers.map((insertionMarker) => { + const markerBounds = insertionMarker.element.getBoundingClientRect(); + marker.set(markerBounds.left, markerBounds.top); + + return { + ...insertionMarker, + distance: marker.distanceTo(current), + }; + }); + const closest = distances.reduce((a, b) => + a.distance < b.distance ? a : b, + ); + + dropIndex = closest.index; + closest.element.style.opacity = '1'; + image.current!.style.position = 'fixed'; + image.current!.style.zIndex = '1'; + image.current!.style.left = `${initialRect.left + delta.x}px`; + image.current!.style.top = `${initialRect.top + delta.y}px`; + } + function handlePointerUp(event: PointerEvent) { + event.preventDefault(); + + image.current!.style.position = 'static'; + image.current!.style.zIndex = 'unset'; + + insertionMarkers.forEach(({ element }) => { + element.style.opacity = '0'; + }); + + window.removeEventListener('pointermove', handlePointerMove); + window.removeEventListener('pointerup', handlePointerUp); + + if (dropIndex === -1) return; + + mutateCompareTemporary((draft) => { + const fromIndex = index; + const toIndex = dropIndex > index ? dropIndex - 1 : dropIndex; + + const member = draft.members[fromIndex]; + draft.members.splice(fromIndex, 1); + draft.members.splice(toIndex, 0, member); + }); + + dropIndex = -1; + } + + image.current?.addEventListener('pointerdown', handlePointerDown); + + return () => { + image.current?.removeEventListener('pointerdown', handlePointerDown); + }; + }, []); + return ( - + {tank.name} @@ -363,10 +457,51 @@ export default function Page() { {tank.name} + + ); } + function InsertionMarker({ index }: { index: number }) { + const marker = useRef(null); + + useEffect(() => { + insertionMarkers.push({ + element: marker.current!, + index, + }); + + console.log(insertionMarkers); + + return () => { + insertionMarkers.splice( + insertionMarkers.findIndex( + (insertionMarker) => insertionMarker.element === marker.current!, + ), + 1, + ); + }; + }); + + return ( +
+ ); + } + return ( @@ -462,7 +597,12 @@ export default function Page() { - + +