diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/CommentThreads/CommentThread.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/CommentThreads/CommentThread.tsx index 1c56c5a4875..ebf55e293c4 100644 --- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/CommentThreads/CommentThread.tsx +++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/CommentThreads/CommentThread.tsx @@ -14,121 +14,123 @@ import { useOvermind } from 'app/overmind'; import { formatDistance } from 'date-fns'; import React from 'react'; -export const CommentThread = React.memo<{ commentThread: TCommentThread }>( - ({ commentThread }) => { - const { state, actions } = useOvermind(); +export const CommentThread = React.memo<{ + commentThread: TCommentThread; + innerRef: React.RefObject; +}>(({ commentThread, innerRef }) => { + const { state, actions } = useOvermind(); - const truncateText = { - maxHeight: 52, - overflow: 'hidden', - textOverflow: 'ellipsis', - maxWidth: '100%', - display: 'block', - // @ts-ignore - // eslint-disable-next-line no-dupe-keys - display: '-webkit-box', - '-webkit-line-clamp': '3', - '-webkit-box-orient': 'vertical', - }; + const truncateText = { + maxHeight: 52, + overflow: 'hidden', + textOverflow: 'ellipsis', + maxWidth: '100%', + display: 'block', + // @ts-ignore + // eslint-disable-next-line no-dupe-keys + display: '-webkit-box', + '-webkit-line-clamp': '3', + '-webkit-box-orient': 'vertical', + }; - return ( - theme.speeds[1], - opacity: commentThread.isResolved ? 0.2 : 1, - paddingRight: 0, // the actions menu should be at the edge - })} - > - - actions.editor.selectCommentThread(commentThread.id)} - > - - - - {commentThread.initialComment.user.username} - - - {formatDistance( - new Date(commentThread.insertedAt), - new Date(), - { - addSuffix: true, - } - )} - - + return ( + theme.speeds[1], + opacity: commentThread.isResolved ? 0.2 : 1, + paddingRight: 0, // the actions menu should be at the edge + })} + onClick={event => { + const target = event.target as HTMLElement; + // don't trigger comment if you click on the menu + // we have to handle this because of an upstream + // bug in reach/menu-button + if (target.tagName === 'button' || target.tagName === 'svg') { + return; + } + + actions.editor.selectCommentThread(commentThread.id); + }} + > + + + + + + {commentThread.initialComment.user.username} + + + {formatDistance(new Date(commentThread.insertedAt), new Date(), { + addSuffix: true, + })} + - - {commentThread.isResolved && ( - - )} - - - + + + {commentThread.isResolved && ( + + )} + + + + + actions.editor.resolveCommentThread({ + commentThreadId: commentThread.id, + isResolved: !commentThread.isResolved, + }) + } + > + Mark as {commentThread.isResolved ? 'Unr' : 'r'}esolved + + {}}>Share Comment + {state.user.id === commentThread.initialComment.user.id && ( - actions.editor.resolveCommentThread({ - commentThreadId: commentThread.id, - isResolved: !commentThread.isResolved, + actions.editor.deleteComment({ + threadId: commentThread.id, + commentId: commentThread.initialComment.id, }) } > - Mark as {commentThread.isResolved ? 'Unr' : 'r'}esolved + Delete - {}}>Share Comment - {state.user.id === commentThread.initialComment.user.id && ( - - actions.editor.deleteComment({ - threadId: commentThread.id, - commentId: commentThread.initialComment.id, - }) - } - > - Delete - - )} - - - + )} + + - actions.editor.selectCommentThread(commentThread.id)} - as="p" - marginY={0} - marginRight={2 /** Adjust for the missing margin in ListAction */} - paddingBottom={ - 6 /** Use padding instead of margin for inset border */ - } - css={css({ - borderBottom: '1px solid', - borderColor: 'sideBar.border', - })} - > - - {commentThread.initialComment.content} - - - {getRepliesString(commentThread.comments.length)} - - - - ); - } -); + + + + {commentThread.initialComment.content} + + + {getRepliesString(commentThread.comments.length)} + + + + ); +}); const getRepliesString = length => { if (length === 0) return 'No Replies'; diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/CommentThreads/Dialog/index.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/CommentThreads/Dialog/index.tsx index 8f41345d623..fb20f57a9af 100644 --- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/CommentThreads/Dialog/index.tsx +++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/CommentThreads/Dialog/index.tsx @@ -16,6 +16,7 @@ import { formatDistance } from 'date-fns'; import React, { useState } from 'react'; import ReactDOM from 'react-dom'; import Draggable from 'react-draggable'; +import { motion } from 'framer-motion'; import { Markdown } from './Markdown'; import { Reply } from './Reply'; @@ -24,17 +25,13 @@ import { useScrollTop } from './use-scroll-top'; export const CommentDialog = props => ReactDOM.createPortal(, document.body); -export const Dialog = props => { +export const Dialog = ({ triggerRef }) => { const { state, actions } = useOvermind(); const [value, setValue] = useState(''); const [edit, setEdit] = useState(false); const thread = state.editor.currentCommentThread; const [editValue, setEditValue] = useState(thread.initialComment.content); - const [position, setPosition] = useState({ - x: props.x || 200, - y: props.y || 40, - }); const closeDialog = () => actions.editor.selectCommentThread(null); const onSubmit = () => { @@ -49,6 +46,23 @@ export const Dialog = props => { } }; + const [position, setPosition] = useState({ x: 400, y: 40 }); + const OVERLAP_WITH_SIDEBAR = 20; + const OFFSET_FROM_SIDEBAR_COMMENT = 90; + + const [animateFrom, setAnimateFrom] = React.useState({ x: 0, y: 0 }); + + React.useEffect(() => { + if (triggerRef.current) { + const { left, right, top } = triggerRef.current.getBoundingClientRect(); + setAnimateFrom({ x: left, y: top }); + setPosition({ + x: right - OVERLAP_WITH_SIDEBAR, + y: top - OFFSET_FROM_SIDEBAR_COMMENT, + }); + } + }, [triggerRef]); + const onDragStop = (_, data) => { setPosition({ x: data.x, @@ -58,202 +72,223 @@ export const Dialog = props => { const { ref: listRef, scrollTop } = useScrollTop(); + // if trigger ref was passed but it's value hasn't + // been set yet, wait (return null) until it is set + if (triggerRef && !triggerRef.current) return null; + return ( - - scrollTop > 0 - ? `0px 32px 32px ${theme.colors.dialog.background}` - : 'none', + backgroundColor: 'dialog.background', + color: 'dialog.foreground', + border: '1px solid', + borderColor: 'dialog.border', + borderRadius: 4, + width: 420, + height: 'auto', + maxHeight: '80vh', + fontFamily: 'Inter, sans-serif', + overflow: 'hidden', + boxShadow: 2, })} > - - Comment - - - - actions.editor.resolveCommentThread({ - commentThreadId: thread.id, - isResolved: !thread.isResolved, - }) - } - name="check" - size={14} - title="Resolve Comment" - css={css({ - transition: 'color', - transitionDuration: theme => theme.speeds[1], - color: thread.isResolved ? 'green' : 'mutedForeground', - })} - /> - + + scrollTop > 0 + ? `0px 32px 32px ${theme.colors.dialog.background}` + : 'none', + })} + > + + Comment + + + + actions.editor.resolveCommentThread({ + commentThreadId: thread.id, + isResolved: !thread.isResolved, + }) + } + name="check" + size={14} + title="Resolve Comment" + css={css({ + transition: 'color', + transitionDuration: theme => theme.speeds[1], + color: thread.isResolved ? 'green' : 'mutedForeground', + })} + /> + + - - {thread && ( - - - - - - - - {thread.initialComment.user.username} - - - {formatDistance(new Date(thread.insertedAt), new Date(), { - addSuffix: true, - })} - + {thread && ( + + + + + + + + {thread.initialComment.user.username} + + + {formatDistance( + new Date(thread.insertedAt), + new Date(), + { + addSuffix: true, + } + )} + + + {state.user.id === thread.initialComment.user.id && ( + + + + + + actions.editor.deleteComment({ + threadId: thread.id, + commentId: thread.initialComment.id, + }) + } + > + Delete + + setEdit(true)}> + Edit Comment + + + + + )} - {state.user.id === thread.initialComment.user.id && ( - - - - - - actions.editor.deleteComment({ + + {!edit ? ( + + ) : ( + <> + +