diff --git a/src/app/components/event-action-button/EventActionButton.css.ts b/src/app/components/event-action-button/EventActionButton.css.ts new file mode 100644 index 00000000..20189ee4 --- /dev/null +++ b/src/app/components/event-action-button/EventActionButton.css.ts @@ -0,0 +1,38 @@ +import { ComplexStyleRule } from '@vanilla-extract/css'; +import { recipe } from '@vanilla-extract/recipes'; +import { color, DefaultReset, MainColor } from 'folds'; + +const getVariant = (variant: MainColor): ComplexStyleRule => ({ + vars: { + color: color[variant].Main, + }, + selectors: { + '&:hover': { + color: color[variant].MainHover, + }, + }, +}); + +export const EventActionButton = recipe({ + base: [ + DefaultReset, + { + ':hover': { + textDecoration: 'underline', + }, + cursor: 'pointer', + }, + ], + variants: { + variant: { + Primary: getVariant('Primary'), + Secondary: getVariant('Secondary'), + Success: getVariant('Success'), + Warning: getVariant('Warning'), + Critical: getVariant('Critical'), + }, + }, + defaultVariants: { + variant: 'Primary', + }, +}); diff --git a/src/app/components/event-action-button/EventActionButton.tsx b/src/app/components/event-action-button/EventActionButton.tsx new file mode 100644 index 00000000..f15d7073 --- /dev/null +++ b/src/app/components/event-action-button/EventActionButton.tsx @@ -0,0 +1,14 @@ +import React from "react"; +import { as, MainColor } from "folds"; +import classNames from "classnames"; +import * as css from "./EventActionButton.css"; + +export const EventActionButton = as<'button', { variant?: MainColor }>( + ({ as: AsCutoutCard = 'button', className, variant = 'Primary', ...props }, ref) => ( + + ) +); diff --git a/src/app/components/message/MessageJumpLink.css.ts b/src/app/components/message/MessageJumpLink.css.ts deleted file mode 100644 index f506af33..00000000 --- a/src/app/components/message/MessageJumpLink.css.ts +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 3af4513f..00000000 --- a/src/app/components/message/MessageJumpLink.tsx +++ /dev/null @@ -1,13 +0,0 @@ -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/hooks/usePinnedEventParser.tsx b/src/app/hooks/usePinnedEventParser.tsx index 48b69648..5ea12eff 100644 --- a/src/app/hooks/usePinnedEventParser.tsx +++ b/src/app/hooks/usePinnedEventParser.tsx @@ -1,54 +1,67 @@ import { MatrixEvent } from 'matrix-js-sdk'; -import React, { ReactNode } from 'react'; -import { IRoomPinnedEventsContent } from '../../types/matrix/room'; +import React, { ReactNode, useCallback } from 'react'; +import { RoomPinnedEventsEventContent } from 'matrix-js-sdk/lib/types'; import { getMxIdLocalPart } from '../utils/matrix'; -import { MessageJumpLink } from '../components/message/MessageJumpLink'; +import { EventActionButton } from '../components/event-action-button/EventActionButton'; +import { useRoomNavigate } from './useRoomNavigate'; +import { singleOrNull } from '../utils/common'; -export type PinnedEventParser = (mEvent: MatrixEvent) => ReactNode; +export type PinnedEventParser = (mEvent: MatrixEvent) => ReactNode | null; export const usePinnedEventParser = (roomId: string): PinnedEventParser => { + const { navigateRoom } = useRoomNavigate(); + + const navigate = useCallback( + (eventId: string) => { + navigateRoom(roomId, eventId); + }, + [navigateRoom, roomId] + ); + const pinnedEventParser = (mEvent: MatrixEvent) => { - const { pinned } = mEvent.getContent(); - const prevPinned = (mEvent.getPrevContent() as Partial).pinned; + const { pinned } = mEvent.getContent(); + const prevPinned = (mEvent.getPrevContent() as Partial).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)) ?? []; + const addedPins = pinned.filter((event) => !(prevPinned?.includes(event) ?? false)); + const removedPins = prevPinned?.filter((event) => !pinned.includes(event)) ?? []; + const bodyMessages: string[] = []; + + // if only one event was added/removed total, show a link to jump to it + const jumpTarget = singleOrNull(addedPins.concat(removedPins)); + + // if this event didn't change anything, don't show the message at all + if (addedPins.length === 0 && removedPins.length === 0) { + return null; + } + + // check for added pins + if (addedPins.length > 0) { + if (addedPins.length === 1) { + bodyMessages.push('pinned a message'); + } else { + bodyMessages.push(`pinned ${addedPins.length} messages`); + } + } + + // check for removed pins + if (removedPins.length > 0) { + if (removedPins.length === 1) { + bodyMessages.push('unpinned a message'); + } else { + bodyMessages.push(`unpinned ${removedPins.length} messages`); + } + } return ( <> {senderName} - {addedPins.length === 0 && removedPins.length === 0 ? ( - ' made no changes to the pinned messages' - ) : ( - <> - {addedPins.length > 0 && ( - <> - {' pinned '} - - {addedPins.length === 1 ? ( - - ) : ( - `${addedPins.length} messages` - )} - - - )} - {addedPins.length > 0 && removedPins.length > 0 && 'and'} - {removedPins.length > 0 && ( - <> - {' unpinned '} - - {removedPins.length === 1 ? ( - - ) : ( - `${removedPins.length} messages` - )} - - - )} - + {` ${bodyMessages.join(' and ')}. `} + {jumpTarget && ( + navigate(jumpTarget)}> + View Message + )} ); diff --git a/src/app/utils/common.ts b/src/app/utils/common.ts index 678f1b6e..5594c7cf 100644 --- a/src/app/utils/common.ts +++ b/src/app/utils/common.ts @@ -138,3 +138,5 @@ export const splitWithSpace = (content: string): string[] => { if (trimmedContent === '') return []; return trimmedContent.split(' '); }; + +export const singleOrNull = (array: T[]): T | null => (array.length === 1 ? array[0] : null); diff --git a/src/types/matrix/room.ts b/src/types/matrix/room.ts index ce907cb4..b866fd77 100644 --- a/src/types/matrix/room.ts +++ b/src/types/matrix/room.ts @@ -77,10 +77,6 @@ export type IRoomCreateContent = { }; }; -export type IRoomPinnedEventsContent = { - pinned: string[]; -}; - export type GetContentCallback = () => T; export type RoomToParents = Map>;