slates: lands drag and drop concept

This commit is contained in:
@wwwjim 2020-08-22 02:32:40 -07:00
parent 94c8508f54
commit 8fab95d691
4 changed files with 187 additions and 33 deletions

View File

@ -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];

View File

@ -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}
/>
);

View File

@ -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>
);
}
}

View File

@ -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>
);
}