diff --git a/src/components/ResponsiveDate.tsx b/src/components/ResponsiveDate.tsx index 433ae5bb..1134f8cc 100644 --- a/src/components/ResponsiveDate.tsx +++ b/src/components/ResponsiveDate.tsx @@ -1,40 +1,66 @@ +'use client'; + import { formatDate } from '@/utility/date'; import { clsx } from 'clsx/lite'; +import { useEffect, useState } from 'react'; export default function ResponsiveDate({ date, className, titleLabel, + timezone: timezoneFromProps, }: { date: Date className?: string titleLabel?: string + timezone?: string | null }) { + const [timezone, setTimezone] = useState(timezoneFromProps); + + useEffect(() => { + if (timezoneFromProps === null) { + setTimezone(Intl.DateTimeFormat().resolvedOptions().timeZone); + } + }, [timezoneFromProps]); + + const showPlaceholderContent = timezone === null; + + const titleDateFormatted = formatDate(date).toLocaleUpperCase(); + const title = titleLabel - ? `${titleLabel}: ${formatDate(date).toLocaleUpperCase()}` - : formatDate(date).toLocaleUpperCase(); + ? `${titleLabel}: ${titleDateFormatted}` + : titleDateFormatted; + + const contentClass = showPlaceholderContent && 'opacity-0 select-none'; + return ( {/* Small */} - {formatDate(date, 'short')} + {formatDate(date, 'short', showPlaceholderContent)} {/* Medium */} - {formatDate(date, 'medium')} + {formatDate(date, 'medium', showPlaceholderContent)} {/* Large */} - - {formatDate(date)} + + {formatDate(date, undefined, showPlaceholderContent)} ); diff --git a/src/photo/PhotoDate.tsx b/src/photo/PhotoDate.tsx index a8c3efb4..8966a6ba 100644 --- a/src/photo/PhotoDate.tsx +++ b/src/photo/PhotoDate.tsx @@ -10,6 +10,7 @@ export default function PhotoDate({ photo: Photo className?: string dateType?: 'takenAt' | 'createdAt' | 'updatedAt' + timezone?: string | null }) { const date = useMemo(() => { const date = new Date(dateType === 'takenAt' @@ -41,6 +42,7 @@ export default function PhotoDate({ date, className, titleLabel: getTitleLabel(), + timezone: null, }} /> ); } diff --git a/src/site/globals.css b/src/site/globals.css index 13d47311..e80a7ad3 100644 --- a/src/site/globals.css +++ b/src/site/globals.css @@ -164,6 +164,10 @@ @apply bg-white dark:bg-black } + .bg-dim { + @apply + bg-gray-100 dark:bg-gray-900/75 + } .bg-content { @apply bg-white border-gray-200 diff --git a/src/utility/date.ts b/src/utility/date.ts index fdbe6454..96f99c99 100644 --- a/src/utility/date.ts +++ b/src/utility/date.ts @@ -1,25 +1,41 @@ import { format, parseISO, parse } from 'date-fns'; -const DATE_STRING_FORMAT_TINY = 'dd MMM yy'; -const DATE_STRING_FORMAT_SHORT = 'dd MMM yyyy'; -const DATE_STRING_FORMAT_MEDIUM = 'dd MMM yy h:mma'; -const DATE_STRING_FORMAT = 'dd MMM yyyy h:mma'; -const DATE_STRING_FORMAT_POSTGRES = 'yyyy-MM-dd HH:mm:ss'; +const DATE_STRING_FORMAT_TINY = 'dd MMM yy'; +const DATE_STRING_FORMAT_TINY_PLACEHOLDER = '00 000 00'; + +const DATE_STRING_FORMAT_SHORT = 'dd MMM yyyy'; +const DATE_STRING_FORMAT_SHORT_PLACEHOLDER = '00 000 0000'; + +const DATE_STRING_FORMAT_MEDIUM = 'dd MMM yy h:mma'; +const DATE_STRING_FORMAT_MEDIUM_PLACEHOLDER = '00 000 00 00:0000'; + +const DATE_STRING_FORMAT_LONG = 'dd MMM yyyy h:mma'; +const DATE_STRING_FORMAT_LONG_PLACEHOLDER = '00 000 0000 00:0000'; + +const DATE_STRING_FORMAT_POSTGRES = 'yyyy-MM-dd HH:mm:ss'; type AmbiguousTimestamp = number | string; type Length = 'tiny' | 'short' | 'medium' | 'long'; -export const formatDate = (date: Date, length: Length = 'long') => { +export const formatDate = ( + date: Date, + length: Length = 'long', + showPlaceholder?: boolean, +) => { switch (length) { - case 'tiny': - return format(date, DATE_STRING_FORMAT_TINY); - case 'short': - return format(date, DATE_STRING_FORMAT_SHORT); - case 'medium': - return format(date, DATE_STRING_FORMAT_MEDIUM); - default: - return format(date, DATE_STRING_FORMAT); + case 'tiny': return showPlaceholder + ? DATE_STRING_FORMAT_TINY_PLACEHOLDER + : format(date, DATE_STRING_FORMAT_TINY); + case 'short': return showPlaceholder + ? DATE_STRING_FORMAT_SHORT_PLACEHOLDER + : format(date, DATE_STRING_FORMAT_SHORT); + case 'medium': return showPlaceholder + ? DATE_STRING_FORMAT_MEDIUM_PLACEHOLDER + : format(date, DATE_STRING_FORMAT_MEDIUM); + default: return showPlaceholder + ? DATE_STRING_FORMAT_LONG_PLACEHOLDER + : format(date, DATE_STRING_FORMAT_LONG); } };