✨(frontend) add doc editor panel header
Add doc editor panel header to show the doc title and other info.
This commit is contained in:
@@ -13,6 +13,7 @@ and this project adheres to
|
|||||||
- 🤡(demo) generate dummy documents on dev users #120
|
- 🤡(demo) generate dummy documents on dev users #120
|
||||||
- ✨(frontend) create side modal component #134
|
- ✨(frontend) create side modal component #134
|
||||||
- ✨(frontend) Doc grid actions (update / delete) #136
|
- ✨(frontend) Doc grid actions (update / delete) #136
|
||||||
|
- ✨(frontend) Doc editor header information #137
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
|
import { goToGridDoc } from './common';
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('Doc Header', () => {
|
||||||
|
test('it checks the element are correctly displayed', async ({ page }) => {
|
||||||
|
await page.route('**/documents/**/', async (route) => {
|
||||||
|
const request = route.request();
|
||||||
|
if (
|
||||||
|
request.method().includes('GET') &&
|
||||||
|
!request.url().includes('page=')
|
||||||
|
) {
|
||||||
|
await route.fulfill({
|
||||||
|
json: {
|
||||||
|
id: 'b0df4343-c8bd-4c20-9ff6-fbf94fc94egg',
|
||||||
|
content: '',
|
||||||
|
title: 'Mocked document',
|
||||||
|
accesses: [
|
||||||
|
{
|
||||||
|
id: 'b0df4343-c8bd-4c20-9ff6-fbf94fc94egg',
|
||||||
|
role: 'owner',
|
||||||
|
user: {
|
||||||
|
email: 'super@owner.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'b0df4343-c8bd-4c20-9ff6-fbf94fc94egg',
|
||||||
|
role: 'admin',
|
||||||
|
user: {
|
||||||
|
email: 'super@admin.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'b0df4343-c8bd-4c20-9ff6-fbf94fc94egg',
|
||||||
|
role: 'owner',
|
||||||
|
user: {
|
||||||
|
email: 'super2@owner.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
abilities: {
|
||||||
|
destroy: true, // Means owner
|
||||||
|
versions_destroy: true,
|
||||||
|
versions_list: true,
|
||||||
|
versions_retrieve: true,
|
||||||
|
manage_accesses: true,
|
||||||
|
update: true,
|
||||||
|
partial_update: true,
|
||||||
|
retrieve: true,
|
||||||
|
},
|
||||||
|
is_public: true,
|
||||||
|
created_at: '2021-09-01T09:00:00Z',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await route.continue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await goToGridDoc(page);
|
||||||
|
|
||||||
|
const card = page.getByLabel(
|
||||||
|
'It is the card information about the document.',
|
||||||
|
);
|
||||||
|
await expect(card.locator('a').getByText('home')).toBeVisible();
|
||||||
|
await expect(card.locator('h2').getByText('Mocked document')).toBeVisible();
|
||||||
|
await expect(card.getByText('Public')).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
card.getByText('Created at 09/01/2021, 11:00 AM'),
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
card.getByText('Owners: super@owner.com / super2@owner.com'),
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(card.getByText('Your role: Owner')).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -48,6 +48,7 @@ export default defineConfig({
|
|||||||
use: {
|
use: {
|
||||||
...devices['Desktop Chrome'],
|
...devices['Desktop Chrome'],
|
||||||
locale: 'en-US',
|
locale: 'en-US',
|
||||||
|
timezoneId: 'Europe/Paris',
|
||||||
storageState: 'playwright/.auth/user-chromium.json',
|
storageState: 'playwright/.auth/user-chromium.json',
|
||||||
},
|
},
|
||||||
dependencies: ['setup'],
|
dependencies: ['setup'],
|
||||||
@@ -57,6 +58,7 @@ export default defineConfig({
|
|||||||
use: {
|
use: {
|
||||||
...devices['Desktop Safari'],
|
...devices['Desktop Safari'],
|
||||||
locale: 'en-US',
|
locale: 'en-US',
|
||||||
|
timezoneId: 'Europe/Paris',
|
||||||
storageState: 'playwright/.auth/user-webkit.json',
|
storageState: 'playwright/.auth/user-webkit.json',
|
||||||
},
|
},
|
||||||
dependencies: ['setup'],
|
dependencies: ['setup'],
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export interface BoxProps {
|
|||||||
$radius?: CSSProperties['borderRadius'];
|
$radius?: CSSProperties['borderRadius'];
|
||||||
$transition?: CSSProperties['transition'];
|
$transition?: CSSProperties['transition'];
|
||||||
$width?: CSSProperties['width'];
|
$width?: CSSProperties['width'];
|
||||||
|
$wrap?: CSSProperties['flexWrap'];
|
||||||
$zIndex?: CSSProperties['zIndex'];
|
$zIndex?: CSSProperties['zIndex'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ export const Box = styled('div')<BoxProps>`
|
|||||||
${({ $radius }) => $radius && `border-radius: ${$radius};`}
|
${({ $radius }) => $radius && `border-radius: ${$radius};`}
|
||||||
${({ $transition }) => $transition && `transition: ${$transition};`}
|
${({ $transition }) => $transition && `transition: ${$transition};`}
|
||||||
${({ $width }) => $width && `width: ${$width};`}
|
${({ $width }) => $width && `width: ${$width};`}
|
||||||
|
${({ $wrap }) => $wrap && `flex-wrap: ${$wrap};`}
|
||||||
${({ $css }) => $css && `${$css};`}
|
${({ $css }) => $css && `${$css};`}
|
||||||
${({ $zIndex }) => $zIndex && `z-index: ${$zIndex};`}
|
${({ $zIndex }) => $zIndex && `z-index: ${$zIndex};`}
|
||||||
${({ $effect }) => {
|
${({ $effect }) => {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export interface TextProps extends BoxProps {
|
|||||||
ReactHTML,
|
ReactHTML,
|
||||||
'p' | 'span' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
|
'p' | 'span' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
|
||||||
>;
|
>;
|
||||||
|
$elipsis?: boolean;
|
||||||
$weight?: CSSProperties['fontWeight'];
|
$weight?: CSSProperties['fontWeight'];
|
||||||
$textAlign?: CSSProperties['textAlign'];
|
$textAlign?: CSSProperties['textAlign'];
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
@@ -49,6 +50,9 @@ export const TextStyled = styled(Box)<TextProps>`
|
|||||||
${({ $theme, $variation }) =>
|
${({ $theme, $variation }) =>
|
||||||
`color: var(--c--theme--colors--${$theme}-${$variation});`}
|
`color: var(--c--theme--colors--${$theme}-${$variation});`}
|
||||||
${({ $color }) => $color && `color: ${$color};`}
|
${({ $color }) => $color && `color: ${$color};`}
|
||||||
|
${({ $elipsis }) =>
|
||||||
|
$elipsis &&
|
||||||
|
`white-space: nowrap; overflow: hidden; text-overflow: ellipsis;`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Text = ({
|
export const Text = ({
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Alert, VariantType } from '@openfun/cunningham-react';
|
import { Alert, VariantType } from '@openfun/cunningham-react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Box, Card, Text } from '@/components';
|
import { Box, Card } from '@/components';
|
||||||
|
import { DocHeader } from '@/features/docs/doc-header';
|
||||||
import { Doc } from '@/features/docs/doc-management';
|
import { Doc } from '@/features/docs/doc-management';
|
||||||
import { DocToolBox } from '@/features/docs/doc-tools';
|
|
||||||
|
|
||||||
import { BlockNoteEditor } from './BlockNoteEditor';
|
import { BlockNoteEditor } from './BlockNoteEditor';
|
||||||
|
|
||||||
@@ -14,19 +14,9 @@ interface DocEditorProps {
|
|||||||
export const DocEditor = ({ doc }: DocEditorProps) => {
|
export const DocEditor = ({ doc }: DocEditorProps) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box
|
<DocHeader doc={doc} />
|
||||||
$direction="row"
|
|
||||||
$margin={{ all: 'big', right: 'none' }}
|
|
||||||
$align="center"
|
|
||||||
$position="relative"
|
|
||||||
>
|
|
||||||
<Text as="h2" $align="center" $margin="auto">
|
|
||||||
{doc.title}
|
|
||||||
</Text>
|
|
||||||
<DocToolBox doc={doc} />
|
|
||||||
</Box>
|
|
||||||
{!doc.abilities.partial_update && (
|
{!doc.abilities.partial_update && (
|
||||||
<Box className="m-b" $css="margin-top:0;">
|
<Box $margin={{ all: 'small', top: 'none' }}>
|
||||||
<Alert
|
<Alert
|
||||||
type={VariantType.WARNING}
|
type={VariantType.WARNING}
|
||||||
>{`Read only, you don't have the right to update this document.`}</Alert>
|
>{`Read only, you don't have the right to update this document.`}</Alert>
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { Box, Card, StyledLink, Text } from '@/components';
|
||||||
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
|
import {
|
||||||
|
Doc,
|
||||||
|
Role,
|
||||||
|
currentDocRole,
|
||||||
|
useTransRole,
|
||||||
|
} from '@/features/docs/doc-management';
|
||||||
|
import { useDate } from '@/hook';
|
||||||
|
|
||||||
|
import { DocToolBox } from './DocToolBox';
|
||||||
|
|
||||||
|
interface DocHeaderProps {
|
||||||
|
doc: Doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DocHeader = ({ doc }: DocHeaderProps) => {
|
||||||
|
const { colorsTokens } = useCunninghamTheme();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { formatDate } = useDate();
|
||||||
|
const transRole = useTransRole();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
$margin="big"
|
||||||
|
aria-label={t('It is the card information about the document.')}
|
||||||
|
>
|
||||||
|
<Box $padding="small" $direction="row" $align="center">
|
||||||
|
<StyledLink href="/">
|
||||||
|
<Text
|
||||||
|
className="material-icons"
|
||||||
|
$theme="primary"
|
||||||
|
$size="2rem"
|
||||||
|
$css={`&:hover {background-color: ${colorsTokens()['primary-100']}; };`}
|
||||||
|
$hasTransition
|
||||||
|
$radius="5px"
|
||||||
|
$padding="tiny"
|
||||||
|
>
|
||||||
|
home
|
||||||
|
</Text>
|
||||||
|
</StyledLink>
|
||||||
|
<Box
|
||||||
|
$width="1px"
|
||||||
|
$height="70%"
|
||||||
|
$background={colorsTokens()['greyscale-100']}
|
||||||
|
$margin={{ horizontal: 'small' }}
|
||||||
|
/>
|
||||||
|
<Text as="h2" $align="center" $margin={{ all: 'none', left: 'tiny' }}>
|
||||||
|
{doc.title}
|
||||||
|
</Text>
|
||||||
|
<DocToolBox doc={doc} />
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
$direction="row"
|
||||||
|
$align="center"
|
||||||
|
$css="border-top:1px solid #eee"
|
||||||
|
$padding={{ horizontal: 'big', vertical: 'tiny' }}
|
||||||
|
$gap="0.5rem 2rem"
|
||||||
|
$justify="space-between"
|
||||||
|
$wrap="wrap"
|
||||||
|
>
|
||||||
|
<Box $direction="row" $align="center" $gap="0.5rem 2rem" $wrap="wrap">
|
||||||
|
{doc.is_public && (
|
||||||
|
<Text
|
||||||
|
$weight="bold"
|
||||||
|
$background={colorsTokens()['primary-600']}
|
||||||
|
$color="white"
|
||||||
|
$padding="xtiny"
|
||||||
|
$radius="3px"
|
||||||
|
$size="s"
|
||||||
|
>
|
||||||
|
{t('Public')}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
<Text $size="s" $display="inline">
|
||||||
|
{t('Created at')} <strong>{formatDate(doc.created_at)}</strong>
|
||||||
|
</Text>
|
||||||
|
<Text $size="s" $display="inline" $elipsis $maxWidth="60vw">
|
||||||
|
{t('Owners:')}{' '}
|
||||||
|
<strong>
|
||||||
|
{doc.accesses
|
||||||
|
.filter((access) => access.role === Role.OWNER)
|
||||||
|
.map((access, index, accesses) => (
|
||||||
|
<Fragment key={`access-${index}`}>
|
||||||
|
{access.user.email}{' '}
|
||||||
|
{index < accesses.length - 1 ? ' / ' : ''}
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</strong>
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Text $size="s" $display="inline">
|
||||||
|
{t('Your role:')}{' '}
|
||||||
|
<strong>{transRole(currentDocRole(doc.abilities))}</strong>
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -28,7 +28,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
|||||||
const [isDropOpen, setIsDropOpen] = useState(false);
|
const [isDropOpen, setIsDropOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box $margin="big" $position="absolute" $css="right:1rem;">
|
<Box $margin={{ left: 'auto' }}>
|
||||||
<DropButton
|
<DropButton
|
||||||
button={
|
button={
|
||||||
<IconOptions
|
<IconOptions
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './DocHeader';
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './DocToolBox';
|
|
||||||
Reference in New Issue
Block a user