diff --git a/src/components/editor/CourtBall.tsx b/src/components/editor/CourtBall.tsx index c9c48dc..6eb1a8a 100644 --- a/src/components/editor/CourtBall.tsx +++ b/src/components/editor/CourtBall.tsx @@ -1,34 +1,31 @@ -import { useRef } from "react" +import { KeyboardEventHandler, RefObject, useRef } from "react" import Draggable from "react-draggable" import { BallPiece } from "./BallPiece" -import { NULL_POS } from "../../geo/Pos" +import { NULL_POS, Pos } from "../../geo/Pos" import { Ball } from "../../model/tactic/CourtObjects" export interface CourtBallProps { + ball: Ball +} + +export interface EditableCourtBallProps extends CourtBallProps { onPosValidated: (rect: DOMRect) => void onRemove: () => void - ball: Ball } -export function CourtBall({ onPosValidated, ball, onRemove }: CourtBallProps) { - const pieceRef = useRef(null) - const { x, y } = ball.pos +export function CourtBall({ onPosValidated, ball, onRemove }: EditableCourtBallProps) { + const pieceRef = useRef(null) - return ( - - onPosValidated(pieceRef.current!.getBoundingClientRect()) - } - position={NULL_POS} - nodeRef={pieceRef}> + function courtBallPiece({ x, y }: Pos, + pieceRef?: RefObject, + onKeyUp?: KeyboardEventHandler) { + return (
{ - if (e.key == "Delete") onRemove() - }} + onKeyUp={onKeyUp} style={{ position: "absolute", left: `${x * 100}%`, @@ -36,6 +33,30 @@ export function CourtBall({ onPosValidated, ball, onRemove }: CourtBallProps) { }}>
+ ) + } + + if (ball.frozen) { + return courtBallPiece(ball.pos) + } + + return ( + + onPosValidated(pieceRef.current!.getBoundingClientRect()) + } + position={NULL_POS} + nodeRef={pieceRef}> + {courtBallPiece( + ball.pos, + pieceRef, + (e) => { + if (e.key == "Delete") onRemove() + }, + )} ) } + + + diff --git a/src/editor/PlayerDomains.ts b/src/editor/PlayerDomains.ts index 19ca23e..6eef2a3 100644 --- a/src/editor/PlayerDomains.ts +++ b/src/editor/PlayerDomains.ts @@ -258,7 +258,7 @@ export function removePlayer( content.components, )! const actions = playerBefore.actions.filter( - (a) => a.target === pos.attach, + (a) => a.target !== pos.attach, ) content = updateComponent( { diff --git a/src/editor/TacticContentDomains.ts b/src/editor/TacticContentDomains.ts index 28ab879..e2e8a2f 100644 --- a/src/editor/TacticContentDomains.ts +++ b/src/editor/TacticContentDomains.ts @@ -77,6 +77,7 @@ export function placeObjectAt( id: BALL_ID, pos, actions: [], + frozen: false } break } @@ -153,6 +154,7 @@ export function placeBallAt( id: BALL_ID, pos, actions: [], + frozen: false, } let components = content.components @@ -198,9 +200,9 @@ export function moveComponent( phantomIdx == 0 ? origin : getComponent( - originPathItems[phantomIdx - 1], - content.components, - ) + originPathItems[phantomIdx - 1], + content.components, + ) // detach the action from the screen target and transform it to a regular move action to the phantom. content = updateComponent( { @@ -208,18 +210,18 @@ export function moveComponent( actions: playerBeforePhantom.actions.map((a) => a.target === referent ? { - ...a, - segments: a.segments.toSpliced( - a.segments.length - 2, - 1, - { - ...a.segments[a.segments.length - 1], - next: component.id, - }, - ), - target: component.id, - type: ActionKind.MOVE, - } + ...a, + segments: a.segments.toSpliced( + a.segments.length - 2, + 1, + { + ...a.segments[a.segments.length - 1], + next: component.id, + }, + ), + target: component.id, + type: ActionKind.MOVE, + } : a, ), }, @@ -232,9 +234,9 @@ export function moveComponent( ...component, pos: isPhantom ? { - type: "fixed", - ...newPos, - } + type: "fixed", + ...newPos, + } : newPos, }, content, @@ -313,12 +315,15 @@ export function computeTerminalState( content.components.filter((c) => c.type !== "phantom") as ( | Player | CourtObject - )[] + )[] const componentsTargetedState = nonPhantomComponents.map((comp) => comp.type === "player" ? getPlayerTerminalState(comp, content, computedPositions) - : comp, + : { + ...comp, + frozen: true, + }, ) return { @@ -396,6 +401,11 @@ export function drainTerminalStateOnChildContent( ): StepContent | null { let gotUpdated = false + //filter out all frozen components that are not present on the parent's terminal state anymore + childContent = { + components: childContent.components.filter(comp => comp.type === "phantom" || (comp.frozen && tryGetComponent(comp.id, parentTerminalState.components))) + } + for (const parentComponent of parentTerminalState.components) { const childComponent = tryGetComponent( parentComponent.id, diff --git a/src/model/tactic/CourtObjects.ts b/src/model/tactic/CourtObjects.ts index 5f72199..6751e65 100644 --- a/src/model/tactic/CourtObjects.ts +++ b/src/model/tactic/CourtObjects.ts @@ -7,4 +7,6 @@ export const BALL_TYPE = "ball" //place here all different kinds of objects export type CourtObject = Ball -export type Ball = Component +export interface Ball extends Component { + readonly frozen: boolean +} diff --git a/src/pages/Editor.tsx b/src/pages/Editor.tsx index da9697d..9d9c4f6 100644 --- a/src/pages/Editor.tsx +++ b/src/pages/Editor.tsx @@ -131,7 +131,7 @@ function EditorPortal({ guestMode }: EditorPageProps) { function GuestModeEditor() { const storageContent = localStorage.getItem( - GUEST_MODE_STEP_CONTENT_STORAGE_KEY + "0", + GUEST_MODE_STEP_CONTENT_STORAGE_KEY + ROOT_STEP_ID, ) const stepInitialContent: StepContent = { @@ -148,7 +148,7 @@ function GuestModeEditor() { if (storageContent == null) { localStorage.setItem( GUEST_MODE_STEP_ROOT_NODE_INFO_STORAGE_KEY, - JSON.stringify({ id: 0, children: [] }), + JSON.stringify({ id: ROOT_STEP_ID, children: [] }), ) localStorage.setItem( GUEST_MODE_STEP_CONTENT_STORAGE_KEY + ROOT_STEP_ID, @@ -156,6 +156,8 @@ function GuestModeEditor() { ) } + const tacticName = localStorage.getItem(GUEST_MODE_TITLE_STORAGE_KEY) ?? "Nouvelle Tactique" + const courtRef = useRef(null) const [stepId, setStepId] = useState(ROOT_STEP_ID) const [stepContent, setStepContent, saveState] = useContentState( @@ -212,9 +214,7 @@ function GuestModeEditor() { tactic={{ id: -1, rootStepNode, - name: - localStorage.getItem(GUEST_MODE_TITLE_STORAGE_KEY) ?? - "Nouvelle Tactique", + name: tacticName, courtType: "PLAIN", }} courtRef={courtRef} @@ -244,9 +244,10 @@ function GuestModeEditor() { const nodeId = getAvailableId(root) const node = { id: nodeId, children: [] } + const resultTree = addStepNode(root, parent, node) localStorage.setItem( GUEST_MODE_STEP_ROOT_NODE_INFO_STORAGE_KEY, - JSON.stringify(addStepNode(root, parent, node)), + JSON.stringify(resultTree), ) localStorage.setItem( GUEST_MODE_STEP_CONTENT_STORAGE_KEY + node.id,