✨(app-impress) add basic blocknotes editor
Create PadEditor, the parent component for the editors. We integrate the BlockNoteEditor into the PadEditor.
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
|
import { keyCloakSignIn } from './common';
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page, browserName }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await keyCloakSignIn(page, browserName);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('Pad Editor', () => {
|
||||||
|
test('checks the Pad Editor interact correctly', async ({ page }) => {
|
||||||
|
await page.getByText('My mocked pad').first().click();
|
||||||
|
|
||||||
|
await expect(page.locator('h2').getByText('My mocked pad')).toBeVisible();
|
||||||
|
|
||||||
|
await page.locator('.ProseMirror.bn-editor').click();
|
||||||
|
await page.locator('.ProseMirror.bn-editor').fill('Hello World');
|
||||||
|
await expect(page.getByText('Hello World')).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import { expect, test } from '@playwright/test';
|
|
||||||
|
|
||||||
import { createTeam, keyCloakSignIn, randomName } from './common';
|
|
||||||
|
|
||||||
test.beforeEach(async ({ page, browserName }) => {
|
|
||||||
await page.goto('/');
|
|
||||||
await keyCloakSignIn(page, browserName);
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Team', () => {
|
|
||||||
test('checks all the top box elements are visible', async ({
|
|
||||||
page,
|
|
||||||
browserName,
|
|
||||||
}) => {
|
|
||||||
const teamName = (
|
|
||||||
await createTeam(page, 'team-top-box', browserName, 1)
|
|
||||||
).shift();
|
|
||||||
|
|
||||||
await expect(page.getByLabel('icon group')).toBeVisible();
|
|
||||||
await expect(
|
|
||||||
page.getByRole('heading', {
|
|
||||||
name: `Members of “${teamName}“`,
|
|
||||||
level: 3,
|
|
||||||
}),
|
|
||||||
).toBeVisible();
|
|
||||||
await expect(
|
|
||||||
page.getByText(`Add people to the “${teamName}“ group.`),
|
|
||||||
).toBeVisible();
|
|
||||||
|
|
||||||
await expect(page.getByText(`1 member`)).toBeVisible();
|
|
||||||
|
|
||||||
const today = new Date(Date.now());
|
|
||||||
const todayFormated = today.toLocaleDateString('en', {
|
|
||||||
month: '2-digit',
|
|
||||||
day: '2-digit',
|
|
||||||
year: 'numeric',
|
|
||||||
});
|
|
||||||
await expect(page.getByText(`Created at ${todayFormated}`)).toBeVisible();
|
|
||||||
await expect(
|
|
||||||
page.getByText(`Last update at ${todayFormated}`),
|
|
||||||
).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it updates the team name', async ({ page, browserName }) => {
|
|
||||||
await createTeam(page, 'team-update-name', browserName, 1);
|
|
||||||
|
|
||||||
await page.getByLabel(`Open the team options`).click();
|
|
||||||
await page.getByRole('button', { name: `Update the team` }).click();
|
|
||||||
|
|
||||||
const teamName = randomName('new-team-update-name', browserName, 1)[0];
|
|
||||||
await page.getByText('New name...', { exact: true }).fill(teamName);
|
|
||||||
|
|
||||||
await page
|
|
||||||
.getByRole('button', { name: 'Validate the modification' })
|
|
||||||
.click();
|
|
||||||
|
|
||||||
await expect(page.getByText('The team has been updated.')).toBeVisible();
|
|
||||||
await expect(
|
|
||||||
page.getByText(`Add people to the “${teamName}“ group.`),
|
|
||||||
).toBeVisible();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { BlockNoteView, useCreateBlockNote } from '@blocknote/react';
|
||||||
|
import '@blocknote/react/style.css';
|
||||||
|
import React from 'react';
|
||||||
|
import { WebrtcProvider } from 'y-webrtc';
|
||||||
|
import * as Y from 'yjs';
|
||||||
|
|
||||||
|
const doc = new Y.Doc();
|
||||||
|
const provider = new WebrtcProvider('my-document-id4', doc, {
|
||||||
|
signaling: ['ws://localhost:4444'],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const BlockNoteEditor = () => {
|
||||||
|
const editor = useCreateBlockNote({
|
||||||
|
collaboration: {
|
||||||
|
provider,
|
||||||
|
fragment: doc.getXmlFragment('document-store'),
|
||||||
|
user: {
|
||||||
|
name: 'My Username',
|
||||||
|
color: '#ff0000',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return <BlockNoteView editor={editor} />;
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Card, Text } from '@/components';
|
||||||
|
|
||||||
|
import { Pad } from '../types';
|
||||||
|
|
||||||
|
import { BlockNoteEditor } from './BlockNoteEditor';
|
||||||
|
|
||||||
|
interface PadEditorProps {
|
||||||
|
pad: Pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PadEditor = ({ pad }: PadEditorProps) => {
|
||||||
|
return (
|
||||||
|
<Card className="m-b p-b" $height="100%">
|
||||||
|
<Text as="h2">{pad.name}</Text>
|
||||||
|
<BlockNoteEditor />
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
import { DateTime, DateTimeFormatOptions } from 'luxon';
|
|
||||||
import React from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
import IconGroup from '@/assets/icons/icon-group2.svg';
|
|
||||||
import { Box, Card, Text } from '@/components';
|
|
||||||
import { useCunninghamTheme } from '@/cunningham';
|
|
||||||
|
|
||||||
import { Pad } from '../types';
|
|
||||||
|
|
||||||
const format: DateTimeFormatOptions = {
|
|
||||||
month: '2-digit',
|
|
||||||
day: '2-digit',
|
|
||||||
year: 'numeric',
|
|
||||||
};
|
|
||||||
|
|
||||||
interface PadInfoProps {
|
|
||||||
pad: Pad;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PadInfo = ({ pad }: PadInfoProps) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { colorsTokens } = useCunninghamTheme();
|
|
||||||
const { i18n } = useTranslation();
|
|
||||||
|
|
||||||
const created_at = DateTime.fromISO(pad.created_at)
|
|
||||||
.setLocale(i18n.language)
|
|
||||||
.toLocaleString(format);
|
|
||||||
|
|
||||||
const updated_at = DateTime.fromISO(pad.updated_at)
|
|
||||||
.setLocale(i18n.language)
|
|
||||||
.toLocaleString(format);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Card className="m-b" style={{ paddingBottom: 0 }}>
|
|
||||||
<Box className="m-b" $direction="row" $align="center" $gap="1.5rem">
|
|
||||||
<IconGroup
|
|
||||||
width={44}
|
|
||||||
color={colorsTokens()['primary-text']}
|
|
||||||
aria-label={t('icon group')}
|
|
||||||
style={{
|
|
||||||
flexShrink: 0,
|
|
||||||
alignSelf: 'start',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Box>
|
|
||||||
<Text as="h3" $weight="bold" $size="1.25rem" className="mt-0">
|
|
||||||
{t('Members of “{{padName}}“', {
|
|
||||||
padName: pad.name,
|
|
||||||
})}
|
|
||||||
</Text>
|
|
||||||
<Text $size="m">
|
|
||||||
{t('Add people to the “{{padName}}“ group.', {
|
|
||||||
padName: pad.name,
|
|
||||||
})}
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
className="p-s"
|
|
||||||
$gap="3rem"
|
|
||||||
$direction="row"
|
|
||||||
$justify="start"
|
|
||||||
$css={`
|
|
||||||
border-top: 1px solid ${colorsTokens()['card-border']};
|
|
||||||
padding-left: 1.5rem;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Text $size="s" as="p">
|
|
||||||
{t('{{count}} member', { count: pad.accesses.length })}
|
|
||||||
</Text>
|
|
||||||
<Text $size="s" $display="inline" as="p">
|
|
||||||
{t('Created at')}
|
|
||||||
<Text $weight="bold" $display="inline">
|
|
||||||
{created_at}
|
|
||||||
</Text>
|
|
||||||
</Text>
|
|
||||||
<Text $size="s" $display="inline" as="p">
|
|
||||||
{t('Last update at')}
|
|
||||||
<Text $weight="bold" $display="inline">
|
|
||||||
{updated_at}
|
|
||||||
</Text>
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
</Card>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1 +1 @@
|
|||||||
export * from './PadInfo';
|
export * from './PadEditor';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { ReactElement } from 'react';
|
|||||||
|
|
||||||
import { Box } from '@/components';
|
import { Box } from '@/components';
|
||||||
import { TextErrors } from '@/components/TextErrors';
|
import { TextErrors } from '@/components/TextErrors';
|
||||||
import { PadInfo, usePad } from '@/features/pads/pad';
|
import { PadEditor, usePad } from '@/features/pads/pad';
|
||||||
import { PadLayout } from '@/layouts';
|
import { PadLayout } from '@/layouts';
|
||||||
import { NextPageWithLayout } from '@/types/next';
|
import { NextPageWithLayout } from '@/types/next';
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ const Pad = ({ id }: PadProps) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <PadInfo pad={pad} />;
|
return <PadEditor pad={pad} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
Page.getLayout = function getLayout(page: ReactElement) {
|
Page.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
|||||||
Reference in New Issue
Block a user