diff --git a/src/components/media/AudioPlayer/styles.scss b/src/components/media/AudioPlayer/styles.scss index e65bcc5f..f4cd63bf 100644 --- a/src/components/media/AudioPlayer/styles.scss +++ b/src/components/media/AudioPlayer/styles.scss @@ -1,6 +1,11 @@ .wrap { display: flex; flex-direction: row; + height: $comment_height; + position: relative; + align-items: center; + justify-content: stretch; + flex: 1; &:global(.playing) { .progress { diff --git a/src/components/node/Comment/index.tsx b/src/components/node/Comment/index.tsx index c66dda99..5fd8b9f6 100644 --- a/src/components/node/Comment/index.tsx +++ b/src/components/node/Comment/index.tsx @@ -1,73 +1,39 @@ -import React, { FC, HTMLAttributes, useMemo } from 'react'; +import React, { FC, HTMLAttributes } from 'react'; import { CommentWrapper } from '~/components/containers/CommentWrapper'; -import { IComment, IFile } from '~/redux/types'; +import { ICommentGroup } from '~/redux/types'; +import { getURL } from '~/utils/dom'; +import { CommentContent } from '~/components/node/CommentContent'; import * as styles from './styles.scss'; -import { formatCommentText, getURL, getPrettyDate } from '~/utils/dom'; -import { Group } from '~/components/containers/Group'; -import assocPath from 'ramda/es/assocPath'; -import append from 'ramda/es/append'; -import reduce from 'ramda/es/reduce'; -import { UPLOAD_TYPES } from '~/redux/uploads/constants'; -import { AudioPlayer } from '~/components/media/AudioPlayer'; type IProps = HTMLAttributes & { is_empty?: boolean; is_loading?: boolean; - comment?: IComment; + comment_group?: ICommentGroup; is_same?: boolean; }; -const Comment: FC = ({ comment, is_empty, is_same, is_loading, className, ...props }) => { - const groupped = useMemo>( - () => - reduce( - (group, file) => assocPath([file.type], append(file, group[file.type]), group), - {}, - comment.files - ), - [comment] - ); - +const Comment: FC = ({ + comment_group, + is_empty, + is_same, + is_loading, + className, + ...props +}) => { return ( - {comment.text && ( - - )} - -
{getPrettyDate(comment.created_at)}
- - {groupped.image && ( -
- {groupped.image.map(file => ( -
- {file.name} -
- ))} -
- )} - - {groupped.audio && ( -
- {groupped.audio.map(file => ( - - ))} -
- )} +
+ {comment_group.comments.map(comment => ( + + ))} +
); }; diff --git a/src/components/node/Comment/styles.scss b/src/components/node/Comment/styles.scss index 723535b9..1afb844d 100644 --- a/src/components/node/Comment/styles.scss +++ b/src/components/node/Comment/styles.scss @@ -1,48 +1,2 @@ -@import 'flexbin/flexbin.scss'; - -.text { - // @include outer_shadow(); - - padding: $gap; - font-weight: 300; - font: $font_16_medium; - min-height: $comment_height; - box-sizing: border-box; - position: relative; - color: #cccccc; - - b { - font-weight: 600; - } -} - -.date { - position: absolute; - bottom: 0; - right: 0; - font: $font_12_regular; - color: transparentize($color: white, $amount: 0.8); - padding: 2px 4px; - border-radius: 0 0 $radius 0; -} - -.images { - @include flexbin(240px, 5px); - - img { - border-radius: $radius; - } -} - -.audios { - & > div { - @include outer_shadow(); - - height: $comment_height; - border-radius: $radius; - display: flex; - justify-content: center; - align-items: center; - text-align: center; - } +.wrap { } diff --git a/src/components/node/CommentContent/index.tsx b/src/components/node/CommentContent/index.tsx new file mode 100644 index 00000000..916e1113 --- /dev/null +++ b/src/components/node/CommentContent/index.tsx @@ -0,0 +1,79 @@ +import React, { FC, useMemo } from 'react'; +import { IComment, IFile } from '~/redux/types'; +import path from 'ramda/es/path'; +import { formatCommentText, getURL } from '~/utils/dom'; +import { Group } from '~/components/containers/Group'; +import * as styles from './styles.scss'; +import { UPLOAD_TYPES } from '~/redux/uploads/constants'; +import assocPath from 'ramda/es/assocPath'; +import append from 'ramda/es/append'; +import reduce from 'ramda/es/reduce'; +import { AudioPlayer } from '~/components/media/AudioPlayer'; +import classnames from 'classnames'; + +interface IProps { + comment: IComment; +} + +const CommentContent: FC = ({ comment }) => { + const groupped = useMemo>( + () => + reduce( + (group, file) => assocPath([file.type], append(file, group[file.type]), group), + {}, + comment.files + ), + [comment] + ); + + return ( + <> + {comment.text && ( +
+ +
+ )} + + {groupped.image && groupped.image.length > 0 && ( +
+
+ {groupped.image.map(file => ( +
+ {file.name} +
+ ))} +
+
+ )} + + {groupped.audio && groupped.audio.length > 0 && ( + <> + {groupped.audio.map(file => ( +
+ +
+ ))} + + )} + + ); +}; + +export { CommentContent }; + +/* +{comment.text && ( + + )} + +
{getPrettyDate(comment.created_at)}
+ + + + + */ diff --git a/src/components/node/CommentContent/styles.scss b/src/components/node/CommentContent/styles.scss new file mode 100644 index 00000000..ccfb4e3d --- /dev/null +++ b/src/components/node/CommentContent/styles.scss @@ -0,0 +1,65 @@ +@import 'flexbin/flexbin.scss'; + +.block { + min-height: $comment_height; + box-shadow: inset rgba(255, 255, 255, 0.05) 1px 1px, inset rgba(0, 0, 0, 0.1) -1px -1px; + display: flex; + align-items: flex-start; + justify-content: flex-start; + + &:first-child { + border-top-right-radius: $radius; + } + + &:last-child { + border-bottom-right-radius: $radius; + } +} + +.block_audio { + align-items: center; + justify-content: center; +} + +.text { + padding: $gap; + font-weight: 300; + font: $font_16_medium; + line-height: 20px; + box-sizing: border-box; + position: relative; + color: #cccccc; + + b { + font-weight: 600; + } +} + +.date { + position: absolute; + bottom: 0; + right: 0; + font: $font_12_regular; + color: transparentize($color: white, $amount: 0.8); + padding: 2px 4px; + border-radius: 0 0 $radius 0; +} + +.images { + @include flexbin(240px, 5px); + + img { + border-radius: $radius; + } +} + +.audios { + & > div { + height: $comment_height; + border-radius: $radius; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + } +} diff --git a/src/components/node/NodeComments/index.tsx b/src/components/node/NodeComments/index.tsx index 339a4a67..ab9982ba 100644 --- a/src/components/node/NodeComments/index.tsx +++ b/src/components/node/NodeComments/index.tsx @@ -1,24 +1,29 @@ -import React, { FC } from 'react'; +import React, { FC, useMemo } from 'react'; import { Comment } from '../Comment'; import { Filler } from '~/components/containers/Filler'; import * as styles from './styles.scss'; +import { ICommentGroup, IComment } from '~/redux/types'; +import { groupCommentsByUser } from '~/utils/fn'; interface IProps { - comments?: any; + comments?: IComment[]; } -const isSameComment = (comments, index) => - comments[index - 1] && comments[index - 1].user.id === comments[index].user.id; +const NodeComments: FC = ({ comments }) => { + const groupped: ICommentGroup[] = useMemo(() => comments.reduce(groupCommentsByUser, []), [ + comments, + ]); -const NodeComments: FC = ({ comments }) => ( -
- {comments.map((comment, index) => ( - - ))} + return ( +
+ {groupped.map(group => ( + + ))} - -
-); + +
+ ); +}; export { NodeComments }; diff --git a/src/containers/node/NodeLayout/index.tsx b/src/containers/node/NodeLayout/index.tsx index cd629d04..02d7b10b 100644 --- a/src/containers/node/NodeLayout/index.tsx +++ b/src/containers/node/NodeLayout/index.tsx @@ -68,13 +68,13 @@ const NodeLayoutUnconnected: FC = ({ - {is_user && } - {is_loading_comments || !comments.length ? ( ) : ( )} + + {is_user && }
diff --git a/src/redux/node/constants.ts b/src/redux/node/constants.ts index cd13c326..f61dad63 100644 --- a/src/redux/node/constants.ts +++ b/src/redux/node/constants.ts @@ -67,6 +67,7 @@ export const NODE_COMPONENTS: INodeComponents = { }; export const EMPTY_COMMENT: IComment = { + id: null, text: '', files: [], temp_ids: [], diff --git a/src/redux/node/sagas.ts b/src/redux/node/sagas.ts index 98fe0693..927b7e87 100644 --- a/src/redux/node/sagas.ts +++ b/src/redux/node/sagas.ts @@ -100,7 +100,7 @@ function* onPostComment({ id }: ReturnType) { if (current_node && current_node.id === current.id) { // if user still browsing that node const { comments } = yield select(selectNode); - yield put(nodeSetComments([comment, ...comments])); + yield put(nodeSetComments([...comments, comment])); yield put(nodeSetCommentData(0, { ...EMPTY_COMMENT })); } } diff --git a/src/redux/types.ts b/src/redux/types.ts index ea6e9a70..a8523790 100644 --- a/src/redux/types.ts +++ b/src/redux/types.ts @@ -133,6 +133,7 @@ export interface INode { } export interface IComment { + id: number; text: string; temp_ids?: string[]; files: IFile[]; @@ -143,6 +144,12 @@ export interface IComment { update_at?: string; } +export interface ICommentGroup { + user: IUser; + comments: IComment[]; + ids: IComment['id'][]; +} + export type IUploadProgressHandler = (progress: ProgressEvent) => void; export type IError = ValueOf; export type IValidationErrors = Record; diff --git a/src/styles/global.scss b/src/styles/global.scss index 3ab58dc1..76ede1f3 100644 --- a/src/styles/global.scss +++ b/src/styles/global.scss @@ -76,6 +76,10 @@ body { height: 40px; } +:global(.grey) { + color: #555555; +} + :global(h2) { font: $font_24_bold; } diff --git a/src/utils/dom.ts b/src/utils/dom.ts index b1bb0baa..62649a81 100644 --- a/src/utils/dom.ts +++ b/src/utils/dom.ts @@ -72,11 +72,15 @@ export const formatCommentText = (author, text: string) => .replace(/(\n{2,})/gi, '\n') .replace(//g, '>') + .replace(/:\/\//gim, ':|--|') + .replace(/(\/\/[^\n]+)/gim, '$1') + .replace(/:\|--\|/gim, '://') .split('\n') .map((el, index) => index === 0 ? `${author ? `

${author}: ` : ''}${el}

` : `

${el}

` ) .join(''); +// .replace(/\/\*(\*(?!\/)|[^*])*\*\//igm, ''); export const getPrettyDate = (date: string): string => formatDistanceToNow(new Date(date), { locale: ru, includeSeconds: true, addSuffix: true }); diff --git a/src/utils/fn.ts b/src/utils/fn.ts index dd239fae..d05c8786 100644 --- a/src/utils/fn.ts +++ b/src/utils/fn.ts @@ -2,7 +2,41 @@ import curry from 'ramda/es/curry'; import insert from 'ramda/es/insert'; import nth from 'ramda/es/nth'; import remove from 'ramda/es/remove'; +import { ICommentGroup, IComment } from '~/redux/types'; +import path from 'ramda/es/path'; export const moveArrItem = curry((at, to, list) => insert(to, nth(at, list), remove(at, 1, list))); export const objFromArray = (array: any[], key: string) => array.reduce((obj, el) => (key && el[key] ? { ...obj, [el[key]]: el } : obj), {}); + +export const groupCommentsByUser = ( + result: ICommentGroup[], + comment: IComment +): ICommentGroup[] => { + const last: ICommentGroup = path([result.length - 1], result) || null; + + return [ + ...(!last || path(['user', 'id'], last) !== path(['user', 'id'], comment) + ? [ + // add new group + ...result, + { + user: comment.user, + comments: [comment], + ids: [comment.id], + }, + ] + : [ + // append to last group + ...result.slice(0, result.length - 1), + { + ...last, + comments: [...last.comments, comment], + ids: [...last.ids, comment.id], + }, + ]), + ]; +}; + +// const isSameComment = (comments, index) => +// comments[index - 1] && comments[index - 1].user.id === comments[index].user.id;