Resizable split pane (#190)
* Integrating with react-split-pane * block event while resizing panels * bring scrollsync back * fixed footer position
This commit is contained in:
parent
d6292bf4ff
commit
635049b8db
@ -135,6 +135,7 @@
|
||||
"react-sidebar": "^2.2.1",
|
||||
"react-simple-dnd": "^0.1.2",
|
||||
"react-sortable": "^1.2.0",
|
||||
"react-split-pane": "^0.1.57",
|
||||
"react-toolbox": "^1.2.1",
|
||||
"react-topbar-progress-indicator": "^1.0.0",
|
||||
"react-waypoint": "^3.1.3",
|
||||
|
@ -4,34 +4,37 @@
|
||||
}
|
||||
|
||||
.root {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.footer {
|
||||
flex: 0;
|
||||
padding: 10px 20px;
|
||||
border-top: 1px solid var(--defaultColorLight);
|
||||
background: var(--backgroundColor);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.controlPane {
|
||||
flex: 1;
|
||||
height: calc(100% - 55px);
|
||||
overflow: auto;
|
||||
padding: 0 20px;
|
||||
border-right: 1px solid var(--defaultColorLight);
|
||||
}
|
||||
|
||||
.previewPane {
|
||||
flex: 1;
|
||||
height: calc(100% - 55px);
|
||||
}
|
||||
|
||||
.blocker {
|
||||
}
|
||||
|
||||
.blocker > * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
.footer {
|
||||
height: 55px;
|
||||
padding: 10px 20px;
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-top: 1px solid var(--defaultColorLight);
|
||||
background: var(--backgroundColor);
|
||||
text-align: right;
|
||||
}
|
||||
|
@ -1,59 +1,86 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import SplitPane from 'react-split-pane';
|
||||
import { ScrollSync, ScrollSyncPane } from '../ScrollSync';
|
||||
import ControlPane from '../ControlPanel/ControlPane';
|
||||
import PreviewPane from '../PreviewPane/PreviewPane';
|
||||
import Toolbar from './EntryEditorToolbar';
|
||||
import styles from './EntryEditor.css';
|
||||
|
||||
export default function EntryEditor(
|
||||
{
|
||||
collection,
|
||||
entry,
|
||||
fields,
|
||||
getMedia,
|
||||
onChange,
|
||||
onAddMedia,
|
||||
onRemoveMedia,
|
||||
onPersist,
|
||||
onCancelEdit,
|
||||
}) {
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<ScrollSync>
|
||||
<div className={styles.container}>
|
||||
<ScrollSyncPane>
|
||||
<div className={styles.controlPane}>
|
||||
<ControlPane
|
||||
collection={collection}
|
||||
entry={entry}
|
||||
fields={fields}
|
||||
getMedia={getMedia}
|
||||
onChange={onChange}
|
||||
onAddMedia={onAddMedia}
|
||||
onRemoveMedia={onRemoveMedia}
|
||||
/>
|
||||
</div>
|
||||
</ScrollSyncPane>
|
||||
<div className={styles.previewPane}>
|
||||
<PreviewPane
|
||||
collection={collection}
|
||||
entry={entry}
|
||||
fields={fields}
|
||||
getMedia={getMedia}
|
||||
/>
|
||||
class EntryEditor extends Component {
|
||||
state = {
|
||||
showEventBlocker: false,
|
||||
};
|
||||
|
||||
handleSplitPaneDragStart = () => {
|
||||
this.setState({ showEventBlocker: true });
|
||||
};
|
||||
|
||||
handleSplitPaneDragFinished = () => {
|
||||
this.setState({ showEventBlocker: false });
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
collection,
|
||||
entry,
|
||||
fields,
|
||||
getMedia,
|
||||
onChange,
|
||||
onAddMedia,
|
||||
onRemoveMedia,
|
||||
onPersist,
|
||||
onCancelEdit,
|
||||
} = this.props;
|
||||
|
||||
const controlClassName = `${ styles.controlPane } ${ this.state.showEventBlocker && styles.blocker }`;
|
||||
const previewClassName = `${ styles.previewPane } ${ this.state.showEventBlocker && styles.blocker }`;
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<ScrollSync>
|
||||
<div className={styles.container}>
|
||||
<SplitPane
|
||||
defaultSize="50%"
|
||||
onDragStarted={this.handleSplitPaneDragStart}
|
||||
onDragFinished={this.handleSplitPaneDragFinished}
|
||||
>
|
||||
<ScrollSyncPane>
|
||||
<div className={controlClassName}>
|
||||
|
||||
<ControlPane
|
||||
collection={collection}
|
||||
entry={entry}
|
||||
fields={fields}
|
||||
getMedia={getMedia}
|
||||
onChange={onChange}
|
||||
onAddMedia={onAddMedia}
|
||||
onRemoveMedia={onRemoveMedia}
|
||||
/>
|
||||
|
||||
</div>
|
||||
</ScrollSyncPane>
|
||||
<div className={previewClassName}>
|
||||
<PreviewPane
|
||||
collection={collection}
|
||||
entry={entry}
|
||||
fields={fields}
|
||||
getMedia={getMedia}
|
||||
/>
|
||||
</div>
|
||||
</SplitPane>
|
||||
</div>
|
||||
</ ScrollSync>
|
||||
<div className={styles.footer}>
|
||||
<Toolbar
|
||||
isPersisting={entry.get('isPersisting')}
|
||||
onPersist={onPersist}
|
||||
onCancelEdit={onCancelEdit}
|
||||
/>
|
||||
</div>
|
||||
</ScrollSync>
|
||||
<div className={styles.footer}>
|
||||
<Toolbar
|
||||
isPersisting={entry.get('isPersisting')}
|
||||
onPersist={onPersist}
|
||||
onCancelEdit={onCancelEdit}
|
||||
/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EntryEditor.propTypes = {
|
||||
@ -67,3 +94,6 @@ EntryEditor.propTypes = {
|
||||
onRemoveMedia: PropTypes.func.isRequired,
|
||||
onCancelEdit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
||||
export default EntryEditor;
|
||||
|
@ -92,6 +92,38 @@ h1 {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
& .Resizer {
|
||||
background: #000;
|
||||
opacity: .2;
|
||||
z-index: 1;
|
||||
box-sizing: border-box;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
& .Resizer:hover {
|
||||
-webkit-transition: all 2s ease;
|
||||
transition: all 2s ease;
|
||||
}
|
||||
|
||||
& .Resizer.vertical {
|
||||
width: 11px;
|
||||
margin: 0 -5px;
|
||||
border-left: 5px solid rgba(255, 255, 255, 0);
|
||||
border-right: 5px solid rgba(255, 255, 255, 0);
|
||||
cursor: col-resize;
|
||||
}
|
||||
|
||||
& .Resizer.vertical:hover {
|
||||
border-left: 5px solid rgba(0, 0, 0, 0.5);
|
||||
border-right: 5px solid rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
& .Resizer.disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
& .Resizer.disabled:hover {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
& .rdt {
|
||||
position: relative;
|
||||
|
26
yarn.lock
26
yarn.lock
@ -1175,6 +1175,10 @@ boom@2.x.x:
|
||||
dependencies:
|
||||
hoek "2.x.x"
|
||||
|
||||
bowser@^1.0.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.6.0.tgz#37fc387b616cb6aef370dab4d6bd402b74c5c54d"
|
||||
|
||||
boxen@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.3.1.tgz#a7d898243ae622f7abb6bb604d740a76c6a5461b"
|
||||
@ -3538,6 +3542,10 @@ https-browserify@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
|
||||
|
||||
hyphenate-style-name@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b"
|
||||
|
||||
iconv-lite@^0.4.13, iconv-lite@~0.4.13, iconv-lite@0.4.13:
|
||||
version "0.4.13"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
|
||||
@ -3643,6 +3651,13 @@ inline-process-browser@^1.0.0:
|
||||
falafel "^1.0.1"
|
||||
through2 "^0.6.5"
|
||||
|
||||
inline-style-prefixer@^2.0.4:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7"
|
||||
dependencies:
|
||||
bowser "^1.0.0"
|
||||
hyphenate-style-name "^1.0.1"
|
||||
|
||||
inquirer@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
|
||||
@ -7105,6 +7120,17 @@ react-sortable@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-sortable/-/react-sortable-1.2.0.tgz#5acd7e1910df665408957035acb5f2354519d849"
|
||||
|
||||
react-split-pane:
|
||||
version "0.1.57"
|
||||
resolved "https://registry.yarnpkg.com/react-split-pane/-/react-split-pane-0.1.57.tgz#7cc2d30841ae6a3e246ee613a9858012528d894f"
|
||||
dependencies:
|
||||
inline-style-prefixer "^2.0.4"
|
||||
react-style-proptype "^1.4.0"
|
||||
|
||||
react-style-proptype@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/react-style-proptype/-/react-style-proptype-1.4.0.tgz#d82c4093b73767e3efaacba013cea22a50e7b5ee"
|
||||
|
||||
react-themeable@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-themeable/-/react-themeable-1.1.0.tgz#7d4466dd9b2b5fa75058727825e9f152ba379a0e"
|
||||
|
Loading…
x
Reference in New Issue
Block a user