mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
[WEB-1204] fix: Kanban and calendar drag and drop in mobile (#4408)
* chore: don't show context menu on mobile devices * fix: drag and drop in mobile * chore: default show more options in mobile * fix: dnd in calendar layout
This commit is contained in:
parent
33079c826d
commit
26188f208b
@ -38,3 +38,5 @@ export const ControlLink = React.forwardRef<HTMLAnchorElement, TControlLink>((pr
|
||||
</a>
|
||||
);
|
||||
});
|
||||
|
||||
ControlLink.displayName = "ControlLink";
|
||||
|
@ -6,6 +6,7 @@ import { ContextMenuItem } from "./item";
|
||||
import { cn } from "../../../helpers";
|
||||
// hooks
|
||||
import useOutsideClickDetector from "../../hooks/use-outside-click-detector";
|
||||
import { usePlatformOS } from "../../hooks/use-platform-os";
|
||||
|
||||
export type TContextMenuItem = {
|
||||
key: string;
|
||||
@ -38,6 +39,7 @@ const ContextMenuWithoutPortal: React.FC<ContextMenuProps> = (props) => {
|
||||
const contextMenuRef = useRef<HTMLDivElement>(null);
|
||||
// derived values
|
||||
const renderedItems = items.filter((item) => item.shouldRender !== false);
|
||||
const { isMobile } = usePlatformOS();
|
||||
|
||||
const handleClose = () => {
|
||||
setIsOpen(false);
|
||||
@ -51,6 +53,8 @@ const ContextMenuWithoutPortal: React.FC<ContextMenuProps> = (props) => {
|
||||
if (!parentElement || !contextMenu) return;
|
||||
|
||||
const handleContextMenu = (e: MouseEvent) => {
|
||||
if (isMobile) return;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
@ -83,7 +87,7 @@ const ContextMenuWithoutPortal: React.FC<ContextMenuProps> = (props) => {
|
||||
parentElement.removeEventListener("contextmenu", handleContextMenu);
|
||||
window.removeEventListener("keydown", hideContextMenu);
|
||||
};
|
||||
}, [contextMenuRef, isOpen, parentRef, setIsOpen, setPosition]);
|
||||
}, [contextMenuRef, isMobile, isOpen, parentRef, setIsOpen, setPosition]);
|
||||
|
||||
// handle keyboard navigation
|
||||
useEffect(() => {
|
||||
|
15
packages/ui/src/hooks/use-platform-os.ts
Normal file
15
packages/ui/src/hooks/use-platform-os.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export const usePlatformOS = () => {
|
||||
// states
|
||||
const [isMobile, setIsMobile] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const userAgent = window.navigator.userAgent;
|
||||
const isMobile = /iPhone|iPad|iPod|Android/i.test(userAgent);
|
||||
|
||||
if (isMobile) setIsMobile(isMobile);
|
||||
}, []);
|
||||
|
||||
return { isMobile };
|
||||
};
|
@ -71,7 +71,7 @@ export const CalendarIssueBlock = observer(
|
||||
target="_blank"
|
||||
onClick={() => handleIssuePeekOverview(issue)}
|
||||
className="block w-full text-sm text-custom-text-100 rounded border-b md:border-[1px] border-custom-border-200 hover:border-custom-border-400"
|
||||
disabled={!!issue?.tempId}
|
||||
disabled={!!issue?.tempId || isMobile}
|
||||
ref={ref}
|
||||
>
|
||||
<>
|
||||
@ -105,9 +105,10 @@ export const CalendarIssueBlock = observer(
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div
|
||||
className={`flex-shrink-0 md:hidden h-5 w-5 group-hover/calendar-block:block ${
|
||||
isMenuActive ? "!block" : ""
|
||||
}`}
|
||||
className={cn("flex-shrink-0 size-5", {
|
||||
"hidden group-hover/calendar-block:block": !isMobile,
|
||||
block: isMenuActive,
|
||||
})}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
@ -63,7 +63,9 @@ const KanbanIssueDetailsBlock: React.FC<IssueDetailsBlockProps> = observer((prop
|
||||
{getProjectIdentifierById(issue.project_id)}-{issue.sequence_id}
|
||||
</div>
|
||||
<div
|
||||
className="absolute -top-1 right-0 hidden group-hover/kanban-block:block"
|
||||
className={cn("absolute -top-1 right-0", {
|
||||
"hidden group-hover/kanban-block:block": !isMobile,
|
||||
})}
|
||||
onClick={handleEventPropagation}
|
||||
>
|
||||
{quickActions({
|
||||
@ -116,6 +118,7 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = observer((props) => {
|
||||
// hooks
|
||||
const { workspaceSlug } = useAppRouter();
|
||||
const { getIsIssuePeeked, setPeekIssue } = useIssueDetail();
|
||||
const { isMobile } = usePlatformOS();
|
||||
|
||||
const handleIssuePeekOverview = (issue: TIssue) =>
|
||||
workspaceSlug &&
|
||||
@ -210,7 +213,7 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = observer((props) => {
|
||||
)}
|
||||
target="_blank"
|
||||
onClick={() => handleIssuePeekOverview(issue)}
|
||||
disabled={!!issue?.tempId}
|
||||
disabled={!!issue?.tempId || isMobile}
|
||||
>
|
||||
<RenderIfVisible
|
||||
classNames="space-y-2 px-3 py-2"
|
||||
|
20
yarn.lock
20
yarn.lock
@ -7945,16 +7945,7 @@ streamx@^2.15.0, streamx@^2.16.1:
|
||||
optionalDependencies:
|
||||
bare-events "^2.2.0"
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^4.1.0:
|
||||
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@ -8034,14 +8025,7 @@ stringify-object@^3.3.0:
|
||||
is-obj "^1.0.1"
|
||||
is-regexp "^1.0.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
|
Loading…
Reference in New Issue
Block a user