Add Fediverse event chat views. Closes #2679

This commit is contained in:
Gabe Kangas 2023-02-05 19:58:24 -08:00
parent 922c68bcf7
commit 313a81359a
No known key found for this signature in database
GPG key ID: 4345B2060657F330
7 changed files with 586 additions and 15 deletions

File diff suppressed because one or more lines are too long

View file

@ -3,6 +3,7 @@ import { useState, useMemo, useRef, CSSProperties, FC, useEffect } from 'react';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { import {
ConnectedClientInfoEvent, ConnectedClientInfoEvent,
FediverseEvent,
MessageType, MessageType,
NameChangeEvent, NameChangeEvent,
} from '../../../interfaces/socket-events'; } from '../../../interfaces/socket-events';
@ -16,6 +17,7 @@ import { ChatSystemMessage } from '../ChatSystemMessage/ChatSystemMessage';
import { ChatJoinMessage } from '../ChatJoinMessage/ChatJoinMessage'; import { ChatJoinMessage } from '../ChatJoinMessage/ChatJoinMessage';
import { ScrollToBotBtn } from './ScrollToBotBtn'; import { ScrollToBotBtn } from './ScrollToBotBtn';
import { ChatActionMessage } from '../ChatActionMessage/ChatActionMessage'; import { ChatActionMessage } from '../ChatActionMessage/ChatActionMessage';
import { ChatSocialMessage } from '../ChatSocialMessage/ChatSocialMessage';
// Lazy loaded components // Lazy loaded components
@ -105,6 +107,8 @@ export const ChatContainer: FC<ChatContainerProps> = ({
); );
}; };
const getFediverseMessage = (message: FediverseEvent) => <ChatSocialMessage message={message} />;
const getUserJoinedMessage = (message: ChatMessage) => { const getUserJoinedMessage = (message: ChatMessage) => {
const { const {
user: { displayName, displayColor }, user: { displayName, displayColor },
@ -138,7 +142,7 @@ export const ChatContainer: FC<ChatContainerProps> = ({
const getViewForMessage = ( const getViewForMessage = (
index: number, index: number,
message: ChatMessage | NameChangeEvent | ConnectedClientInfoEvent, message: ChatMessage | NameChangeEvent | ConnectedClientInfoEvent | FediverseEvent,
) => { ) => {
switch (message.type) { switch (message.type) {
case MessageType.CHAT: case MessageType.CHAT:
@ -147,18 +151,18 @@ export const ChatContainer: FC<ChatContainerProps> = ({
message={message as ChatMessage} message={message as ChatMessage}
showModeratorMenu={isModerator} // Moderators have access to an additional menu showModeratorMenu={isModerator} // Moderators have access to an additional menu
highlightString={usernameToHighlight} // What to highlight in the message highlightString={usernameToHighlight} // What to highlight in the message
sentBySelf={message.user?.id === chatUserId} // The local user sent this message sentBySelf={(message as ChatMessage).user?.id === chatUserId} // The local user sent this message
sameUserAsLast={shouldCollapseMessages(messages, index)} sameUserAsLast={shouldCollapseMessages(messages, index)}
isAuthorModerator={(message as ChatMessage).user.scopes?.includes('MODERATOR')} isAuthorModerator={(message as ChatMessage).user.scopes?.includes('MODERATOR')}
isAuthorBot={(message as ChatMessage).user.scopes?.includes('BOT')} isAuthorBot={(message as ChatMessage).user.scopes?.includes('BOT')}
isAuthorAuthenticated={message.user?.authenticated} isAuthorAuthenticated={(message as ChatMessage).user?.authenticated}
key={message.id} key={message.id}
/> />
); );
case MessageType.NAME_CHANGE: case MessageType.NAME_CHANGE:
return getNameChangeViewForMessage(message as NameChangeEvent); return getNameChangeViewForMessage(message as NameChangeEvent);
case MessageType.CONNECTED_USER_INFO: case MessageType.CONNECTED_USER_INFO:
return getConnectedInfoMessage(message); return getConnectedInfoMessage(message as ConnectedClientInfoEvent);
case MessageType.USER_JOINED: case MessageType.USER_JOINED:
return getUserJoinedMessage(message as ChatMessage); return getUserJoinedMessage(message as ChatMessage);
case MessageType.CHAT_ACTION: case MessageType.CHAT_ACTION:
@ -171,6 +175,12 @@ export const ChatContainer: FC<ChatContainerProps> = ({
key={message.id} key={message.id}
/> />
); );
case MessageType.FEDIVERSE_ENGAGEMENT_FOLLOW:
return getFediverseMessage(message as FediverseEvent);
case MessageType.FEDIVERSE_ENGAGEMENT_LIKE:
return getFediverseMessage(message as FediverseEvent);
case MessageType.FEDIVERSE_ENGAGEMENT_REPOST:
return getFediverseMessage(message as FediverseEvent);
default: default:
return null; return null;

View file

@ -7,6 +7,7 @@
height: 85px; height: 85px;
width: 300px; width: 300px;
overflow: hidden; overflow: hidden;
background-color: var(--theme-color-background-main);
&:hover { &:hover {
border-color: var(--theme-text-link); border-color: var(--theme-text-link);
@ -23,6 +24,7 @@
.body { .body {
color: var(--theme-color-components-text-on-light); color: var(--theme-color-components-text-on-light);
text-overflow: ellipsis; text-overflow: ellipsis;
line-height: 1.2rem;
} }
.account { .account {
@ -37,8 +39,8 @@
height: 25px; height: 25px;
top: -20px; top: -20px;
left: 40px; left: 40px;
border-color: white; border-color: var(--theme-color-background-main);
border-width: 1px; border-width: 2px;
border-style: solid; border-style: solid;
border-radius: 50%; border-radius: 50%;
background-size: cover; background-size: cover;

View file

@ -13,7 +13,7 @@ const Template: ComponentStory<typeof ChatSocialMessage> = args => <ChatSocialMe
export const Follow = Template.bind({}); export const Follow = Template.bind({});
Follow.args = { Follow.args = {
message: { message: {
type: 'follow', type: 'FEDIVERSE_ENGAGEMENT_FOLLOW',
body: 'james followed this live stream.', body: 'james followed this live stream.',
title: 'james@mastodon.social', title: 'james@mastodon.social',
image: 'https://mastodon.social/avatars/original/missing.png', image: 'https://mastodon.social/avatars/original/missing.png',
@ -24,7 +24,7 @@ Follow.args = {
export const Like = Template.bind({}); export const Like = Template.bind({});
Like.args = { Like.args = {
message: { message: {
type: 'like', type: 'FEDIVERSE_ENGAGEMENT_LIKE',
body: 'james liked that this stream went live.', body: 'james liked that this stream went live.',
title: 'james@mastodon.social', title: 'james@mastodon.social',
image: 'https://mastodon.social/avatars/original/missing.png', image: 'https://mastodon.social/avatars/original/missing.png',
@ -35,7 +35,7 @@ Like.args = {
export const Repost = Template.bind({}); export const Repost = Template.bind({});
Repost.args = { Repost.args = {
message: { message: {
type: 'repost', type: 'FEDIVERSE_ENGAGEMENT_REPOST',
body: 'james shared this stream with their followers.', body: 'james shared this stream with their followers.',
title: 'james@mastodon.social', title: 'james@mastodon.social',
image: 'https://mastodon.social/avatars/original/missing.png', image: 'https://mastodon.social/avatars/original/missing.png',

View file

@ -25,13 +25,13 @@ export const ChatSocialMessage: FC<ChatSocialMessageProps> = ({ message }) => {
let Icon; let Icon;
switch (type.toString()) { switch (type.toString()) {
case 'follow': case 'FEDIVERSE_ENGAGEMENT_FOLLOW':
Icon = FollowIcon; Icon = FollowIcon;
break; break;
case 'like': case 'FEDIVERSE_ENGAGEMENT_LIKE':
Icon = LikeIcon; Icon = LikeIcon;
break; break;
case 'repost': case 'FEDIVERSE_ENGAGEMENT_REPOST':
Icon = RepostIcon; Icon = RepostIcon;
break; break;
default: default:

View file

@ -20,6 +20,7 @@ import {
ChatEvent, ChatEvent,
MessageVisibilityEvent, MessageVisibilityEvent,
SocketEvent, SocketEvent,
FediverseEvent,
} from '../../interfaces/socket-events'; } from '../../interfaces/socket-events';
import { mergeMeta } from '../../utils/helpers'; import { mergeMeta } from '../../utils/helpers';
import handleConnectedClientInfoMessage from './eventhandlers/connected-client-info-handler'; import handleConnectedClientInfoMessage from './eventhandlers/connected-client-info-handler';
@ -160,7 +161,7 @@ export const ClientConfigStore: FC = () => {
const [clientConfig, setClientConfig] = useRecoilState<ClientConfig>(clientConfigStateAtom); const [clientConfig, setClientConfig] = useRecoilState<ClientConfig>(clientConfigStateAtom);
const [, setServerStatus] = useRecoilState<ServerStatus>(serverStatusState); const [, setServerStatus] = useRecoilState<ServerStatus>(serverStatusState);
const setClockSkew = useSetRecoilState<Number>(clockSkewAtom); const setClockSkew = useSetRecoilState<Number>(clockSkewAtom);
const [chatMessages, setChatMessages] = useRecoilState<ChatMessage[]>(chatMessagesAtom); const [chatMessages, setChatMessages] = useRecoilState<SocketEvent[]>(chatMessagesAtom);
const [accessToken, setAccessToken] = useRecoilState<string>(accessTokenAtom); const [accessToken, setAccessToken] = useRecoilState<string>(accessTokenAtom);
const setAppState = useSetRecoilState<AppStateOptions>(appStateAtom); const setAppState = useSetRecoilState<AppStateOptions>(appStateAtom);
const setGlobalFatalErrorMessage = useSetRecoilState<DisplayableError>(fatalErrorStateAtom); const setGlobalFatalErrorMessage = useSetRecoilState<DisplayableError>(fatalErrorStateAtom);
@ -307,6 +308,15 @@ export const ClientConfigStore: FC = () => {
case MessageType.CHAT_ACTION: case MessageType.CHAT_ACTION:
setChatMessages(currentState => [...currentState, message as ChatEvent]); setChatMessages(currentState => [...currentState, message as ChatEvent]);
break; break;
case MessageType.FEDIVERSE_ENGAGEMENT_FOLLOW:
setChatMessages(currentState => [...currentState, message as FediverseEvent]);
break;
case MessageType.FEDIVERSE_ENGAGEMENT_LIKE:
setChatMessages(currentState => [...currentState, message as FediverseEvent]);
break;
case MessageType.FEDIVERSE_ENGAGEMENT_REPOST:
setChatMessages(currentState => [...currentState, message as FediverseEvent]);
break;
case MessageType.VISIBILITY_UPDATE: case MessageType.VISIBILITY_UPDATE:
handleMessageVisibilityChange(message as MessageVisibilityEvent); handleMessageVisibilityChange(message as MessageVisibilityEvent);
break; break;

View file

@ -42,3 +42,10 @@ export interface MessageVisibilityEvent extends SocketEvent {
visible: boolean; visible: boolean;
ids: string[]; ids: string[];
} }
export interface FediverseEvent extends SocketEvent {
title: string;
image: string;
link: string;
body: string;
}