2026-09-18 21:07:33 -04:00
|
|
|
import React, { MouseEventHandler } from 'react';
|
|
|
|
|
import { Box, Icon, Icons, Text, as, toRem } from 'folds';
|
|
|
|
|
import { MatrixClient } from 'matrix-js-sdk';
|
|
|
|
|
import classNames from 'classnames';
|
|
|
|
|
import * as css from './Reply.css';
|
|
|
|
|
import { ForwardedMeta } from '../../features/room/message/forwardContent';
|
|
|
|
|
import { getMemberDisplayName } from '../../utils/room';
|
|
|
|
|
import { getMxIdLocalPart } from '../../utils/matrix';
|
2026-09-20 00:28:47 -04:00
|
|
|
import { formatTimestamp } from '../../utils/formatTimestamp';
|
2026-09-18 21:07:33 -04:00
|
|
|
|
|
|
|
|
type ForwardedHeaderProps = {
|
|
|
|
|
mx: MatrixClient;
|
|
|
|
|
meta: ForwardedMeta;
|
|
|
|
|
hour24Clock: boolean;
|
|
|
|
|
dateFormatString: string;
|
|
|
|
|
/** Present when the viewer can open the original (they are in the source room). */
|
|
|
|
|
onJump?: MouseEventHandler;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* "↪ Forwarded · from <sender> in <room> · <time>" — the provenance line above
|
|
|
|
|
* a forwarded message (Gitea: forwards used to look like the forwarder's own
|
|
|
|
|
* words). Renders in the same visual slot and style as a reply quote so it
|
|
|
|
|
* reads as message context, not as content.
|
|
|
|
|
*/
|
|
|
|
|
export const ForwardedHeader = as<'div', ForwardedHeaderProps>(
|
|
|
|
|
({ mx, meta, hour24Clock, dateFormatString, onJump, className, ...props }, ref) => {
|
|
|
|
|
const sourceRoom = meta.room_id ? mx.getRoom(meta.room_id) : null;
|
|
|
|
|
const senderName =
|
|
|
|
|
(sourceRoom && getMemberDisplayName(sourceRoom, meta.sender)) ??
|
|
|
|
|
mx.getUser(meta.sender)?.displayName ??
|
|
|
|
|
getMxIdLocalPart(meta.sender) ??
|
|
|
|
|
meta.sender;
|
|
|
|
|
const ts = meta.origin_server_ts;
|
2026-09-20 00:28:47 -04:00
|
|
|
const when = formatTimestamp(ts, { hour24Clock, dateFormatString });
|
2026-09-18 21:07:33 -04:00
|
|
|
const canJump = !!sourceRoom && !!onJump;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Box
|
|
|
|
|
as={canJump ? 'button' : 'div'}
|
|
|
|
|
className={classNames(css.Reply, className)}
|
|
|
|
|
alignItems="Center"
|
|
|
|
|
gap="100"
|
|
|
|
|
onClick={canJump ? onJump : undefined}
|
|
|
|
|
title={canJump ? 'Jump to the original message' : undefined}
|
|
|
|
|
aria-label={`Forwarded from ${senderName}${sourceRoom ? ` in ${sourceRoom.name}` : ''}, ${when}`}
|
|
|
|
|
{...props}
|
|
|
|
|
ref={ref}
|
|
|
|
|
>
|
|
|
|
|
<Box alignItems="Center" gap="100" shrink="No" style={{ maxWidth: toRem(420) }}>
|
|
|
|
|
<Icon size="100" src={Icons.ArrowGoRight} />
|
|
|
|
|
<Text size="T300" priority="300" truncate>
|
|
|
|
|
Forwarded from <b>{senderName}</b>
|
|
|
|
|
{sourceRoom ? (
|
|
|
|
|
<>
|
|
|
|
|
{' in '}
|
|
|
|
|
<b>{sourceRoom.name}</b>
|
|
|
|
|
</>
|
|
|
|
|
) : null}
|
|
|
|
|
{' · '}
|
|
|
|
|
{when}
|
|
|
|
|
</Text>
|
|
|
|
|
</Box>
|
|
|
|
|
</Box>
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|