Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/styling-pin-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: minor
---

Made pin events show a tally of the messages that are pinned.
5 changes: 5 additions & 0 deletions .changeset/styling-state-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: fix
---

Made events follow the colors of the name of the person initiating them
33 changes: 29 additions & 4 deletions src/app/components/message/Reply.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ type ReplyLayoutProps = {
userColor?: string;
username?: ReactNode;
icon?: IconSrc;
replyIcon?: JSX.Element;
};
export const ReplyLayout = as<'div', ReplyLayoutProps>(
({ username, userColor, icon, className, children, ...props }, ref) => (
({ username, userColor, icon, className, children, replyIcon, ...props }, ref) => (
<Box
className={classNames(css.Reply, className)}
alignItems="Center"
Expand All @@ -47,7 +48,7 @@ export const ReplyLayout = as<'div', ReplyLayoutProps>(
ref={ref}
>
<Box style={{ color: userColor }} alignItems="Center" shrink="No">
<Icon size="100" src={Icons.ReplyArrow} />
{replyIcon || <Icon size="100" src={Icons.ReplyArrow} />}
</Box>
{!!icon && <Icon style={{ opacity: 0.6 }} size="50" src={icon} />}
<Box style={{ color: userColor, maxWidth: toRem(200) }} alignItems="Center" shrink="No">
Expand Down Expand Up @@ -80,10 +81,11 @@ type ReplyProps = {
replyEventId: string;
threadRootId?: string;
onClick?: MouseEventHandler;
replyIcon?: JSX.Element;
};

export const Reply = as<'div', ReplyProps>(
({ room, timelineSet, replyEventId, threadRootId, onClick, ...props }, ref) => {
({ room, timelineSet, replyEventId, threadRootId, onClick, replyIcon, ...props }, ref) => {
const placeholderWidth = useMemo(() => randomNumberBetween(40, 400), []);
const getFromLocalTimeline = useCallback(
() => timelineSet?.findEventById(replyEventId),
Expand Down Expand Up @@ -161,7 +163,29 @@ export const Reply = as<'div', ReplyProps>(
const callJoined = replyEvent.getContent<SessionMembershipData>().application;
image = callJoined ? Icons.Phone : Icons.PhoneDown;
bodyJSX = callJoined ? ' joined the call' : ' ended the call';
} else if (Object.values(MessageEvent).every((v) => v !== eventType)) {
} else if (eventType === StateEvent.RoomPinnedEvents && replyEvent) {
const { pinned } = replyEvent.getContent();
const prevPinned = replyEvent.getPrevContent().pinned;
const pinsAdded =
prevPinned && pinned && pinned.filter((x: string) => !prevPinned.includes(x));
const pinsRemoved =
prevPinned && pinned && prevPinned.filter((x: string) => !pinned.includes(x));
image = Icons.Pin;
bodyJSX = (
<>
{(pinsAdded?.length > 0 &&
`pinned ${pinsAdded.length} message${pinsAdded.length > 1 ? 's' : ''}`) ||
''}
{(pinsAdded?.length > 0 && pinsRemoved?.length > 0 && `and`) || ''}
{(pinsRemoved?.length > 0 &&
`unpinned ${pinsRemoved.length} message${pinsRemoved.length > 1 ? 's' : ''}`) ||
''}
{(!pinsAdded || pinsAdded.length <= 0) &&
(!pinsRemoved || pinsRemoved.length <= 0) &&
`has not changed the pins`}
</>
);
} else if (Object.values(MessageEvent).every((v) => v !== eventType && !!eventType)) {
image = Icons.Code;
bodyJSX = (
<>
Expand All @@ -180,6 +204,7 @@ export const Reply = as<'div', ReplyProps>(
as="button"
userColor={usernameColor}
icon={image}
replyIcon={replyIcon}
username={
sender &&
eventType !== StateEvent.RoomMember && (
Expand Down
111 changes: 104 additions & 7 deletions src/app/hooks/timeline/useTimelineEventRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import { SessionMembershipData } from 'matrix-js-sdk/lib/matrixrtc/CallMembership';
import { HTMLReactParserOptions } from 'html-react-parser';
import { Opts as LinkifyOpts } from 'linkifyjs';
import { Box, Chip, Avatar, Text, Icons, config, toRem } from 'folds';
import { Box, Chip, Avatar, Text, Icons, config, toRem, Icon } from 'folds';
import { MessageLayout } from '$state/settings';
import { nicknamesAtom } from '$state/nicknames';
import { useGetMemberPowerTag } from '$hooks/useMemberPowerTag';
Expand Down Expand Up @@ -52,6 +52,18 @@ import {
Message,
Reactions,
} from '$features/room/message';
import { useSableCosmetics } from '$hooks/useSableCosmetics';

function DecoratedUser({ room, userId, userName }: DecoratedUserProps) {
const { color, font } = useSableCosmetics(userId, room ?? ({} as Room));
return <b style={{ color, font }}> {userName ?? userId} </b>;
}

type DecoratedUserProps = {
room: Room;
userId: string;
userName?: string;
};

type ThreadReplyChipProps = {
room: Room;
Expand Down Expand Up @@ -769,7 +781,6 @@ export function useTimelineEventRenderer({
const senderId = getSender.call(mEvent) ?? '';
const senderName =
getMemberDisplayName(room, senderId, nicknames) || getMxIdLocalPart(senderId);

const timeJSX = (
<Time
ts={getTs.call(mEvent)}
Expand Down Expand Up @@ -801,7 +812,7 @@ export function useTimelineEventRenderer({
content={
<Box grow="Yes" direction="Column">
<Text size="T300" priority="300">
<b>{senderName}</b>
<DecoratedUser userId={senderId} userName={senderName} room={room} />
{t('Organisms.RoomCommon.changed_room_name')}
</Text>
</Box>
Expand Down Expand Up @@ -848,7 +859,7 @@ export function useTimelineEventRenderer({
content={
<Box grow="Yes" direction="Column">
<Text size="T300" priority="300">
<b>{senderName}</b>
<DecoratedUser userId={senderId} userName={senderName} room={room} />
{' changed room topic'}
</Text>
</Box>
Expand Down Expand Up @@ -895,7 +906,7 @@ export function useTimelineEventRenderer({
content={
<Box grow="Yes" direction="Column">
<Text size="T300" priority="300">
<b>{senderName}</b>
<DecoratedUser userId={senderId} userName={senderName} room={room} />
{' changed room avatar'}
</Text>
</Box>
Expand Down Expand Up @@ -949,7 +960,7 @@ export function useTimelineEventRenderer({
content={
<Box grow="Yes" direction="Column">
<Text size="T300" priority="300">
<b>{senderName}</b>
<DecoratedUser userId={senderId} userName={senderName} room={room} />
{callJoined ? ' joined the call' : ' ended the call'}
</Text>
</Box>
Expand All @@ -958,6 +969,92 @@ export function useTimelineEventRenderer({
</Event>
);
},
[StateEvent.RoomPinnedEvents]: (mEventId, mEvent, item, timelineSet, collapse) => {
const { getSender, getTs, getContent, getPrevContent } = mEvent;
if (!showHiddenEvents) return null;
const highlighted = focusItem?.index === item && focusItem.highlight;
const senderId = getSender.call(mEvent) ?? '';
const senderName =
getMemberDisplayName(room, senderId, nicknames) || getMxIdLocalPart(senderId);

const { pinned } = getContent.call(mEvent);
const prevPinned = getPrevContent.call(mEvent).pinned;
const pinsAdded =
prevPinned && pinned && pinned.filter((x: string) => !prevPinned.includes(x));
const pinsRemoved =
prevPinned && pinned && prevPinned.filter((x: string) => !pinned.includes(x));

const timeJSX = (
<Time
ts={getTs.call(mEvent)}
compact={messageLayout === MessageLayout.Compact}
hour24Clock={hour24Clock}
dateFormatString={dateFormatString}
/>
);

return (
<Event
key={mEventId}
data-message-item={item}
data-message-id={mEventId}
room={room}
mEvent={mEvent}
highlight={highlighted}
collapse={collapse}
canDelete={canRedact || senderId === mx.getUserId()}
onReplyClick={onReplyClick}
hideReadReceipts={hideReads}
showDeveloperTools={showDeveloperTools}
messageSpacing={messageSpacing}
>
<EventContent
messageLayout={messageLayout}
time={timeJSX}
iconSrc={Icons.Pin}
content={
<Box grow="Yes" direction="Column">
<Text size="T300" priority="300">
<DecoratedUser userId={senderId} userName={senderName} room={room} />
{(pinsAdded?.length > 0 &&
`pinned ${pinsAdded.length} message${pinsAdded.length > 1 ? 's' : ''}`) ||
''}
{(pinsAdded?.length > 0 && pinsRemoved?.length > 0 && ` and`) || ''}
{(pinsRemoved?.length > 0 &&
`unpinned ${pinsRemoved.length} message${pinsRemoved.length > 1 ? 's' : ''}`) ||
''}
{((!pinsAdded || pinsAdded.length <= 0) &&
(!pinsRemoved || pinsRemoved.length <= 0) &&
`has not changed the pins`) ||
`:`}
</Text>
{(pinsAdded || pinsRemoved) &&
pinsAdded
.concat(pinsRemoved)
.slice(0, 4)
.map((x: string) => (
<Reply
style={{ opacity: '80%' }}
room={room}
replyEventId={x ?? ''}
onClick={handleOpenReply}
replyIcon={
<>
<Icon size="100" src={Icons.Pin} />
<Icon
size="100"
src={pinned.includes(x) ? Icons.Plus : Icons.Minus}
/>
</>
}
/>
))}
</Box>
}
/>
</Event>
);
},
},
(mEventId, mEvent, item, timelineSet, collapse) => {
const { getSender, getTs, getType } = mEvent;
Expand Down Expand Up @@ -998,7 +1095,7 @@ export function useTimelineEventRenderer({
content={
<Box grow="Yes" direction="Column">
<Text size="T300" priority="300">
<b>{senderName}</b>
<DecoratedUser userId={senderId} userName={senderName} room={room} />
{' sent '}
<code className={customHtmlCss.Code}>{getType.call(mEvent)}</code>
{' state event'}
Expand Down
Loading
Loading