mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-07 08:53:25 +01:00
improve history timeline scroll
This commit is contained in:
parent
b8053c5e25
commit
6f95b5ae80
8 changed files with 160 additions and 36 deletions
|
|
@ -14,19 +14,52 @@ import {EMPTY_OBJECT} from '../../../../../modules/gems/objects';
|
||||||
import {VIEWER_SELECTOR} from '../../dom/components/View3d';
|
import {VIEWER_SELECTOR} from '../../dom/components/View3d';
|
||||||
import {aboveElement} from '../../../../../modules/ui/positionUtils';
|
import {aboveElement} from '../../../../../modules/ui/positionUtils';
|
||||||
|
|
||||||
function HistoryTimeline({history, pointer, setHistoryPointer, remove, getOperation}) {
|
|
||||||
return <div className={ls.root}>
|
|
||||||
<Controls pointer={pointer} eoh={history.length-1} setHistoryPointer={setHistoryPointer}/>
|
class HistoryTimeline extends React.Component {
|
||||||
{history.map((m, i) => <React.Fragment key={i}>
|
|
||||||
<Timesplitter active={i-1 === pointer} onClick={() => setHistoryPointer(i-1)} />
|
render() {
|
||||||
<HistoryItem index={i} modification={m} getOperation={getOperation}
|
let {history, pointer, setHistoryPointer, remove, getOperation} = this.props;
|
||||||
disabled={pointer < i}
|
let scrolly;
|
||||||
inProgress={pointer === i-1} />
|
return <div className={ls.root} ref={this.keepRef}>
|
||||||
</React.Fragment>)}
|
<Controls pointer={pointer} eoh={history.length-1} setHistoryPointer={this.setHistoryPointerAndRequestScroll}/>
|
||||||
<Timesplitter eoh active={history.length-1 === pointer} onClick={() => setHistoryPointer(history.length-1)}/>
|
<div className={ls.scroller} onClick={e => scrolly.scrollLeft -= 60}><Fa icon='caret-left'/></div>
|
||||||
<InProgressOperation getOperation={getOperation}/>
|
<div className={ls.history} ref={el => scrolly = el}>
|
||||||
<AddButton />
|
{history.map((m, i) => <React.Fragment key={i}>
|
||||||
</div>;
|
<Timesplitter active={i-1 === pointer} onClick={() => setHistoryPointer(i-1)} />
|
||||||
|
<HistoryItem index={i} modification={m} getOperation={getOperation}
|
||||||
|
disabled={pointer < i}
|
||||||
|
inProgress={pointer === i-1} />
|
||||||
|
</React.Fragment>)}
|
||||||
|
<Timesplitter eoh active={history.length-1 === pointer} onClick={() => setHistoryPointer(history.length-1)}/>
|
||||||
|
</div>
|
||||||
|
<div className={ls.scroller} onClick={e => scrolly.scrollLeft += 60}><Fa icon='caret-right'/></div>
|
||||||
|
<InProgressOperation getOperation={getOperation}/>
|
||||||
|
<AddButton />
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scrollInProgressToVisibleRequest = false;
|
||||||
|
|
||||||
|
setHistoryPointerAndRequestScroll = (pointer) => {
|
||||||
|
// this.scrollInProgressToVisibleRequest = true;
|
||||||
|
this.props.setHistoryPointer(pointer);
|
||||||
|
};
|
||||||
|
|
||||||
|
keepRef = el => this.el = el;
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
// this.scrollInProgressToVisibleRequest = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
let item = this.el.querySelector(`.${ls.historyItem}.${ls.inProgress}`);
|
||||||
|
if (item) {
|
||||||
|
item.scrollIntoView({behavior: "smooth", inline: "center"});
|
||||||
|
} else {
|
||||||
|
let history = this.el.querySelector(`.${ls.history}`);
|
||||||
|
history.scrollLeft = history.scrollWidth;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const InProgressOperation = connect(streams => streams.wizard.map(wizard => ({wizard})))(
|
const InProgressOperation = connect(streams => streams.wizard.map(wizard => ({wizard})))(
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@
|
||||||
.root {
|
.root {
|
||||||
background-color: rgba(0, 0, 0, 0.1);
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: stretch;
|
|
||||||
height: 34px;
|
align-items: flex-end;
|
||||||
|
height: 48px;
|
||||||
//&:hover .timesplitter .handlePoly {
|
//&:hover .timesplitter .handlePoly {
|
||||||
// visibility: visible;
|
// visibility: visible;
|
||||||
//}
|
//}
|
||||||
|
|
@ -14,13 +15,37 @@
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
align-items: flex-end;
|
||||||
.handle {
|
.handle {
|
||||||
margin-top: -15px;
|
//margin-top: -15px;
|
||||||
margin-left: -4px;
|
margin-left: -4px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.history {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
height: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
.scroller {
|
||||||
|
padding: 0 5px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background-color: #BFBFBF;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: #7e7e7e;
|
||||||
|
transition: 100ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.timesplitter.active:not(.eoh) {
|
.timesplitter.active:not(.eoh) {
|
||||||
background-color: #ff940b;
|
background-color: #ff940b;
|
||||||
|
|
||||||
|
|
@ -50,6 +75,8 @@
|
||||||
//ITEMS
|
//ITEMS
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
height: 30px;
|
||||||
|
flex-shrink: 0;
|
||||||
margin: 2px 0;
|
margin: 2px 0;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
border: #2e2e2e 1px solid;
|
border: #2e2e2e 1px solid;
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
background-color: #780000;
|
background-color: #780000;
|
||||||
}
|
}
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
align-items: center;
|
||||||
align-items: baseline;
|
|
||||||
& .buttons {
|
& .buttons {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +18,7 @@
|
||||||
.buttons {
|
.buttons {
|
||||||
display: none;
|
display: none;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
margin-left: auto;
|
||||||
& > * {
|
& > * {
|
||||||
padding: 0 3px;
|
padding: 0 3px;
|
||||||
&.danger:hover {
|
&.danger:hover {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import decoratorChain from '../../../../../modules/ui/decoratorChain';
|
||||||
import {combine, merger} from '../../../../../modules/lstream';
|
import {combine, merger} from '../../../../../modules/lstream';
|
||||||
import ls from './SelectedModificationInfo.less';
|
import ls from './SelectedModificationInfo.less';
|
||||||
import ImgIcon from 'ui/components/ImgIcon';
|
import ImgIcon from 'ui/components/ImgIcon';
|
||||||
import YAML from 'yamljs';
|
|
||||||
import mapContext from 'ui/mapContext';
|
import mapContext from 'ui/mapContext';
|
||||||
import {EMPTY_OBJECT} from '../../../../../modules/gems/objects';
|
import {EMPTY_OBJECT} from '../../../../../modules/gems/objects';
|
||||||
import ButtonGroup from '../../../../../modules/ui/components/controls/ButtonGroup';
|
import ButtonGroup from '../../../../../modules/ui/components/controls/ButtonGroup';
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,45 @@
|
||||||
import React, {Fragment} from 'react';
|
import React from 'react';
|
||||||
import ObjectExplorer from '../../craft/ui/ObjectExplorer';
|
import ObjectExplorer from '../../craft/ui/ObjectExplorer';
|
||||||
import OperationHistory from '../../craft/ui/OperationHistory';
|
import OperationHistory from '../../craft/ui/OperationHistory';
|
||||||
import Folder from 'ui/components/Folder';
|
import Folder from 'ui/components/Folder';
|
||||||
import Fa from '../../../../../modules/ui/components/Fa';
|
import Fa from '../../../../../modules/ui/components/Fa';
|
||||||
|
import ls from './FloatView.less';
|
||||||
|
import cx from 'classnames';
|
||||||
|
|
||||||
export default function FloatView() {
|
export default class FloatView extends React.Component {
|
||||||
return <Fragment>
|
|
||||||
<Folder title={<span> <Fa fw icon='cubes' /> Model</span>}>
|
state = {
|
||||||
<ObjectExplorer/>
|
selected: null
|
||||||
</Folder>
|
};
|
||||||
<Folder title={<span> <Fa fw icon='history' /> Modifications</span>}>
|
|
||||||
<OperationHistory/>
|
render() {
|
||||||
</Folder>
|
return <div className={ls.root}>
|
||||||
</Fragment>;
|
<div className={ls.tabs}>
|
||||||
|
{['project', 'history'].map(tabId => <Tab selected={this.state.selected === tabId} key={tabId}
|
||||||
|
onClick={() => this.setState({selected: this.state.selected === tabId ? null : tabId})}>{getIcon(tabId)}</Tab>)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{this.state.selected && <div className={ls.main}>
|
||||||
|
{this.state.selected === 'project' && <Folder title={<span> <Fa fw icon='cubes'/> Model</span>}>
|
||||||
|
<ObjectExplorer/>
|
||||||
|
</Folder>}
|
||||||
|
{this.state.selected === 'history' && <Folder title={<span> <Fa fw icon='history'/> Modifications</span>}>
|
||||||
|
<OperationHistory/>
|
||||||
|
</Folder>}
|
||||||
|
|
||||||
|
</div>}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Tab({children, selected, onClick}) {
|
||||||
|
return <div className={cx(ls.tab, selected && ls.selected)} onClick={onClick}>{children}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIcon(id) {
|
||||||
|
if (id === 'history') {
|
||||||
|
return <Fa fw icon='history'/>;
|
||||||
|
} else if (id === 'project') {
|
||||||
|
return <Fa fw icon='file-o'/>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
42
web/app/cad/dom/components/FloatView.less
Normal file
42
web/app/cad/dom/components/FloatView.less
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
@import "~ui/styles/theme.less";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
position: relative;
|
||||||
|
border-right: 1px solid @border-color;
|
||||||
|
background-color: @bg-color-alt;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 235px;
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
|
||||||
|
border: 1px solid @bg-color;
|
||||||
|
margin: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
padding: 5px 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: @bg-color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #9c9c9c !important;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
transition: 200ms;
|
||||||
|
background-color: #BFBFBF !important;
|
||||||
|
}
|
||||||
|
&.selected {
|
||||||
|
background-color: #7d7d7d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,9 +20,7 @@ export default class View3d extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <UISystem className={ls.root}>
|
return <UISystem className={ls.root}>
|
||||||
<div className={ls.sideBar}>
|
<FloatView />
|
||||||
<FloatView />
|
|
||||||
</div>
|
|
||||||
<div className={ls.viewer} id='viewer-container'>
|
<div className={ls.viewer} id='viewer-container'>
|
||||||
<Abs left='0.8em' top='0.8em'>
|
<Abs left='0.8em' top='0.8em'>
|
||||||
<HeadsUpToolbar/>
|
<HeadsUpToolbar/>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,3 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sideBar {
|
|
||||||
flex-basis: 250px;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue