Add placeholder client logic to date primitive
This commit is contained in:
parent
0b63cf76e7
commit
3d69e2d20c
@ -1,40 +1,66 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
import { formatDate } from '@/utility/date';
|
import { formatDate } from '@/utility/date';
|
||||||
import { clsx } from 'clsx/lite';
|
import { clsx } from 'clsx/lite';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
export default function ResponsiveDate({
|
export default function ResponsiveDate({
|
||||||
date,
|
date,
|
||||||
className,
|
className,
|
||||||
titleLabel,
|
titleLabel,
|
||||||
|
timezone: timezoneFromProps,
|
||||||
}: {
|
}: {
|
||||||
date: Date
|
date: Date
|
||||||
className?: string
|
className?: string
|
||||||
titleLabel?: 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
|
const title = titleLabel
|
||||||
? `${titleLabel}: ${formatDate(date).toLocaleUpperCase()}`
|
? `${titleLabel}: ${titleDateFormatted}`
|
||||||
: formatDate(date).toLocaleUpperCase();
|
: titleDateFormatted;
|
||||||
|
|
||||||
|
const contentClass = showPlaceholderContent && 'opacity-0 select-none';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
title={title}
|
title={showPlaceholderContent ? 'LOADING LOCAL TIME' : title}
|
||||||
className={clsx(className, 'uppercase')}
|
className={clsx(
|
||||||
|
'uppercase rounded-md transition-colors',
|
||||||
|
showPlaceholderContent && 'bg-dim',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{/* Small */}
|
{/* Small */}
|
||||||
<span
|
<span
|
||||||
className="xs:hidden"
|
className={clsx('xs:hidden', contentClass)}
|
||||||
aria-hidden
|
aria-hidden
|
||||||
>
|
>
|
||||||
{formatDate(date, 'short')}
|
{formatDate(date, 'short', showPlaceholderContent)}
|
||||||
</span>
|
</span>
|
||||||
{/* Medium */}
|
{/* Medium */}
|
||||||
<span
|
<span
|
||||||
className="hidden xs:inline-block sm:hidden"
|
className={clsx('hidden xs:inline-block sm:hidden', contentClass)}
|
||||||
aria-hidden
|
aria-hidden
|
||||||
>
|
>
|
||||||
{formatDate(date, 'medium')}
|
{formatDate(date, 'medium', showPlaceholderContent)}
|
||||||
</span>
|
</span>
|
||||||
{/* Large */}
|
{/* Large */}
|
||||||
<span className="hidden sm:inline-block">
|
<span
|
||||||
{formatDate(date)}
|
className={clsx('hidden sm:inline-block', contentClass)}
|
||||||
|
>
|
||||||
|
{formatDate(date, undefined, showPlaceholderContent)}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,6 +10,7 @@ export default function PhotoDate({
|
|||||||
photo: Photo
|
photo: Photo
|
||||||
className?: string
|
className?: string
|
||||||
dateType?: 'takenAt' | 'createdAt' | 'updatedAt'
|
dateType?: 'takenAt' | 'createdAt' | 'updatedAt'
|
||||||
|
timezone?: string | null
|
||||||
}) {
|
}) {
|
||||||
const date = useMemo(() => {
|
const date = useMemo(() => {
|
||||||
const date = new Date(dateType === 'takenAt'
|
const date = new Date(dateType === 'takenAt'
|
||||||
@ -41,6 +42,7 @@ export default function PhotoDate({
|
|||||||
date,
|
date,
|
||||||
className,
|
className,
|
||||||
titleLabel: getTitleLabel(),
|
titleLabel: getTitleLabel(),
|
||||||
|
timezone: null,
|
||||||
}} />
|
}} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -164,6 +164,10 @@
|
|||||||
@apply
|
@apply
|
||||||
bg-white dark:bg-black
|
bg-white dark:bg-black
|
||||||
}
|
}
|
||||||
|
.bg-dim {
|
||||||
|
@apply
|
||||||
|
bg-gray-100 dark:bg-gray-900/75
|
||||||
|
}
|
||||||
.bg-content {
|
.bg-content {
|
||||||
@apply
|
@apply
|
||||||
bg-white border-gray-200
|
bg-white border-gray-200
|
||||||
|
|||||||
@ -1,25 +1,41 @@
|
|||||||
import { format, parseISO, parse } from 'date-fns';
|
import { format, parseISO, parse } from 'date-fns';
|
||||||
|
|
||||||
const DATE_STRING_FORMAT_TINY = 'dd MMM yy';
|
const DATE_STRING_FORMAT_TINY = 'dd MMM yy';
|
||||||
const DATE_STRING_FORMAT_SHORT = 'dd MMM yyyy';
|
const DATE_STRING_FORMAT_TINY_PLACEHOLDER = '00 000 00';
|
||||||
const DATE_STRING_FORMAT_MEDIUM = 'dd MMM yy h:mma';
|
|
||||||
const DATE_STRING_FORMAT = 'dd MMM yyyy h:mma';
|
const DATE_STRING_FORMAT_SHORT = 'dd MMM yyyy';
|
||||||
const DATE_STRING_FORMAT_POSTGRES = 'yyyy-MM-dd HH:mm:ss';
|
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 AmbiguousTimestamp = number | string;
|
||||||
|
|
||||||
type Length = 'tiny' | 'short' | 'medium' | 'long';
|
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) {
|
switch (length) {
|
||||||
case 'tiny':
|
case 'tiny': return showPlaceholder
|
||||||
return format(date, DATE_STRING_FORMAT_TINY);
|
? DATE_STRING_FORMAT_TINY_PLACEHOLDER
|
||||||
case 'short':
|
: format(date, DATE_STRING_FORMAT_TINY);
|
||||||
return format(date, DATE_STRING_FORMAT_SHORT);
|
case 'short': return showPlaceholder
|
||||||
case 'medium':
|
? DATE_STRING_FORMAT_SHORT_PLACEHOLDER
|
||||||
return format(date, DATE_STRING_FORMAT_MEDIUM);
|
: format(date, DATE_STRING_FORMAT_SHORT);
|
||||||
default:
|
case 'medium': return showPlaceholder
|
||||||
return format(date, DATE_STRING_FORMAT);
|
? 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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user