mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 04:46:40 +07:00
sorting image attaches on comment form
This commit is contained in:
parent
3e1583f0af
commit
72ef4be7a6
6 changed files with 136 additions and 22 deletions
|
@ -12,12 +12,17 @@ const SortableImageGrid = SortableContainer(
|
||||||
items,
|
items,
|
||||||
locked,
|
locked,
|
||||||
onDrop,
|
onDrop,
|
||||||
|
size = 200,
|
||||||
}: {
|
}: {
|
||||||
items: IFile[];
|
items: IFile[];
|
||||||
locked: IUploadStatus[];
|
locked: IUploadStatus[];
|
||||||
onDrop: (file_id: IFile['id']) => void;
|
onDrop: (file_id: IFile['id']) => void;
|
||||||
|
size?: number;
|
||||||
}) => (
|
}) => (
|
||||||
<div className={styles.grid}>
|
<div
|
||||||
|
className={styles.grid}
|
||||||
|
style={{ gridTemplateColumns: `repeat(auto-fill, minmax(${size}px, 1fr))` }}
|
||||||
|
>
|
||||||
{items
|
{items
|
||||||
.filter(file => file && file.id)
|
.filter(file => file && file.id)
|
||||||
.map((file, index) => (
|
.map((file, index) => (
|
||||||
|
|
|
@ -8,9 +8,6 @@ $stamp_color: $content_bg;
|
||||||
|
|
||||||
.grid_test {
|
.grid_test {
|
||||||
display: grid;
|
display: grid;
|
||||||
// grid-template-columns: repeat(auto-fit, minmax($cell, 1fr));
|
|
||||||
// grid-template-rows: 50vh $cell;
|
|
||||||
// grid-auto-rows: $cell;
|
|
||||||
|
|
||||||
grid-template-columns: repeat(5, 1fr);
|
grid-template-columns: repeat(5, 1fr);
|
||||||
grid-template-rows: 50vh $cell;
|
grid-template-rows: 50vh $cell;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React, { FC, useCallback, KeyboardEventHandler, useEffect } from 'react';
|
import React, { FC, useCallback, KeyboardEventHandler, useEffect, useMemo } from 'react';
|
||||||
import { Textarea } from '~/components/input/Textarea';
|
import { Textarea } from '~/components/input/Textarea';
|
||||||
import { CommentWrapper } from '~/components/containers/CommentWrapper';
|
import { CommentWrapper } from '~/components/containers/CommentWrapper';
|
||||||
import * as styles from './styles.scss';
|
import * as styles from './styles.scss';
|
||||||
import { Filler } from '~/components/containers/Filler';
|
import { Filler } from '~/components/containers/Filler';
|
||||||
import { Button } from '~/components/input/Button';
|
import { Button } from '~/components/input/Button';
|
||||||
import assocPath from 'ramda/es/assocPath';
|
import assocPath from 'ramda/es/assocPath';
|
||||||
import { InputHandler, IFileWithUUID } from '~/redux/types';
|
import { InputHandler, IFileWithUUID, IFile } from '~/redux/types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as NODE_ACTIONS from '~/redux/node/actions';
|
import * as NODE_ACTIONS from '~/redux/node/actions';
|
||||||
import { selectNode } from '~/redux/node/selectors';
|
import { selectNode } from '~/redux/node/selectors';
|
||||||
|
@ -21,6 +21,9 @@ import { selectUser } from '~/redux/auth/selectors';
|
||||||
import { getURL } from '~/utils/dom';
|
import { getURL } from '~/utils/dom';
|
||||||
import { ButtonGroup } from '~/components/input/ButtonGroup';
|
import { ButtonGroup } from '~/components/input/ButtonGroup';
|
||||||
import { AudioPlayer } from '~/components/media/AudioPlayer';
|
import { AudioPlayer } from '~/components/media/AudioPlayer';
|
||||||
|
import { SortableImageGrid } from '~/components/editors/SortableImageGrid';
|
||||||
|
import { moveArrItem } from '~/utils/fn';
|
||||||
|
import { SortEnd } from 'react-sortable-hoc';
|
||||||
|
|
||||||
const mapStateToProps = (state: IState) => ({
|
const mapStateToProps = (state: IState) => ({
|
||||||
node: selectNode(state),
|
node: selectNode(state),
|
||||||
|
@ -121,6 +124,41 @@ const CommentFormUnconnected: FC<IProps> = ({
|
||||||
|
|
||||||
const comment = comment_data[id];
|
const comment = comment_data[id];
|
||||||
|
|
||||||
|
const images = useMemo(() => comment.files.filter(file => file.type === UPLOAD_TYPES.IMAGE), [
|
||||||
|
comment.files,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const audios = useMemo(() => comment.files.filter(file => file.type === UPLOAD_TYPES.AUDIO), [
|
||||||
|
comment.files,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const onFileDrop = useCallback(
|
||||||
|
(file_id: IFile['id']) => {
|
||||||
|
nodeSetCommentData(
|
||||||
|
id,
|
||||||
|
assocPath(['files'], comment.files.filter(file => file.id != file_id), comment_data[id])
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[comment_data, id, nodeSetCommentData]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onImageMove = useCallback(
|
||||||
|
({ oldIndex, newIndex }: SortEnd) => {
|
||||||
|
nodeSetCommentData(
|
||||||
|
id,
|
||||||
|
assocPath(
|
||||||
|
['files'],
|
||||||
|
[
|
||||||
|
...audios,
|
||||||
|
...(moveArrItem(oldIndex, newIndex, images.filter(file => !!file)) as IFile[]),
|
||||||
|
],
|
||||||
|
comment_data[id]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[images, audios]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CommentWrapper user={user}>
|
<CommentWrapper user={user}>
|
||||||
<form onSubmit={onSubmit} className={styles.wrap}>
|
<form onSubmit={onSubmit} className={styles.wrap}>
|
||||||
|
@ -134,22 +172,25 @@ const CommentFormUnconnected: FC<IProps> = ({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{comment.temp_ids.map(
|
{(!!images.length || !!audios.length) && (
|
||||||
temp_id =>
|
<div className={styles.attaches}>
|
||||||
statuses[temp_id] &&
|
<SortableImageGrid
|
||||||
statuses[temp_id].is_uploading && (
|
onDrop={onFileDrop}
|
||||||
<div key={statuses[temp_id].temp_id}>{statuses[temp_id].progress}</div>
|
onSortEnd={onImageMove}
|
||||||
)
|
axis="xy"
|
||||||
|
items={images}
|
||||||
|
locked={[]}
|
||||||
|
pressDelay={window.innerWidth < 768 ? 200 : 0}
|
||||||
|
helperClass={styles.helper}
|
||||||
|
size={120}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{audios.map(file => (
|
||||||
|
<AudioPlayer file={file} key={file.id} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{comment.files.map(file => {
|
|
||||||
if (file.type === UPLOAD_TYPES.AUDIO) {
|
|
||||||
return <AudioPlayer file={file} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div>file.name</div>;
|
|
||||||
})}
|
|
||||||
|
|
||||||
<Group horizontal className={styles.buttons}>
|
<Group horizontal className={styles.buttons}>
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Button iconLeft="image" size="small" grey iconOnly>
|
<Button iconLeft="image" size="small" grey iconOnly>
|
||||||
|
|
|
@ -8,11 +8,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
|
@include outer_shadow();
|
||||||
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: ($gap / 2) ($gap / 2 + 1px);
|
padding: ($gap / 2) ($gap / 2 + 1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons {
|
.buttons {
|
||||||
|
@include outer_shadow();
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
background: transparentize(black, 0.8);
|
background: transparentize(black, 0.8);
|
||||||
|
@ -28,3 +32,10 @@
|
||||||
grid-row-gap: $gap / 2;
|
grid-row-gap: $gap / 2;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.attaches {
|
||||||
|
@include outer_shadow();
|
||||||
|
|
||||||
|
padding: $gap;
|
||||||
|
// background: darken($comment_bg, 2%);
|
||||||
|
}
|
||||||
|
|
|
@ -87,7 +87,63 @@ export const NODE_INLINES: INodeComponents = {
|
||||||
export const EMPTY_COMMENT: IComment = {
|
export const EMPTY_COMMENT: IComment = {
|
||||||
id: null,
|
id: null,
|
||||||
text: '',
|
text: '',
|
||||||
files: [],
|
// files: [],
|
||||||
|
// temp_ids: [],
|
||||||
|
// is_private: false,
|
||||||
|
// user: null,
|
||||||
|
|
||||||
|
// id: null,
|
||||||
|
// text: '',
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
name: 'screenshot_2019-09-29_21-13-38_502253296-1572589001092.png',
|
||||||
|
path: 'uploads/2019/10/image/',
|
||||||
|
full_path:
|
||||||
|
'public/uploads/2019/10/image/screenshot_2019-09-29_21-13-38_502253296-1572589001092.png',
|
||||||
|
url:
|
||||||
|
'REMOTE_CURRENT://uploads/2019/10/image/screenshot_2019-09-29_21-13-38_502253296-1572589001092.png',
|
||||||
|
size: 994331,
|
||||||
|
type: 'image',
|
||||||
|
mime: 'image/png',
|
||||||
|
metadata: {
|
||||||
|
width: 1919,
|
||||||
|
height: 1079,
|
||||||
|
},
|
||||||
|
id: 8709,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'screenshot_2019-09-29_19-05-41_148603009-1572589001080.png',
|
||||||
|
path: 'uploads/2019/10/image/',
|
||||||
|
full_path:
|
||||||
|
'public/uploads/2019/10/image/screenshot_2019-09-29_19-05-41_148603009-1572589001080.png',
|
||||||
|
url:
|
||||||
|
'REMOTE_CURRENT://uploads/2019/10/image/screenshot_2019-09-29_19-05-41_148603009-1572589001080.png',
|
||||||
|
size: 2145,
|
||||||
|
type: 'image',
|
||||||
|
mime: 'image/png',
|
||||||
|
metadata: {
|
||||||
|
width: 445,
|
||||||
|
height: 446,
|
||||||
|
},
|
||||||
|
id: 8708,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'screenshot_2019-09-29_21-13-26_924738012-1572589001110.png',
|
||||||
|
path: 'uploads/2019/10/image/',
|
||||||
|
full_path:
|
||||||
|
'public/uploads/2019/10/image/screenshot_2019-09-29_21-13-26_924738012-1572589001110.png',
|
||||||
|
url:
|
||||||
|
'REMOTE_CURRENT://uploads/2019/10/image/screenshot_2019-09-29_21-13-26_924738012-1572589001110.png',
|
||||||
|
size: 881224,
|
||||||
|
type: 'image',
|
||||||
|
mime: 'image/png',
|
||||||
|
metadata: {
|
||||||
|
width: 1919,
|
||||||
|
height: 1079,
|
||||||
|
},
|
||||||
|
id: 8710,
|
||||||
|
},
|
||||||
|
],
|
||||||
temp_ids: [],
|
temp_ids: [],
|
||||||
is_private: false,
|
is_private: false,
|
||||||
user: null,
|
user: null,
|
||||||
|
|
|
@ -30,7 +30,11 @@ const INITIAL_STATE: INodeState = {
|
||||||
files: [],
|
files: [],
|
||||||
},
|
},
|
||||||
current: { ...EMPTY_NODE },
|
current: { ...EMPTY_NODE },
|
||||||
comment_data: { 0: { ...EMPTY_COMMENT } },
|
comment_data: {
|
||||||
|
0: {
|
||||||
|
...EMPTY_COMMENT,
|
||||||
|
},
|
||||||
|
},
|
||||||
comments: [],
|
comments: [],
|
||||||
related: null,
|
related: null,
|
||||||
current_cover_image: null,
|
current_cover_image: null,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue