From 4180e79794b08aa8a842b13f89e6d10abb6af755 Mon Sep 17 00:00:00 2001 From: Ginger Date: Fri, 12 Sep 2025 09:49:27 -0400 Subject: [PATCH] Show pin/unpin events in the timeline --- .../components/message/MessageJumpLink.css.ts | 8 +++ .../components/message/MessageJumpLink.tsx | 13 +++++ src/app/features/room/RoomTimeline.tsx | 43 ++++++++++++++ src/app/hooks/usePinnedEventParser.tsx | 57 +++++++++++++++++++ src/types/matrix/room.ts | 4 ++ 5 files changed, 125 insertions(+) create mode 100644 src/app/components/message/MessageJumpLink.css.ts create mode 100644 src/app/components/message/MessageJumpLink.tsx create mode 100644 src/app/hooks/usePinnedEventParser.tsx diff --git a/src/app/components/message/MessageJumpLink.css.ts b/src/app/components/message/MessageJumpLink.css.ts new file mode 100644 index 00000000..f506af33 --- /dev/null +++ b/src/app/components/message/MessageJumpLink.css.ts @@ -0,0 +1,8 @@ +import { style } from '@vanilla-extract/css'; + +export const messageJumpLink = style({ + ':hover': { + cursor: 'pointer', + textDecoration: 'underline', + }, +}); diff --git a/src/app/components/message/MessageJumpLink.tsx b/src/app/components/message/MessageJumpLink.tsx new file mode 100644 index 00000000..3af4513f --- /dev/null +++ b/src/app/components/message/MessageJumpLink.tsx @@ -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 ( + + ); +} \ No newline at end of file diff --git a/src/app/features/room/RoomTimeline.tsx b/src/app/features/room/RoomTimeline.tsx index 2281b59d..13a89e08 100644 --- a/src/app/features/room/RoomTimeline.tsx +++ b/src/app/features/room/RoomTimeline.tsx @@ -126,6 +126,7 @@ import { useAccessiblePowerTagColors, useGetMemberPowerTag } from '../../hooks/u import { useTheme } from '../../hooks/useTheme'; import { useRoomCreatorsTag } from '../../hooks/useRoomCreatorsTag'; import { usePowerLevelTags } from '../../hooks/usePowerLevelTags'; +import { usePinnedEventParser } from '../../hooks/usePinnedEventParser'; const TimelineFloat = as<'div', css.TimelineFloatVariants>( ({ position, className, ...props }, ref) => ( @@ -532,6 +533,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli [mx, room, linkifyOpts, spoilerClickHandler, mentionClickHandler, useAuthentication] ); const parseMemberEvent = useMemberEventParser(); + const parsePinnedEvent = usePinnedEventParser(room.roomId); const [timeline, setTimeline] = useState(() => eventId ? getEmptyTimeline() : getInitialTimeline(room) @@ -1468,6 +1470,47 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli ); }, + [StateEvent.RoomPinnedEvents]: (mEventId, mEvent, item) => { + const highlighted = focusItem?.index === item && focusItem.highlight; + const parsed = parsePinnedEvent(mEvent); + + const timeJSX = ( +