2021-02-06 13:32:38 +11:00
|
|
|
import React, { useEffect, useState } from "react";
|
2021-06-17 11:05:25 +10:00
|
|
|
import { Box, Flex, Text, IconButton } from "theme-ui";
|
2020-11-06 13:35:11 +11:00
|
|
|
|
|
|
|
|
import Slider from "../Slider";
|
2021-06-17 11:05:25 +10:00
|
|
|
import TextareaAutosize from "../TextareaAutoSize";
|
2020-11-04 15:03:34 +11:00
|
|
|
|
|
|
|
|
import MapMenu from "../map/MapMenu";
|
|
|
|
|
|
|
|
|
|
import colors, { colorOptions } from "../../helpers/colors";
|
|
|
|
|
|
2021-02-04 15:06:34 +11:00
|
|
|
import usePrevious from "../../hooks/usePrevious";
|
2020-11-04 15:03:34 +11:00
|
|
|
|
|
|
|
|
import LockIcon from "../../icons/TokenLockIcon";
|
|
|
|
|
import UnlockIcon from "../../icons/TokenUnlockIcon";
|
|
|
|
|
import ShowIcon from "../../icons/TokenShowIcon";
|
|
|
|
|
import HideIcon from "../../icons/TokenHideIcon";
|
2021-01-25 10:03:20 +11:00
|
|
|
import NoteIcon from "../../icons/NoteToolIcon";
|
|
|
|
|
import TextIcon from "../../icons/NoteTextIcon";
|
2020-11-04 15:03:34 +11:00
|
|
|
|
2021-06-24 16:14:20 +10:00
|
|
|
import { useUserId } from "../../contexts/UserIdContext";
|
2020-11-04 15:03:34 +11:00
|
|
|
|
|
|
|
|
const defaultNoteMaxSize = 6;
|
|
|
|
|
|
2020-11-05 14:41:33 +11:00
|
|
|
function NoteMenu({
|
2020-11-04 15:03:34 +11:00
|
|
|
isOpen,
|
|
|
|
|
onRequestClose,
|
|
|
|
|
note,
|
|
|
|
|
noteNode,
|
|
|
|
|
onNoteChange,
|
|
|
|
|
map,
|
|
|
|
|
}) {
|
2021-06-24 16:14:20 +10:00
|
|
|
const userId = useUserId();
|
2020-11-04 15:03:34 +11:00
|
|
|
|
|
|
|
|
const wasOpen = usePrevious(isOpen);
|
|
|
|
|
|
|
|
|
|
const [noteMaxSize, setNoteMaxSize] = useState(defaultNoteMaxSize);
|
|
|
|
|
const [menuLeft, setMenuLeft] = useState(0);
|
|
|
|
|
const [menuTop, setMenuTop] = useState(0);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (isOpen && !wasOpen && note) {
|
|
|
|
|
setNoteMaxSize(Math.max(note.size, defaultNoteMaxSize));
|
|
|
|
|
// Update menu position
|
|
|
|
|
if (noteNode) {
|
|
|
|
|
const nodeRect = noteNode.getClientRect();
|
|
|
|
|
const mapElement = document.querySelector(".map");
|
|
|
|
|
const mapRect = mapElement.getBoundingClientRect();
|
|
|
|
|
|
|
|
|
|
// Center X for the menu which is 156px wide
|
|
|
|
|
setMenuLeft(mapRect.left + nodeRect.x + nodeRect.width / 2 - 156 / 2);
|
|
|
|
|
// Y 12px from the bottom
|
|
|
|
|
setMenuTop(mapRect.top + nodeRect.y + nodeRect.height + 12);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, [isOpen, note, wasOpen, noteNode]);
|
|
|
|
|
|
|
|
|
|
function handleTextChange(event) {
|
2021-02-13 10:45:28 +11:00
|
|
|
const text = event.target.value.substring(0, 1024);
|
2020-11-04 15:03:34 +11:00
|
|
|
note && onNoteChange({ ...note, text: text });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleColorChange(color) {
|
|
|
|
|
if (!note) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
onNoteChange({ ...note, color: color });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleSizeChange(event) {
|
2020-11-06 15:48:35 +11:00
|
|
|
const newSize = parseFloat(event.target.value);
|
2020-11-04 15:03:34 +11:00
|
|
|
note && onNoteChange({ ...note, size: newSize });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleVisibleChange() {
|
|
|
|
|
note && onNoteChange({ ...note, visible: !note.visible });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleLockChange() {
|
|
|
|
|
note && onNoteChange({ ...note, locked: !note.locked });
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-25 10:03:20 +11:00
|
|
|
function handleModeChange() {
|
|
|
|
|
note && onNoteChange({ ...note, textOnly: !note.textOnly });
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 15:03:34 +11:00
|
|
|
function handleModalContent(node) {
|
|
|
|
|
if (node) {
|
|
|
|
|
// Focus input
|
|
|
|
|
const tokenLabelInput = node.querySelector("#changeNoteText");
|
|
|
|
|
tokenLabelInput.focus();
|
|
|
|
|
tokenLabelInput.select();
|
|
|
|
|
|
|
|
|
|
// Ensure menu is in bounds
|
|
|
|
|
const nodeRect = node.getBoundingClientRect();
|
|
|
|
|
const mapElement = document.querySelector(".map");
|
|
|
|
|
const mapRect = mapElement.getBoundingClientRect();
|
|
|
|
|
setMenuLeft((prevLeft) =>
|
|
|
|
|
Math.min(
|
|
|
|
|
mapRect.right - nodeRect.width,
|
|
|
|
|
Math.max(mapRect.left, prevLeft)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
setMenuTop((prevTop) =>
|
|
|
|
|
Math.min(mapRect.bottom - nodeRect.height, prevTop)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 12:36:48 +11:00
|
|
|
function handleTextKeyPress(e) {
|
|
|
|
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
onRequestClose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 15:03:34 +11:00
|
|
|
return (
|
|
|
|
|
<MapMenu
|
|
|
|
|
isOpen={isOpen}
|
|
|
|
|
onRequestClose={onRequestClose}
|
|
|
|
|
top={`${menuTop}px`}
|
|
|
|
|
left={`${menuLeft}px`}
|
|
|
|
|
onModalContent={handleModalContent}
|
|
|
|
|
>
|
2021-01-21 14:47:49 +11:00
|
|
|
<Box sx={{ width: "156px", overflow: "hidden" }} p={1}>
|
2020-11-04 15:03:34 +11:00
|
|
|
<Flex
|
|
|
|
|
as="form"
|
|
|
|
|
onSubmit={(e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
onRequestClose();
|
|
|
|
|
}}
|
|
|
|
|
sx={{ alignItems: "center" }}
|
|
|
|
|
>
|
2021-06-17 11:05:25 +10:00
|
|
|
<TextareaAutosize
|
2020-11-04 15:03:34 +11:00
|
|
|
id="changeNoteText"
|
|
|
|
|
onChange={handleTextChange}
|
|
|
|
|
value={(note && note.text) || ""}
|
2021-01-14 12:36:48 +11:00
|
|
|
onKeyPress={handleTextKeyPress}
|
2021-06-17 11:05:25 +10:00
|
|
|
maxRows={4}
|
2020-11-04 15:03:34 +11:00
|
|
|
/>
|
|
|
|
|
</Flex>
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexWrap: "wrap",
|
|
|
|
|
justifyContent: "space-between",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{colorOptions.map((color) => (
|
|
|
|
|
<Box
|
|
|
|
|
key={color}
|
|
|
|
|
sx={{
|
|
|
|
|
width: "16.66%",
|
|
|
|
|
paddingTop: "16.66%",
|
|
|
|
|
borderRadius: "50%",
|
|
|
|
|
transform: "scale(0.75)",
|
|
|
|
|
backgroundColor: colors[color],
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
}}
|
|
|
|
|
onClick={() => handleColorChange(color)}
|
|
|
|
|
aria-label={`Note label Color ${color}`}
|
|
|
|
|
>
|
|
|
|
|
{note && note.color === color && (
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
width: "100%",
|
|
|
|
|
height: "100%",
|
|
|
|
|
border: "2px solid white",
|
|
|
|
|
position: "absolute",
|
|
|
|
|
top: 0,
|
|
|
|
|
borderRadius: "50%",
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Box>
|
|
|
|
|
))}
|
|
|
|
|
</Box>
|
|
|
|
|
<Flex sx={{ alignItems: "center" }}>
|
|
|
|
|
<Text
|
|
|
|
|
as="label"
|
|
|
|
|
variant="body2"
|
|
|
|
|
sx={{ width: "40%", fontSize: "16px" }}
|
|
|
|
|
p={1}
|
|
|
|
|
>
|
|
|
|
|
Size:
|
|
|
|
|
</Text>
|
|
|
|
|
<Slider
|
|
|
|
|
value={(note && note.size) || 1}
|
|
|
|
|
onChange={handleSizeChange}
|
2020-11-06 15:48:35 +11:00
|
|
|
step={0.5}
|
|
|
|
|
min={0.5}
|
2020-11-04 15:03:34 +11:00
|
|
|
max={noteMaxSize}
|
|
|
|
|
mr={1}
|
|
|
|
|
/>
|
|
|
|
|
</Flex>
|
|
|
|
|
{/* Only show hide and lock token actions to map owners */}
|
|
|
|
|
{map && map.owner === userId && (
|
|
|
|
|
<Flex sx={{ alignItems: "center", justifyContent: "space-around" }}>
|
|
|
|
|
<IconButton
|
|
|
|
|
onClick={handleVisibleChange}
|
|
|
|
|
title={note && note.visible ? "Hide Note" : "Show Note"}
|
|
|
|
|
aria-label={note && note.visible ? "Hide Note" : "Show Note"}
|
|
|
|
|
>
|
|
|
|
|
{note && note.visible ? <ShowIcon /> : <HideIcon />}
|
|
|
|
|
</IconButton>
|
|
|
|
|
<IconButton
|
|
|
|
|
onClick={handleLockChange}
|
|
|
|
|
title={note && note.locked ? "Unlock Note" : "Lock Note"}
|
|
|
|
|
aria-label={note && note.locked ? "Unlock Note" : "Lock Note"}
|
|
|
|
|
>
|
|
|
|
|
{note && note.locked ? <LockIcon /> : <UnlockIcon />}
|
|
|
|
|
</IconButton>
|
2021-01-25 10:03:20 +11:00
|
|
|
<IconButton
|
|
|
|
|
onClick={handleModeChange}
|
|
|
|
|
title={note && note.textOnly ? "Note Mode" : "Text Mode"}
|
|
|
|
|
aria-label={note && note.textOnly ? "Note Mode" : "Text Mode"}
|
|
|
|
|
>
|
|
|
|
|
{note && note.textOnly ? <TextIcon /> : <NoteIcon />}
|
|
|
|
|
</IconButton>
|
2020-11-04 15:03:34 +11:00
|
|
|
</Flex>
|
|
|
|
|
)}
|
|
|
|
|
</Box>
|
|
|
|
|
</MapMenu>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-05 14:41:33 +11:00
|
|
|
export default NoteMenu;
|