diff --git a/packages/superdoc/package.json b/packages/superdoc/package.json index 9bbf053ea0..df1c1e3b52 100644 --- a/packages/superdoc/package.json +++ b/packages/superdoc/package.json @@ -1,7 +1,7 @@ { "name": "@harbour-enterprises/superdoc", "type": "module", - "version": "1.0.0-alpha.8", + "version": "1.0.0-alpha.16", "files": [ "dist" ], diff --git a/packages/superdoc/src/Superdoc.vue b/packages/superdoc/src/Superdoc.vue index 1d63064f7b..bf68d75fdb 100644 --- a/packages/superdoc/src/Superdoc.vue +++ b/packages/superdoc/src/Superdoc.vue @@ -1,11 +1,11 @@ @@ -213,7 +226,8 @@ onBeforeUnmount(() => { /* Right sidebar drawer */ .right-sidebar { width: 320px; - padding: 10px; + padding: 0 10px; + min-height: 100%; position: relative; } @@ -244,7 +258,6 @@ onBeforeUnmount(() => { } .layers { position: relative; - display: inline-block; } /* Document Styles */ @@ -298,4 +311,15 @@ onBeforeUnmount(() => { background-color: #DBDBDB; } +@media (max-width: 768px) { + .sub-document { + max-width: 100%; + overflow: hidden; + } + .right-sidebar { + padding: 10px; + width: 55px; + position: relative; + } +} diff --git a/packages/superdoc/src/assets/test-data.js b/packages/superdoc/src/assets/test-data.js index c99c5725d5..18f2e25e8a 100644 --- a/packages/superdoc/src/assets/test-data.js +++ b/packages/superdoc/src/assets/test-data.js @@ -540,8 +540,9 @@ export const fields = [ } ] -export const conversations = [{ - "conversationId": "384db7b4-d95c-478e-bd3e-03bacaed6fc5", +export const conversations = [ + { + "conversationId": "convo-1", "documentId": "456", "creatorEmail": "nick@harbourshare.com", "creatorName": "Nick Bernal", @@ -567,8 +568,45 @@ export const conversations = [{ }, "markedDone": null, "isFocused": true -},{ - "conversationId": "384db7b4-d95c-478e-bd3e-ABC", +}, +{ + "conversationId": "convo-2", + "documentId": "456", + "creatorEmail": "nick@harbourshare.com", + "creatorName": "Nick Bernal", + "comments": [ + { + "comment": "initial top COMMENT", + "user": { + "name": "Nick Bernal", + "email": "nick@harbourshare.com" + }, + "timestamp": "2024-05-31T19:18:25.522Z" + }, + { + "comment": "comment in thread", + "user": { + "name": "Nick Bernal", + "email": "nick@harbourshare.com" + }, + "timestamp": "2024-05-31T19:20:25.522Z" + } + ], + "selection": { + "documentId": "456", + "page": "1", + "selectionBounds": { + "top": 0.296875, + "left": 500.91461181640625, + "bottom": 200.296875, + "right": 550.99163818359375 + } + }, + "markedDone": null, + "isFocused": true + }, + { + "conversationId": "convo-3", "documentId": "456", "creatorEmail": "nick@harbourshare.com", "creatorName": "Nick Bernal", @@ -594,7 +632,36 @@ export const conversations = [{ }, "markedDone": null, "isFocused": true - }] + }, + { + "conversationId": "convo-4-page2", + "documentId": "456", + "creatorEmail": "nick@harbourshare.com", + "creatorName": "Nick Bernal", + "comments": [ + { + "comment": "pg1 - 1", + "user": { + "name": "Nick Bernal", + "email": "nick@harbourshare.com" + }, + "timestamp": "2024-05-31T19:18:25.522Z" + } + ], + "selection": { + "documentId": "456", + "page": "2", + "selectionBounds": { + "top": 105.296875, + "left": 413.91461181640625, + "bottom": 125.296875, + "right": 487.99163818359375 + } + }, + "markedDone": null, + "isFocused": true + }, +] export const annotations = [ diff --git a/packages/superdoc/src/components/CommentsLayer/CommentDialog.vue b/packages/superdoc/src/components/CommentsLayer/CommentDialog.vue index b0c551b7f3..ea1574854f 100644 --- a/packages/superdoc/src/components/CommentsLayer/CommentDialog.vue +++ b/packages/superdoc/src/components/CommentsLayer/CommentDialog.vue @@ -3,17 +3,18 @@ import { computed, toRefs, ref, getCurrentInstance, onMounted } from 'vue'; import { storeToRefs } from 'pinia'; import { useCommentsStore } from '@/stores/comments-store'; import { useSuperdocStore } from '@/stores/superdoc-store'; +import useSelection from '@/helpers/use-selection'; import useComment from '@/components/CommentsLayer/use-comment'; import Avatar from '@/components/general/Avatar.vue'; const superdocStore = useSuperdocStore(); const commentsStore = useCommentsStore(); -const { COMMENT_EVENTS, getCommentLocation, checkOverlaps } = commentsStore; -const { getConfig, activeComment, overlappingComments } = storeToRefs(commentsStore); +const { COMMENT_EVENTS } = commentsStore; +const { getConfig, activeComment, pendingComment, floatingCommentsOffset } = storeToRefs(commentsStore); const { areDocumentsReady } = superdocStore; +const { selectionPosition } = storeToRefs(superdocStore); const { proxy } = getCurrentInstance(); -const emit = defineEmits(['click-outside']); const props = defineProps({ user: { type: Object, @@ -31,19 +32,16 @@ const props = defineProps({ type: Object, required: true, }, - showGrouped: { - type: Boolean, - required: false, - default: false, - }, }); +const emit = defineEmits(['click-outside', 'ready', 'dialog-exit']); const currentElement = ref(null); const inputIsFocused = ref(false); const input = ref(null); const addComment = () => { if (!input.value?.value) return; + // create the new comment for the conversation const comment = useComment({ user: { email: props.user.email, @@ -53,10 +51,38 @@ const addComment = () => { comment: input.value.value, }); - props.data.comments.push(comment); + // If this conversation is pending addition, add to the document first + if (pendingComment.value && pendingComment.value.conversationId === props.data.conversationId) { + const newConversation = { ...pendingComment.value } + + const selection = pendingComment.value.selection.getValues(); + const bounds = selection.selectionBounds; + if (bounds.top > bounds.bottom) { + const temp = bounds.top; + bounds.top = bounds.bottom; + bounds.bottom = temp; + } + if (bounds.left > bounds.right) { + const temp = bounds.left; + bounds.left = bounds.right; + bounds.right = temp; + } + newConversation.selection = useSelection(selection) + + // Remove the pending comment + pendingComment.value = null; + + // Reset the original selection + selectionPosition.value = null; + newConversation.comments.push(comment); + props.currentDocument.conversations.push(newConversation); + proxy.$superdoc.broadcastComments(COMMENT_EVENTS.ADD, props.data.getValues()); + } else { + props.data.comments.push(comment); + proxy.$superdoc.broadcastComments(COMMENT_EVENTS.ADD, props.data.getValues()); + } + input.value.value = ''; - proxy.$superdoc.broadcastComments(COMMENT_EVENTS.ADD, props.data.getValues()); - checkOverlaps(currentElement.value, props.data, props.currentDocument); } function formatDate(timestamp) { @@ -78,36 +104,42 @@ const handleKeyUp = () => { } const getSidebarCommentStyle = computed(() => { - const style = {} + const style = {}; if (isActiveComment.value) { style.backgroundColor = 'white'; style.zIndex = 10; } - if (!props.parent) { - style.position = 'relative'; - return style; + if (!props.data.comments.length && currentElement.value) { + const selectionBounds = props.data.selection.getContainerLocation(props.parent) + const bounds = props.data.selection.selectionBounds; + const parentTop = props.parent.getBoundingClientRect().top; + const currentBounds = currentElement.value.getBoundingClientRect(); + style.top = bounds.top + selectionBounds.top + 'px'; + style.width = 300 + 'px'; } - const topOffset = 10; - const location = getCommentLocation(props.data.selection, props.parent); - if (!location) return {}; - - style.top = location.top - topOffset + 'px'; return style; }); const cleanConversations = () => { if (props.data.comments.length) return; + if (pendingComment.value) selectionPosition.value = null; const id = props.data.conversationId; + pendingComment.value = null; props.currentDocument.removeConversation(id); proxy.$superdoc.broadcastComments(COMMENT_EVENTS.DELETED, id); } const handleClickOutside = (e) => { - if (e.target.dataset.id) activeComment.value = e.target.dataset.id; - else activeComment.value = null; - cleanConversations(); + if (activeComment.value === props.data.conversationId) { + floatingCommentsOffset.value = 0; + + emit('dialog-exit'); + if (e.target.dataset.id) activeComment.value = e.target.dataset.id; + else activeComment.value = null; + cleanConversations(); + } } const setFocus = () => { @@ -119,22 +151,11 @@ const markDone = () => { convo.markDone(props.user.email, props.user.name); props.currentDocument.removeConversation(convo.conversationId); proxy.$superdoc.broadcastComments(COMMENT_EVENTS.RESOLVED, convo.getValues()); - - const group = overlappingComments.value.find((g) => g.includes(props.data)); - if (!group) return; - const index = group.findIndex((c) => c.conversationId === props.data.conversationId); - if (index > -1) group.splice(index, 1); - if (group.length === 1) { - const conversation = group[0]; - const groupIndex = overlappingComments.value.findIndex((g) => g.includes(conversation)); - - overlappingComments.value.splice(groupIndex, 1); - conversation.group = false; - } } const cancelComment = () => { activeComment.value = null; + pendingComment.value = null; if (!props.data.comments.length) { cleanConversations(); } @@ -144,28 +165,26 @@ const isActiveComment = computed(() => { return activeComment.value === props.data.conversationId; }); -const trackContainers = (e) => { - currentElement.value = e; - const conversations = props.currentDocument.conversations; - const currentConversation = conversations.find((c) => c.conversationId === props.data.conversationId); - if (!currentConversation) return; - currentConversation.conversationElement = e; -} + +onMounted(() => { + emit('ready', props.data.conversationId, currentElement); +});