mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-09-13 22:32:26 +03:00
Show pin/unpin events in the timeline
This commit is contained in:
parent
7f40605bfe
commit
4180e79794
5 changed files with 125 additions and 0 deletions
8
src/app/components/message/MessageJumpLink.css.ts
Normal file
8
src/app/components/message/MessageJumpLink.css.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
|
export const messageJumpLink = style({
|
||||||
|
':hover': {
|
||||||
|
cursor: 'pointer',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
},
|
||||||
|
});
|
13
src/app/components/message/MessageJumpLink.tsx
Normal file
13
src/app/components/message/MessageJumpLink.tsx
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import React from "react";
|
||||||
|
import { messageJumpLink } from "./MessageJumpLink.css";
|
||||||
|
import { useRoomNavigate } from "../../hooks/useRoomNavigate";
|
||||||
|
|
||||||
|
export function MessageJumpLink({ roomId, eventId }: { roomId: string, eventId: string }) {
|
||||||
|
const { navigateRoom } = useRoomNavigate();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button type="button" className={messageJumpLink} onClick={() => navigateRoom(roomId, eventId)}>
|
||||||
|
a message
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
|
@ -126,6 +126,7 @@ import { useAccessiblePowerTagColors, useGetMemberPowerTag } from '../../hooks/u
|
||||||
import { useTheme } from '../../hooks/useTheme';
|
import { useTheme } from '../../hooks/useTheme';
|
||||||
import { useRoomCreatorsTag } from '../../hooks/useRoomCreatorsTag';
|
import { useRoomCreatorsTag } from '../../hooks/useRoomCreatorsTag';
|
||||||
import { usePowerLevelTags } from '../../hooks/usePowerLevelTags';
|
import { usePowerLevelTags } from '../../hooks/usePowerLevelTags';
|
||||||
|
import { usePinnedEventParser } from '../../hooks/usePinnedEventParser';
|
||||||
|
|
||||||
const TimelineFloat = as<'div', css.TimelineFloatVariants>(
|
const TimelineFloat = as<'div', css.TimelineFloatVariants>(
|
||||||
({ position, className, ...props }, ref) => (
|
({ position, className, ...props }, ref) => (
|
||||||
|
@ -532,6 +533,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
||||||
[mx, room, linkifyOpts, spoilerClickHandler, mentionClickHandler, useAuthentication]
|
[mx, room, linkifyOpts, spoilerClickHandler, mentionClickHandler, useAuthentication]
|
||||||
);
|
);
|
||||||
const parseMemberEvent = useMemberEventParser();
|
const parseMemberEvent = useMemberEventParser();
|
||||||
|
const parsePinnedEvent = usePinnedEventParser(room.roomId);
|
||||||
|
|
||||||
const [timeline, setTimeline] = useState<Timeline>(() =>
|
const [timeline, setTimeline] = useState<Timeline>(() =>
|
||||||
eventId ? getEmptyTimeline() : getInitialTimeline(room)
|
eventId ? getEmptyTimeline() : getInitialTimeline(room)
|
||||||
|
@ -1468,6 +1470,47 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
||||||
</Event>
|
</Event>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
[StateEvent.RoomPinnedEvents]: (mEventId, mEvent, item) => {
|
||||||
|
const highlighted = focusItem?.index === item && focusItem.highlight;
|
||||||
|
const parsed = parsePinnedEvent(mEvent);
|
||||||
|
|
||||||
|
const timeJSX = (
|
||||||
|
<Time
|
||||||
|
ts={mEvent.getTs()}
|
||||||
|
compact={messageLayout === MessageLayout.Compact}
|
||||||
|
hour24Clock={hour24Clock}
|
||||||
|
dateFormatString={dateFormatString}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Event
|
||||||
|
key={mEvent.getId()}
|
||||||
|
data-message-item={item}
|
||||||
|
data-message-id={mEventId}
|
||||||
|
room={room}
|
||||||
|
mEvent={mEvent}
|
||||||
|
highlight={highlighted}
|
||||||
|
messageSpacing={messageSpacing}
|
||||||
|
canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
|
||||||
|
hideReadReceipts={hideActivity}
|
||||||
|
showDeveloperTools={showDeveloperTools}
|
||||||
|
>
|
||||||
|
<EventContent
|
||||||
|
messageLayout={messageLayout}
|
||||||
|
time={timeJSX}
|
||||||
|
iconSrc={Icons.Pin}
|
||||||
|
content={
|
||||||
|
<Box grow="Yes" direction="Column">
|
||||||
|
<Text size="T300" priority="300">
|
||||||
|
{parsed}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Event>
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(mEventId, mEvent, item) => {
|
(mEventId, mEvent, item) => {
|
||||||
if (!showHiddenEvents) return null;
|
if (!showHiddenEvents) return null;
|
||||||
|
|
57
src/app/hooks/usePinnedEventParser.tsx
Normal file
57
src/app/hooks/usePinnedEventParser.tsx
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import { MatrixEvent } from 'matrix-js-sdk';
|
||||||
|
import React, { ReactNode } from 'react';
|
||||||
|
import { IRoomPinnedEventsContent } from '../../types/matrix/room';
|
||||||
|
import { getMxIdLocalPart } from '../utils/matrix';
|
||||||
|
import { MessageJumpLink } from '../components/message/MessageJumpLink';
|
||||||
|
|
||||||
|
export type PinnedEventParser = (mEvent: MatrixEvent) => ReactNode;
|
||||||
|
|
||||||
|
export const usePinnedEventParser = (roomId: string): PinnedEventParser => {
|
||||||
|
const pinnedEventParser = (mEvent: MatrixEvent) => {
|
||||||
|
const { pinned } = mEvent.getContent<IRoomPinnedEventsContent>();
|
||||||
|
const prevPinned = (mEvent.getPrevContent() as Partial<IRoomPinnedEventsContent>).pinned;
|
||||||
|
const senderId = mEvent.getSender() ?? '';
|
||||||
|
const senderName = getMxIdLocalPart(senderId);
|
||||||
|
|
||||||
|
const addedPins = pinned.filter((pdu) => !(prevPinned?.includes(pdu) ?? false));
|
||||||
|
const removedPins = prevPinned?.filter((pdu) => !pinned.includes(pdu)) ?? [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<b>{senderName}</b>
|
||||||
|
{addedPins.length === 0 && removedPins.length === 0 ? (
|
||||||
|
' made no changes to the pinned messages'
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{addedPins.length > 0 && (
|
||||||
|
<>
|
||||||
|
{' pinned '}
|
||||||
|
<b>
|
||||||
|
{addedPins.length === 1 ? (
|
||||||
|
<MessageJumpLink roomId={roomId} eventId={addedPins[0]} />
|
||||||
|
) : (
|
||||||
|
`${addedPins.length} messages`
|
||||||
|
)}
|
||||||
|
</b>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{addedPins.length > 0 && removedPins.length > 0 && 'and'}
|
||||||
|
{removedPins.length > 0 && (
|
||||||
|
<>
|
||||||
|
{' unpinned '}
|
||||||
|
<b>
|
||||||
|
{removedPins.length === 1 ? (
|
||||||
|
<MessageJumpLink roomId={roomId} eventId={removedPins[0]} />
|
||||||
|
) : (
|
||||||
|
`${removedPins.length} messages`
|
||||||
|
)}
|
||||||
|
</b>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return pinnedEventParser;
|
||||||
|
};
|
|
@ -77,6 +77,10 @@ export type IRoomCreateContent = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type IRoomPinnedEventsContent = {
|
||||||
|
pinned: string[];
|
||||||
|
};
|
||||||
|
|
||||||
export type GetContentCallback = <T>() => T;
|
export type GetContentCallback = <T>() => T;
|
||||||
|
|
||||||
export type RoomToParents = Map<string, Set<string>>;
|
export type RoomToParents = Map<string, Set<string>>;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue