mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 17:36:08 +08:00
ui: scratchpad sidebar
This commit is contained in:
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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user