ui: scratchpad sidebar

This commit is contained in:
undefined committed 2022-08-01 22:56:04 +08:00
1 parent 981f8a4b9d
commit e3a5543d9f
14 files changed
+239 -65

No files matched your search

@@ -48,6 +48,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor e
);
window.editor = this.editor;
window.monaco = monaco;
window.Hydro.bus.emit('scratchpadEditorCreate', this.editor, monaco);
}
}
@@ -1,9 +0,0 @@
import React from 'react';
export default function ScratchpadSidebar({ name }) {
const Component = window.Hydro.scratchpad?.[name];
const [state, setState] = React.useState(0);
if (Component) return <Component />;
setTimeout(() => setState(state + 1), 1000);
return <div>No registered providers.</div>;
}
@@ -16,7 +16,6 @@ import Toolbar, {
const mapStateToProps = (state) => ({
pretestVisible: state.ui.pretest.visible,
sidebarVisible: state.ui.sidebar.visible,
recordsVisible: state.ui.records.visible,
isPosting: state.ui.isPosting,
isRunning: state.pretest.isRunning,
@@ -185,16 +184,6 @@ export default connect(mapStateToProps, mapDispatchToProps)(class ScratchpadTool
{i18n('Records')}
</ToolbarButton>
)}
{/* <ToolbarButton
activated={this.props.sidebarVisible}
onClick={() => this.props.togglePanel('sidebar')}
data-global-hotkey="alt+w"
data-tooltip={`${i18n('Toggle Sidebar')} (Alt+L)`}
>
<Icon name="edit" />
{' '}
{i18n('Pretest')}
</ToolbarButton> */}
</Toolbar>
);
}
@@ -0,0 +1,24 @@
.scratchpad__tablist
user-select: none
div
display: flex
width: 50px
height: 50px
font-size: 28px
flex-direction: row
align-items: center
justify-content: center
margin: rem(8px) 0
fill: #666
color: #666
cursor: pointer
&:hover
fill: #000
color: #000
div.scratchpad__tab-active
border-left: 4px solid #000
fill: #000
color: #000
cursor: default
@@ -1,14 +1,14 @@
import React from 'react';
import SplitPane from 'react-split-pane';
import { connect } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import _ from 'lodash';
import SplitPaneFillOverlay from 'vj/components/react-splitpane/SplitPaneFillOverlayComponent';
import ProblemIcon from '@vscode/codicons/src/icons/file.svg?react';
import Dom from 'vj/components/react/DomComponent';
import ScratchpadToolbar from './ScratchpadToolbarContainer';
import ScratchpadEditor from './ScratchpadEditorContainer';
import ScratchpadPretest from './ScratchpadPretestContainer';
import ScratchpadRecords from './ScratchpadRecordsContainer';
import ScratchpadSidebar from './ScratchpadSidebar';
function buildNestedPane([a, ...panes], mode = 'horizontal') {
const elements = [
@@ -31,12 +31,36 @@ function buildNestedPane([a, ...panes], mode = 'horizontal') {
));
}
const mapStateToProps = (state) => ({
ui: state.ui,
});
const pages = {
problem: {
icon: () => <ProblemIcon />,
component: () => {
console.log($('.problem-content'));
return <Dom childDom={$('.problem-content').get(0)} id="problem-content" />;
},
},
};
const mapDispatchToProps = (dispatch) => ({
changeUiSize: _.debounce((uiElement, size) => {
let rerenderCallback = null;
export function addPage(key, icon, component) {
pages[key] = {
icon,
component,
};
rerenderCallback?.();
}
window.Hydro.scratchpad = { addPage, pages };
export default function ScratchpadContainer() {
const [, updateState] = React.useState();
const forceUpdate = React.useCallback(() => updateState({}), []);
React.useEffect(() => {
rerenderCallback = forceUpdate;
}, []);
const dispatch = useDispatch();
const ui = useSelector((state) => state.ui, _.isEqual);
const handleChangeSize = _.debounce((uiElement, size) => {
dispatch({
type: 'SCRATCHPAD_UI_CHANGE_SIZE',
payload: {
@@ -44,52 +68,67 @@ const mapDispatchToProps = (dispatch) => ({
size,
},
});
}, 500),
});
export default connect(mapStateToProps, mapDispatchToProps)(class ScratchpadContainer extends React.PureComponent {
handleChangeSize(uiElement, size) {
this.props.changeUiSize(uiElement, size);
$('#scratchpad').trigger('vjScratchpadRelayout');
this.props.ui.pretest.visible = !!this.props.ui.pretest.visible;
this.forceUpdate();
}
forceUpdate();
}, 500);
const switchToPage = (target) => {
dispatch({
type: 'SCRATCHPAD_SWITCH_TO_PAGE',
payload: target,
});
};
render() {
return (
return (
<SplitPane
split="vertical"
primary="first"
defaultSize={50}
allowResize={false}
>
<div className="scratchpad__tablist">
{Object.keys(pages).map((key) => {
const Component = pages[key].icon;
return (
<div key={key} className={key === ui.activePage ? 'scratchpad__tab-active' : ''} onClick={() => switchToPage(key)}>
<Component />
</div>
);
})}
</div>
<SplitPane
defaultSize={this.props.ui.main.size}
defaultSize={ui.main.size}
minSize={250}
split="vertical"
primary="second"
onChange={(size) => this.handleChangeSize('main', size)}
onChange={(size) => handleChangeSize('main', size)}
>
<SplitPane
defaultSize={this.props.ui.sidebar.visible ? this.props.ui.sidebar.size : 0}
split="vertical"
primary="second"
onChange={(size) => this.handleChangeSize('sidebar', size)}
>
<Dom className="scratchpad__problem" childDom={$('.problem-content').get(0)} />
<ScratchpadSidebar name="debug" />
</SplitPane>
<div className="scratchpad__problem">
{Object.keys(pages).map((key) => {
const Component = pages[key].component;
return (
<div key={key} style={{ display: key === ui.activePage ? 'block' : 'none' }}>
<Component />
</div>
);
})}
</div>
{buildNestedPane([
<SplitPaneFillOverlay key="editor" className="flex-col">
<ScratchpadToolbar />
<ScratchpadEditor />
</SplitPaneFillOverlay>,
{
props: this.props.ui.pretest,
onChange: (size) => this.handleChangeSize('pretest', size),
props: ui.pretest,
onChange: (size) => handleChangeSize('pretest', size),
element: <ScratchpadPretest key="pretest" />,
},
{
props: this.props.ui.records,
onChange: (size) => this.handleChangeSize('records', size),
props: ui.records,
onChange: (size) => handleChangeSize('records', size),
element: <ScratchpadRecords key="records" />,
},
])}
</SplitPane>
);
}
});
</SplitPane>
);
}
@@ -3,12 +3,14 @@ import ui from './ui';
import editor from './editor';
import pretest from './pretest';
import records from './records';
import state from './state';
const reducer = combineReducers({
ui,
editor,
pretest,
records,
state,
});
export default reducer;
@@ -0,0 +1,10 @@
export default function reducer(state = {}, action) {
if (action.type === 'SCRATCHPAD_STATE_UPDATE') {
const { key, value } = action.payload;
return {
...state,
[key]: value,
};
}
return state;
}
@@ -11,10 +11,6 @@ export default function reducer(state = {
: false,
size: 200,
},
sidebar: {
visible: false,
size: 100,
},
records: {
visible: UiContext.canViewRecord && localStorage.getItem('scratchpad/records') === 'true',
size: 100,
@@ -23,6 +19,7 @@ export default function reducer(state = {
isPosting: false,
waitSec: 0,
isWaiting: false,
activePage: 'problem',
}, action) {
switch (action.type) {
case 'SCRATCHPAD_UI_CHANGE_SIZE': {
@@ -122,6 +119,12 @@ export default function reducer(state = {
},
};
}
case 'SCRATCHPAD_SWITCH_TO_PAGE': {
return {
...state,
activePage: action.payload,
};
}
default:
return state;
}