feat(client): place tool panel at the bottom
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex';
|
import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
@ -14,7 +14,8 @@ const propTypes = {
|
|||||||
onStopResize: PropTypes.func,
|
onStopResize: PropTypes.func,
|
||||||
onResize: PropTypes.func
|
onResize: PropTypes.func
|
||||||
}),
|
}),
|
||||||
testOutput: PropTypes.element
|
testOutput: PropTypes.element,
|
||||||
|
toolPanel: PropTypes.element
|
||||||
};
|
};
|
||||||
|
|
||||||
class DesktopLayout extends Component {
|
class DesktopLayout extends Component {
|
||||||
@ -26,46 +27,50 @@ class DesktopLayout extends Component {
|
|||||||
editor,
|
editor,
|
||||||
testOutput,
|
testOutput,
|
||||||
hasPreview,
|
hasPreview,
|
||||||
preview
|
preview,
|
||||||
|
toolPanel
|
||||||
} = this.props;
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<ReflexContainer className='desktop-layout' orientation='vertical'>
|
<Fragment>
|
||||||
<ReflexElement flex={1} {...resizeProps}>
|
<ReflexContainer className='desktop-layout' orientation='vertical'>
|
||||||
{instructions}
|
<ReflexElement flex={1} {...resizeProps}>
|
||||||
</ReflexElement>
|
{instructions}
|
||||||
<ReflexSplitter propagate={true} {...resizeProps} />
|
|
||||||
<ReflexElement flex={1} {...resizeProps}>
|
|
||||||
{challengeFile && (
|
|
||||||
<ReflexContainer key={challengeFile.key} orientation='horizontal'>
|
|
||||||
<ReflexElement
|
|
||||||
flex={1}
|
|
||||||
propagateDimensions={true}
|
|
||||||
renderOnResize={true}
|
|
||||||
renderOnResizeRate={20}
|
|
||||||
{...resizeProps}
|
|
||||||
>
|
|
||||||
{editor}
|
|
||||||
</ReflexElement>
|
|
||||||
<ReflexSplitter propagate={true} {...resizeProps} />
|
|
||||||
<ReflexElement
|
|
||||||
flex={0.25}
|
|
||||||
propagateDimensions={true}
|
|
||||||
renderOnResize={true}
|
|
||||||
renderOnResizeRate={20}
|
|
||||||
{...resizeProps}
|
|
||||||
>
|
|
||||||
{testOutput}
|
|
||||||
</ReflexElement>
|
|
||||||
</ReflexContainer>
|
|
||||||
)}
|
|
||||||
</ReflexElement>
|
|
||||||
{hasPreview && <ReflexSplitter propagate={true} {...resizeProps} />}
|
|
||||||
{hasPreview && (
|
|
||||||
<ReflexElement flex={0.7} {...resizeProps}>
|
|
||||||
{preview}
|
|
||||||
</ReflexElement>
|
</ReflexElement>
|
||||||
)}
|
<ReflexSplitter propagate={true} {...resizeProps} />
|
||||||
</ReflexContainer>
|
<ReflexElement flex={1} {...resizeProps}>
|
||||||
|
{challengeFile && (
|
||||||
|
<ReflexContainer key={challengeFile.key} orientation='horizontal'>
|
||||||
|
<ReflexElement
|
||||||
|
flex={1}
|
||||||
|
propagateDimensions={true}
|
||||||
|
renderOnResize={true}
|
||||||
|
renderOnResizeRate={20}
|
||||||
|
{...resizeProps}
|
||||||
|
>
|
||||||
|
{editor}
|
||||||
|
</ReflexElement>
|
||||||
|
<ReflexSplitter propagate={true} {...resizeProps} />
|
||||||
|
<ReflexElement
|
||||||
|
flex={0.25}
|
||||||
|
propagateDimensions={true}
|
||||||
|
renderOnResize={true}
|
||||||
|
renderOnResizeRate={20}
|
||||||
|
{...resizeProps}
|
||||||
|
>
|
||||||
|
{testOutput}
|
||||||
|
</ReflexElement>
|
||||||
|
</ReflexContainer>
|
||||||
|
)}
|
||||||
|
</ReflexElement>
|
||||||
|
{hasPreview && <ReflexSplitter propagate={true} {...resizeProps} />}
|
||||||
|
{hasPreview && (
|
||||||
|
<ReflexElement flex={0.7} {...resizeProps}>
|
||||||
|
{preview}
|
||||||
|
</ReflexElement>
|
||||||
|
)}
|
||||||
|
</ReflexContainer>
|
||||||
|
{toolPanel}
|
||||||
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
|
|||||||
import { TabPane, Tabs } from '@freecodecamp/react-bootstrap';
|
import { TabPane, Tabs } from '@freecodecamp/react-bootstrap';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import ToolPanel from '../components/Tool-Panel';
|
|
||||||
import { createStructuredSelector } from 'reselect';
|
import { createStructuredSelector } from 'reselect';
|
||||||
import { currentTabSelector, moveToTab } from '../redux';
|
import { currentTabSelector, moveToTab } from '../redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
@ -23,13 +22,12 @@ const mapDispatchToProps = dispatch =>
|
|||||||
const propTypes = {
|
const propTypes = {
|
||||||
currentTab: PropTypes.number,
|
currentTab: PropTypes.number,
|
||||||
editor: PropTypes.element,
|
editor: PropTypes.element,
|
||||||
guideUrl: PropTypes.string,
|
|
||||||
hasPreview: PropTypes.bool,
|
hasPreview: PropTypes.bool,
|
||||||
instructions: PropTypes.element,
|
instructions: PropTypes.element,
|
||||||
moveToTab: PropTypes.func,
|
moveToTab: PropTypes.func,
|
||||||
preview: PropTypes.element,
|
preview: PropTypes.element,
|
||||||
testOutput: PropTypes.element,
|
testOutput: PropTypes.element,
|
||||||
videoUrl: PropTypes.string
|
toolPanel: PropTypes.element
|
||||||
};
|
};
|
||||||
|
|
||||||
class MobileLayout extends Component {
|
class MobileLayout extends Component {
|
||||||
@ -42,8 +40,7 @@ class MobileLayout extends Component {
|
|||||||
testOutput,
|
testOutput,
|
||||||
hasPreview,
|
hasPreview,
|
||||||
preview,
|
preview,
|
||||||
guideUrl,
|
toolPanel
|
||||||
videoUrl
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const editorTabPaneProps = {
|
const editorTabPaneProps = {
|
||||||
@ -74,7 +71,7 @@ class MobileLayout extends Component {
|
|||||||
</TabPane>
|
</TabPane>
|
||||||
)}
|
)}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<ToolPanel guideUrl={guideUrl} isMobile={true} videoUrl={videoUrl} />
|
{toolPanel}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import VideoModal from '../components/VideoModal';
|
|||||||
import ResetModal from '../components/ResetModal';
|
import ResetModal from '../components/ResetModal';
|
||||||
import MobileLayout from './MobileLayout';
|
import MobileLayout from './MobileLayout';
|
||||||
import DesktopLayout from './DesktopLayout';
|
import DesktopLayout from './DesktopLayout';
|
||||||
|
import ToolPanel from '../components/Tool-Panel';
|
||||||
|
|
||||||
import { randomCompliment } from '../utils/get-words';
|
import { randomCompliment } from '../utils/get-words';
|
||||||
import { createGuideUrl } from '../utils';
|
import { createGuideUrl } from '../utils';
|
||||||
@ -246,6 +247,17 @@ class ShowClassic extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderToolPanel(isMobile) {
|
||||||
|
return (
|
||||||
|
<ToolPanel
|
||||||
|
className='classic-tool-panel'
|
||||||
|
guideUrl={this.getGuideUrl()}
|
||||||
|
isMobile={isMobile}
|
||||||
|
videoUrl={this.getVideoUrl()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<LearnLayout>
|
<LearnLayout>
|
||||||
@ -257,14 +269,13 @@ class ShowClassic extends Component {
|
|||||||
matches ? (
|
matches ? (
|
||||||
<MobileLayout
|
<MobileLayout
|
||||||
editor={this.renderEditor()}
|
editor={this.renderEditor()}
|
||||||
guideUrl={this.getGuideUrl()}
|
|
||||||
hasPreview={this.hasPreview()}
|
hasPreview={this.hasPreview()}
|
||||||
instructions={this.renderInstructionsPanel({
|
instructions={this.renderInstructionsPanel({
|
||||||
showToolPanel: false
|
showToolPanel: false
|
||||||
})}
|
})}
|
||||||
preview={this.renderPreview()}
|
preview={this.renderPreview()}
|
||||||
testOutput={this.renderTestOutput()}
|
testOutput={this.renderTestOutput()}
|
||||||
videoUrl={this.getVideoUrl()}
|
toolPanel={this.renderToolPanel(true)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DesktopLayout
|
<DesktopLayout
|
||||||
@ -272,11 +283,12 @@ class ShowClassic extends Component {
|
|||||||
editor={this.renderEditor()}
|
editor={this.renderEditor()}
|
||||||
hasPreview={this.hasPreview()}
|
hasPreview={this.hasPreview()}
|
||||||
instructions={this.renderInstructionsPanel({
|
instructions={this.renderInstructionsPanel({
|
||||||
showToolPanel: true
|
showToolPanel: false
|
||||||
})}
|
})}
|
||||||
preview={this.renderPreview()}
|
preview={this.renderPreview()}
|
||||||
resizeProps={this.resizeProps}
|
resizeProps={this.resizeProps}
|
||||||
testOutput={this.renderTestOutput()}
|
testOutput={this.renderTestOutput()}
|
||||||
|
toolPanel={this.renderToolPanel(false)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.desktop-layout {
|
.desktop-layout {
|
||||||
height: calc(100vh - var(--header-height));
|
height: calc(100vh - var(--header-height) - 42px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-menu .action-label {
|
.monaco-menu .action-label {
|
||||||
@ -34,3 +34,13 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.classic-tool-panel.tool-panel-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
padding: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.classic-tool-panel.tool-panel-group .btn-block + .btn-block {
|
||||||
|
margin: 0 2px 0 0;
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ const mapDispatchToProps = dispatch =>
|
|||||||
);
|
);
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
executeChallenge: PropTypes.func.isRequired,
|
executeChallenge: PropTypes.func.isRequired,
|
||||||
guideUrl: PropTypes.string,
|
guideUrl: PropTypes.string,
|
||||||
isMobile: PropTypes.bool,
|
isMobile: PropTypes.bool,
|
||||||
@ -31,6 +32,7 @@ const propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function ToolPanel({
|
function ToolPanel({
|
||||||
|
className,
|
||||||
executeChallenge,
|
executeChallenge,
|
||||||
isMobile,
|
isMobile,
|
||||||
openHelpModal,
|
openHelpModal,
|
||||||
@ -41,9 +43,11 @@ function ToolPanel({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className={`tool-panel-group ${
|
<div
|
||||||
|
className={`tool-panel-group ${
|
||||||
isMobile ? 'tool-panel-group-mobile' : ''
|
isMobile ? 'tool-panel-group-mobile' : ''
|
||||||
}`}>
|
} ${className}`}
|
||||||
|
>
|
||||||
<Button block={true} bsStyle='primary' onClick={executeChallenge}>
|
<Button block={true} bsStyle='primary' onClick={executeChallenge}>
|
||||||
{isMobile ? 'Run' : 'Run the Tests'}
|
{isMobile ? 'Run' : 'Run the Tests'}
|
||||||
</Button>
|
</Button>
|
||||||
@ -92,7 +96,10 @@ function ToolPanel({
|
|||||||
ToolPanel.displayName = 'ToolPanel';
|
ToolPanel.displayName = 'ToolPanel';
|
||||||
ToolPanel.propTypes = propTypes;
|
ToolPanel.propTypes = propTypes;
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ToolPanel);
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(ToolPanel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
<Button
|
<Button
|
||||||
|
Reference in New Issue
Block a user