Skip to content

Commit f91d2bc

Browse files
committed
⚡️(frontend) improve Comments feature
Improve the comments feature to reduce annoyance: - gives focus on input when opening comment threads - hide comment button when mobile view - improve contrast of overline commented text - remove thread if last comment deleted - scroll to bottom thread when adding new comment
1 parent 54fe70d commit f91d2bc

File tree

4 files changed

+55
-6
lines changed

4 files changed

+55
-6
lines changed

src/frontend/apps/impress/src/features/docs/doc-editor/components/comments/CommentToolbarButton.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/**
2+
* This file is adapted from BlockNote's AddCommentButton component
3+
* https://github.com/TypeCellOS/BlockNote/blob/main/packages/react/src/components/FormattingToolbar/DefaultButtons/AddCommentButton.tsx
4+
*/
5+
16
import {
27
useBlockNoteEditor,
38
useComponentsContext,
@@ -10,6 +15,7 @@ import { css } from 'styled-components';
1015
import { Box, Icon } from '@/components';
1116
import { useCunninghamTheme } from '@/cunningham';
1217
import { useDocStore } from '@/features/docs/doc-management';
18+
import { useResponsiveStore } from '@/stores';
1319

1420
import {
1521
DocsBlockSchema,
@@ -22,6 +28,7 @@ export const CommentToolbarButton = () => {
2228
const { currentDoc } = useDocStore();
2329
const { t } = useTranslation();
2430
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
31+
const { isDesktop } = useResponsiveStore();
2532

2633
const editor = useBlockNoteEditor<
2734
DocsBlockSchema,
@@ -35,7 +42,18 @@ export const CommentToolbarButton = () => {
3542
return !!selectedBlocks.find((block) => block.content !== undefined);
3643
}, [selectedBlocks]);
3744

45+
const focusOnInputThread = () => {
46+
// Use setTimeout to ensure the DOM has been updated with the new comment
47+
setTimeout(() => {
48+
const threadElement = document.querySelector<HTMLElement>(
49+
'.bn-thread .bn-editor',
50+
);
51+
threadElement?.focus();
52+
}, 400);
53+
};
54+
3855
if (
56+
!isDesktop ||
3957
!show ||
4058
!editor.isEditable ||
4159
!Components ||
@@ -51,6 +69,7 @@ export const CommentToolbarButton = () => {
5169
onClick={() => {
5270
editor.comments?.startPendingComment();
5371
editor.formattingToolbar.closeMenu();
72+
focusOnInputThread();
5473
}}
5574
aria-haspopup="dialog"
5675
data-test="comment-toolbar-button"

src/frontend/apps/impress/src/features/docs/doc-editor/components/comments/DocsThreadStore.tsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,21 @@ export class DocsThreadStore extends ThreadStore {
117117
});
118118
}
119119

120+
/**
121+
* Scrolls to the bottom of a thread modal
122+
* @param threadId
123+
*/
124+
private scrollToBottomOfThread() {
125+
// Use setTimeout to ensure the DOM has been updated with the new comment
126+
setTimeout(() => {
127+
const threadElement = document.querySelector('.bn-thread');
128+
threadElement?.scrollBy({
129+
top: threadElement.scrollHeight,
130+
behavior: 'smooth',
131+
});
132+
}, 200);
133+
}
134+
120135
/**
121136
* Notifies all subscribers about the current thread state
122137
*/
@@ -345,6 +360,10 @@ export class DocsThreadStore extends ThreadStore {
345360
await this.refreshThread(threadId);
346361
}
347362
this.ping(threadId);
363+
364+
// Auto-scroll to bottom of thread after adding comment
365+
this.scrollToBottomOfThread();
366+
348367
return serverCommentToClientComment(comment);
349368
};
350369

@@ -405,10 +424,20 @@ export class DocsThreadStore extends ThreadStore {
405424
// Optimistically remove the comment locally if we have the thread
406425
const existing = this.threads.get(threadId);
407426
if (existing) {
427+
const updatedComments = existing.comments.filter(
428+
(c) => c.id !== commentId,
429+
);
430+
431+
// If this was the last comment, delete the thread
432+
if (updatedComments.length === 0) {
433+
await this.deleteThread({ threadId });
434+
return;
435+
}
436+
408437
const updated: ClientThreadData = {
409438
...existing,
410439
updatedAt: new Date(),
411-
comments: existing.comments.filter((c) => c.id !== commentId),
440+
comments: updatedComments,
412441
};
413442
this.upsertClientThreadData(updated);
414443
this.notifySubscribers();
@@ -419,10 +448,6 @@ export class DocsThreadStore extends ThreadStore {
419448
this.ping(threadId);
420449
};
421450

422-
/**
423-
* UI not implemented
424-
* @param _options
425-
*/
426451
public deleteThread = async (_options: { threadId: string }) => {
427452
const response = await fetchAPI(
428453
`documents/${this.docId}/threads/${_options.threadId}/`,

src/frontend/apps/impress/src/features/docs/doc-editor/components/comments/styles.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ export const cssComments = (
1313
background: ${canSeeComment ? '#EDB40066' : 'transparent'};
1414
color: var(--c--globals--colors--gray-700);
1515
}
16+
17+
[data-show-selection] {
18+
color: HighlightText;
19+
}
1620
}
1721
1822
em-emoji-picker {

src/frontend/apps/impress/src/features/docs/doc-management/components/SimpleDocItem.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import { css } from 'styled-components';
44

55
import { Box, Text } from '@/components';
66
import { useCunninghamTheme } from '@/cunningham';
7-
import { Doc, useDocUtils, useTrans } from '@/docs/doc-management';
87
import { useResponsiveStore } from '@/stores';
98

109
import ChildDocument from '../assets/child-document.svg';
1110
import PinnedDocumentIcon from '../assets/pinned-document.svg';
1211
import SimpleFileIcon from '../assets/simple-document.svg';
12+
import { useDocUtils, useTrans } from '../hooks';
13+
import { Doc } from '../types';
1314

1415
const ItemTextCss = css`
1516
overflow: hidden;

0 commit comments

Comments
 (0)