♻️(frontend) better handling css doc states

We simplify the way we handle different doc
states (deleted / readonly) in the CSS, we avoid
props drilling and are more component focused.
This commit is contained in:
Anthony LC
2025-11-07 15:31:05 +01:00
parent b91840c819
commit e5581e52f7
6 changed files with 40 additions and 25 deletions

View File

@@ -119,6 +119,10 @@ test.describe('Doc Trashbin', () => {
await row.getByText(subDocName).click();
await verifyDocName(page, subDocName);
await expect(
page.locator('.--docs--editor-container.--docs--doc-deleted'),
).toBeVisible();
await expect(page.getByLabel('Alert deleted document')).toBeVisible();
await expect(page.getByRole('button', { name: 'Share' })).toBeDisabled();
await expect(page.locator('.bn-editor')).toHaveAttribute(

View File

@@ -260,6 +260,10 @@ test.describe('Doc Visibility: Public', () => {
await expect(card).toBeVisible();
await expect(card.getByText('Reader')).toBeVisible();
await expect(
otherPage.locator('.--docs--editor-container.--docs--doc-readonly'),
).toBeVisible();
const otherEditor = await getEditor({ page: otherPage });
await expect(otherEditor).toHaveAttribute('contenteditable', 'false');
await expect(otherEditor.getByText('Hello Public Viewonly')).toBeVisible();

View File

@@ -28,6 +28,7 @@ import {
useUploadStatus,
} from '../hook';
import { useEditorStore } from '../stores';
import { cssEditor } from '../styles';
import { DocsBlockNoteEditor } from '../types';
import { randomColor } from '../utils';
@@ -169,7 +170,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
}, [setEditor, editor]);
return (
<Box ref={refEditorContainer}>
<Box ref={refEditorContainer} $css={cssEditor}>
{errorAttachment && (
<Box $margin={{ bottom: 'big', top: 'none', horizontal: 'large' }}>
<TextErrors
@@ -225,12 +226,14 @@ export const BlockNoteReader = ({ initialContent }: BlockNoteReaderProps) => {
useHeadings(editor);
return (
<BlockNoteView
editor={editor}
editable={false}
theme="light"
formattingToolbar={false}
slashMenu={false}
/>
<Box $css={cssEditor}>
<BlockNoteView
editor={editor}
editable={false}
theme="light"
formattingToolbar={false}
slashMenu={false}
/>
</Box>
);
};

View File

@@ -1,3 +1,4 @@
import clsx from 'clsx';
import { useEffect } from 'react';
import { css } from 'styled-components';
@@ -12,8 +13,6 @@ import { TableContent } from '@/docs/doc-table-content/';
import { useSkeletonStore } from '@/features/skeletons';
import { useResponsiveStore } from '@/stores';
import { cssEditor } from '../styles';
import { BlockNoteEditor, BlockNoteReader } from './BlockNoteEditor';
interface DocEditorContainerProps {
@@ -55,10 +54,13 @@ export const DocEditorContainer = ({
>
<Box $css="flex:1;" $position="relative" $width="100%">
<Box
$padding={{ top: 'md' }}
$padding={{ top: 'md', bottom: '2rem' }}
$background="white"
$css={cssEditor(readOnly, isDeletedDoc)}
className="--docs--editor-container"
className={clsx('--docs--editor-container', {
'--docs--doc-readonly': readOnly,
'--docs--doc-deleted': isDeletedDoc,
})}
$height="100%"
>
{docEditor}
</Box>
@@ -77,7 +79,9 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
const { isDesktop } = useResponsiveStore();
const { provider, isReady } = useProviderStore();
const { isEditable, isLoading } = useIsCollaborativeEditable(doc);
const readOnly = !doc.abilities.partial_update || !isEditable || isLoading;
const isDeletedDoc = !!doc.deleted_at;
const readOnly =
!doc.abilities.partial_update || !isEditable || isLoading || isDeletedDoc;
const { setIsSkeletonVisible } = useSkeletonStore();
const isProviderReady = isReady && provider;
@@ -117,7 +121,7 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
<BlockNoteEditor doc={doc} provider={provider} />
)
}
isDeletedDoc={!!doc.deleted_at}
isDeletedDoc={isDeletedDoc}
readOnly={readOnly}
/>
</>

View File

@@ -89,6 +89,10 @@ const LinkSelected = ({ url, title }: LinkSelectedProps) => {
background-color: ${colorsTokens['greyscale-100']};
}
transition: background-color 0.2s ease-in-out;
.--docs--doc-deleted & {
pointer-events: none;
}
`}
>
{emoji ? (

View File

@@ -1,12 +1,13 @@
import { css } from 'styled-components';
export const cssEditor = (readonly: boolean, isDeletedDoc: boolean) => css`
export const cssEditor = css`
&,
& > .bn-container,
& .ProseMirror {
height: 100%;
padding-bottom: 2rem;
}
& .ProseMirror {
/**
* WCAG Accessibility contrast fixes for BlockNote editor
*/
@@ -131,13 +132,6 @@ export const cssEditor = (readonly: boolean, isDeletedDoc: boolean) => css`
.bn-block-outer:not([data-prev-depth-changed]):before {
border-left: none;
}
${isDeletedDoc &&
`
.node-interlinkingLinkInline button {
pointer-events: none;
}
`}
}
& .bn-editor {
@@ -187,8 +181,10 @@ export const cssEditor = (readonly: boolean, isDeletedDoc: boolean) => css`
}
@media screen and (width <= 560px) {
.--docs--doc-readonly & .bn-editor {
padding-left: 10px;
}
& .bn-editor {
${readonly && `padding-left: 10px;`}
padding-right: 10px;
}
.bn-side-menu[data-block-type='heading'][data-level='1'] {