Skip to content

Commit

Permalink
feat(structure): add changes by tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
pedrobonamin committed Nov 6, 2024
1 parent e7b714d commit bd8f436
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 8 deletions.
3 changes: 2 additions & 1 deletion packages/sanity/src/core/i18n/bundles/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1594,7 +1594,8 @@ export const studioLocaleStrings = defineLocalesResources('studio', {
'sheet-list.select-fields': 'Select up to 5 field types',
/** Accessibility label for the navbar status button */
'status-button.aria-label': 'Configuration status',

/** Title for the changes tooltip in the history inspector*/
'timeline.changes.title': 'Changes by',
/** Description for error when the timeline for the given document can't be loaded */
'timeline.error.load-document-changes-description':
'Document history transactions have not been affected.',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import {Card, Flex, Stack, Text} from '@sanity/ui'
import {Box, Card, Flex, Skeleton, Stack, Text} from '@sanity/ui'
// eslint-disable-next-line camelcase
import {getTheme_v2, type ThemeColorAvatarColorKey} from '@sanity/ui/theme'
import {createElement, type MouseEvent, useCallback, useMemo} from 'react'
import {
type ChunkType,
type RelativeTimeOptions,
useDateTimeFormat,
UserAvatar,
useRelativeTime,
useTranslation,
useUser,
} from 'sanity'
import {css, styled} from 'styled-components'

import {Tooltip} from '../../../../ui-components'
import {getTimelineEventIconComponent} from './helpers'
import {TIMELINE_ITEM_I18N_KEY_MAPPING} from './timelineI18n'
import {UserAvatarStack} from './userAvatarStack'
Expand Down Expand Up @@ -59,6 +62,58 @@ const RELATIVE_TIME_OPTIONS: RelativeTimeOptions = {
useTemporalPhrase: true,
}

const AvatarSkeleton = styled(Skeleton)((props) => {
const theme = getTheme_v2(props.theme)
return css`
border-radius: 50%;
width: ${theme.avatar.sizes[1].size}px;
height: ${theme.avatar.sizes[1].size}px;
`
})

const NameSkeleton = styled(Skeleton)((props) => {
const theme = getTheme_v2(props.theme)
return css`
width: 6ch;
height: ${theme.font.text.sizes[0].lineHeight}px;
`
})

const UserLine = ({userId}: {userId: string}) => {
const [user, loading] = useUser(userId)

return (
<Flex align="center" gap={2} key={userId} padding={1}>
<Box>{loading || !user ? <AvatarSkeleton animated /> : <UserAvatar user={user} />}</Box>
<Box>
{loading || !user?.displayName ? (
<Text size={1}>
<NameSkeleton animated />
</Text>
) : (
<Text muted size={1}>
{user.displayName}
</Text>
)}
</Box>
</Flex>
)
}
const TooltipContent = ({collaborators}: {collaborators: string[]}) => {
const {t} = useTranslation('studio')
return (
<Stack paddingBottom={1}>
<Box padding={1} paddingBottom={2}>
<Text size={1} weight="medium">
{t('timeline.changes.title')}
</Text>
</Box>
{collaborators.map((userId) => (
<UserLine key={userId} userId={userId} />
))}
</Stack>
)
}
export function TimelineItem({
chunk,
isSelected,
Expand Down Expand Up @@ -127,7 +182,20 @@ export function TimelineItem({

{collaboratorsUsersIds.length > 0 && (
<Flex flex={1} justify="flex-end" align="center">
<UserAvatarStack maxLength={3} userIds={collaboratorsUsersIds} size={0} />
<Tooltip
placement="top"
content={<TooltipContent collaborators={collaboratorsUsersIds} />}
portal
>
<Box paddingLeft={2} paddingY={2}>
<UserAvatarStack
maxLength={3}
userIds={collaboratorsUsersIds}
size={0}
withTooltip={false}
/>
</Box>
</Tooltip>
</Flex>
)}
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@ interface UserAvatarStackProps {
maxLength?: number
userIds: string[]
size?: AvatarSize
withTooltip?: boolean
}

export function UserAvatarStack({maxLength, userIds, size}: UserAvatarStackProps) {
export function UserAvatarStack({
maxLength,
userIds,
size,
withTooltip = true,
}: UserAvatarStackProps) {
return (
<AvatarStack maxLength={maxLength} size={size}>
{userIds.map((userId) => (
<UserAvatar key={userId} user={userId} withTooltip />
<UserAvatar key={userId} user={userId} withTooltip={withTooltip} />
))}
</AvatarStack>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ describe('Tests addChunksMetadata', () => {
"0181e905-db87-4a71-9b8d-dc61c3281686",
],
"collaborators": Set {
"author1",
"author2",
},
"draftState": "missing",
Expand Down Expand Up @@ -171,6 +172,7 @@ describe('Tests addChunksMetadata', () => {
"collaborators": Set {
"author1",
"author2",
"author3",
},
"draftState": "missing",
"end": -1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ export function addChunksMetadata(chunks: Chunk[]): ChunksWithCollapsedDrafts[]
const previousPublish = getPreviousPublishAction(result)
if (chunk.type === 'editDraft' && previousPublish?.type === 'publish') {
Array.from(chunk.authors).forEach((id) => {
if (!previousPublish.authors.has(id)) {
previousPublish.collaborators.add(id)
}
previousPublish.collaborators.add(id)
})
previousPublish.children.push(chunk.id)
result.push({
Expand Down

0 comments on commit bd8f436

Please sign in to comment.