1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-25 12:56:41 +07:00

sorting image attaches on comment form

This commit is contained in:
Fedor Katurov 2019-11-01 15:42:34 +07:00
parent 3e1583f0af
commit 72ef4be7a6
6 changed files with 136 additions and 22 deletions

View file

@ -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) => (

View file

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

View file

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

View file

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

View file

@ -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,

View file

@ -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,