Skip to content

Commit

Permalink
Merge pull request #4976 from thematters/feat/comment-animation
Browse files Browse the repository at this point in the history
Feat/comment animation
  • Loading branch information
Kechicode authored Dec 16, 2024
2 parents 16e17eb + 71519dd commit 2bd1568
Show file tree
Hide file tree
Showing 12 changed files with 307 additions and 35 deletions.
3 changes: 3 additions & 0 deletions src/common/enums/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ export const REFERRAL_QUERY_REFERRAL_KEY = 'referral'
export const REFERRAL_STORAGE_REFERRAL_CODE = '__REFERRAL_CODE'

export const HAS_SHOW_MOMENT_BANNER = '__HAS_SHOW_MOMENT_BANNER'

export const NEW_POST_COMMENT_MUTATION_RESULT =
'__NEW_POST_COMMENT_MUTATION_RESULT'
44 changes: 36 additions & 8 deletions src/components/Comment/DropdownActions/DeleteComment/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import gql from 'graphql-tag'
import { FormattedMessage } from 'react-intl'

import { TEST_ID } from '~/common/enums'
import { COMMENT_FEED_ID_PREFIX, TEST_ID } from '~/common/enums'
import {
Dialog,
toast,
Expand All @@ -15,6 +15,8 @@ import {
DeleteCommentMutation,
} from '~/gql/graphql'

import styles from './styles.module.css'

const DELETE_COMMENT = gql`
mutation DeleteComment($id: ID!) {
deleteComment(input: { id: $id }) {
Expand Down Expand Up @@ -42,20 +44,23 @@ const DeleteCommentDialog = ({
}: DeleteCommentDialogProps) => {
const { show, openDialog, closeDialog } = useDialogSwitch(true)
const { routerLang } = useRoute()
const commentId = comment.id
const { id, parentComment } = comment
const node =
comment.node.__typename === 'Article' ||
comment.node.__typename === 'Moment'
? comment.node
: undefined
const isArticle = comment.node.__typename === 'Article'
const isMoment = comment.node.__typename === 'Moment'
const isDescendantComment = parentComment !== null

const nodeId = parentComment ? `${parentComment.id}-${id}` : id

const [deleteComment] = useMutation<DeleteCommentMutation>(DELETE_COMMENT, {
variables: { id: commentId },
variables: { id: id },
optimisticResponse: {
deleteComment: {
id: commentId,
id: id,
state: 'archived' as any,
node:
isMoment && node?.__typename === 'Moment'
Expand Down Expand Up @@ -103,8 +108,31 @@ const DeleteCommentDialog = ({
},
})

const onDelete = async () => {
await deleteComment()
const playAnimationAndDelete = async () => {
// play animation
const commentElements = document.querySelectorAll(
`#${COMMENT_FEED_ID_PREFIX}${nodeId}`
)

if (commentElements.length > 0) {
commentElements.forEach((commentElement) => {
commentElement.parentElement?.addEventListener('animationend', () => {
commentElement.parentElement?.classList.add(styles.hideComment)
deleteComment()
})
})
}
if (commentElements.length > 0 && !isDescendantComment) {
commentElements.forEach((commentElement) => {
commentElement.parentElement?.classList.add(styles.deletedComment)
})
} else if (commentElements.length > 0 && isDescendantComment) {
commentElements.forEach((commentElement) => {
commentElement.parentElement?.classList.add(
styles.deletedDescendantComment
)
})
}

toast.success({
message: isMoment ? (
Expand Down Expand Up @@ -171,7 +199,7 @@ const DeleteCommentDialog = ({
text={<FormattedMessage defaultMessage="Delete" id="K3r6DQ" />}
color="red"
onClick={() => {
onDelete()
playAnimationAndDelete()
closeDialog()
}}
/>
Expand All @@ -181,7 +209,7 @@ const DeleteCommentDialog = ({
text={<FormattedMessage defaultMessage="Delete" id="K3r6DQ" />}
color="red"
onClick={() => {
onDelete()
playAnimationAndDelete()
closeDialog()
}}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.hideComment {
display: none;
}

.deletedComment {
overflow: hidden;
animation:
slide-up-fade 1.6s,
maintain-padding 1.6s;
}

.deletedDescendantComment {
overflow: hidden;
animation: slide-up-fade 1.6s;
}

@keyframes slide-up-fade {
0% {
max-height: 500px;
background: var(--color-insufficient-red);
}

/* 1s later */
62.5% {
background: var(--color-insufficient-red);
}

100% {
display: none;
max-height: 0;
background: var(--color-white);
}
}

@keyframes maintain-padding {
0% {
padding-right: var(--sp16);
padding-left: var(--sp16);
margin-right: calc(-1 * var(--sp16));
margin-left: calc(-1 * var(--sp16));
}

99% {
padding-right: var(--sp16);
padding-left: var(--sp16);
margin-right: calc(-1 * var(--sp16));
margin-left: calc(-1 * var(--sp16));
}

100% {
padding-right: 0;
padding-left: 0;
margin-right: 0;
margin-left: 0;
}
}
27 changes: 24 additions & 3 deletions src/components/Comment/Feed/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import classNames from 'classnames'
import React from 'react'

import { COMMENT_FEED_ID_PREFIX, TEST_ID } from '~/common/enums'
import { toPath } from '~/common/utils'
import {
COMMENT_FEED_ID_PREFIX,
NEW_POST_COMMENT_MUTATION_RESULT,
TEST_ID,
} from '~/common/enums'
import { sessionStorage, toPath } from '~/common/utils'
import {
Avatar,
AvatarSize,
Expand Down Expand Up @@ -80,11 +84,28 @@ const BaseCommentFeed = ({
moment: node,
})

const newPostCommentMutationResult = sessionStorage.get(
NEW_POST_COMMENT_MUTATION_RESULT
)

const isNewPostComment = newPostCommentMutationResult === id

const commentClasses = classNames({
[styles.comment]: true,
[styles.playSlideDownFade]: isNewPostComment,
[styles.momentComment]: isMoment,
})

return (
<article
className={styles.comment}
className={commentClasses}
id={`${COMMENT_FEED_ID_PREFIX}${nodeId}`}
data-test-id={TEST_ID.ARTICLE_COMMENT_FEED}
onAnimationEnd={() => {
if (isNewPostComment) {
sessionStorage.remove(NEW_POST_COMMENT_MUTATION_RESULT)
}
}}
>
<header className={styles.header}>
<section className={styles.left}>
Expand Down
58 changes: 58 additions & 0 deletions src/components/Comment/Feed/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,61 @@
.momentComment {
padding: var(--sp8) 0;

@media (--sm-up) {
padding: var(--sp12) 0;
}
}

.playSlideDownFade {
overflow: hidden;
animation:
slide-down-fade 1.6s,
maintain-padding 1.6s;
}

@keyframes slide-down-fade {
0% {
max-height: 0;
background: var(--color-green-lighter);
opacity: 0;
}

/* 1s later */
62.5% {
background: var(--color-green-lighter);
}

100% {
max-height: 500px;
background: var(--color-white);
opacity: 1;
}
}

@keyframes maintain-padding {
0% {
padding-right: var(--sp16);
padding-left: var(--sp16);
margin-right: calc(-1 * var(--sp16));
margin-left: calc(-1 * var(--sp16));
}

/* keep the padding and margin not change */
99% {
padding-right: var(--sp16);
padding-left: var(--sp16);
margin-right: calc(-1 * var(--sp16));
margin-left: calc(-1 * var(--sp16));
}

100% {
padding-right: 0;
padding-left: 0;
margin-right: 0;
margin-left: 0;
}
}

.header {
@mixin flex-start-space-between;

Expand Down
42 changes: 30 additions & 12 deletions src/components/Comment/FooterActions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,31 @@ const BaseFooterActions = ({
)} `
: ''

const [isHiding, setIsHiding] = useState(false)

const handleHideForm = () => {
// Start hide animation
setIsHiding(true)
}

const handleHideComplete = () => {
// End hide animation
setIsHiding(false)

if (editor === activeEditor) {
setActiveEditor(null)
}
setShowForm(false)
}

const handleReplyButtonClick = () => {
if (showForm) {
handleHideForm()
} else {
toggleShowForm()
}
}

return (
<>
<footer
Expand Down Expand Up @@ -232,12 +257,7 @@ const BaseFooterActions = ({
{...buttonProps}
{...replyButtonProps}
{...replyCustomButtonProps}
onClick={() => {
if (editor === activeEditor) {
setActiveEditor(null)
}
toggleShowForm()
}}
onClick={handleReplyButtonClick}
/>
</Media>
</>
Expand Down Expand Up @@ -275,14 +295,12 @@ const BaseFooterActions = ({
replyToId={comment.id}
parentId={comment.parentComment?.id || comment.id}
submitCallback={submitCallback}
closeCallback={() => {
if (editor === activeEditor) {
setActiveEditor(null)
}
setShowForm(false)
}}
closeCallback={handleHideForm}
isInCommentDetail={isInCommentDetail}
defaultContent={defaultContent}
playAnimation
isHiding={isHiding}
onHideComplete={handleHideComplete}
/>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@ import dynamic from 'next/dynamic'
import { useContext, useEffect, useRef, useState } from 'react'
import { FormattedMessage } from 'react-intl'

import { MAX_ARTICLE_COMMENT_LENGTH } from '~/common/enums'
import { dom, formStorage, sanitizeContent, stripHtml } from '~/common/utils'
import {
MAX_ARTICLE_COMMENT_LENGTH,
NEW_POST_COMMENT_MUTATION_RESULT,
} from '~/common/enums'
import {
dom,
formStorage,
sanitizeContent,
sessionStorage,
stripHtml,
} from '~/common/utils'
import {
Dialog,
SpinnerBlock,
Expand Down Expand Up @@ -93,27 +102,35 @@ const CommentForm: React.FC<CommentFormProps> = ({
await putComment({
variables: { input },
update: (cache, mutationResult) => {
const newComment = mutationResult.data?.putComment

if (!newComment) {
return
}

sessionStorage.set(NEW_POST_COMMENT_MUTATION_RESULT, newComment.id)

if (!!parentId && !isInCommentDetail) {
updateArticleComments({
cache,
articleId,
commentId: parentId,
type: 'addSecondaryComment',
comment: mutationResult.data?.putComment,
comment: newComment,
})
} else if (!!parentId && isInCommentDetail) {
updateCommentDetail({
cache,
commentId: parentId || '',
type: 'add',
comment: mutationResult.data?.putComment,
comment: newComment,
})
} else {
updateArticleComments({
cache,
articleId,
type: 'add',
comment: mutationResult.data?.putComment,
comment: newComment,
})
}
},
Expand Down
Loading

0 comments on commit 2bd1568

Please sign in to comment.