diff --git a/src/index.ts b/src/index.ts index ae16fa7..bed17cf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ -import { StickyNote, Image } from "@mirohq/websdk-types"; -import { getStickiesToChopInTree } from "./todo-tree-helper"; +import { StickyNote, Image, Group, BaseItem, GroupableItem } from "@mirohq/websdk-types"; +import { getStickiesToChopInTree, getTypedMiroItem } from "./todo-tree-helper"; export const init = async () => { miro.board.ui.on('icon:click', async () => { @@ -34,30 +34,83 @@ interface AxeAnimationArgs { onChopped: () => void } +type RotatableItem = BaseItem & { rotation: number }; + +interface ItemState { + item: GroupableItem; + x: number; + y: number; + rotation: number; + deltaX: number; + deltaY: number; +} + +const MOVABLE_TYPES = ["card", "shape", "frame", "image", "text", "app_card", "sticky_note"]; +const ROTATABLE_TYPES = ["card", "shape", "image", "text", "app_card", "sticky_note"]; + +const isMovable = (item: GroupableItem) => MOVABLE_TYPES.includes(item.type); +const isRotatable = (item: GroupableItem) => ROTATABLE_TYPES.includes(item.type); + +const updateItemPosition = async (state: ItemState, x: number, y: number, rotation?: number) => { + if (!isMovable(state.item)) + return; + + (state.item as BaseItem).x = x; + (state.item as BaseItem).y = y; + if (rotation !== undefined && isRotatable(state.item)) { + (state.item as RotatableItem).rotation = rotation; + } + await state.item.sync(); +}; + const playAxeAnimation = async ({axe, stickyNote, onChopped}: AxeAnimationArgs) => { - const originalX = axe.x; - const originalY = axe.y; + const groupItems = axe.groupId + ? await (await getTypedMiroItem(axe.groupId, "group"))?.getItems() ?? [axe] + : [axe]; + + const initialStates: ItemState[] = groupItems.map(item => ({ + item, + x: (item as BaseItem).x, + y: (item as BaseItem).y, + rotation: isRotatable(item) ? (item as RotatableItem).rotation : 0, + deltaX: (item as BaseItem).x - axe.x, + deltaY: (item as BaseItem).y - axe.y + })); await miro.board.bringToFront(axe); - axe.x = stickyNote.x; - axe.y = stickyNote.y; - await axe.sync(); + const deltaX = stickyNote.x - axe.x; + const deltaY = stickyNote.y - axe.y; + // Move to target + for (const state of initialStates) { + await updateItemPosition(state, state.x + deltaX, state.y + deltaY); + } + + // Rotation animation + const rad = Math.PI / 2; + const cos = Math.cos(rad); + const sin = Math.sin(rad); + for (let i = 0; i < 3; i++) { - axe.rotation = 90; - await axe.sync(); + for (const state of initialStates) { + const rotatedX = stickyNote.x + (state.deltaX * cos - state.deltaY * sin); + const rotatedY = stickyNote.y + (state.deltaX * sin + state.deltaY * cos); + await updateItemPosition(state, rotatedX, rotatedY, state.rotation + 90); + } await new Promise(resolve => setTimeout(resolve, 300)); - axe.rotation = 0; - await axe.sync(); + for (const state of initialStates) { + await updateItemPosition(state, stickyNote.x + state.deltaX, stickyNote.y + state.deltaY, state.rotation); + } await new Promise(resolve => setTimeout(resolve, 300)); } onChopped(); - axe.x = originalX; - axe.y = originalY; - await axe.sync(); + // Move back to original position + for (const state of initialStates) { + await updateItemPosition(state, state.x, state.y); + } } const postInfoNotification = async (message: string) => diff --git a/src/todo-tree-helper.ts b/src/todo-tree-helper.ts index 857ad27..0f76916 100644 --- a/src/todo-tree-helper.ts +++ b/src/todo-tree-helper.ts @@ -1,6 +1,6 @@ import { Connector, Item, StickyNote } from "@mirohq/websdk-types"; -const getTypedMiroItem = async (id: string, type: T['type']): Promise => { +export const getTypedMiroItem = async (id: string, type: T['type']): Promise => { const item = await miro.board.getById(id); return item?.type === type ? item as T : undefined; };