From 614f402fda99b961bc2ea24021bc8a9e46ca5d53 Mon Sep 17 00:00:00 2001 From: Herman Wikner Date: Mon, 25 Sep 2023 15:54:06 +0200 Subject: [PATCH] feat: ui updates --- .../components/avatars/CommentsAvatar.tsx | 41 ++++++++++++ .../components/avatars/SpacerAvatar.tsx | 13 ++++ .../core/comments/components/avatars/index.ts | 2 + .../src/core/comments/components/constants.ts | 1 - .../components/list/CommentThreadLayout.tsx | 2 +- .../comments/components/list/CommentsList.tsx | 10 +-- .../components/list/CommentsListItem.tsx | 18 +++--- .../list/CommentsListItemLayout.tsx | 44 ++++++++----- .../components/mentions/MentionsMenuItem.tsx | 10 ++- ...lizer.tsx => CommentMessageSerializer.tsx} | 22 +++++-- .../pte/blocks/MentionInlineBlock.tsx | 4 +- .../pte/comment-input/CommentInputInner.tsx | 14 ++--- .../src/core/comments/components/pte/index.ts | 2 +- .../comments/hooks/useCommentOperations.ts | 4 +- .../comments/hooks/useFieldCommentsCount.ts | 8 +-- .../comments/utils/buildCommentBreadcrumbs.ts | 4 +- .../core/components/userAvatar/UserAvatar.tsx | 3 +- .../src/desk/comments/field/CommentField.tsx | 62 ++++++++++++------- 18 files changed, 172 insertions(+), 92 deletions(-) create mode 100644 packages/sanity/src/core/comments/components/avatars/CommentsAvatar.tsx create mode 100644 packages/sanity/src/core/comments/components/avatars/SpacerAvatar.tsx create mode 100644 packages/sanity/src/core/comments/components/avatars/index.ts rename packages/sanity/src/core/comments/components/pte/{Serializer.tsx => CommentMessageSerializer.tsx} (74%) diff --git a/packages/sanity/src/core/comments/components/avatars/CommentsAvatar.tsx b/packages/sanity/src/core/comments/components/avatars/CommentsAvatar.tsx new file mode 100644 index 00000000000..9108523a6c1 --- /dev/null +++ b/packages/sanity/src/core/comments/components/avatars/CommentsAvatar.tsx @@ -0,0 +1,41 @@ +import React from 'react' +import styled from 'styled-components' +import {Avatar, AvatarProps} from '@sanity/ui' +import {User} from '@sanity/types' + +const StyledAvatar = styled(Avatar)` + svg > ellipse { + stroke: transparent; + } +` + +const SYMBOLS = /[^\p{Alpha}\p{White_Space}]/gu +const WHITESPACE = /\p{White_Space}+/u + +function nameToInitials(fullName: string) { + const namesArray = fullName.replace(SYMBOLS, '').split(WHITESPACE) + + if (namesArray.length === 1) { + return `${namesArray[0].charAt(0)}`.toUpperCase() + } + + return `${namesArray[0].charAt(0)}${namesArray[namesArray.length - 1].charAt(0)}` +} + +interface CommentsAvatarProps extends AvatarProps { + user: User | undefined | null +} + +export function CommentsAvatar(props: CommentsAvatarProps) { + const {user: userProp, ...restProps} = props + const user = userProp as User + const initials = nameToInitials(user?.displayName || '') + + const avatar = user ? ( + + ) : ( + + ) + + return avatar +} diff --git a/packages/sanity/src/core/comments/components/avatars/SpacerAvatar.tsx b/packages/sanity/src/core/comments/components/avatars/SpacerAvatar.tsx new file mode 100644 index 00000000000..fed96082ac4 --- /dev/null +++ b/packages/sanity/src/core/comments/components/avatars/SpacerAvatar.tsx @@ -0,0 +1,13 @@ +import React from 'react' + +const INLINE_STYLE: React.CSSProperties = { + minWidth: 25, +} + +/** + * This component is used to as a spacer in situations where we want to align + * components without avatars with components that have avatars. + */ +export function SpacerAvatar() { + return
+} diff --git a/packages/sanity/src/core/comments/components/avatars/index.ts b/packages/sanity/src/core/comments/components/avatars/index.ts new file mode 100644 index 00000000000..90ba25005e0 --- /dev/null +++ b/packages/sanity/src/core/comments/components/avatars/index.ts @@ -0,0 +1,2 @@ +export * from './CommentsAvatar' +export * from './SpacerAvatar' diff --git a/packages/sanity/src/core/comments/components/constants.ts b/packages/sanity/src/core/comments/components/constants.ts index 2377a8c1d06..50d00d1193b 100644 --- a/packages/sanity/src/core/comments/components/constants.ts +++ b/packages/sanity/src/core/comments/components/constants.ts @@ -1,4 +1,3 @@ import {FlexProps} from '@sanity/ui' export const FLEX_GAP: FlexProps['gap'] = 3 -export const AVATAR_SIZE = 25 diff --git a/packages/sanity/src/core/comments/components/list/CommentThreadLayout.tsx b/packages/sanity/src/core/comments/components/list/CommentThreadLayout.tsx index 2ffea4e85e2..8ca9ed452c9 100644 --- a/packages/sanity/src/core/comments/components/list/CommentThreadLayout.tsx +++ b/packages/sanity/src/core/comments/components/list/CommentThreadLayout.tsx @@ -145,7 +145,7 @@ export function CommentThreadLayout(props: CommentThreadLayoutProps) { )} - {children} + {children} ) } diff --git a/packages/sanity/src/core/comments/components/list/CommentsList.tsx b/packages/sanity/src/core/comments/components/list/CommentsList.tsx index 813cf6aa9ab..4771e5c1d4b 100644 --- a/packages/sanity/src/core/comments/components/list/CommentsList.tsx +++ b/packages/sanity/src/core/comments/components/list/CommentsList.tsx @@ -183,15 +183,7 @@ export const CommentsList = forwardRef(fu )} {showComments && ( - + {groupedComments.map(([fieldPath, group]) => { const parentComments = group.filter((c) => !c.parentCommentId) diff --git a/packages/sanity/src/core/comments/components/list/CommentsListItem.tsx b/packages/sanity/src/core/comments/components/list/CommentsListItem.tsx index 828b4c28eca..ebf4d8d447e 100644 --- a/packages/sanity/src/core/comments/components/list/CommentsListItem.tsx +++ b/packages/sanity/src/core/comments/components/list/CommentsListItem.tsx @@ -12,7 +12,7 @@ import { CommentStatus, } from '../../types' import {MentionOptionsHookValue} from '../../hooks' -import {AVATAR_SIZE} from '../constants' +import {SpacerAvatar} from '../avatars' import {CommentsListItemLayout} from './CommentsListItemLayout' const EMPTY_ARRAY: [] = [] @@ -123,6 +123,12 @@ export function CommentsListItem(props: CommentsListItemProps) { return replies.length > MAX_COLLAPSED_REPLIES }, [replies]) + const expandButtonText = useMemo(() => { + return `${replies?.length - MAX_COLLAPSED_REPLIES} more ${ + replies?.length - MAX_COLLAPSED_REPLIES === 1 ? 'comment' : 'comments' + }` + }, [replies?.length]) + useEffect(() => { if (replies.length > MAX_COLLAPSED_REPLIES && !didExpand.current) { setCollapsed(true) @@ -149,11 +155,7 @@ export function CommentsListItem(props: CommentsListItemProps) { {showCollapseButton && !didExpand.current && ( -
+ )} diff --git a/packages/sanity/src/core/comments/components/list/CommentsListItemLayout.tsx b/packages/sanity/src/core/comments/components/list/CommentsListItemLayout.tsx index 6018f6ec630..55b63ee755e 100644 --- a/packages/sanity/src/core/comments/components/list/CommentsListItemLayout.tsx +++ b/packages/sanity/src/core/comments/components/list/CommentsListItemLayout.tsx @@ -7,7 +7,6 @@ import { EyeOpenIcon, } from '@sanity/icons' import { - Avatar, TextSkeleton, Flex, Button, @@ -28,17 +27,17 @@ import {CurrentUser, Path} from '@sanity/types' import styled, {css} from 'styled-components' import {format} from 'date-fns' import * as PathUtils from '@sanity/util/paths' -import {UserAvatar} from '../../../components' import {TimeAgoOpts, useTimeAgo} from '../../../hooks' import {useUser} from '../../../store' import {CommentMessageSerializer} from '../pte' import {CommentInput} from '../pte/comment-input' import {CommentDocument, CommentEditPayload, CommentMessage, CommentStatus} from '../../types' -import {AVATAR_SIZE, FLEX_GAP} from '../constants' +import {FLEX_GAP} from '../constants' import {useDidUpdate} from '../../../form' import {useCommentHasChanged} from '../../helpers' import {MentionOptionsHookValue} from '../../hooks' import {TextTooltip} from '../TextTooltip' +import {CommentsAvatar, SpacerAvatar} from '../avatars' const FloatingLayer = styled(Layer)(({theme}) => { const {space} = theme.sanity @@ -126,9 +125,8 @@ export function CommentsListItemLayout(props: CommentsListItemLayoutProps) { const hasChanges = useCommentHasChanged(value) - const _date = lastEditedAt || _createdAt - const date = _date ? new Date(_date) : new Date() - const timeAgo = useTimeAgo(date, TIME_AGO_OPTS) + const createdDate = _createdAt ? new Date(_createdAt) : new Date() + const createdTimeAgo = useTimeAgo(createdDate, TIME_AGO_OPTS) const handleMenuOpen = useCallback(() => setMenuOpen(true), []) const handleMenuClose = useCallback(() => setMenuOpen(false), []) @@ -181,7 +179,7 @@ export function CommentsListItemLayout(props: CommentsListItemLayoutProps) { } }, [rootElement]) - const avatar = user ? : + const avatar = const name = user?.displayName ? ( @@ -207,20 +205,34 @@ export function CommentsListItemLayout(props: CommentsListItemLayoutProps) { {name} - - {timeAgo} {lastEditedAt && <>(edited)} - + + + {createdTimeAgo} + + + {lastEditedAt && ( + + (edited) + + )} + {isEditing && ( -
+ -