✨(frontend) enhance document editor and header components
- Improved styling for headings in BlockNoteEditor for better visual hierarchy. - Adjusted padding in DocEditor and DocHeader based on device type for responsive design. - Updated DocTitle and ModalExport components to enhance typography and spacing. - Refactored DocToolBox to improve share button functionality and access display. - Enhanced versioning modal with better layout and accessibility features. - Cleaned up unused imports and optimized component structures for maintainability.
This commit is contained in:
committed by
Anthony LC
parent
6ad1e27acf
commit
fc27043e9e
@@ -24,6 +24,49 @@ const cssEditor = (readonly: boolean) => `
|
|||||||
&, & > .bn-container, & .ProseMirror {
|
&, & > .bn-container, & .ProseMirror {
|
||||||
height:100%;
|
height:100%;
|
||||||
|
|
||||||
|
.bn-side-menu[data-block-type=heading][data-level="1"] {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
.bn-side-menu[data-block-type=heading][data-level="2"] {
|
||||||
|
height: 43px;
|
||||||
|
}
|
||||||
|
.bn-side-menu[data-block-type=heading][data-level="3"] {
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 1.875rem;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: var(--c--theme--colors--greyscale-500);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.bn-block-group
|
||||||
|
.bn-block-group
|
||||||
|
.bn-block-outer:not([data-prev-depth-changed]):before {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bn-editor {
|
||||||
|
|
||||||
|
color: var(--c--theme--colors--greyscale-700);
|
||||||
|
}
|
||||||
|
.bn-block-outer:not(:first-child) {
|
||||||
|
&:has(h1) {
|
||||||
|
padding-top: 32px;
|
||||||
|
}
|
||||||
|
&:has(h2) {
|
||||||
|
padding-top: 24px;
|
||||||
|
}
|
||||||
|
&:has(h3) {
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
& .bn-inline-content code {
|
& .bn-inline-content code {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export const DocEditor = ({ doc, versionId }: DocEditorProps) => {
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
<Box $maxWidth="868px" $width="100%" $height="100%">
|
<Box $maxWidth="868px" $width="100%" $height="100%">
|
||||||
<Box $padding={{ horizontal: '54px' }}>
|
<Box $padding={{ horizontal: isDesktop ? '54px' : 'base' }}>
|
||||||
{isVersion ? (
|
{isVersion ? (
|
||||||
<DocVersionHeader title={doc.title} />
|
<DocVersionHeader title={doc.title} />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export const DocHeader = ({ doc }: DocHeaderProps) => {
|
|||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
$width="100%"
|
$width="100%"
|
||||||
$padding={{ top: 'base' }}
|
$padding={{ top: isDesktop ? '4xl' : 'md' }}
|
||||||
$gap={spacings['base']}
|
$gap={spacings['base']}
|
||||||
aria-label={t('It is the card information about the document.')}
|
aria-label={t('It is the card information about the document.')}
|
||||||
>
|
>
|
||||||
@@ -72,10 +72,10 @@ export const DocHeader = ({ doc }: DocHeaderProps) => {
|
|||||||
<Box $direction="row">
|
<Box $direction="row">
|
||||||
{isDesktop && (
|
{isDesktop && (
|
||||||
<>
|
<>
|
||||||
<Text $variation="400" $size="s" $weight="bold">
|
<Text $variation="600" $size="s" $weight="bold">
|
||||||
{transRole(currentDocRole(doc.abilities))} ·
|
{transRole(currentDocRole(doc.abilities))} ·
|
||||||
</Text>
|
</Text>
|
||||||
<Text $variation="400" $size="s">
|
<Text $variation="600" $size="s">
|
||||||
{t('Last update: {{update}}', {
|
{t('Last update: {{update}}', {
|
||||||
update: DateTime.fromISO(doc.updated_at).toRelative(),
|
update: DateTime.fromISO(doc.updated_at).toRelative(),
|
||||||
})}
|
})}
|
||||||
@@ -92,7 +92,7 @@ export const DocHeader = ({ doc }: DocHeaderProps) => {
|
|||||||
<DocToolBox doc={doc} />
|
<DocToolBox doc={doc} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<HorizontalSeparator />
|
<HorizontalSeparator $withPadding={true} />
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export const DocTitleText = ({ title }: DocTitleTextProps) => {
|
|||||||
as="h2"
|
as="h2"
|
||||||
$margin={{ all: 'none', left: 'none' }}
|
$margin={{ all: 'none', left: 'none' }}
|
||||||
$size={isMobile ? 'h4' : 'h2'}
|
$size={isMobile ? 'h4' : 'h2'}
|
||||||
|
$variation="1000"
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -113,7 +114,7 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
|
|||||||
onBlurCapture={(event) =>
|
onBlurCapture={(event) =>
|
||||||
handleTitleSubmit(event.target.textContent || '')
|
handleTitleSubmit(event.target.textContent || '')
|
||||||
}
|
}
|
||||||
$color={colorsTokens()['greyscale-text']}
|
$color={colorsTokens()['greyscale-1000']}
|
||||||
$margin={{ left: '-2px', right: '10px' }}
|
$margin={{ left: '-2px', right: '10px' }}
|
||||||
$css={css`
|
$css={css`
|
||||||
&[contenteditable='true']:empty:not(:focus):before {
|
&[contenteditable='true']:empty:not(:focus):before {
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import {
|
|||||||
useModal,
|
useModal,
|
||||||
useToastProvider,
|
useToastProvider,
|
||||||
} from '@openfun/cunningham-react';
|
} from '@openfun/cunningham-react';
|
||||||
import { useState } from 'react';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { css } from 'styled-components';
|
import { css } from 'styled-components';
|
||||||
|
|
||||||
@@ -17,12 +18,12 @@ import {
|
|||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { useAuthStore } from '@/core';
|
import { useAuthStore } from '@/core';
|
||||||
import { useCunninghamTheme } from '@/cunningham';
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
import {
|
import { useEditorStore } from '@/features/docs/doc-editor/';
|
||||||
useEditorStore,
|
|
||||||
usePanelEditorStore,
|
|
||||||
} from '@/features/docs/doc-editor/';
|
|
||||||
import { Doc, ModalRemoveDoc } from '@/features/docs/doc-management';
|
import { Doc, ModalRemoveDoc } from '@/features/docs/doc-management';
|
||||||
import { ModalSelectVersion } from '@/features/docs/doc-versioning';
|
import {
|
||||||
|
KEY_LIST_DOC_VERSIONS,
|
||||||
|
ModalSelectVersion,
|
||||||
|
} from '@/features/docs/doc-versioning';
|
||||||
import { useResponsiveStore } from '@/stores';
|
import { useResponsiveStore } from '@/stores';
|
||||||
|
|
||||||
import { DocShareModal } from '../../doc-share/component/DocShareModal';
|
import { DocShareModal } from '../../doc-share/component/DocShareModal';
|
||||||
@@ -35,6 +36,8 @@ interface DocToolBoxProps {
|
|||||||
|
|
||||||
export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const hasAccesses = doc.nb_accesses > 1;
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
|
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
|
||||||
|
|
||||||
const spacings = spacingsTokens();
|
const spacings = spacingsTokens();
|
||||||
@@ -44,7 +47,6 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
|||||||
const [isModalPDFOpen, setIsModalPDFOpen] = useState(false);
|
const [isModalPDFOpen, setIsModalPDFOpen] = useState(false);
|
||||||
const selectHistoryModal = useModal();
|
const selectHistoryModal = useModal();
|
||||||
const modalShare = useModal();
|
const modalShare = useModal();
|
||||||
const { setIsPanelOpen, setIsPanelTableContentOpen } = usePanelEditorStore();
|
|
||||||
|
|
||||||
const { isSmallMobile, isDesktop } = useResponsiveStore();
|
const { isSmallMobile, isDesktop } = useResponsiveStore();
|
||||||
const { authenticated } = useAuthStore();
|
const { authenticated } = useAuthStore();
|
||||||
@@ -80,14 +82,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
|||||||
},
|
},
|
||||||
show: isDesktop,
|
show: isDesktop,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: t('Table of contents'),
|
|
||||||
icon: 'summarize',
|
|
||||||
callback: () => {
|
|
||||||
setIsPanelOpen(true);
|
|
||||||
setIsPanelTableContentOpen(true);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: t('Copy as {{format}}', { format: 'Markdown' }),
|
label: t('Copy as {{format}}', { format: 'Markdown' }),
|
||||||
icon: 'content_copy',
|
icon: 'content_copy',
|
||||||
@@ -135,6 +130,16 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectHistoryModal.isOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void queryClient.resetQueries({
|
||||||
|
queryKey: [KEY_LIST_DOC_VERSIONS],
|
||||||
|
});
|
||||||
|
}, [selectHistoryModal.isOpen, queryClient]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
$margin={{ left: 'auto' }}
|
$margin={{ left: 'auto' }}
|
||||||
@@ -143,21 +148,55 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
|||||||
$gap="0.5rem 1.5rem"
|
$gap="0.5rem 1.5rem"
|
||||||
$wrap={isSmallMobile ? 'wrap' : 'nowrap'}
|
$wrap={isSmallMobile ? 'wrap' : 'nowrap'}
|
||||||
>
|
>
|
||||||
<Box $direction="row" $margin={{ left: 'auto' }} $gap={spacings['2xs']}>
|
<Box
|
||||||
|
$direction="row"
|
||||||
|
$align="center"
|
||||||
|
$margin={{ left: 'auto' }}
|
||||||
|
$gap={spacings['2xs']}
|
||||||
|
>
|
||||||
{authenticated && !isSmallMobile && (
|
{authenticated && !isSmallMobile && (
|
||||||
<Button
|
<>
|
||||||
color="primary-text"
|
{!hasAccesses && (
|
||||||
onClick={() => {
|
<Button
|
||||||
modalShare.open();
|
color="tertiary-text"
|
||||||
}}
|
onClick={() => {
|
||||||
size={isSmallMobile ? 'small' : 'medium'}
|
modalShare.open();
|
||||||
>
|
}}
|
||||||
{t('Share')}
|
size={isSmallMobile ? 'small' : 'medium'}
|
||||||
</Button>
|
>
|
||||||
|
{t('Share')}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{hasAccesses && (
|
||||||
|
<Box
|
||||||
|
$css={css`
|
||||||
|
.c__button--medium {
|
||||||
|
height: 32px;
|
||||||
|
padding: 10px var(--c--theme--spacings--xs);
|
||||||
|
gap: 7px;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
color="tertiary"
|
||||||
|
aria-label="Share button"
|
||||||
|
icon={
|
||||||
|
<Icon iconName="group" $theme="primary" $variation="800" />
|
||||||
|
}
|
||||||
|
onClick={() => {
|
||||||
|
modalShare.open();
|
||||||
|
}}
|
||||||
|
size={isSmallMobile ? 'small' : 'medium'}
|
||||||
|
>
|
||||||
|
{doc.nb_accesses}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{!isSmallMobile && (
|
{!isSmallMobile && (
|
||||||
<Button
|
<Button
|
||||||
color="primary-text"
|
color="tertiary-text"
|
||||||
icon={
|
icon={
|
||||||
<Icon iconName="download" $theme="primary" $variation="800" />
|
<Icon iconName="download" $theme="primary" $variation="800" />
|
||||||
}
|
}
|
||||||
@@ -171,15 +210,18 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
|||||||
<IconOptions
|
<IconOptions
|
||||||
isHorizontal
|
isHorizontal
|
||||||
$theme="primary"
|
$theme="primary"
|
||||||
$radius={spacings['3xs']}
|
$padding={{ all: 'xs' }}
|
||||||
$css={
|
$css={css`
|
||||||
isSmallMobile
|
&:hover {
|
||||||
|
background-color: ${colors['greyscale-100']};
|
||||||
|
}
|
||||||
|
${isSmallMobile
|
||||||
? css`
|
? css`
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid ${colors['greyscale-300']};
|
border: 1px solid ${colors['greyscale-300']};
|
||||||
`
|
`
|
||||||
: ''
|
: ''}
|
||||||
}
|
`}
|
||||||
aria-label={t('Open the document options')}
|
aria-label={t('Open the document options')}
|
||||||
/>
|
/>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|||||||
@@ -130,7 +130,6 @@ export const ModalPDF = ({ onClose, doc }: ModalPDFProps) => {
|
|||||||
data-testid="modal-export"
|
data-testid="modal-export"
|
||||||
isOpen
|
isOpen
|
||||||
closeOnClickOutside
|
closeOnClickOutside
|
||||||
hideCloseButton
|
|
||||||
onClose={() => onClose()}
|
onClose={() => onClose()}
|
||||||
rightActions={
|
rightActions={
|
||||||
<>
|
<>
|
||||||
@@ -155,7 +154,7 @@ export const ModalPDF = ({ onClose, doc }: ModalPDFProps) => {
|
|||||||
}
|
}
|
||||||
size={ModalSize.MEDIUM}
|
size={ModalSize.MEDIUM}
|
||||||
title={
|
title={
|
||||||
<Text $size="h6" $align="flex-start">
|
<Text $size="h6" $variation="1000" $align="flex-start">
|
||||||
{t('Download')}
|
{t('Download')}
|
||||||
</Text>
|
</Text>
|
||||||
}
|
}
|
||||||
@@ -163,9 +162,9 @@ export const ModalPDF = ({ onClose, doc }: ModalPDFProps) => {
|
|||||||
<Box
|
<Box
|
||||||
$margin={{ bottom: 'xl' }}
|
$margin={{ bottom: 'xl' }}
|
||||||
aria-label={t('Content modal to export the document')}
|
aria-label={t('Content modal to export the document')}
|
||||||
$gap="1.5rem"
|
$gap="1rem"
|
||||||
>
|
>
|
||||||
<Text $variation="600">
|
<Text $variation="600" $size="sm">
|
||||||
{t(
|
{t(
|
||||||
'Upload your docs to a Microsoft Word, Open Office or PDF document.',
|
'Upload your docs to a Microsoft Word, Open Office or PDF document.',
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function useUpdateDoc({
|
|||||||
mutationFn: updateDoc,
|
mutationFn: updateDoc,
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
listInvalideQueries?.forEach((queryKey) => {
|
listInvalideQueries?.forEach((queryKey) => {
|
||||||
void queryClient.resetQueries({
|
void queryClient.invalidateQueries({
|
||||||
queryKey: [queryKey],
|
queryKey: [queryKey],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
Alert,
|
|
||||||
Button,
|
Button,
|
||||||
Modal,
|
Modal,
|
||||||
ModalSize,
|
ModalSize,
|
||||||
@@ -48,41 +47,36 @@ export const ModalRemoveDoc = ({ onClose, doc }: ModalRemoveDocProps) => {
|
|||||||
isOpen
|
isOpen
|
||||||
closeOnClickOutside
|
closeOnClickOutside
|
||||||
hideCloseButton
|
hideCloseButton
|
||||||
leftActions={
|
|
||||||
<Button
|
|
||||||
aria-label={t('Close the modal')}
|
|
||||||
color="secondary"
|
|
||||||
fullWidth
|
|
||||||
onClick={() => onClose()}
|
|
||||||
>
|
|
||||||
{t('Cancel')}
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
onClose={() => onClose()}
|
onClose={() => onClose()}
|
||||||
rightActions={
|
rightActions={
|
||||||
<Button
|
<>
|
||||||
aria-label={t('Confirm deletion')}
|
<Button
|
||||||
color="danger"
|
aria-label={t('Close the modal')}
|
||||||
fullWidth
|
color="secondary"
|
||||||
onClick={() =>
|
fullWidth
|
||||||
removeDoc({
|
onClick={() => onClose()}
|
||||||
docId: doc.id,
|
>
|
||||||
})
|
{t('Cancel')}
|
||||||
}
|
</Button>
|
||||||
>
|
<Button
|
||||||
{t('Confirm deletion')}
|
aria-label={t('Confirm deletion')}
|
||||||
</Button>
|
color="danger"
|
||||||
|
fullWidth
|
||||||
|
onClick={() =>
|
||||||
|
removeDoc({
|
||||||
|
docId: doc.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t('Delete')}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
size={ModalSize.MEDIUM}
|
size={ModalSize.SMALL}
|
||||||
title={
|
title={
|
||||||
<Box $align="center" $gap="1rem">
|
<Text $size="h6" as="h6" $margin={{ all: '0' }} $align="flex-start">
|
||||||
<Text $isMaterialIcon $size="48px" $theme="primary" $variation="600">
|
{t('Delete a doc')}
|
||||||
delete_forever
|
</Text>
|
||||||
</Text>
|
|
||||||
<Text as="h2" $size="h3" $margin="none">
|
|
||||||
{t('Deleting the document "{{title}}"', { title: doc.title })}
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
@@ -90,13 +84,11 @@ export const ModalRemoveDoc = ({ onClose, doc }: ModalRemoveDocProps) => {
|
|||||||
aria-label={t('Content modal to delete document')}
|
aria-label={t('Content modal to delete document')}
|
||||||
>
|
>
|
||||||
{!isError && (
|
{!isError && (
|
||||||
<Alert canClose={false} type={VariantType.WARNING}>
|
<Text $size="sm" $variation="600">
|
||||||
<Text>
|
{t('Are you sure you want to delete the document "{{title}}"?', {
|
||||||
{t('Are you sure you want to delete the document "{{title}}"?', {
|
title: doc.title,
|
||||||
title: doc.title,
|
})}
|
||||||
})}
|
</Text>
|
||||||
</Text>
|
|
||||||
</Alert>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isError && <TextErrors causes={error.cause} />}
|
{isError && <TextErrors causes={error.cause} />}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import { useEffect, useState } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { css } from 'styled-components';
|
import { css } from 'styled-components';
|
||||||
|
|
||||||
import { Box, Icon, Text } from '@/components';
|
import { Box, BoxButton, Icon, Text } from '@/components';
|
||||||
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
import { useEditorStore, useHeadingStore } from '@/features/docs/doc-editor';
|
import { useEditorStore, useHeadingStore } from '@/features/docs/doc-editor';
|
||||||
import { MAIN_LAYOUT_ID } from '@/layouts/conf';
|
import { MAIN_LAYOUT_ID } from '@/layouts/conf';
|
||||||
|
|
||||||
@@ -11,6 +12,8 @@ import { Heading } from './Heading';
|
|||||||
export const TableContent = () => {
|
export const TableContent = () => {
|
||||||
const { headings } = useHeadingStore();
|
const { headings } = useHeadingStore();
|
||||||
const { editor } = useEditorStore();
|
const { editor } = useEditorStore();
|
||||||
|
const { spacingsTokens } = useCunninghamTheme();
|
||||||
|
const spacing = spacingsTokens();
|
||||||
|
|
||||||
const [headingIdHighlight, setHeadingIdHighlight] = useState<string>();
|
const [headingIdHighlight, setHeadingIdHighlight] = useState<string>();
|
||||||
|
|
||||||
@@ -58,33 +61,33 @@ export const TableContent = () => {
|
|||||||
};
|
};
|
||||||
}, [headings, setHeadingIdHighlight]);
|
}, [headings, setHeadingIdHighlight]);
|
||||||
|
|
||||||
|
const onOpen = () => {
|
||||||
|
setIsHover(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
const element = document.getElementById(`heading-${headingIdHighlight}`);
|
||||||
|
|
||||||
|
element?.scrollIntoView({
|
||||||
|
behavior: 'instant',
|
||||||
|
inline: 'center',
|
||||||
|
block: 'center',
|
||||||
|
});
|
||||||
|
}, 0); // 300ms is the transition time of the box
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
setIsHover(false);
|
||||||
|
};
|
||||||
|
|
||||||
if (!editor) {
|
if (!editor) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
onMouseEnter={() => {
|
|
||||||
setIsHover(true);
|
|
||||||
setTimeout(() => {
|
|
||||||
const element = document.getElementById(
|
|
||||||
`heading-${headingIdHighlight}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
element?.scrollIntoView({
|
|
||||||
behavior: 'smooth',
|
|
||||||
inline: 'center',
|
|
||||||
block: 'center',
|
|
||||||
});
|
|
||||||
}, 250); // 300ms is the transition time of the box
|
|
||||||
}}
|
|
||||||
onMouseLeave={() => {
|
|
||||||
setIsHover(false);
|
|
||||||
}}
|
|
||||||
id="summaryContainer"
|
id="summaryContainer"
|
||||||
$effect="show"
|
$width={!isHover ? '40px' : '200px'}
|
||||||
$width="40px"
|
$height={!isHover ? '40px' : 'auto'}
|
||||||
$height="40px"
|
$maxHeight="calc(50vh - 60px)"
|
||||||
$zIndex={1000}
|
$zIndex={1000}
|
||||||
$align="center"
|
$align="center"
|
||||||
$padding="xs"
|
$padding="xs"
|
||||||
@@ -94,51 +97,69 @@ export const TableContent = () => {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: var(--c--theme--spacings--3xs);
|
border-radius: var(--c--theme--spacings--3xs);
|
||||||
background: var(--c--theme--colors--greyscale-000);
|
background: var(--c--theme--colors--greyscale-000);
|
||||||
|
${isHover &&
|
||||||
&:hover {
|
css`
|
||||||
overflow-y: auto;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: var(--c--theme--spacings--2xs);
|
gap: var(--c--theme--spacings--2xs);
|
||||||
width: 200px;
|
`}
|
||||||
height: auto;
|
|
||||||
max-height: calc(100vh - 60px - 15vh);
|
|
||||||
}
|
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
{!isHover && (
|
{!isHover && (
|
||||||
<Box $justify="center" $align="center">
|
<BoxButton onClick={onOpen} $justify="center" $align="center">
|
||||||
<Icon iconName="list" $theme="primary" $variation="800" />
|
<Icon iconName="list" $theme="primary" $variation="800" />
|
||||||
</Box>
|
</BoxButton>
|
||||||
)}
|
)}
|
||||||
{isHover && (
|
{isHover && (
|
||||||
<Box $width="100%">
|
<Box
|
||||||
|
$width="100%"
|
||||||
|
$overflow="hidden"
|
||||||
|
$css={css`
|
||||||
|
user-select: none;
|
||||||
|
`}
|
||||||
|
>
|
||||||
<Box
|
<Box
|
||||||
$margin={{ bottom: '20px' }}
|
$margin={{ bottom: '10px' }}
|
||||||
$direction="row"
|
$direction="row"
|
||||||
$justify="space-between"
|
$justify="space-between"
|
||||||
$align="center"
|
$align="center"
|
||||||
>
|
>
|
||||||
<Text $weight="bold" $variation="800" $theme="primary">
|
<Text $weight="500" $size="sm" $variation="800" $theme="primary">
|
||||||
{t('Summary')}
|
{t('Summary')}
|
||||||
</Text>
|
</Text>
|
||||||
<Icon iconName="list" $theme="primary" $variation="800" />
|
<BoxButton
|
||||||
|
onClick={onClose}
|
||||||
|
$justify="center"
|
||||||
|
$align="center"
|
||||||
|
$css={css`
|
||||||
|
transform: rotate(180deg);
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<Icon iconName="menu_open" $theme="primary" $variation="800" />
|
||||||
|
</BoxButton>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
$gap={spacing['3xs']}
|
||||||
|
$css={css`
|
||||||
|
overflow-y: auto;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{headings?.map(
|
||||||
|
(heading) =>
|
||||||
|
heading.contentText && (
|
||||||
|
<Heading
|
||||||
|
editor={editor}
|
||||||
|
headingId={heading.id}
|
||||||
|
level={heading.props.level}
|
||||||
|
text={heading.contentText}
|
||||||
|
key={heading.id}
|
||||||
|
isHighlight={headingIdHighlight === heading.id}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
{headings?.map(
|
|
||||||
(heading) =>
|
|
||||||
heading.contentText && (
|
|
||||||
<Heading
|
|
||||||
editor={editor}
|
|
||||||
headingId={heading.id}
|
|
||||||
level={heading.props.level}
|
|
||||||
text={heading.contentText}
|
|
||||||
key={heading.id}
|
|
||||||
isHighlight={headingIdHighlight === heading.id}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ export const ModalSelectVersion = ({
|
|||||||
aria-label="version history modal"
|
aria-label="version history modal"
|
||||||
className="noPadding"
|
className="noPadding"
|
||||||
$direction="row"
|
$direction="row"
|
||||||
$height="calc(100vh - 50px);"
|
$height="100%"
|
||||||
|
$maxHeight="calc(100vh - 2em - 12px)"
|
||||||
$overflow="hidden"
|
$overflow="hidden"
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
@@ -64,7 +65,11 @@ export const ModalSelectVersion = ({
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
<Box $width="100%" $padding="base" $align="center">
|
<Box
|
||||||
|
$width="100%"
|
||||||
|
$padding={{ horizontal: 'base', vertical: 'xl' }}
|
||||||
|
$align="center"
|
||||||
|
>
|
||||||
{selectedVersionId && (
|
{selectedVersionId && (
|
||||||
<DocEditor doc={doc} versionId={selectedVersionId} />
|
<DocEditor doc={doc} versionId={selectedVersionId} />
|
||||||
)}
|
)}
|
||||||
@@ -81,7 +86,7 @@ export const ModalSelectVersion = ({
|
|||||||
$direction="column"
|
$direction="column"
|
||||||
$justify="space-between"
|
$justify="space-between"
|
||||||
$width="250px"
|
$width="250px"
|
||||||
$height="calc(100vh - 2em - 30px);"
|
$height="calc(100vh - 2em - 12px)"
|
||||||
$css={css`
|
$css={css`
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
border-left: 1px solid var(--c--theme--colors--greyscale-200);
|
border-left: 1px solid var(--c--theme--colors--greyscale-200);
|
||||||
@@ -105,7 +110,7 @@ export const ModalSelectVersion = ({
|
|||||||
`}
|
`}
|
||||||
$padding="sm"
|
$padding="sm"
|
||||||
>
|
>
|
||||||
<Text $size="h6" $weight="bold">
|
<Text $size="h6" $variation="1000" $weight="bold">
|
||||||
{t('History')}
|
{t('History')}
|
||||||
</Text>
|
</Text>
|
||||||
<Button
|
<Button
|
||||||
@@ -123,7 +128,7 @@ export const ModalSelectVersion = ({
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
$padding="base"
|
$padding="xs"
|
||||||
$css={css`
|
$css={css`
|
||||||
border-top: 1px solid var(--c--theme--colors--greyscale-200);
|
border-top: 1px solid var(--c--theme--colors--greyscale-200);
|
||||||
`}
|
`}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Loader } from '@openfun/cunningham-react';
|
import { Loader } from '@openfun/cunningham-react';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { APIError } from '@/api';
|
import { APIError } from '@/api';
|
||||||
@@ -105,11 +104,9 @@ export const VersionList = ({
|
|||||||
docId: doc.id,
|
docId: doc.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const versions = useMemo(() => {
|
const versions = data?.pages.reduce((acc, page) => {
|
||||||
return data?.pages.reduce((acc, page) => {
|
return acc.concat(page.versions);
|
||||||
return acc.concat(page.versions);
|
}, [] as Versions[]);
|
||||||
}, [] as Versions[]);
|
|
||||||
}, [data?.pages]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box $css="overflow-y: auto; overflow-x: hidden;">
|
<Box $css="overflow-y: auto; overflow-x: hidden;">
|
||||||
|
|||||||
Reference in New Issue
Block a user