Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to

- ♿(frontend) improve accessibility:
- ♿(frontend) add skip to content button for keyboard accessibility #1624
- ⚡️(frontend) improve Comments feature #1687

### Fixed

Expand Down
49 changes: 47 additions & 2 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-comments.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ test.describe('Doc Comments', () => {
await createDoc(page, 'comment-interaction', browserName, 1);

// Checks add react reaction
const editor = page.locator('.ProseMirror');
await editor.locator('.bn-block-outer').last().fill('Hello World');
const editor = await writeInEditor({ page, text: 'Hello' });
await editor.getByText('Hello').selectText();
await page.getByRole('button', { name: 'Comment' }).click();

Expand Down Expand Up @@ -181,6 +180,28 @@ test.describe('Doc Comments', () => {
'background-color',
'rgba(0, 0, 0, 0)',
);

/* Delete the last comment remove the thread */
await editor.getByText('Hello').selectText();
await page.getByRole('button', { name: 'Comment' }).click();

await thread.getByRole('paragraph').first().fill('This is a new comment');
await thread.locator('[data-test="save"]').click();

await expect(editor.getByText('Hello')).toHaveCSS(
'background-color',
'rgba(237, 180, 0, 0.4)',
);
await editor.getByText('Hello').click();

await thread.getByText('This is a new comment').first().hover();
await thread.locator('[data-test="moreactions"]').first().click();
await thread.getByRole('menuitem', { name: 'Delete comment' }).click();

await expect(editor.getByText('Hello')).toHaveCSS(
'background-color',
'rgba(0, 0, 0, 0)',
);
});

test('it checks the comments abilities', async ({ page, browserName }) => {
Expand Down Expand Up @@ -293,3 +314,27 @@ test.describe('Doc Comments', () => {
await cleanup();
});
});

test.describe('Doc Comments mobile', () => {
test.use({ viewport: { width: 500, height: 1200 } });

test('Comments are not visible on mobile', async ({ page, browserName }) => {
await page
.locator('header')
.first()
.getByLabel('Open the header menu')
.click();
await createDoc(page, 'comment-mobile', browserName, 1);
await page
.locator('header')
.first()
.getByLabel('Open the header menu')
.click();

// Checks add react reaction
const editor = await writeInEditor({ page, text: 'Hello' });
await editor.getByText('Hello').selectText();
await expect(page.getByRole('button', { name: 'Comment' })).toBeHidden();
await expect(page.getByRole('button', { name: 'Paragraph' })).toBeVisible();
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* This file is adapted from BlockNote's AddCommentButton component
* https://github.com/TypeCellOS/BlockNote/blob/main/packages/react/src/components/FormattingToolbar/DefaultButtons/AddCommentButton.tsx
*/

import {
useBlockNoteEditor,
useComponentsContext,
Expand All @@ -10,6 +15,7 @@ import { css } from 'styled-components';
import { Box, Icon } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { useDocStore } from '@/features/docs/doc-management';
import { useResponsiveStore } from '@/stores';

import {
DocsBlockSchema,
Expand All @@ -22,6 +28,7 @@ export const CommentToolbarButton = () => {
const { currentDoc } = useDocStore();
const { t } = useTranslation();
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
const { isDesktop } = useResponsiveStore();

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

const focusOnInputThread = () => {
// Use setTimeout to ensure the DOM has been updated with the new comment
setTimeout(() => {
const threadElement = document.querySelector<HTMLElement>(
'.bn-thread .bn-editor',
);
threadElement?.focus();
}, 400);
};

if (
!isDesktop ||
!show ||
!editor.isEditable ||
!Components ||
Expand All @@ -51,6 +69,7 @@ export const CommentToolbarButton = () => {
onClick={() => {
editor.comments?.startPendingComment();
editor.formattingToolbar.closeMenu();
focusOnInputThread();
}}
aria-haspopup="dialog"
data-test="comment-toolbar-button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,21 @@ export class DocsThreadStore extends ThreadStore {
});
}

/**
* Scrolls to the bottom of a thread modal
* @param threadId
*/
private scrollToBottomOfThread() {
// Use setTimeout to ensure the DOM has been updated with the new comment
setTimeout(() => {
const threadElement = document.querySelector('.bn-thread');
threadElement?.scrollBy({
top: threadElement.scrollHeight,
behavior: 'smooth',
});
}, 200);
}

/**
* Notifies all subscribers about the current thread state
*/
Expand Down Expand Up @@ -345,6 +360,10 @@ export class DocsThreadStore extends ThreadStore {
await this.refreshThread(threadId);
}
this.ping(threadId);

// Auto-scroll to bottom of thread after adding comment
this.scrollToBottomOfThread();

return serverCommentToClientComment(comment);
};

Expand Down Expand Up @@ -405,10 +424,20 @@ export class DocsThreadStore extends ThreadStore {
// Optimistically remove the comment locally if we have the thread
const existing = this.threads.get(threadId);
if (existing) {
const updatedComments = existing.comments.filter(
(c) => c.id !== commentId,
);

// If this was the last comment, delete the thread
if (updatedComments.length === 0) {
await this.deleteThread({ threadId });
return;
}

const updated: ClientThreadData = {
...existing,
updatedAt: new Date(),
comments: existing.comments.filter((c) => c.id !== commentId),
comments: updatedComments,
};
this.upsertClientThreadData(updated);
this.notifySubscribers();
Expand All @@ -419,10 +448,6 @@ export class DocsThreadStore extends ThreadStore {
this.ping(threadId);
};

/**
* UI not implemented
* @param _options
*/
public deleteThread = async (_options: { threadId: string }) => {
const response = await fetchAPI(
`documents/${this.docId}/threads/${_options.threadId}/`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export const cssComments = (
background: ${canSeeComment ? '#EDB40066' : 'transparent'};
color: var(--c--globals--colors--gray-700);
}

[data-show-selection] {
color: HighlightText;
}
}

em-emoji-picker {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import { css } from 'styled-components';

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

import ChildDocument from '../assets/child-document.svg';
import PinnedDocumentIcon from '../assets/pinned-document.svg';
import SimpleFileIcon from '../assets/simple-document.svg';
import { useDocUtils, useTrans } from '../hooks';
import { Doc } from '../types';

const ItemTextCss = css`
overflow: hidden;
Expand Down
Loading