Skip to content

Commit

Permalink
Add MessageBodyPreview
Browse files Browse the repository at this point in the history
  • Loading branch information
tassoevan committed Jun 2, 2022
1 parent 66f61d3 commit 4ca837f
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 40 deletions.
74 changes: 74 additions & 0 deletions apps/meteor/client/components/message/body/MessageBodyPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import * as MessageParser from '@rocket.chat/message-parser';
import React, { memo, ReactElement } from 'react';

import PreviewBigEmojiBlock from './preview/PreviewBigEmojiBlock';
import PreviewInlineElements from './preview/PreviewInlineElements';

const isOnlyBigEmojiBlock = (tokens: MessageParser.MarkdownAST): tokens is [MessageParser.BigEmoji] =>
tokens.length === 1 && tokens[0].type === 'BIG_EMOJI';

type MessageBodyRenderProps = {
tokens: MessageParser.MarkdownAST;
};

const MessageBodyPreview = ({ tokens }: MessageBodyRenderProps): ReactElement | null => {
if (isOnlyBigEmojiBlock(tokens)) {
return <PreviewBigEmojiBlock emojis={tokens[0].value} />;
}

const firstBlock = tokens.find((block) => block.type !== 'LINE_BREAK');

if (!firstBlock) {
return null;
}

switch (firstBlock.type) {
case 'PARAGRAPH':
return <PreviewInlineElements children={firstBlock.value} />;

case 'HEADING':
return <>{firstBlock.value.map((plain) => plain.value).join('')}</>;

case 'UNORDERED_LIST':
case 'ORDERED_LIST': {
const firstItem = firstBlock.value[0];

return (
<>
{firstItem.number ? `${firstItem.number}.` : '-'} <PreviewInlineElements children={firstItem.value} />
</>
);
}

case 'TASKS': {
const firstTask = firstBlock.value[0];

return (
<>
{firstTask.status ? '\u2611' : '\u2610'} <PreviewInlineElements children={firstTask.value} />
</>
);
}

case 'QUOTE': {
const firstParagraph = firstBlock.value[0];

return (
<>
&gt; <PreviewInlineElements children={firstParagraph.value} />
</>
);
}

case 'CODE': {
const firstLine = firstBlock.value.find((line) => line.value.value.trim());

return firstLine ? <>{firstLine.value.value.trim()}</> : null;
}

default:
return null;
}
};

export default memo(MessageBodyPreview);
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
import * as MessageParser from '@rocket.chat/message-parser';
import React, { ReactElement, useMemo } from 'react';

import { flattenMarkup } from '../flattenMarkup';
const flattenMarkup = (markup: MessageParser.Markup | MessageParser.Link): string => {
switch (markup.type) {
case 'PLAIN_TEXT':
return markup.value;

case 'ITALIC':
case 'BOLD':
case 'STRIKE':
return markup.value.map(flattenMarkup).join('');

case 'LINK': {
const label = flattenMarkup(markup.value.label);
const href = markup.value.src.value;

return label ? `${label} (${href})` : href;
}

default:
return '';
}
};

const style = {
maxWidth: '100%',
Expand Down
23 changes: 0 additions & 23 deletions apps/meteor/client/components/message/body/flattenMarkup.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as MessageParser from '@rocket.chat/message-parser';
import React, { ReactElement } from 'react';

import EmojiElement from '../elements/EmojiElement';

type PreviewBigEmojiBlockProps = {
emojis: MessageParser.Emoji[];
};

const PreviewBigEmojiBlock = ({ emojis }: PreviewBigEmojiBlockProps): ReactElement => (
<>
{emojis.map((emoji, index) => (
<EmojiElement key={index} handle={emoji.value.value} />
))}
</>
);

export default PreviewBigEmojiBlock;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { ReactElement } from 'react';

const toHexByte = (value: number): string => value.toString(16).padStart(2, '0');

type PreviewColorElementProps = {
r: number;
g: number;
b: number;
a: number;
};

const PreviewColorElement = ({ r, g, b, a }: PreviewColorElementProps): ReactElement => {
if (a === 255) {
return (
<>
#{toHexByte(r)}
{toHexByte(g)}
{toHexByte(b)}
</>
);
}

return (
<>
#{toHexByte(r)}
{toHexByte(g)}
{toHexByte(b)}
{toHexByte(a)}
</>
);
};

export default PreviewColorElement;
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as MessageParser from '@rocket.chat/message-parser';
import React, { Fragment, ReactElement } from 'react';

import EmojiElement from '../elements/EmojiElement';
import PreviewColorElement from './PreviewColorElement';

type PreviewInlineElementsProps = {
children: MessageParser.Inlines[];
};

const PreviewInlineElements = ({ children }: PreviewInlineElementsProps): ReactElement => (
<>
{children.map((child, index) => {
switch (child.type) {
case 'BOLD':
case 'ITALIC':
case 'STRIKE':
return <PreviewInlineElements key={index} children={child.value} />;

case 'LINK':
return <PreviewInlineElements key={index} children={[child.value.label]} />;

case 'PLAIN_TEXT':
return <Fragment key={index} children={child.value} />;

case 'IMAGE':
return <PreviewInlineElements key={index} children={[child.value.label]} />;

case 'MENTION_USER':
return <Fragment key={index}>@{child.value.value}</Fragment>;

case 'MENTION_CHANNEL':
return <Fragment key={index}>#{child.value.value}</Fragment>;

case 'INLINE_CODE':
return <Fragment key={index} children={child.value.value} />;

case 'EMOJI':
return <EmojiElement key={index} handle={child.value.value} />;

case 'COLOR':
return <PreviewColorElement key={index} {...child.value} />;

default:
return null;
}
})}
</>
);

export default PreviewInlineElements;
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
import { IMessage } from '@rocket.chat/core-typings';
import React, { ReactElement } from 'react';

import MessageBodyRender from '../../../../components/message/body/MessageBodyRender';
import { useMessageActions } from '../../contexts/MessageContext';
import MessageBodyPreview from '../../../../components/message/body/MessageBodyPreview';
import { useParsedMessage } from '../hooks/useParsedMessage';

type ThreadMessagePreviewBodyProps = {
message: IMessage;
};

const ThreadMessagePreviewBody = ({ message }: ThreadMessagePreviewBodyProps): ReactElement => {
const {
actions: { openRoom, openUserCard },
} = useMessageActions();

const tokens = useParsedMessage(message);

return (
<MessageBodyRender
onUserMentionClick={openUserCard}
onChannelMentionClick={openRoom}
mentions={message?.mentions || []}
channels={message?.channels || []}
tokens={tokens}
isThreadPreview
/>
);
return <MessageBodyPreview tokens={tokens} />;
};

export default ThreadMessagePreviewBody;

0 comments on commit 4ca837f

Please sign in to comment.