mirror of
https://github.com/filecoin-project/slate.git
synced 2024-11-23 22:12:19 +03:00
slates: lands drag and drop concept
This commit is contained in:
parent
94c8508f54
commit
8fab95d691
@ -114,11 +114,19 @@ export default class ApplicationPage extends React.Component {
|
||||
};
|
||||
|
||||
_handleDragEnter = (e) => {
|
||||
e.preventDefault();
|
||||
if (this.state.sidebar) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
// NOTE(jim): Only allow the sidebar to show with file drag and drop.
|
||||
if (
|
||||
e.dataTransfer.items &&
|
||||
e.dataTransfer.items.length &&
|
||||
e.dataTransfer.items[0].kind !== "file"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._handleAction({
|
||||
type: "SIDEBAR",
|
||||
@ -137,6 +145,12 @@ export default class ApplicationPage extends React.Component {
|
||||
_handleSidebarLoading = (sidebarLoading) => this.setState({ sidebarLoading });
|
||||
|
||||
_handleDrop = async (e) => {
|
||||
// NOTE(jim): If this is true, then drag and drop came from a slate object.
|
||||
const data = e.dataTransfer.getData("slate-object-drag-data");
|
||||
if (data) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.setState({ fileLoading: true });
|
||||
@ -154,7 +168,7 @@ export default class ApplicationPage extends React.Component {
|
||||
|
||||
const files = [];
|
||||
let fileLoading = {};
|
||||
if (e.dataTransfer.items) {
|
||||
if (e.dataTransfer.items && e.dataTransfer.items.length) {
|
||||
for (var i = 0; i < e.dataTransfer.items.length; i++) {
|
||||
if (e.dataTransfer.items[i].kind === "file") {
|
||||
var file = e.dataTransfer.items[i].getAsFile();
|
||||
@ -445,8 +459,6 @@ export default class ApplicationPage extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
console.log(this.state.viewer);
|
||||
|
||||
// NOTE(jim): Authenticated.
|
||||
const navigation = NavigationData.generate(this.state.viewer);
|
||||
const next = this.state.history[this.state.currentIndex];
|
||||
|
@ -17,15 +17,45 @@ const STYLES_SLATE = css`
|
||||
`;
|
||||
|
||||
export default class Slate extends React.Component {
|
||||
state = { index: null, hiddenIndex: null };
|
||||
|
||||
_handleSetHoveringIndex = ({ index }) => {
|
||||
if (!this.props.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state.index !== index) {
|
||||
this.setState({ index });
|
||||
}
|
||||
};
|
||||
|
||||
_handleSetHiddenIndex = ({ index }) => {
|
||||
if (!this.props.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state.index !== index) {
|
||||
this.setState({ hiddenIndex: index });
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div css={STYLES_SLATE}>
|
||||
{this.props.items.map((each, index) => {
|
||||
return (
|
||||
<SlateMediaObjectPreview
|
||||
editing={this.props.editing}
|
||||
index={index}
|
||||
hovering={index === this.state.index}
|
||||
lastIndex={this.props.items.length - 1 === index}
|
||||
hiddenIndex={this.state.hiddenIndex}
|
||||
key={each.id}
|
||||
type={each.type}
|
||||
onClick={() => this.props.onSelect(index)}
|
||||
onSetHoveringIndex={this._handleSetHoveringIndex}
|
||||
onSetHiddenIndex={this._handleSetHiddenIndex}
|
||||
onMoveIndex={this.props.onMoveIndex}
|
||||
url={each.url}
|
||||
/>
|
||||
);
|
||||
|
@ -12,6 +12,7 @@ const STYLES_ITEM = css`
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
transition: 200ms ease all;
|
||||
transform: translateX(0px);
|
||||
`;
|
||||
|
||||
const STYLES_IMAGE = css`
|
||||
@ -21,63 +22,155 @@ const STYLES_IMAGE = css`
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const STYLES_PDF = css`
|
||||
const STYLES_ENTITY = css`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: 1px solid ${Constants.system.border};
|
||||
background-color: ${Constants.system.foreground};
|
||||
font-size: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
const STYLES_ROOT = css`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
export default class SlateMediaObjectPreview extends React.Component {
|
||||
_handleDragStart = (e) => {
|
||||
if (!this.props.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
e.dataTransfer.setData(
|
||||
"slate-object-drag-data",
|
||||
JSON.stringify({
|
||||
...this.props,
|
||||
dragging: true,
|
||||
})
|
||||
);
|
||||
|
||||
this.props.onSetHiddenIndex({ index: this.props.index });
|
||||
};
|
||||
|
||||
_handleDragOver = (e) => {
|
||||
if (!this.props.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
this.props.onSetHoveringIndex({ index: this.props.index });
|
||||
};
|
||||
|
||||
_handleDragEnd = (e) => {
|
||||
if (!this.props.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
this.props.onSetHoveringIndex({ index: null });
|
||||
this.props.onSetHiddenIndex({ index: null });
|
||||
};
|
||||
|
||||
_handleDrop = async (e) => {
|
||||
if (!this.props.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
this.props.onSetHoveringIndex({ index: null });
|
||||
this.props.onSetHiddenIndex({ index: null });
|
||||
const data = e.dataTransfer.getData("slate-object-drag-data");
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
let parsed = JSON.parse(data);
|
||||
|
||||
return await this.props.onMoveIndex(parsed, this.props);
|
||||
};
|
||||
|
||||
render() {
|
||||
let element = (
|
||||
<div css={STYLES_ENTITY} onClick={this.props.onClick}>
|
||||
No Preview
|
||||
</div>
|
||||
);
|
||||
|
||||
if (this.props.type && this.props.type.startsWith("video/")) {
|
||||
return (
|
||||
<span css={STYLES_ITEM}>
|
||||
<div css={STYLES_PDF} onClick={this.props.onClick}>
|
||||
Video
|
||||
</div>
|
||||
</span>
|
||||
element = (
|
||||
<div css={STYLES_ENTITY} onClick={this.props.onClick}>
|
||||
Video
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.type && this.props.type.startsWith("audio/")) {
|
||||
return (
|
||||
<span css={STYLES_ITEM}>
|
||||
<div css={STYLES_PDF} onClick={this.props.onClick}>
|
||||
Audio
|
||||
</div>
|
||||
</span>
|
||||
element = (
|
||||
<div css={STYLES_ENTITY} onClick={this.props.onClick}>
|
||||
Audio
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.type && this.props.type.startsWith("application/epub")) {
|
||||
return (
|
||||
<span css={STYLES_ITEM}>
|
||||
<div css={STYLES_PDF} onClick={this.props.onClick}>
|
||||
EPub
|
||||
</div>
|
||||
</span>
|
||||
element = (
|
||||
<div css={STYLES_ENTITY} onClick={this.props.onClick}>
|
||||
EPub
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.type && this.props.type.startsWith("application/pdf")) {
|
||||
return (
|
||||
<span css={STYLES_ITEM}>
|
||||
<div css={STYLES_PDF} onClick={this.props.onClick}>
|
||||
PDF
|
||||
</div>
|
||||
</span>
|
||||
element = (
|
||||
<div css={STYLES_ENTITY} onClick={this.props.onClick}>
|
||||
PDF
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.type && this.props.type.startsWith("image/")) {
|
||||
element = (
|
||||
<img
|
||||
css={STYLES_IMAGE}
|
||||
src={this.props.url}
|
||||
onClick={this.props.onClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const translateDirection = this.props.lastIndex
|
||||
? `translateX(-228px)`
|
||||
: `translateX(228px)`;
|
||||
|
||||
return (
|
||||
<span css={STYLES_ITEM}>
|
||||
<img css={STYLES_IMAGE} src={this.props.url} onClick={this.props.onClick} />
|
||||
</span>
|
||||
<div
|
||||
css={STYLES_ROOT}
|
||||
onDragStart={this._handleDragStart}
|
||||
onDragOver={this._handleDragOver}
|
||||
onDragEnd={this._handleDragEnd}
|
||||
onDrop={this._handleDrop}
|
||||
style={{
|
||||
visibility:
|
||||
this.props.hiddenIndex === this.props.index ? "hidden" : null,
|
||||
}}
|
||||
draggable="true"
|
||||
>
|
||||
<span
|
||||
css={STYLES_ITEM}
|
||||
style={{
|
||||
transform: this.props.hovering ? translateDirection : null,
|
||||
zIndex: this.props.hovering ? `1` : null,
|
||||
}}
|
||||
>
|
||||
{element}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,14 @@ import Slate from "~/components/core/Slate";
|
||||
import SlateMediaObject from "~/components/core/SlateMediaObject";
|
||||
import CircleButtonLight from "~/components/core/CircleButtonLight";
|
||||
|
||||
const moveIndex = (set, fromIndex, toIndex) => {
|
||||
const element = set[fromIndex];
|
||||
set.splice(fromIndex, 1);
|
||||
set.splice(toIndex, 0, element);
|
||||
|
||||
return set;
|
||||
};
|
||||
|
||||
export default class SceneSlate extends React.Component {
|
||||
state = {
|
||||
slatename: this.props.current.slatename,
|
||||
@ -56,6 +64,12 @@ export default class SceneSlate extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
_handleMoveIndex = async (from, to) => {
|
||||
const objects = moveIndex(this.state.objects, from.index, to.index);
|
||||
this.setState({ objects });
|
||||
await this._handleSave(null, objects);
|
||||
};
|
||||
|
||||
_handleSave = async (e, objects) => {
|
||||
this.setState({ loading: true });
|
||||
|
||||
@ -217,7 +231,12 @@ export default class SceneSlate extends React.Component {
|
||||
>
|
||||
{body}
|
||||
</ScenePageHeader>
|
||||
<Slate editing items={objects} onSelect={this._handleSelect} />
|
||||
<Slate
|
||||
editing
|
||||
items={objects}
|
||||
onMoveIndex={this._handleMoveIndex}
|
||||
onSelect={this._handleSelect}
|
||||
/>
|
||||
</ScenePage>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user