diff --git a/src/components/Board/Items/Item/Image.js b/src/components/Board/Items/Item/Image.js index ebccd23..d9905ae 100644 --- a/src/components/Board/Items/Item/Image.js +++ b/src/components/Board/Items/Item/Image.js @@ -63,7 +63,6 @@ const Image = ({ content = "/default.png", backContent, flipped = false, - setState, unflippedFor, text, backText, @@ -78,38 +77,11 @@ const Image = ({ size.height = height; } - const onDblClick = React.useCallback( - (e) => { - if (!backContent) return; - if (e.ctrlKey) { - // Reveal only for current player - setState((prevItem) => { - if (prevItem.unflippedFor !== undefined) { - return { ...prevItem, unflippedFor: undefined }; - } else { - return { - ...prevItem, - unflippedFor: currentUser.id, - flipped: true, - }; - } - }); - } else { - setState((prevItem) => ({ - ...prevItem, - flipped: !prevItem.flipped, - unflippedFor: undefined, - })); - } - }, - [setState, currentUser.id, backContent] - ); - const flippedForMe = backContent && flipped && unflippedFor !== currentUser.id; return ( - + {unflippedFor === currentUser.id && Only you} {flippedForMe && backText && } {(!flippedForMe || !backText) && text && } diff --git a/src/components/Board/Items/Item/allItems.js b/src/components/Board/Items/Item/allItems.js index 458330f..4cf7ecc 100644 --- a/src/components/Board/Items/Item/allItems.js +++ b/src/components/Board/Items/Item/allItems.js @@ -35,9 +35,17 @@ export const itemMap = { component: Image, defaultActions: (item) => { if (item.backContent) { - return ["flip", "tap", "lock", "remove", "stack"]; + return [ + "flip", + "flipSelf", + "tap", + "stack", + "shuffle", + "lock", + "remove", + ]; } else { - return ["tap", "lock", "remove", "stack"]; + return ["tap", "stack", "shuffle", "lock", "remove"]; } }, form: ImageFormFields, diff --git a/src/components/SelectedItemsPane.js b/src/components/SelectedItemsPane.js index 4caa209..920ec36 100644 --- a/src/components/SelectedItemsPane.js +++ b/src/components/SelectedItemsPane.js @@ -4,7 +4,7 @@ import styled from "styled-components"; import { useRecoilValue } from "recoil"; import { useItems } from "./Board/Items"; import { useItemActions } from "./Board/Items"; -import { selectedItemsAtom } from "../components/Board/Selector"; +import { selectedItemsAtom } from "../components/Board/"; import { insideClass } from "../utils"; @@ -50,32 +50,90 @@ export const SelectedItems = ({ edit }) => { const selectedItems = useRecoilValue(selectedItemsAtom); + const actionMap = React.useMemo( + () => ({ + flip: { + action: toggleFlip, + label: t("Reveal") + "/" + t("Hide"), + shortcut: "f", + }, + flipSelf: { + action: revealForMe, + label: t("Reveal for me"), + shortcut: "o", + }, + tap: { + action: toggleTap, + label: t("Tap") + "/" + t("Untap"), + shortcut: "t", + }, + rotate90: { + action: rotate.bind(null, 90), + label: t("Rotate 90"), + }, + rotate60: { + action: rotate.bind(null, 60), + label: t("Rotate 60"), + }, + rotate45: { + action: rotate.bind(null, 45), + label: t("Rotate 45"), + }, + rotate30: { + action: rotate.bind(null, 30), + label: t("Rotate 30"), + }, + stack: { + action: align, + label: t("Stack"), + shortcut: "", + multiple: true, + }, + shuffle: { + action: shuffle, + label: t("Shuffle"), + shortcut: "", + multiple: true, + }, + lock: { + action: toggleLock, + label: t("Unlock") + "/" + t("Lock"), + }, + remove: { + action: remove, + label: t("Remove all"), + shortcut: "r", + edit: true, + }, + }), + [ + align, + remove, + revealForMe, + rotate, + shuffle, + t, + toggleFlip, + toggleLock, + toggleTap, + ] + ); + React.useEffect(() => { const onKeyUp = (e) => { // Block shortcut if we are typing in a textarea or input if (["INPUT", "TEXTAREA"].includes(e.target.tagName)) return; - if (e.key === "f") { - if (insideClass(e.target, "item")) return; - toggleFlip(); - } - if (e.key === "t") { - if (insideClass(e.target, "item")) return; - toggleTap(); - } - if (e.key === "o") { - if (insideClass(e.target, "item")) return; - revealForMe(); - } - if (e.key === "r") { - if (insideClass(e.target, "item")) return; - remove(); - } + Object.values(actionMap).forEach(({ shortcut, action }) => { + if (e.key === shortcut) { + action(); + } + }); }; document.addEventListener("keyup", onKeyUp); return () => { document.removeEventListener("keyup", onKeyUp); }; - }, [revealForMe, toggleFlip, toggleTap, remove]); + }, [actionMap]); const onSubmitHandler = React.useCallback( (formValues) => { @@ -87,6 +145,29 @@ export const SelectedItems = ({ edit }) => { [updateItem] ); + const onDblClick = React.useCallback( + (e) => { + const foundElement = insideClass(e.target, "item"); + // We dblclick oustside of an element + if (!foundElement) return; + + if (e.ctrlKey && availableActions.length > 1) { + // Use second action + actionMap[availableActions[1]].action(); + } else { + actionMap[availableActions[0]].action(); + } + }, + [actionMap, availableActions] + ); + + React.useEffect(() => { + document.addEventListener("dblclick", onDblClick); + return () => { + document.removeEventListener("dblclick", onDblClick); + }; + }, [onDblClick]); + if (selectedItems.length === 0) { return null; } @@ -135,62 +216,21 @@ export const SelectedItems = ({ edit }) => {

{t("items selected", { count: selectedItems.length })}

- {availableActions.includes("flip") && ( - - )} - {availableActions.includes("tap") && ( - - )} - {availableActions.includes("rotate90") && ( - - )} - {availableActions.includes("rotate60") && ( - - )} - {availableActions.includes("rotate45") && ( - - )} - {availableActions.includes("rotate30") && ( - - )} - {selectedItems.length > 1 && ( - <> - - - - )} - {availableActions.includes("lock") && ( - - )} - {edit && } + {availableActions.map((action) => { + const { + label, + action: handler, + multiple, + edit: onlyEdit, + } = actionMap[action]; + if (multiple && selectedItems.length < 2) return null; + if (onlyEdit && !edit) return null; + return ( + + ); + })}