From 150fa3515e60fa7f1662bd898ddb96e2a4fb3d59 Mon Sep 17 00:00:00 2001 From: jmoguilevsky Date: Thu, 10 Aug 2023 12:38:00 -0300 Subject: [PATCH] custom chat entry --- src/components/VideoConference/Chat/Chat.tsx | 3 +- .../VideoConference/Chat/ChatEntry.tsx | 75 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/components/VideoConference/Chat/ChatEntry.tsx diff --git a/src/components/VideoConference/Chat/Chat.tsx b/src/components/VideoConference/Chat/Chat.tsx index 97f5f51..752da8c 100644 --- a/src/components/VideoConference/Chat/Chat.tsx +++ b/src/components/VideoConference/Chat/Chat.tsx @@ -1,7 +1,8 @@ import type { ChatMessage, ReceivedChatMessage } from '@livekit/components-core' -import { ChatEntry, MessageFormatter, useLocalParticipant, useMaybeLayoutContext, useRoomContext } from '@livekit/components-react' +import { MessageFormatter, useLocalParticipant, useMaybeLayoutContext, useRoomContext } from '@livekit/components-react' import * as React from 'react' import { cloneSingleChild, setupChat, useObservableState } from './utils' +import { ChatEntry } from './ChatEntry' export type { ChatMessage, ReceivedChatMessage } diff --git a/src/components/VideoConference/Chat/ChatEntry.tsx b/src/components/VideoConference/Chat/ChatEntry.tsx new file mode 100644 index 0000000..6d134d1 --- /dev/null +++ b/src/components/VideoConference/Chat/ChatEntry.tsx @@ -0,0 +1,75 @@ +import { tokenize, createDefaultGrammar, ReceivedChatMessage } from '@livekit/components-core' +import * as React from 'react' +import Profile from 'decentraland-dapps/dist/containers/Profile' +import { MessageFormatter } from '@livekit/components-react' + +/** + * ChatEntry composes the HTML div element under the hood, so you can pass all its props. + * These are the props specific to the ChatEntry component: + * @public + */ +export interface ChatEntryProps extends React.HTMLAttributes { + /** The chat massage object to display. */ + entry: ReceivedChatMessage + /** Hide sender name. Useful when displaying multiple consecutive chat messages from the same person. */ + hideName?: boolean + /** Hide message timestamp. */ + hideTimestamp?: boolean + /** An optional formatter for the message body. */ + messageFormatter?: MessageFormatter +} + +/** + * The `ChatEntry` component holds and displays one chat message. + * + * @example + * ```tsx + * + * + * + * ``` + * @see `Chat` + * @public + */ +export function ChatEntry({ entry, hideName = false, hideTimestamp = false, messageFormatter, ...props }: ChatEntryProps) { + const formattedMessage = React.useMemo(() => { + return messageFormatter ? messageFormatter(entry.message) : entry.message + }, [entry.message, messageFormatter]) + const time = new Date(entry.timestamp) + const locale = navigator ? navigator.language : 'en-US' + + return ( +
  • + {(!hideTimestamp || !hideName) && ( + + {entry.from?.identity && } + {!hideName && {entry.from?.name ?? entry.from?.identity}} + {!hideTimestamp && {time.toLocaleTimeString(locale, { timeStyle: 'short' })}} + + )} + {formattedMessage} +
  • + ) +} + +/** @public */ +export function formatChatMessageLinks(message: string): React.ReactNode { + return tokenize(message, createDefaultGrammar()).map((tok, i) => { + if (typeof tok === `string`) { + return tok + } else { + const content = tok.content.toString() + const href = tok.type === `url` ? (/^http(s?):\/\//.test(content) ? content : `https://${content}`) : `mailto:${content}` + return ( + + {content} + + ) + } + }) +}