From 9a811da9a3e40af97b4d85b126a9032f265995b2 Mon Sep 17 00:00:00 2001 From: Robin Pyon Date: Fri, 8 Dec 2023 03:59:30 +0000 Subject: [PATCH] feat: add absolute tooltip dates to document statusbar, don't render statusbar until ready, minor cleanup --- .../ReferenceInput/ReferencePreview.tsx | 4 +- packages/sanity/src/core/hooks/index.ts | 2 +- .../src/core/hooks/useDocumentStatus.ts | 58 ++++++++++++++++++ .../core/hooks/useDocumentStatusTimeAgo.ts | 43 ------------- .../components/paneItem/PaneItemPreview.tsx | 4 +- .../document/statusBar/DocumentStatusBar.tsx | 22 +++---- .../statusBar/sparkline/DocumentSparkline.tsx | 61 +++++-------------- .../sparkline/DocumentStatusLine.tsx | 45 ++++++++++++++ .../DocumentStatusPulse.tsx | 9 ++- .../src/ui/documentStatus/DocumentStatus.tsx | 4 +- 10 files changed, 139 insertions(+), 113 deletions(-) create mode 100644 packages/sanity/src/core/hooks/useDocumentStatus.ts delete mode 100644 packages/sanity/src/core/hooks/useDocumentStatusTimeAgo.ts create mode 100644 packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentStatusLine.tsx diff --git a/packages/sanity/src/core/form/inputs/ReferenceInput/ReferencePreview.tsx b/packages/sanity/src/core/form/inputs/ReferenceInput/ReferencePreview.tsx index 103f1848c2e..5aeb4d3efe6 100644 --- a/packages/sanity/src/core/form/inputs/ReferenceInput/ReferencePreview.tsx +++ b/packages/sanity/src/core/form/inputs/ReferenceInput/ReferencePreview.tsx @@ -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' /** @@ -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( () => ({ diff --git a/packages/sanity/src/core/hooks/index.ts b/packages/sanity/src/core/hooks/index.ts index fca4f3b548c..2d855c9822c 100644 --- a/packages/sanity/src/core/hooks/index.ts +++ b/packages/sanity/src/core/hooks/index.ts @@ -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' diff --git a/packages/sanity/src/core/hooks/useDocumentStatus.ts b/packages/sanity/src/core/hooks/useDocumentStatus.ts new file mode 100644 index 00000000000..356bfaebee9 --- /dev/null +++ b/packages/sanity/src/core/hooks/useDocumentStatus.ts @@ -0,0 +1,58 @@ +import {PreviewValue, SanityDocument} from '@sanity/types' +import {useIntlDateTimeFormat} from '../i18n' +import {useRelativeTime} from './useRelativeTime' + +interface DocumentStatusTimeAgoOptions { + draft?: PreviewValue | Partial | null + hidePublishedDate?: boolean + published?: PreviewValue | Partial | 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(' ') +} diff --git a/packages/sanity/src/core/hooks/useDocumentStatusTimeAgo.ts b/packages/sanity/src/core/hooks/useDocumentStatusTimeAgo.ts deleted file mode 100644 index 5b951d74b57..00000000000 --- a/packages/sanity/src/core/hooks/useDocumentStatusTimeAgo.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {PreviewValue, SanityDocument} from '@sanity/types' -import {useRelativeTime} from './useRelativeTime' - -/** - * React hook which returns a human readable string of the provided document's status. - * - * @internal - * @hidden - */ -export function useDocumentStatusTimeAgo({ - draft, - hidePublishedDate, - published, -}: { - draft?: PreviewValue | Partial | null - hidePublishedDate?: boolean - published?: PreviewValue | Partial | null -}): string | undefined { - const draftUpdatedAt = draft && '_updatedAt' in draft ? draft._updatedAt : '' - const publishedUpdatedAt = published && '_updatedAt' in published ? published._updatedAt : '' - - const updatedDateTimeAgo = useRelativeTime(draftUpdatedAt || '', { - minimal: true, - useTemporalPhrase: true, - }) - const publishedTimeAgo = useRelativeTime(publishedUpdatedAt || '', { - minimal: true, - useTemporalPhrase: true, - }) - - // @todo: localize correctly - - const documentStatus = [ - // Published status - publishedTimeAgo - ? `Published${hidePublishedDate ? '' : ` ${publishedTimeAgo}`}` - : `Not published`, - // Last updated (draft) status - ...(updatedDateTimeAgo ? [`(Updated ${updatedDateTimeAgo})`] : []), - ] - - return documentStatus.join(' ') -} diff --git a/packages/sanity/src/desk/components/paneItem/PaneItemPreview.tsx b/packages/sanity/src/desk/components/paneItem/PaneItemPreview.tsx index 63fb9adcf97..796d508032b 100644 --- a/packages/sanity/src/desk/components/paneItem/PaneItemPreview.tsx +++ b/packages/sanity/src/desk/components/paneItem/PaneItemPreview.tsx @@ -15,7 +15,7 @@ import { getPreviewValueWithFallback, SanityDefaultPreview, isRecord, - useDocumentStatusTimeAgo, + useDocumentStatus, } from 'sanity' export interface PaneItemPreviewProps { @@ -59,7 +59,7 @@ export function PaneItemPreview(props: PaneItemPreviewProps) { ) - const tooltipLabel = useDocumentStatusTimeAgo({draft, published}) + const tooltipLabel = useDocumentStatus({draft, published}) return ( state.onOlderRevision) return useMemo( () => ( - - - {badges && } + + + + - - - {showingRevision ? : } - - - + + + {showingRevision ? : } + + ), - [actionsBoxRef, badges, showingRevision], + [actionsBoxRef, showingRevision], ) } diff --git a/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentSparkline.tsx b/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentSparkline.tsx index 15de9ce0a31..de0bf3b593b 100644 --- a/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentSparkline.tsx +++ b/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentSparkline.tsx @@ -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(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. @@ -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 ( - - - - - - {statusTimeAgo} - - - - - - - {!collapsed && } + + + + {badges && } ) diff --git a/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentStatusLine.tsx b/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentStatusLine.tsx new file mode 100644 index 00000000000..cb5f78a75a4 --- /dev/null +++ b/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentStatusLine.tsx @@ -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 ( + + + + + + {statusTimeAgo} + + + + + ) +} diff --git a/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentStatusPulse/DocumentStatusPulse.tsx b/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentStatusPulse/DocumentStatusPulse.tsx index 19e276f7214..80c6e57f28d 100644 --- a/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentStatusPulse/DocumentStatusPulse.tsx +++ b/packages/sanity/src/desk/panes/document/statusBar/sparkline/DocumentStatusPulse/DocumentStatusPulse.tsx @@ -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, 'size' | 'width' | 'as' | 'type'> { - status?: StatusType +interface ReviewChangesButtonProps { collapsed?: boolean + status?: StatusType } const STATUS_DICTIONARY: Record = { @@ -31,7 +30,7 @@ export const DocumentStatusPulse = (props: ReviewChangesButtonProps) => { const currentStatus = STATUS_DICTIONARY[status] return ( - + diff --git a/packages/sanity/src/ui/documentStatus/DocumentStatus.tsx b/packages/sanity/src/ui/documentStatus/DocumentStatus.tsx index 7029c83fc3a..ba260d7596e 100644 --- a/packages/sanity/src/ui/documentStatus/DocumentStatus.tsx +++ b/packages/sanity/src/ui/documentStatus/DocumentStatus.tsx @@ -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 | null @@ -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