Show full timestamp on hover (#714)

* Show full timestamp on hover

* Not always display time

* Always show full timestamp in search
This commit is contained in:
ginnyTheCat 2022-08-06 06:05:56 +02:00 committed by GitHub
parent 04f910ee03
commit 21726b63f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 17 deletions

View file

@ -0,0 +1,44 @@
import React from 'react';
import PropTypes from 'prop-types';
import dateFormat from 'dateformat';
import { isInSameDay } from '../../../util/common';
function Time({ timestamp, fullTime }) {
const date = new Date(timestamp);
const formattedFullTime = dateFormat(date, 'dd mmmm yyyy, hh:MM TT');
let formattedDate = formattedFullTime;
if (!fullTime) {
const compareDate = new Date();
const isToday = isInSameDay(date, compareDate);
compareDate.setDate(compareDate.getDate() - 1);
const isYesterday = isInSameDay(date, compareDate);
formattedDate = dateFormat(date, isToday || isYesterday ? 'hh:MM TT' : 'dd/mm/yyyy');
if (isYesterday) {
formattedDate = `Yesterday, ${formattedDate}`;
}
}
return (
<time
dateTime={date.toISOString()}
title={formattedFullTime}
>
{formattedDate}
</time>
);
}
Time.defaultProps = {
fullTime: false,
};
Time.propTypes = {
timestamp: PropTypes.number.isRequired,
fullTime: PropTypes.bool,
};
export default Time;

View file

@ -24,6 +24,7 @@ import Tooltip from '../../atoms/tooltip/Tooltip';
import Input from '../../atoms/input/Input'; import Input from '../../atoms/input/Input';
import Avatar from '../../atoms/avatar/Avatar'; import Avatar from '../../atoms/avatar/Avatar';
import IconButton from '../../atoms/button/IconButton'; import IconButton from '../../atoms/button/IconButton';
import Time from '../../atoms/time/Time';
import ContextMenu, { MenuHeader, MenuItem, MenuBorder } from '../../atoms/context-menu/ContextMenu'; import ContextMenu, { MenuHeader, MenuItem, MenuBorder } from '../../atoms/context-menu/ContextMenu';
import * as Media from '../media/Media'; import * as Media from '../media/Media';
@ -67,7 +68,7 @@ const MessageAvatar = React.memo(({
)); ));
const MessageHeader = React.memo(({ const MessageHeader = React.memo(({
userId, username, time, userId, username, timestamp, fullTime,
}) => ( }) => (
<div className="message__header"> <div className="message__header">
<Text <Text
@ -81,14 +82,20 @@ const MessageHeader = React.memo(({
<span>{twemojify(userId)}</span> <span>{twemojify(userId)}</span>
</Text> </Text>
<div className="message__time"> <div className="message__time">
<Text variant="b3">{time}</Text> <Text variant="b3">
<Time timestamp={timestamp} fullTime={fullTime} />
</Text>
</div> </div>
</div> </div>
)); ));
MessageHeader.defaultProps = {
fullTime: false,
};
MessageHeader.propTypes = { MessageHeader.propTypes = {
userId: PropTypes.string.isRequired, userId: PropTypes.string.isRequired,
username: PropTypes.string.isRequired, username: PropTypes.string.isRequired,
time: PropTypes.string.isRequired, timestamp: PropTypes.number.isRequired,
fullTime: PropTypes.bool,
}; };
function MessageReply({ name, color, body }) { function MessageReply({ name, color, body }) {
@ -690,7 +697,7 @@ function getEditedBody(editedMEvent) {
} }
function Message({ function Message({
mEvent, isBodyOnly, roomTimeline, focus, time, mEvent, isBodyOnly, roomTimeline, focus, fullTime,
}) { }) {
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const roomId = mEvent.getRoomId(); const roomId = mEvent.getRoomId();
@ -751,7 +758,12 @@ function Message({
} }
<div className="message__main-container"> <div className="message__main-container">
{!isBodyOnly && ( {!isBodyOnly && (
<MessageHeader userId={senderId} username={username} time={time} /> <MessageHeader
userId={senderId}
username={username}
timestamp={mEvent.getTs()}
fullTime={fullTime}
/>
)} )}
{roomTimeline && isReply && ( {roomTimeline && isReply && (
<MessageReplyWrapper <MessageReplyWrapper
@ -799,13 +811,14 @@ Message.defaultProps = {
isBodyOnly: false, isBodyOnly: false,
focus: false, focus: false,
roomTimeline: null, roomTimeline: null,
fullTime: false,
}; };
Message.propTypes = { Message.propTypes = {
mEvent: PropTypes.shape({}).isRequired, mEvent: PropTypes.shape({}).isRequired,
isBodyOnly: PropTypes.bool, isBodyOnly: PropTypes.bool,
roomTimeline: PropTypes.shape({}), roomTimeline: PropTypes.shape({}),
focus: PropTypes.bool, focus: PropTypes.bool,
time: PropTypes.string.isRequired, fullTime: PropTypes.bool,
}; };
export { Message, MessageReply, PlaceholderMessage }; export { Message, MessageReply, PlaceholderMessage };

View file

@ -4,6 +4,7 @@ import './TimelineChange.scss';
import Text from '../../atoms/text/Text'; import Text from '../../atoms/text/Text';
import RawIcon from '../../atoms/system-icons/RawIcon'; import RawIcon from '../../atoms/system-icons/RawIcon';
import Time from '../../atoms/time/Time';
import JoinArraowIC from '../../../../public/res/ic/outlined/join-arrow.svg'; import JoinArraowIC from '../../../../public/res/ic/outlined/join-arrow.svg';
import LeaveArraowIC from '../../../../public/res/ic/outlined/leave-arrow.svg'; import LeaveArraowIC from '../../../../public/res/ic/outlined/leave-arrow.svg';
@ -12,7 +13,7 @@ import InviteCancelArraowIC from '../../../../public/res/ic/outlined/invite-canc
import UserIC from '../../../../public/res/ic/outlined/user.svg'; import UserIC from '../../../../public/res/ic/outlined/user.svg';
function TimelineChange({ function TimelineChange({
variant, content, time, onClick, variant, content, timestamp, onClick,
}) { }) {
let iconSrc; let iconSrc;
@ -48,7 +49,9 @@ function TimelineChange({
</Text> </Text>
</div> </div>
<div className="timeline-change__time"> <div className="timeline-change__time">
<Text variant="b3">{time}</Text> <Text variant="b3">
<Time timestamp={timestamp} />
</Text>
</div> </div>
</button> </button>
); );
@ -68,7 +71,7 @@ TimelineChange.propTypes = {
PropTypes.string, PropTypes.string,
PropTypes.node, PropTypes.node,
]).isRequired, ]).isRequired,
time: PropTypes.string.isRequired, timestamp: PropTypes.number.isRequired,
onClick: PropTypes.func, onClick: PropTypes.func,
}; };

View file

@ -120,14 +120,13 @@ function RoomSearch({ roomId }) {
const renderTimeline = (timeline) => ( const renderTimeline = (timeline) => (
<div className="room-search__result-item" key={timeline[0].getId()}> <div className="room-search__result-item" key={timeline[0].getId()}>
{ timeline.map((mEvent) => { { timeline.map((mEvent) => {
const time = dateFormat(mEvent.getDate(), 'dd/mm/yyyy - hh:MM TT');
const id = mEvent.getId(); const id = mEvent.getId();
return ( return (
<React.Fragment key={id}> <React.Fragment key={id}>
<Message <Message
mEvent={mEvent} mEvent={mEvent}
isBodyOnly={false} isBodyOnly={false}
time={time} fullTime
/> />
<Button onClick={() => selectRoom(roomId, id)}>View</Button> <Button onClick={() => selectRoom(roomId, id)}>View</Button>
</React.Fragment> </React.Fragment>

View file

@ -125,10 +125,7 @@ function renderEvent(roomTimeline, mEvent, prevMEvent, isFocus = false) {
&& prevMEvent.getType() !== 'm.room.create' && prevMEvent.getType() !== 'm.room.create'
&& diffMinutes(mEvent.getDate(), prevMEvent.getDate()) <= MAX_MSG_DIFF_MINUTES && diffMinutes(mEvent.getDate(), prevMEvent.getDate()) <= MAX_MSG_DIFF_MINUTES
); );
const mDate = mEvent.getDate(); const timestamp = mEvent.getTs();
const isToday = isInSameDay(mDate, new Date());
const time = dateFormat(mDate, isToday ? 'hh:MM TT' : 'dd/mm/yyyy');
if (mEvent.getType() === 'm.room.member') { if (mEvent.getType() === 'm.room.member') {
const timelineChange = parseTimelineChange(mEvent); const timelineChange = parseTimelineChange(mEvent);
@ -138,7 +135,7 @@ function renderEvent(roomTimeline, mEvent, prevMEvent, isFocus = false) {
key={mEvent.getId()} key={mEvent.getId()}
variant={timelineChange.variant} variant={timelineChange.variant}
content={timelineChange.content} content={timelineChange.content}
time={time} timestamp={timestamp}
/> />
); );
} }
@ -149,7 +146,7 @@ function renderEvent(roomTimeline, mEvent, prevMEvent, isFocus = false) {
isBodyOnly={isBodyOnly} isBodyOnly={isBodyOnly}
roomTimeline={roomTimeline} roomTimeline={roomTimeline}
focus={isFocus} focus={isFocus}
time={time} fullTime={false}
/> />
); );
} }