Skip to content

Commit

Permalink
feat: add absolute tooltip dates to document statusbar, don't render …
Browse files Browse the repository at this point in the history
…statusbar until ready, minor cleanup
  • Loading branch information
robinpyon authored and rexxars committed Dec 19, 2023
1 parent a6fd7f6 commit 9a811da
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {PreviewLayoutKey} from '../../../components'
import {RenderPreviewCallback} from '../../types'
import {useDocumentPresence} from '../../../store'
import {DocumentPreviewPresence} from '../../../presence'
import {useDocumentStatusTimeAgo} from '../../../hooks'
import {useDocumentStatus} from '../../../hooks'
import {ReferenceInfo} from './types'

/**
Expand Down Expand Up @@ -44,7 +44,7 @@ export function ReferencePreview(props: {
)

const {draft, published} = preview
const tooltipLabel = useDocumentStatusTimeAgo({draft, published})
const tooltipLabel = useDocumentStatus({draft, published})

const previewProps = useMemo(
() => ({
Expand Down
2 changes: 1 addition & 1 deletion packages/sanity/src/core/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export * from './useDataset'
export * from './useDateTimeFormat'
export * from './useDocumentOperation'
export * from './useDocumentOperationEvent'
export * from './useDocumentStatusTimeAgo'
export * from './useDocumentStatus'
export * from './useEditState'
export * from './useFeatureEnabled'
export * from './useFormattedDuration'
Expand Down
58 changes: 58 additions & 0 deletions packages/sanity/src/core/hooks/useDocumentStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {PreviewValue, SanityDocument} from '@sanity/types'
import {useIntlDateTimeFormat} from '../i18n'
import {useRelativeTime} from './useRelativeTime'

interface DocumentStatusTimeAgoOptions {
draft?: PreviewValue | Partial<SanityDocument> | null
hidePublishedDate?: boolean
published?: PreviewValue | Partial<SanityDocument> | null
absoluteDate?: boolean
}

/**
* React hook which returns a human readable string of the provided document's status.
*
* @internal
* @hidden
*/
export function useDocumentStatus({
absoluteDate,
draft,
hidePublishedDate,
published,
}: DocumentStatusTimeAgoOptions): string | undefined {
const draftUpdatedAt = draft && '_updatedAt' in draft ? draft._updatedAt : ''
const publishedUpdatedAt = published && '_updatedAt' in published ? published._updatedAt : ''

const intlDateFormat = useIntlDateTimeFormat({
dateStyle: 'medium',
timeStyle: 'short',
})

const draftDateAbsolute = draftUpdatedAt && intlDateFormat.format(new Date(draftUpdatedAt))
const publishedDateAbsolute =
publishedUpdatedAt && intlDateFormat.format(new Date(publishedUpdatedAt))

const draftUpdatedTimeAgo = useRelativeTime(draftUpdatedAt || '', {
minimal: true,
useTemporalPhrase: true,
})
const publishedUpdatedTimeAgo = useRelativeTime(publishedUpdatedAt || '', {
minimal: true,
useTemporalPhrase: true,
})

const publishedDate = absoluteDate ? publishedDateAbsolute : publishedUpdatedTimeAgo
const updatedDate = absoluteDate ? draftDateAbsolute : draftUpdatedTimeAgo

const documentStatus = [
// Published status
publishedUpdatedTimeAgo
? `Published${hidePublishedDate ? '' : ` ${publishedDate}`}`
: `Not published`,
// Last updated (draft) status
...(draftUpdatedTimeAgo ? [`(Updated ${updatedDate})`] : []),
]

return documentStatus.join(' ')
}
43 changes: 0 additions & 43 deletions packages/sanity/src/core/hooks/useDocumentStatusTimeAgo.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
getPreviewValueWithFallback,
SanityDefaultPreview,
isRecord,
useDocumentStatusTimeAgo,
useDocumentStatus,
} from 'sanity'

export interface PaneItemPreviewProps {
Expand Down Expand Up @@ -59,7 +59,7 @@ export function PaneItemPreview(props: PaneItemPreviewProps) {
</TooltipDelayGroupProvider>
)

const tooltipLabel = useDocumentStatusTimeAgo({draft, published})
const tooltipLabel = useDocumentStatus({draft, published})

return (
<SanityDefaultPreview
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,24 @@ const DocumentActionsFlex = styled(Flex)`

export function DocumentStatusBar(props: DocumentStatusBarProps) {
const {actionsBoxRef} = props
const {badges, timelineStore} = useDocumentPane()
const {timelineStore} = useDocumentPane()

// Subscribe to external timeline state changes
const showingRevision = useTimelineSelector(timelineStore, (state) => state.onOlderRevision)

return useMemo(
() => (
<Box padding={2}>
<Flex align="center">
<Box flex={[1, 2]}>{badges && <DocumentSparkline />}</Box>
<Flex align="center" gap={1} padding={2} paddingLeft={3}>
<Box flex={[1, 2]}>
<DocumentSparkline />
</Box>

<DocumentActionsFlex flex={1} justify="flex-end" marginLeft={[1, 3]} ref={actionsBoxRef}>
<SpacerButton size="large" />
{showingRevision ? <HistoryStatusBarActions /> : <DocumentStatusBarActions />}
</DocumentActionsFlex>
</Flex>
</Box>
<DocumentActionsFlex flex={1} justify="flex-end" ref={actionsBoxRef}>
<SpacerButton size="large" />
{showingRevision ? <HistoryStatusBarActions /> : <DocumentStatusBarActions />}
</DocumentActionsFlex>
</Flex>
),
[actionsBoxRef, badges, showingRevision],
[actionsBoxRef, showingRevision],
)
}
Original file line number Diff line number Diff line change
@@ -1,38 +1,26 @@
import {Box, Flex, Text, useElementRect} from '@sanity/ui'
import React, {useEffect, useState, memo, useLayoutEffect} from 'react'
import {DocumentStatus} from '../../../../../ui/documentStatus'
import {Flex, useElementSize} from '@sanity/ui'
import React, {useState, memo, useLayoutEffect, useEffect} from 'react'
import {useDocumentPane} from '../../useDocumentPane'
import {DocumentBadges} from './DocumentBadges'
import {DocumentStatusLine} from './DocumentStatusLine'
import {DocumentStatusPulse} from './DocumentStatusPulse'
import {useDocumentStatusTimeAgo, useSyncState, useTimelineSelector} from 'sanity'
import {useSyncState} from 'sanity'

const SYNCING_TIMEOUT = 1000
const SAVED_TIMEOUT = 3000

export const DocumentSparkline = memo(function DocumentSparkline() {
const {
changesOpen,
documentId,
documentType,
editState,
onHistoryClose,
onHistoryOpen,
timelineStore,
value,
} = useDocumentPane()
const {badges, documentId, documentType, editState, value} = useDocumentPane()
const syncState = useSyncState(documentId, documentType)

const lastUpdated = value?._updatedAt

const [rootFlexElement, setRootFlexElement] = useState<HTMLDivElement | null>(null)
const rootFlexRect = useElementRect(rootFlexElement)
const collapsed = !rootFlexRect || rootFlexRect?.width < 300
const rootFlexRect = useElementSize(rootFlexElement)
const collapsed = !rootFlexRect || rootFlexRect?.content.width < 380

const [status, setStatus] = useState<'saved' | 'syncing' | null>(null)

// Subscribe to TimelineController changes and store internal state.
const showingRevision = useTimelineSelector(timelineStore, (state) => state.onOlderRevision)

// eslint-disable-next-line consistent-return
useEffect(() => {
// Schedule an update to set the status to 'saved' when status changed to 'syncing.
Expand Down Expand Up @@ -60,37 +48,16 @@ export const DocumentSparkline = memo(function DocumentSparkline() {
}
}, [syncState.isSyncing, lastUpdated])

const statusTimeAgo = useDocumentStatusTimeAgo({
draft: editState?.draft,
hidePublishedDate: true,
published: editState?.published,
})
if (!editState?.ready) {
return null
}

return (
<Flex align="center" data-ui="DocumentSparkline" ref={setRootFlexElement}>
<Flex align="center" flex={1} gap={3} marginLeft={3}>
<Flex align="center" gap={2}>
<DocumentStatus
draft={editState?.draft}
published={editState?.published}
showPublishedIcon
/>
<Box flex={1}>
<Text muted textOverflow="ellipsis" size={1} weight="medium">
{statusTimeAgo}
</Text>
</Box>
</Flex>

<DocumentStatusPulse
status={status || undefined}
onClick={changesOpen ? onHistoryClose : onHistoryOpen}
disabled={showingRevision}
selected={changesOpen}
collapsed={collapsed}
/>

{!collapsed && <DocumentBadges />}
<Flex align="center" flex={1} gap={3}>
<DocumentStatusLine collapsed={collapsed} editState={editState} />
<DocumentStatusPulse collapsed={collapsed} status={status || undefined} />
{badges && <DocumentBadges />}
</Flex>
</Flex>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {Box, Flex, Text} from '@sanity/ui'
import React from 'react'
import {Tooltip} from '../../../../../ui'
import {DocumentStatus} from '../../../../../ui/documentStatus'
import {EditStateFor, useDocumentStatus} from 'sanity'

interface DocumentStatusLineProps {
collapsed?: boolean
editState: EditStateFor | null
}

export function DocumentStatusLine({collapsed, editState}: DocumentStatusLineProps) {
const statusTimeAgo = useDocumentStatus({
draft: editState?.draft,
hidePublishedDate: collapsed,
published: editState?.published,
})

const statusAbsolute = useDocumentStatus({
absoluteDate: true,
draft: editState?.draft,
published: editState?.published,
})

if (!editState) {
return null
}

return (
<Tooltip content={statusAbsolute}>
<Flex align="center" gap={3} paddingLeft={1} paddingY={2}>
<DocumentStatus
draft={editState?.draft}
published={editState?.published}
showPublishedIcon
/>
<Box flex={1}>
<Text muted textOverflow="ellipsis" size={1} weight="medium">
{statusTimeAgo}
</Text>
</Box>
</Flex>
</Tooltip>
)
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import {ButtonTone, Flex, Inline} from '@sanity/ui'
import {ButtonTone, Flex} from '@sanity/ui'
import React from 'react'
import {AnimatedStatusIcon} from './AnimatedStatusIcon'
import {TextWithTone} from 'sanity'

type StatusType = 'saved' | 'syncing'
interface ReviewChangesButtonProps
extends Omit<React.HTMLProps<HTMLButtonElement>, 'size' | 'width' | 'as' | 'type'> {
status?: StatusType
interface ReviewChangesButtonProps {
collapsed?: boolean
status?: StatusType
}

const STATUS_DICTIONARY: Record<StatusType, {text: string; tone: ButtonTone}> = {
Expand All @@ -31,7 +30,7 @@ export const DocumentStatusPulse = (props: ReviewChangesButtonProps) => {
const currentStatus = STATUS_DICTIONARY[status]

return (
<Flex align="center" gap={3} marginLeft={1}>
<Flex align="center" gap={3}>
<TextWithTone size={1} tone={currentStatus.tone}>
<AnimatedStatusIcon status={status} />
</TextWithTone>
Expand Down
4 changes: 2 additions & 2 deletions packages/sanity/src/ui/documentStatus/DocumentStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {PreviewValue, SanityDocument} from '@sanity/types'
import {Box, ButtonTone, Flex} from '@sanity/ui'
import React from 'react'
import styled, {css} from 'styled-components'
import {TextWithTone, useDocumentStatusTimeAgo} from '../../core'
import {TextWithTone, useDocumentStatus} from '../../core'

export interface DocumentStatusProps {
draft?: PreviewValue | Partial<SanityDocument> | null
Expand Down Expand Up @@ -31,7 +31,7 @@ const Dot = styled(Box)<{$draft?: boolean; $published: boolean}>(({theme, $draft
})

export function DocumentStatus({draft, published, showPublishedIcon}: DocumentStatusProps) {
const statusTimeAgo = useDocumentStatusTimeAgo({draft, published})
const statusTimeAgo = useDocumentStatus({draft, published})

if (!draft && !published) {
return null
Expand Down

0 comments on commit 9a811da

Please sign in to comment.