Skip to content

Commit 6a6c8cf

Browse files
committed
feat: add fullscreen button to editor
1 parent 5672644 commit 6a6c8cf

File tree

6 files changed

+104
-28
lines changed

6 files changed

+104
-28
lines changed

src/editors/AdvancedEditor.tsx

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import React, { useEffect } from 'react';
22
import { getConfig } from '@edx/frontend-platform';
33
import { useIntl } from '@edx/frontend-platform/i18n';
4-
import { useToggle } from '@openedx/paragon';
4+
import {
5+
ActionRow,
6+
Icon,
7+
IconButton,
8+
ModalDialog,
9+
ModalCloseButton,
10+
Stack,
11+
useToggle,
12+
} from '@openedx/paragon';
13+
import { Close, CloseFullscreen, OpenInFull } from '@openedx/paragon/icons';
514

615
import { LibraryBlock } from '../library-authoring/LibraryBlock';
716
import { EditorModalWrapper } from './containers/EditorContainer';
@@ -11,6 +20,8 @@ import messages from './messages';
1120
import CancelConfirmModal from './containers/EditorContainer/components/CancelConfirmModal';
1221
import { IframeProvider } from '../generic/hooks/context/iFrameContext';
1322

23+
import editorModalWrapperMessages from './containers/EditorContainer/messages';
24+
1425
interface AdvancedEditorProps {
1526
usageKey: string,
1627
onClose: (() => void) | null,
@@ -20,6 +31,7 @@ const AdvancedEditor = ({ usageKey, onClose }: AdvancedEditorProps) => {
2031
const intl = useIntl();
2132
const { showToast } = React.useContext(ToastContext);
2233
const [isCancelConfirmOpen, openCancelConfirmModal, closeCancelConfirmModal] = useToggle(false);
34+
const [isFullscreen, , , toggleFullscreen] = useToggle(false);
2335

2436
useEffect(() => {
2537
const handleIframeMessage = (event) => {
@@ -49,7 +61,28 @@ const AdvancedEditor = ({ usageKey, onClose }: AdvancedEditorProps) => {
4961

5062
return (
5163
<>
52-
<EditorModalWrapper onClose={openCancelConfirmModal}>
64+
<EditorModalWrapper onClose={openCancelConfirmModal} fullscreen={isFullscreen}>
65+
<ModalDialog.Header>
66+
<ActionRow>
67+
<ModalDialog.Title>
68+
{intl.formatMessage(editorModalWrapperMessages.modalTitle)}
69+
</ModalDialog.Title>
70+
<ActionRow.Spacer />
71+
<Stack direction="horizontal" reversed>
72+
<ModalCloseButton
73+
as={IconButton}
74+
src={Close}
75+
iconAs={Icon}
76+
/>
77+
<IconButton
78+
src={isFullscreen ? CloseFullscreen : OpenInFull}
79+
iconAs={Icon}
80+
alt={intl.formatMessage(messages.advancedEditorFullscreenButtonAlt)}
81+
onClick={toggleFullscreen}
82+
/>
83+
</Stack>
84+
</ActionRow>
85+
</ModalDialog.Header>
5386
<IframeProvider>
5487
<LibraryBlock
5588
usageKey={usageKey}

src/editors/containers/EditorContainer/index.tsx

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,57 @@ import {
88
IconButton,
99
ModalDialog,
1010
Spinner,
11+
Stack,
1112
Toast,
13+
useToggle,
1214
} from '@openedx/paragon';
13-
import { Close } from '@openedx/paragon/icons';
15+
import { Close, CloseFullscreen, OpenInFull } from '@openedx/paragon/icons';
1416
import { useIntl, FormattedMessage } from '@edx/frontend-platform/i18n';
1517

18+
import { parseErrorMsg } from '@src/library-authoring/add-content/AddContent';
19+
import libraryMessages from '@src/library-authoring/add-content/messages';
20+
import usePromptIfDirty from '@src/generic/promptIfDirty/usePromptIfDirty';
21+
1622
import { EditorComponent } from '../../EditorComponent';
1723
import TitleHeader from './components/TitleHeader';
1824
import * as hooks from './hooks';
1925
import messages from './messages';
20-
import { parseErrorMsg } from '../../../library-authoring/add-content/AddContent';
21-
import libraryMessages from '../../../library-authoring/add-content/messages';
2226

2327
import './index.scss';
24-
import usePromptIfDirty from '../../../generic/promptIfDirty/usePromptIfDirty';
2528
import CancelConfirmModal from './components/CancelConfirmModal';
2629

2730
interface WrapperProps {
2831
children: React.ReactNode;
2932
}
3033

31-
export const EditorModalWrapper: React.FC<WrapperProps & { onClose: () => void }> = ({ children, onClose }) => {
34+
export const EditorModalWrapper: React.FC<WrapperProps & { onClose: () => void, fullscreen?: boolean }> = (
35+
{
36+
children,
37+
onClose,
38+
fullscreen = false,
39+
},
40+
) => {
3241
const intl = useIntl();
3342

3443
const title = intl.formatMessage(messages.modalTitle);
3544
return (
36-
<ModalDialog isOpen size="xl" isOverflowVisible={false} onClose={onClose} title={title}>{children}</ModalDialog>
45+
<ModalDialog
46+
isOpen
47+
onClose={onClose}
48+
title={title}
49+
size={fullscreen ? 'fullscreen' : 'xl'}
50+
isOverflowVisible={false}
51+
hasCloseButton={false}
52+
>
53+
{children}
54+
</ModalDialog>
3755
);
3856
};
3957

40-
export const EditorModalBody: React.FC<WrapperProps> = ({ children }) => <ModalDialog.Body className="pb-0">{ children }</ModalDialog.Body>;
58+
export const EditorModalBody: React.FC<WrapperProps> = ({ children }) => <ModalDialog.Body className="pb-0">{children}</ModalDialog.Body>;
4159

4260
// eslint-disable-next-line react/jsx-no-useless-fragment
43-
export const FooterWrapper: React.FC<WrapperProps> = ({ children }) => <>{ children }</>;
61+
export const FooterWrapper: React.FC<WrapperProps> = ({ children }) => <>{children}</>;
4462

4563
interface Props extends EditorComponent {
4664
children: React.ReactNode;
@@ -63,6 +81,7 @@ const EditorContainer: React.FC<Props> = ({
6381
const [saved, setSaved] = React.useState(false);
6482
const isInitialized = hooks.isInitialized();
6583
const { isCancelConfirmOpen, openCancelConfirmModal, closeCancelConfirmModal } = hooks.cancelConfirmModalToggle();
84+
const [isFullscreen, , , toggleFullscreen] = useToggle(false);
6685
const handleCancel = hooks.handleCancel({ onClose, returnFunction });
6786
const { createFailed, createFailedError } = hooks.createFailed();
6887
const disableSave = !isInitialized;
@@ -97,8 +116,9 @@ const EditorContainer: React.FC<Props> = ({
97116
handleCancel();
98117
}
99118
};
119+
100120
return (
101-
<EditorModalWrapper onClose={confirmCancelIfDirty}>
121+
<EditorModalWrapper onClose={confirmCancelIfDirty} fullscreen={isFullscreen}>
102122
{createFailed && (
103123
<Toast show onClose={clearCreateFailed}>
104124
{parseErrorMsg(
@@ -127,15 +147,27 @@ const EditorContainer: React.FC<Props> = ({
127147
/>
128148
<ModalDialog.Header className="shadow-sm zindex-10">
129149
<div className="d-flex flex-row justify-content-between">
130-
<h2 className="h3 col pl-0">
131-
<TitleHeader isInitialized={isInitialized} />
132-
</h2>
133-
<IconButton
134-
src={Close}
135-
iconAs={Icon}
136-
onClick={confirmCancelIfDirty}
137-
alt={intl.formatMessage(messages.exitButtonAlt)}
138-
/>
150+
<ActionRow>
151+
<h2 className="h3 col pl-0">
152+
<TitleHeader isInitialized={isInitialized} />
153+
</h2>
154+
<ActionRow.Spacer />
155+
<Stack direction="horizontal" reversed>
156+
<IconButton
157+
src={Close}
158+
iconAs={Icon}
159+
onClick={confirmCancelIfDirty}
160+
alt={intl.formatMessage(messages.exitButtonAlt)}
161+
autoFocus
162+
/>
163+
<IconButton
164+
src={isFullscreen ? CloseFullscreen : OpenInFull}
165+
iconAs={Icon}
166+
alt={intl.formatMessage(messages.toggleFullscreenButtonLabel)}
167+
onClick={toggleFullscreen}
168+
/>
169+
</Stack>
170+
</ActionRow>
139171
</div>
140172
</ModalDialog.Header>
141173
<EditorModalBody>

src/editors/containers/EditorContainer/messages.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { defineMessages } from '@edx/frontend-platform/i18n';
22

33
const messages = defineMessages({
4-
54
cancelConfirmTitle: {
65
id: 'authoring.editorContainer.cancelConfirm.title',
76
defaultMessage: 'Exit the editor?',
@@ -57,6 +56,11 @@ const messages = defineMessages({
5756
defaultMessage: 'Save',
5857
description: 'Label for Save button',
5958
},
59+
toggleFullscreenButtonLabel: {
60+
id: 'authoring.editorfooter.toggleFullscreen.label',
61+
defaultMessage: 'Toggle Fullscreen',
62+
description: 'Label for toggle fullscreen button',
63+
},
6064
});
6165

6266
export default messages;

src/editors/messages.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ const messages = defineMessages({
3636
defaultMessage: 'An unexpected error occurred in the editor',
3737
description: 'Generic error message shown when an error occurs in the Advanced Editor.',
3838
},
39+
advancedEditorFullscreenButtonAlt: {
40+
id: 'authoring.advancedEditor.fullscreenButton.alt',
41+
defaultMessage: 'Toggle Fullscreen',
42+
description: 'Alt text for the Fullscreen button',
43+
},
3944
});
4045

4146
export default messages;

src/generic/modal-iframe/index.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ export const SANDBOX_OPTIONS = [
2020
].join(' ');
2121

2222
const ModalIframe = forwardRef<HTMLIFrameElement, ModalIframeProps>(
23-
({ title, className, ...props }, ref: ForwardedRef<HTMLIFrameElement>) => (
23+
({
24+
title,
25+
className = '',
26+
...props
27+
}, ref: ForwardedRef<HTMLIFrameElement>) => (
2428
<iframe
2529
title={title}
2630
className={classNames('modal-iframe', className)}
@@ -36,8 +40,4 @@ const ModalIframe = forwardRef<HTMLIFrameElement, ModalIframeProps>(
3640
),
3741
);
3842

39-
ModalIframe.defaultProps = {
40-
className: '',
41-
};
42-
4343
export default ModalIframe;

src/library-authoring/components/ComponentEditorModal.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import { getConfig } from '@edx/frontend-platform';
22
import React from 'react';
33

44
import { useQueryClient } from '@tanstack/react-query';
5-
import EditorPage from '../../editors/EditorPage';
6-
import { getBlockType } from '../../generic/key-utils';
5+
6+
import EditorPage from '@src/editors/EditorPage';
7+
import { getBlockType } from '@src/generic/key-utils';
8+
79
import { useLibraryContext } from '../common/context/LibraryContext';
810
import { invalidateComponentData } from '../data/apiHooks';
911

0 commit comments

Comments
 (0)