Skip to content

Commit

Permalink
Use Intl.DateTimeFormat for datetime formatting
Browse files Browse the repository at this point in the history
Also makes 12/24 clock style configurable
  • Loading branch information
greentore committed Aug 3, 2024
1 parent 3b5a66d commit 9e25d8c
Show file tree
Hide file tree
Showing 14 changed files with 189 additions and 77 deletions.
15 changes: 0 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@
"blurhash": "2.0.4",
"browser-encrypt-attachment": "0.3.0",
"classnames": "2.3.2",
"dateformat": "5.0.3",
"dayjs": "1.11.10",
"domhandler": "5.0.3",
"emojibase": "6.1.0",
"emojibase-data": "7.0.1",
Expand Down
29 changes: 19 additions & 10 deletions src/app/components/message/Time.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
import React, { ComponentProps } from 'react';
import { Text, as } from 'folds';
import { timeDayMonYear, timeHourMinute, today, yesterday } from '../../utils/time';
import { DateTime } from '../../utils/time';

export type TimeProps = {
compact?: boolean;
ts: number;
dateTime: DateTime;
};

export const Time = as<'span', TimeProps & ComponentProps<typeof Text>>(
({ compact, ts, ...props }, ref) => {
({ compact, ts, dateTime, ...props }, ref) => {
const date = new Date(ts);
const { isToday, isYesterday, relativeTerm } = dateTime.relative(date);
let time = '';
if (compact) {
time = timeHourMinute(ts);
} else if (today(ts)) {
time = timeHourMinute(ts);
} else if (yesterday(ts)) {
time = `Yesterday ${timeHourMinute(ts)}`;
if (compact || isToday) {
time = dateTime.time(date);
} else if (isYesterday) {
time = `${relativeTerm}, ${dateTime.time(date)}`;
} else {
time = `${timeDayMonYear(ts)} ${timeHourMinute(ts)}`;
time = `${dateTime.dateTime(date)}`;
}

return (
<Text as="time" style={{ flexShrink: 0 }} size="T200" priority="300" {...props} ref={ref}>
<Text
as="time"
style={{ flexShrink: 0 }}
size="T200"
priority="300"
title={dateTime.full(date)}
{...props}
ref={ref}
>
{time}
</Text>
);
Expand Down
7 changes: 4 additions & 3 deletions src/app/components/room-intro/RoomIntro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getMemberDisplayName, getStateEvent } from '../../utils/room';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { getMxIdLocalPart } from '../../utils/matrix';
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
import { timeDayMonthYear, timeHourMinute } from '../../utils/time';
import { DateTime } from '../../utils/time';
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
import { RoomAvatar } from '../room-avatar';
import { nameInitials } from '../../utils/common';
Expand All @@ -17,9 +17,10 @@ import { mDirectAtom } from '../../state/mDirectList';

export type RoomIntroProps = {
room: Room;
dateTime: DateTime;
};

export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) => {
export const RoomIntro = as<'div', RoomIntroProps>(({ room, dateTime, ...props }, ref) => {
const mx = useMatrixClient();
const { navigateRoom } = useRoomNavigate();
const mDirects = useAtomValue(mDirectAtom);
Expand Down Expand Up @@ -65,7 +66,7 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) =>
<Text size="T200" priority="300">
{'Created by '}
<b>@{creatorName}</b>
{` on ${timeDayMonthYear(ts)} ${timeHourMinute(ts)}`}
{` on ${dateTime.full(ts)}`}
</Text>
)}
</Box>
Expand Down
3 changes: 3 additions & 0 deletions src/app/features/message-search/MessageSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { SearchResultGroup } from './SearchResultGroup';
import { SearchInput } from './SearchInput';
import { SearchFilters } from './SearchFilters';
import { VirtualTile } from '../../components/virtualizer';
import { useDateTime } from '../../utils/time';

const useSearchPathSearchParams = (searchParams: URLSearchParams): _SearchPathSearchParams =>
useMemo(
Expand Down Expand Up @@ -53,6 +54,7 @@ export function MessageSearch({
const mx = useMatrixClient();
const mDirects = useAtomValue(mDirectAtom);
const allRooms = useRooms(mx, allRoomsAtom, mDirects);
const dateTime = useDateTime();
const [mediaAutoLoad] = useSetting(settingsAtom, 'mediaAutoLoad');
const [urlPreview] = useSetting(settingsAtom, 'urlPreview');
const searchInputRef = useRef<HTMLInputElement>(null);
Expand Down Expand Up @@ -294,6 +296,7 @@ export function MessageSearch({
room={groupRoom}
highlights={highlights}
items={group.items}
dateTime={dateTime}
mediaAutoLoad={mediaAutoLoad}
urlPreview={urlPreview}
onOpen={navigateRoom}
Expand Down
5 changes: 4 additions & 1 deletion src/app/features/message-search/SearchResultGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ import { ResultItem } from './useMessageSearch';
import { SequenceCard } from '../../components/sequence-card';
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
import { UserAvatar } from '../../components/user-avatar';
import { DateTime } from '../../utils/time';

type SearchResultGroupProps = {
room: Room;
highlights: string[];
items: ResultItem[];
dateTime: DateTime;
mediaAutoLoad?: boolean;
urlPreview?: boolean;
onOpen: (roomId: string, eventId: string) => void;
Expand All @@ -46,6 +48,7 @@ export function SearchResultGroup({
room,
highlights,
items,
dateTime,
mediaAutoLoad,
urlPreview,
onOpen,
Expand Down Expand Up @@ -228,7 +231,7 @@ export function SearchResultGroup({
<b>{displayName}</b>
</Text>
</Username>
<Time ts={event.origin_server_ts} />
<Time ts={event.origin_server_ts} dateTime={dateTime} />
</Box>
<Box shrink="No" gap="200" alignItems="Center">
<Chip
Expand Down
42 changes: 29 additions & 13 deletions src/app/features/room/RoomTimeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ import { markAsRead } from '../../../client/action/notifications';
import { useDebounce } from '../../hooks/useDebounce';
import { getResizeObserverEntry, useResizeObserver } from '../../hooks/useResizeObserver';
import * as css from './RoomTimeline.css';
import { inSameDay, minuteDifference, timeDayMonthYear, today, yesterday } from '../../utils/time';
import { isSameDay, minuteDifference, useDateTime } from '../../utils/time';
import { createMentionElement, isEmptyEditor, moveCursor } from '../../components/editor';
import { roomIdToReplyDraftAtomFamily } from '../../state/room/roomInputDrafts';
import { usePowerLevelsAPI, usePowerLevelsContext } from '../../hooks/usePowerLevels';
Expand Down Expand Up @@ -448,6 +448,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const { navigateRoom, navigateSpace } = useRoomNavigate();
const roomToParents = useAtomValue(roomToParentsAtom);
const unread = useRoomUnread(room.roomId, roomToUnreadAtom);
const dateTime = useDateTime();

const imagePackRooms: Room[] = useMemo(() => {
const allParentSpaces = [room.roomId].concat(
Expand Down Expand Up @@ -984,6 +985,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
data-message-id={mEventId}
room={room}
mEvent={mEvent}
dateTime={dateTime}
messageSpacing={messageSpacing}
messageLayout={messageLayout}
collapse={collapse}
Expand Down Expand Up @@ -1056,6 +1058,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
data-message-id={mEventId}
room={room}
mEvent={mEvent}
dateTime={dateTime}
messageSpacing={messageSpacing}
messageLayout={messageLayout}
collapse={collapse}
Expand Down Expand Up @@ -1165,6 +1168,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
data-message-id={mEventId}
room={room}
mEvent={mEvent}
dateTime={dateTime}
messageSpacing={messageSpacing}
messageLayout={messageLayout}
collapse={collapse}
Expand Down Expand Up @@ -1216,7 +1220,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const highlighted = focusItem?.index === item && focusItem.highlight;
const parsed = parseMemberEvent(mEvent);

const timeJSX = <Time ts={mEvent.getTs()} compact={messageLayout === 1} />;
const timeJSX = (
<Time ts={mEvent.getTs()} compact={messageLayout === 1} dateTime={dateTime} />
);

return (
<Event
Expand Down Expand Up @@ -1249,7 +1255,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const senderId = mEvent.getSender() ?? '';
const senderName = getMemberDisplayName(room, senderId) || getMxIdLocalPart(senderId);

const timeJSX = <Time ts={mEvent.getTs()} compact={messageLayout === 1} />;
const timeJSX = (
<Time ts={mEvent.getTs()} compact={messageLayout === 1} dateTime={dateTime} />
);

return (
<Event
Expand Down Expand Up @@ -1283,7 +1291,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const senderId = mEvent.getSender() ?? '';
const senderName = getMemberDisplayName(room, senderId) || getMxIdLocalPart(senderId);

const timeJSX = <Time ts={mEvent.getTs()} compact={messageLayout === 1} />;
const timeJSX = (
<Time ts={mEvent.getTs()} compact={messageLayout === 1} dateTime={dateTime} />
);

return (
<Event
Expand Down Expand Up @@ -1317,7 +1327,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const senderId = mEvent.getSender() ?? '';
const senderName = getMemberDisplayName(room, senderId) || getMxIdLocalPart(senderId);

const timeJSX = <Time ts={mEvent.getTs()} compact={messageLayout === 1} />;
const timeJSX = (
<Time ts={mEvent.getTs()} compact={messageLayout === 1} dateTime={dateTime} />
);

return (
<Event
Expand Down Expand Up @@ -1353,7 +1365,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const senderId = mEvent.getSender() ?? '';
const senderName = getMemberDisplayName(room, senderId) || getMxIdLocalPart(senderId);

const timeJSX = <Time ts={mEvent.getTs()} compact={messageLayout === 1} />;
const timeJSX = (
<Time ts={mEvent.getTs()} compact={messageLayout === 1} dateTime={dateTime} />
);

return (
<Event
Expand Down Expand Up @@ -1394,7 +1408,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const senderId = mEvent.getSender() ?? '';
const senderName = getMemberDisplayName(room, senderId) || getMxIdLocalPart(senderId);

const timeJSX = <Time ts={mEvent.getTs()} compact={messageLayout === 1} />;
const timeJSX = (
<Time ts={mEvent.getTs()} compact={messageLayout === 1} dateTime={dateTime} />
);

return (
<Event
Expand Down Expand Up @@ -1444,7 +1460,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
newDivider = prevEvent?.getId() === readUptoEventIdRef.current;
}
if (!dayDivider) {
dayDivider = prevEvent ? !inSameDay(prevEvent.getTs(), mEvent.getTs()) : false;
dayDivider = prevEvent ? !isSameDay(prevEvent.getDate()!, mEvent.getDate()!) : false;
}

const collapsed =
Expand All @@ -1454,7 +1470,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
prevEvent !== undefined &&
prevEvent.getSender() === mEvent.getSender() &&
prevEvent.getType() === mEvent.getType() &&
minuteDifference(prevEvent.getTs(), mEvent.getTs()) < 2;
minuteDifference(prevEvent.getDate()!, mEvent.getDate()!) < 2;

const eventJSX = reactionOrEditEvent(mEvent)
? null
Expand Down Expand Up @@ -1488,9 +1504,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
<Badge as="span" size="500" variant="Secondary" fill="None" radii="300">
<Text size="L400">
{(() => {
if (today(mEvent.getTs())) return 'Today';
if (yesterday(mEvent.getTs())) return 'Yesterday';
return timeDayMonthYear(mEvent.getTs());
const date = mEvent.getDate()!;
const { relativeTerm } = dateTime.relative(date);
return relativeTerm || dateTime.date(date);
})()}
</Text>
</Badge>
Expand Down Expand Up @@ -1553,7 +1569,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
}`,
}}
>
<RoomIntro room={room} />
<RoomIntro room={room} dateTime={dateTime} />
</div>
)}
{(canPaginateBack || !rangeAtStart) &&
Expand Down
5 changes: 4 additions & 1 deletion src/app/features/room/message/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import {
import { copyToClipboard } from '../../../utils/dom';
import { useClientConfig } from '../../../hooks/useClientConfig';
import { stopPropagation } from '../../../utils/keyboard';
import { DateTime } from '../../../utils/time';

export type ReactionHandler = (keyOrMxc: string, shortcode: string) => void;

Expand Down Expand Up @@ -630,6 +631,7 @@ export type MessageProps = {
canSendReaction?: boolean;
imagePackRooms?: Room[];
relations?: Relations;
dateTime: DateTime;
messageLayout: MessageLayout;
messageSpacing: MessageSpacing;
onUserClick: MouseEventHandler<HTMLButtonElement>;
Expand All @@ -653,6 +655,7 @@ export const Message = as<'div', MessageProps>(
canSendReaction,
imagePackRooms,
relations,
dateTime,
messageLayout,
messageSpacing,
onUserClick,
Expand Down Expand Up @@ -709,7 +712,7 @@ export const Message = as<'div', MessageProps>(
</Text>
</>
)}
<Time ts={mEvent.getTs()} compact={messageLayout === 1} />
<Time ts={mEvent.getTs()} compact={messageLayout === 1} dateTime={dateTime} />
</Box>
</Box>
);
Expand Down
7 changes: 4 additions & 3 deletions src/app/organisms/settings/DeviceManage.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import './DeviceManage.scss';
import dateFormat from 'dateformat';
import { useDateTime } from '../../utils/time';

import { isCrossVerified } from '../../../util/matrixUtil';
import { openReusableDialog, openEmojiVerification } from '../../../client/action/navigation';
Expand Down Expand Up @@ -71,6 +71,7 @@ function DeviceManage() {
const mountStore = useStore();
mountStore.setItem(true);
const isMeVerified = isCrossVerified(mx, mx.deviceId);
const dateTime = useDateTime();

useEffect(() => {
setProcessing([]);
Expand Down Expand Up @@ -184,9 +185,9 @@ function DeviceManage() {
<Text variant="b3">
Last activity
<span style={{ color: 'var(--tc-surface-normal)' }}>
{dateFormat(new Date(lastTS), ' hh:MM TT, dd/mm/yyyy')}
{` ${ dateTime.full(new Date(lastTS))}`}
</span>
{lastIP ? ` at ${lastIP}` : ''}
{lastIP ? ` from ${lastIP}` : ''}
</Text>
)}
{isCurrentDevice && (
Expand Down
6 changes: 6 additions & 0 deletions src/app/organisms/settings/Settings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ function AppearanceSection() {
const [urlPreview, setUrlPreview] = useSetting(settingsAtom, 'urlPreview');
const [encUrlPreview, setEncUrlPreview] = useSetting(settingsAtom, 'encUrlPreview');
const [showHiddenEvents, setShowHiddenEvents] = useSetting(settingsAtom, 'showHiddenEvents');
const [hour12, setHour12] = useSetting(settingsAtom, 'hour12');
const spacings = ['0', '100', '200', '300', '400', '500'];

const [currentZoom, setCurrentZoom] = useState(`${pageZoom}`);
Expand Down Expand Up @@ -266,6 +267,11 @@ function AppearanceSection() {
}
content={<Text variant="b3">Show hidden state and message events.</Text>}
/>
<SettingTile
title="12-hour time"
options={<Toggle isActive={hour12} onToggle={() => setHour12(!hour12)} />}
content={<Text variant="b3">Show timestamps in 12-hour format.</Text>}
/>
</div>
</div>
);
Expand Down
Loading

0 comments on commit 9e25d8c

Please sign in to comment.