fix(client): store challenge panes sizes (#42519)
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@ -8,12 +8,23 @@ import envData from '../../../../../config/env.json';
|
||||
|
||||
const { showUpcomingChanges } = envData;
|
||||
|
||||
const paneType = {
|
||||
flex: PropTypes.number
|
||||
};
|
||||
|
||||
const propTypes = {
|
||||
challengeFiles: PropTypes.object,
|
||||
editor: PropTypes.element,
|
||||
hasEditableBoundries: PropTypes.bool,
|
||||
hasPreview: PropTypes.bool,
|
||||
instructions: PropTypes.element,
|
||||
layoutState: PropTypes.shape({
|
||||
codePane: paneType,
|
||||
editorPane: paneType,
|
||||
instructionPane: paneType,
|
||||
previewPane: paneType,
|
||||
testsPane: paneType
|
||||
}),
|
||||
preview: PropTypes.element,
|
||||
resizeProps: PropTypes.shape({
|
||||
onStopResize: PropTypes.func,
|
||||
@ -55,6 +66,7 @@ class DesktopLayout extends Component {
|
||||
editor,
|
||||
testOutput,
|
||||
hasPreview,
|
||||
layoutState,
|
||||
preview,
|
||||
hasEditableBoundries
|
||||
} = this.props;
|
||||
@ -67,6 +79,8 @@ class DesktopLayout extends Component {
|
||||
? showPreview && hasPreview
|
||||
: hasPreview;
|
||||
const isConsoleDisplayable = projectBasedChallenge ? showConsole : true;
|
||||
const { codePane, editorPane, instructionPane, previewPane, testsPane } =
|
||||
layoutState;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
@ -75,7 +89,11 @@ class DesktopLayout extends Component {
|
||||
)}
|
||||
<ReflexContainer className='desktop-layout' orientation='vertical'>
|
||||
{!projectBasedChallenge && (
|
||||
<ReflexElement flex={1} {...resizeProps}>
|
||||
<ReflexElement
|
||||
flex={instructionPane.flex}
|
||||
name='instructionPane'
|
||||
{...resizeProps}
|
||||
>
|
||||
{instructions}
|
||||
</ReflexElement>
|
||||
)}
|
||||
@ -83,20 +101,34 @@ class DesktopLayout extends Component {
|
||||
<ReflexSplitter propagate={true} {...resizeProps} />
|
||||
)}
|
||||
|
||||
<ReflexElement flex={1} {...resizeProps}>
|
||||
<ReflexElement
|
||||
flex={editorPane.flex}
|
||||
name='editorPane'
|
||||
{...resizeProps}
|
||||
>
|
||||
{challengeFile && showUpcomingChanges && !hasEditableBoundries && (
|
||||
<EditorTabs />
|
||||
)}
|
||||
{challengeFile && (
|
||||
<ReflexContainer key={challengeFile.key} orientation='horizontal'>
|
||||
<ReflexElement flex={1} {...reflexProps} {...resizeProps}>
|
||||
<ReflexElement
|
||||
flex={codePane.flex}
|
||||
name='codePane'
|
||||
{...reflexProps}
|
||||
{...resizeProps}
|
||||
>
|
||||
{<Fragment>{editor}</Fragment>}
|
||||
</ReflexElement>
|
||||
{isConsoleDisplayable && (
|
||||
<ReflexSplitter propagate={true} {...resizeProps} />
|
||||
)}
|
||||
{isConsoleDisplayable && (
|
||||
<ReflexElement flex={0.25} {...reflexProps} {...resizeProps}>
|
||||
<ReflexElement
|
||||
flex={testsPane.flex}
|
||||
name='testsPane'
|
||||
{...reflexProps}
|
||||
{...resizeProps}
|
||||
>
|
||||
{testOutput}
|
||||
</ReflexElement>
|
||||
)}
|
||||
@ -107,7 +139,11 @@ class DesktopLayout extends Component {
|
||||
<ReflexSplitter propagate={true} {...resizeProps} />
|
||||
)}
|
||||
{isPreviewDisplayable && (
|
||||
<ReflexElement flex={0.7} {...resizeProps}>
|
||||
<ReflexElement
|
||||
flex={previewPane.flex}
|
||||
name='previewPane'
|
||||
{...resizeProps}
|
||||
>
|
||||
{preview}
|
||||
</ReflexElement>
|
||||
)}
|
||||
|
@ -22,7 +22,9 @@ import DesktopLayout from './DesktopLayout';
|
||||
import Hotkeys from '../components/Hotkeys';
|
||||
|
||||
import { getGuideUrl } from '../utils';
|
||||
import store from 'store';
|
||||
import { challengeTypes } from '../../../../utils/challengeTypes';
|
||||
import { isContained } from '../../../utils/is-contained';
|
||||
import { ChallengeNode } from '../../../redux/prop-types';
|
||||
import {
|
||||
createFiles,
|
||||
@ -92,6 +94,24 @@ const propTypes = {
|
||||
};
|
||||
|
||||
const MAX_MOBILE_WIDTH = 767;
|
||||
const REFLEX_LAYOUT = 'challenge-layout';
|
||||
const BASE_LAYOUT = {
|
||||
codePane: {
|
||||
flex: 1
|
||||
},
|
||||
editorPane: {
|
||||
flex: 1
|
||||
},
|
||||
instructionPane: {
|
||||
flex: 1
|
||||
},
|
||||
previewPane: {
|
||||
flex: 0.7
|
||||
},
|
||||
testsPane: {
|
||||
flex: 0.25
|
||||
}
|
||||
};
|
||||
|
||||
class ShowClassic extends Component {
|
||||
constructor() {
|
||||
@ -108,13 +128,44 @@ class ShowClassic extends Component {
|
||||
|
||||
this.containerRef = React.createRef();
|
||||
this.editorRef = React.createRef();
|
||||
// Holds the information of the panes sizes for desktop view
|
||||
this.layoutState = this.getLayoutState();
|
||||
}
|
||||
|
||||
getLayoutState() {
|
||||
const reflexLayout = store.get(REFLEX_LAYOUT);
|
||||
|
||||
// Validate if user has not done any resize of the panes
|
||||
if (!reflexLayout) return BASE_LAYOUT;
|
||||
|
||||
// Check that the layout values stored are valid (exist in base layout). If
|
||||
// not valid, it will fallback to the base layout values and be set on next
|
||||
// user resize.
|
||||
const isValidLayout = isContained(
|
||||
Object.keys(BASE_LAYOUT),
|
||||
Object.keys(reflexLayout)
|
||||
);
|
||||
|
||||
return isValidLayout ? reflexLayout : BASE_LAYOUT;
|
||||
}
|
||||
|
||||
onResize() {
|
||||
this.setState({ resizing: true });
|
||||
}
|
||||
|
||||
onStopResize() {
|
||||
onStopResize(event) {
|
||||
const { name, flex } = event.component.props;
|
||||
|
||||
this.setState({ resizing: false });
|
||||
|
||||
// Only interested in tracking layout updates for ReflexElement's
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.layoutState[name].flex = flex;
|
||||
|
||||
store.set(REFLEX_LAYOUT, this.layoutState);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@ -325,6 +376,7 @@ class ShowClassic extends Component {
|
||||
instructions={this.renderInstructionsPanel({
|
||||
showToolPanel: true
|
||||
})}
|
||||
layoutState={this.layoutState}
|
||||
preview={this.renderPreview()}
|
||||
resizeProps={this.resizeProps}
|
||||
testOutput={this.renderTestOutput()}
|
||||
|
15
client/src/utils/is-contained.test.ts
Normal file
15
client/src/utils/is-contained.test.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { isContained } from './is-contained';
|
||||
|
||||
describe('client/src isContained', () => {
|
||||
it('returns true if `arr1` values are contained in `arr2`', () => {
|
||||
const arr1 = ['dog', 'cat'];
|
||||
const arr2 = ['cat', 'dog'];
|
||||
expect(isContained(arr1, arr2)).toEqual(true);
|
||||
});
|
||||
|
||||
it('returns true if `arr1` values are not contained in `arr2`', () => {
|
||||
const arr1 = ['dog', 'cat'];
|
||||
const arr2 = ['cat', 'monkey', 'bird'];
|
||||
expect(isContained(arr1, arr2)).toEqual(false);
|
||||
});
|
||||
});
|
4
client/src/utils/is-contained.ts
Normal file
4
client/src/utils/is-contained.ts
Normal file
@ -0,0 +1,4 @@
|
||||
// Performs a check if the items in `value` exist in `other`
|
||||
export function isContained(value: string[], other: string[]): boolean {
|
||||
return value.every(i => other.includes(i));
|
||||
}
|
Reference in New Issue
Block a user