reafctor: normalize component formatting (#2082)

* refactor: move/rename BanUserButton file

* refactor: move/rename Chart file

* refactor: update generic component filenames to PascalCase

* refactor: update config component filenames to PascalCase

* refactor: update AdminLayout component filename to PascalCase

* refactor: update/move VideoJS component

* chore(eslint): disable bad react/require-default-props rule

* refactor: normalize ActionButton component

* refactor: normalize ActionButtonRow component

* refactor: normalize FollowButton component

* refactor: normalize NotifyButton component

* refactor: normalize ChatActionMessage component

* refactor: normalize ChatContainer component

* refactor: normalize ChatJoinMessage component

* refactor: normalize ChatModerationActionMenu component

* refactor: normalize ChatModerationDetailsModal component

* refactor: normalize ChatModeratorNotification component

* refactor: normalize ChatSocialMessage component

* refactor: normalize ChatSystemMessage component

* refactor: normalize ChatTextField component

* refactor: normalize ChatUserBadge component

* refactor: normalize ChatUserMessage component

* refactor: normalize ContentHeader component

* refactor: normalize OwncastLogo component

* refactor: normalize UserDropdown component

* chore(eslint): modify react/function-component-definition rule

* refactor: normalize CodecSelector component

* refactor: update a bunch of functional components using eslint

* refactor: update a bunch of functional components using eslint, pt2

* refactor: update a bunch of functional components using eslint, pt3

* refactor: replace all component->component default imports with named imports

* refactor: replace all component-stories->component default imports with named imports

* refactor: remove default exports from most components

* chore(eslint): add eslint config files for the components and pages dirs

* fix: use-before-define error in ChatContainer

* Fix ChatContainer import

* Only process .tsx files in Next builds

Co-authored-by: Gabe Kangas <gabek@real-ity.com>
This commit is contained in:
James Young
2022-09-07 09:00:28 +02:00
committed by GitHub
parent ee333ef10a
commit d1f3fffe2f
178 changed files with 1258 additions and 1227 deletions

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import ChatActionMessage from './ChatActionMessage';
import { ChatActionMessage } from './ChatActionMessage';
import Mock from '../../../stories/assets/mocks/chatmessage-action.png';
export default {

View File

@@ -1,13 +1,12 @@
import s from './ChatActionMessage.module.scss';
import { FC } from 'react';
import styles from './ChatActionMessage.module.scss';
/* eslint-disable react/no-danger */
interface Props {
export type ChatActionMessageProps = {
body: string;
}
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default function ChatActionMessage(props: Props) {
const { body } = props;
return <div dangerouslySetInnerHTML={{ __html: body }} className={s.chatAction} />;
}
export const ChatActionMessage: FC<ChatActionMessageProps> = ({ body }) => (
<div dangerouslySetInnerHTML={{ __html: body }} className={styles.chatAction} />
);

View File

@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import ChatContainer from './index';
import { ChatContainer } from './ChatContainer';
import { ChatMessage } from '../../../interfaces/chat-message.model';
export default {

View File

@@ -1,32 +1,77 @@
import { Button } from 'antd';
import { Virtuoso } from 'react-virtuoso';
import { useState, useMemo, useRef, CSSProperties } from 'react';
import { useState, useMemo, useRef, CSSProperties, FC } from 'react';
import { EditFilled, VerticalAlignBottomOutlined } from '@ant-design/icons';
import {
ConnectedClientInfoEvent,
MessageType,
NameChangeEvent,
} from '../../../interfaces/socket-events';
import s from './ChatContainer.module.scss';
import styles from './ChatContainer.module.scss';
import { ChatMessage } from '../../../interfaces/chat-message.model';
import { ChatTextField, ChatUserMessage } from '..';
import ChatModeratorNotification from '../ChatModeratorNotification/ChatModeratorNotification';
import { ChatUserMessage } from '../ChatUserMessage/ChatUserMessage';
import { ChatTextField } from '../ChatTextField/ChatTextField';
import { ChatModeratorNotification } from '../ChatModeratorNotification/ChatModeratorNotification';
// import ChatActionMessage from '../ChatAction/ChatActionMessage';
import ChatSystemMessage from '../ChatSystemMessage/ChatSystemMessage';
import ChatJoinMessage from '../ChatJoinMessage/ChatJoinMessage';
import { ChatSystemMessage } from '../ChatSystemMessage/ChatSystemMessage';
import { ChatJoinMessage } from '../ChatJoinMessage/ChatJoinMessage';
interface Props {
export type ChatContainerProps = {
messages: ChatMessage[];
usernameToHighlight: string;
chatUserId: string;
isModerator: boolean;
showInput?: boolean;
height?: string;
};
function shouldCollapseMessages(messages: ChatMessage[], index: number): boolean {
if (messages.length < 2) {
return false;
}
const message = messages[index];
const {
user: { id },
} = message;
const lastMessage = messages[index - 1];
if (lastMessage?.type !== MessageType.CHAT) {
return false;
}
if (!lastMessage.timestamp || !message.timestamp) {
return false;
}
const maxTimestampDelta = 1000 * 60 * 2; // 2 minutes
const lastTimestamp = new Date(lastMessage.timestamp).getTime();
const thisTimestamp = new Date(message.timestamp).getTime();
if (thisTimestamp - lastTimestamp > maxTimestampDelta) {
return false;
}
return id === lastMessage?.user.id;
}
export default function ChatContainer(props: Props) {
const { messages, usernameToHighlight, chatUserId, isModerator, showInput, height } = props;
function checkIsModerator(message) {
const { user } = message;
const { scopes } = user;
if (!scopes || scopes.length === 0) {
return false;
}
return scopes.includes('MODERATOR');
}
export const ChatContainer: FC<ChatContainerProps> = ({
messages,
usernameToHighlight,
chatUserId,
isModerator,
showInput,
height,
}) => {
const [atBottom, setAtBottom] = useState(false);
// const [showButton, setShowButton] = useState(false);
const chatContainerRef = useRef(null);
@@ -38,13 +83,13 @@ export default function ChatContainer(props: Props) {
const color = `var(--theme-color-users-${displayColor})`;
return (
<div className={s.nameChangeView}>
<div className={styles.nameChangeView}>
<div style={{ marginRight: 5, height: 'max-content', margin: 'auto 5px auto 0' }}>
<EditFilled />
</div>
<div className={s.nameChangeText}>
<div className={styles.nameChangeText}>
<span style={{ color }}>{oldName}</span>
<span className={s.plain}> is now known as </span>
<span className={styles.plain}> is now known as </span>
<span style={{ color }}>{displayName}</span>
</div>
</div>
@@ -129,7 +174,7 @@ export default function ChatContainer(props: Props) {
atBottomStateChange={bottom => setAtBottom(bottom)}
/>
{!atBottom && (
<div className={s.toBottomWrap}>
<div className={styles.toBottomWrap}>
<Button
type="default"
icon={<VerticalAlignBottomOutlined />}
@@ -161,46 +206,7 @@ export default function ChatContainer(props: Props) {
{showInput && <ChatTextField />}
</div>
);
}
function shouldCollapseMessages(messages: ChatMessage[], index: number): boolean {
if (messages.length < 2) {
return false;
}
const message = messages[index];
const {
user: { id },
} = message;
const lastMessage = messages[index - 1];
if (lastMessage?.type !== MessageType.CHAT) {
return false;
}
if (!lastMessage.timestamp || !message.timestamp) {
return false;
}
const maxTimestampDelta = 1000 * 60 * 2; // 2 minutes
const lastTimestamp = new Date(lastMessage.timestamp).getTime();
const thisTimestamp = new Date(message.timestamp).getTime();
if (thisTimestamp - lastTimestamp > maxTimestampDelta) {
return false;
}
return id === lastMessage?.user.id;
}
function checkIsModerator(message) {
const { user } = message;
const { scopes } = user;
if (!scopes || scopes.length === 0) {
return false;
}
return scopes.includes('MODERATOR');
}
};
ChatContainer.defaultProps = {
showInput: true,

View File

@@ -1 +0,0 @@
export { default } from './ChatContainer';

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import ChatJoinMessage from './ChatJoinMessage';
import { ChatJoinMessage } from './ChatJoinMessage';
import Mock from '../../../stories/assets/mocks/chatmessage-action.png';
export default {

View File

@@ -1,18 +1,22 @@
import s from './ChatJoinMessage.module.scss';
import ChatUserBadge from '../ChatUserBadge/ChatUserBadge';
import { FC } from 'react';
import styles from './ChatJoinMessage.module.scss';
import { ChatUserBadge } from '../ChatUserBadge/ChatUserBadge';
interface Props {
export type ChatJoinMessageProps = {
isAuthorModerator: boolean;
userColor: number;
displayName: string;
}
};
export default function ChatJoinMessage(props: Props) {
const { isAuthorModerator, userColor, displayName } = props;
export const ChatJoinMessage: FC<ChatJoinMessageProps> = ({
isAuthorModerator,
userColor,
displayName,
}) => {
const color = `var(--theme-user-colors-${userColor})`;
return (
<div className={s.join}>
<div className={styles.join}>
<span style={{ color }}>
{displayName}
{isAuthorModerator && (
@@ -24,4 +28,4 @@ export default function ChatJoinMessage(props: Props) {
joined the chat.
</div>
);
}
};

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import ChatModerationActionMenu from './ChatModerationActionMenu';
import { ChatModerationActionMenu } from './ChatModerationActionMenu';
const mocks = {
mocks: [
@@ -82,7 +82,7 @@ export default {
} as ComponentMeta<typeof ChatModerationActionMenu>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const Template: ComponentStory<typeof ChatModerationActionMenu> = args => (
const Template: ComponentStory<typeof ChatModerationActionMenu> = () => (
<RecoilRoot>
<ChatModerationActionMenu
accessToken="abc123"

View File

@@ -5,22 +5,26 @@ import {
SmallDashOutlined,
} from '@ant-design/icons';
import { Dropdown, Menu, MenuProps, Space, Modal, message } from 'antd';
import { useState } from 'react';
import ChatModerationDetailsModal from '../ChatModerationDetailsModal/ChatModerationDetailsModal';
import s from './ChatModerationActionMenu.module.scss';
import { FC, useState } from 'react';
import { ChatModerationDetailsModal } from '../ChatModerationDetailsModal/ChatModerationDetailsModal';
import styles from './ChatModerationActionMenu.module.scss';
import ChatModeration from '../../../services/moderation-service';
const { confirm } = Modal;
interface Props {
export type ChatModerationActionMenuProps = {
accessToken: string;
messageID: string;
userID: string;
userDisplayName: string;
}
};
export default function ChatModerationActionMenu(props: Props) {
const { messageID, userID, userDisplayName, accessToken } = props;
export const ChatModerationActionMenu: FC<ChatModerationActionMenuProps> = ({
messageID,
userID,
userDisplayName,
accessToken,
}) => {
const [showUserDetailsModal, setShowUserDetailsModal] = useState(false);
const handleBanUser = async () => {
@@ -78,7 +82,7 @@ export default function ChatModerationActionMenu(props: Props) {
{
label: (
<div>
<span className={s.icon}>
<span className={styles.icon}>
<EyeInvisibleOutlined />
</span>
Hide Message
@@ -89,7 +93,7 @@ export default function ChatModerationActionMenu(props: Props) {
{
label: (
<div>
<span className={s.icon}>
<span className={styles.icon}>
<CloseCircleOutlined />
</span>
Ban User
@@ -127,4 +131,4 @@ export default function ChatModerationActionMenu(props: Props) {
</Modal>
</>
);
}
};

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import ChatModerationDetailsModal from './ChatModerationDetailsModal';
import { ChatModerationDetailsModal } from './ChatModerationDetailsModal';
const mocks = {
mocks: [
@@ -82,7 +82,7 @@ export default {
} as ComponentMeta<typeof ChatModerationDetailsModal>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const Template: ComponentStory<typeof ChatModerationDetailsModal> = args => (
const Template: ComponentStory<typeof ChatModerationDetailsModal> = () => (
<RecoilRoot>
<ChatModerationDetailsModal userId="testuser123" accessToken="fakeaccesstoken4839" />
</RecoilRoot>

View File

@@ -1,12 +1,12 @@
import { Button, Col, Row, Spin } from 'antd';
import { useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import ChatModeration from '../../../services/moderation-service';
import s from './ChatModerationDetailsModal.module.scss';
import styles from './ChatModerationDetailsModal.module.scss';
interface Props {
export type ChatModerationDetailsModalProps = {
userId: string;
accessToken: string;
}
};
export interface UserDetails {
user: User;
@@ -91,7 +91,7 @@ const UserColorBlock = ({ color }) => {
<Row justify="space-around" align="middle">
<Col span={12}>Color</Col>
<Col span={12}>
<div className={s.colorBlock} style={{ backgroundColor: bg }}>
<div className={styles.colorBlock} style={{ backgroundColor: bg }}>
{color}
</div>
</Col>
@@ -99,8 +99,10 @@ const UserColorBlock = ({ color }) => {
);
};
export default function ChatModerationDetailsModal(props: Props) {
const { userId, accessToken } = props;
export const ChatModerationDetailsModal: FC<ChatModerationDetailsModalProps> = ({
userId,
accessToken,
}) => {
const [userDetails, setUserDetails] = useState<UserDetails | null>(null);
const [loading, setLoading] = useState(true);
@@ -127,7 +129,7 @@ export default function ChatModerationDetailsModal(props: Props) {
user;
return (
<div className={s.modalContainer}>
<div className={styles.modalContainer}>
<Spin spinning={loading}>
<h1>{displayName}</h1>
<Row justify="space-around" align="middle">
@@ -161,7 +163,7 @@ export default function ChatModerationDetailsModal(props: Props) {
<div>
<h1>Recent Chat Messages</h1>
<div className={s.chatHistory}>
<div className={styles.chatHistory}>
{messages.map(message => (
<ChatMessageRow
key={message.id}
@@ -176,4 +178,4 @@ export default function ChatModerationDetailsModal(props: Props) {
</Spin>
</div>
);
}
};

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import ChatModeratorNotification from './ChatModeratorNotification';
import { ChatModeratorNotification } from './ChatModeratorNotification';
export default {
title: 'owncast/Chat/Messages/Moderation Role Notification',

View File

@@ -1,12 +1,9 @@
import s from './ChatModeratorNotification.module.scss';
import styles from './ChatModeratorNotification.module.scss';
import Icon from '../../../assets/images/moderator.svg';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default function ModeratorNotification() {
return (
<div className={s.chatModerationNotification}>
<Icon className={s.icon} />
You are now a moderator.
</div>
);
}
export const ChatModeratorNotification = () => (
<div className={styles.chatModerationNotification}>
<Icon className={styles.icon} />
You are now a moderator.
</div>
);

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import ChatSocialMessage from './ChatSocialMessage';
import { ChatSocialMessage } from './ChatSocialMessage';
export default {
title: 'owncast/Chat/Messages/Social-fediverse event',

View File

@@ -1,11 +1,11 @@
/* eslint-disable react/no-unused-prop-types */
/* eslint-disable @typescript-eslint/no-unused-vars */
// TODO remove unused props
import { FC } from 'react';
import { ChatMessage } from '../../../interfaces/chat-message.model';
interface Props {
export interface ChatSocialMessageProps {
message: ChatMessage;
}
export default function ChatSocialMessage(props: Props) {
return <div>Component goes here</div>;
}
export const ChatSocialMessage: FC<ChatSocialMessageProps> = () => <div>Component goes here</div>;

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import ChatSystemMessage from './ChatSystemMessage';
import { ChatSystemMessage } from './ChatSystemMessage';
import Mock from '../../../stories/assets/mocks/chatmessage-system.png';
import { ChatMessage } from '../../../interfaces/chat-message.model';

View File

@@ -1,25 +1,27 @@
/* eslint-disable react/no-danger */
import { Highlight } from 'react-highlighter-ts';
import { FC } from 'react';
import { ChatMessage } from '../../../interfaces/chat-message.model';
import s from './ChatSystemMessage.module.scss';
import styles from './ChatSystemMessage.module.scss';
interface Props {
export type ChatSystemMessageProps = {
message: ChatMessage;
highlightString: string;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default function ChatSystemMessage({ message, highlightString }: Props) {
const { body, user } = message;
const { displayName } = user;
};
return (
<div className={s.chatSystemMessage}>
<div className={s.user}>
<span className={s.userName}>{displayName}</span>
</div>
<Highlight search={highlightString}>
<div className={s.message} dangerouslySetInnerHTML={{ __html: body }} />
</Highlight>
export const ChatSystemMessage: FC<ChatSystemMessageProps> = ({
message: {
body,
user: { displayName },
},
highlightString,
}) => (
<div className={styles.chatSystemMessage}>
<div className={styles.user}>
<span className={styles.userName}>{displayName}</span>
</div>
);
}
<Highlight search={highlightString}>
<div className={styles.message} dangerouslySetInnerHTML={{ __html: body }} />
</Highlight>
</div>
);

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import ChatTextField from './ChatTextField';
import { ChatTextField } from './ChatTextField';
import Mockup from '../../../stories/assets/mocks/chatinput-mock.png';
const mockResponse = JSON.parse(

View File

@@ -1,14 +1,14 @@
import { SendOutlined, SmileOutlined } from '@ant-design/icons';
import { Button, Popover } from 'antd';
import React, { useMemo, useState } from 'react';
import React, { FC, useMemo, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { Editor, Node, Path, Transforms, createEditor, BaseEditor, Text, Descendant } from 'slate';
import { Transforms, createEditor, BaseEditor, Text, Descendant, Editor, Node, Path } from 'slate';
import { Slate, Editable, withReact, ReactEditor, useSelected, useFocused } from 'slate-react';
import EmojiPicker from './EmojiPicker';
import { EmojiPicker } from './EmojiPicker';
import WebsocketService from '../../../services/websocket-service';
import { websocketServiceAtom } from '../../stores/ClientConfigStore';
import { MessageType } from '../../../interfaces/socket-events';
import style from './ChatTextField.module.scss';
import styles from './ChatTextField.module.scss';
type CustomElement = { type: 'paragraph' | 'span'; children: CustomText[] } | ImageNode;
type CustomText = { text: string };
@@ -90,7 +90,9 @@ const serialize = node => {
}
};
export default function ChatTextField() {
export type ChatTextFieldProps = {};
export const ChatTextField: FC<ChatTextFieldProps> = () => {
const [showEmojis, setShowEmojis] = useState(false);
const websocketService = useRecoilValue<WebsocketService>(websocketServiceAtom);
const editor = useMemo(() => withReact(withImages(createEditor())), []);
@@ -196,14 +198,13 @@ export default function ChatTextField() {
return (
<div>
<div className={style.root}>
<div className={styles.root}>
<Slate editor={editor} value={defaultEditorValue}>
<Editable
onKeyDown={onKeyDown}
renderElement={renderElement}
placeholder="Chat message goes here..."
style={{ width: '100%' }}
// onChange={change => setValue(change.value)}
autoFocus
/>
<Popover
@@ -221,14 +222,14 @@ export default function ChatTextField() {
<button
type="button"
className={style.emojiButton}
className={styles.emojiButton}
title="Emoji picker button"
onClick={() => setShowEmojis(!showEmojis)}
>
<SmileOutlined />
</button>
<Button
className={style.sendButton}
className={styles.sendButton}
size="large"
type="ghost"
icon={<SendOutlined />}
@@ -237,4 +238,4 @@ export default function ChatTextField() {
</div>
</div>
);
}
};

View File

@@ -9,7 +9,7 @@ interface Props {
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default function EmojiPicker(props: Props) {
export const EmojiPicker = (props: Props) => {
const [customEmoji, setCustomEmoji] = useState([]);
const { onEmojiSelect, onCustomEmojiSelect } = props;
const ref = useRef();
@@ -54,4 +54,4 @@ export default function EmojiPicker(props: Props) {
}, [customEmoji]);
return <div ref={ref} />;
}
};

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import ChatUserBadge from './ChatUserBadge';
import { ChatUserBadge } from './ChatUserBadge';
export default {
title: 'owncast/Chat/Messages/User Flag',

View File

@@ -1,19 +1,18 @@
import React from 'react';
import s from './ChatUserBadge.module.scss';
import React, { FC } from 'react';
import styles from './ChatUserBadge.module.scss';
interface Props {
export type ChatUserBadgeProps = {
badge: React.ReactNode;
userColor: number;
}
};
export default function ChatUserBadge(props: Props) {
const { badge, userColor } = props;
export const ChatUserBadge: FC<ChatUserBadgeProps> = ({ badge, userColor }) => {
const color = `var(--theme-user-colors-${userColor})`;
const style = { color, borderColor: color };
return (
<span style={style} className={s.badge}>
<span style={style} className={styles.badge}>
{badge}
</span>
);
}
};

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import ChatUserMessage from './index';
import { ChatUserMessage } from './ChatUserMessage';
import { ChatMessage } from '../../../interfaces/chat-message.model';
import Mock from '../../../stories/assets/mocks/chatmessage-user.png';

View File

@@ -1,19 +1,19 @@
/* eslint-disable react/no-danger */
import { useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { Highlight } from 'react-highlighter-ts';
import he from 'he';
import cn from 'classnames';
import { Tooltip } from 'antd';
import { LinkOutlined } from '@ant-design/icons';
import { useRecoilValue } from 'recoil';
import s from './ChatUserMessage.module.scss';
import styles from './ChatUserMessage.module.scss';
import { formatTimestamp } from './messageFmt';
import { ChatMessage } from '../../../interfaces/chat-message.model';
import ChatModerationActionMenu from '../ChatModerationActionMenu/ChatModerationActionMenu';
import ChatUserBadge from '../ChatUserBadge/ChatUserBadge';
import { ChatModerationActionMenu } from '../ChatModerationActionMenu/ChatModerationActionMenu';
import { ChatUserBadge } from '../ChatUserBadge/ChatUserBadge';
import { accessTokenAtom } from '../../stores/ClientConfigStore';
interface Props {
export type ChatUserMessageProps = {
message: ChatMessage;
showModeratorMenu: boolean;
highlightString: string;
@@ -21,9 +21,9 @@ interface Props {
sameUserAsLast: boolean;
isAuthorModerator: boolean;
isAuthorAuthenticated: boolean;
}
};
export default function ChatUserMessage({
export const ChatUserMessage: FC<ChatUserMessageProps> = ({
message,
highlightString,
showModeratorMenu,
@@ -31,7 +31,7 @@ export default function ChatUserMessage({
sameUserAsLast,
isAuthorModerator,
isAuthorAuthenticated,
}: Props) {
}) => {
const { id: messageId, body, user, timestamp } = message;
const { id: userId, displayName, displayColor } = user;
const accessToken = useRecoilValue<string>(accessTokenAtom);
@@ -59,29 +59,32 @@ export default function ChatUserMessage({
}, [message]);
return (
<div className={cn(s.messagePadding, sameUserAsLast && s.messagePaddingCollapsed)}>
<div className={cn(styles.messagePadding, sameUserAsLast && styles.messagePaddingCollapsed)}>
<div
className={cn(s.root, {
[s.ownMessage]: sentBySelf,
className={cn(styles.root, {
[styles.ownMessage]: sentBySelf,
})}
style={{ borderColor: color }}
>
{!sameUserAsLast && (
<Tooltip title="user info goes here" placement="topLeft" mouseEnterDelay={1}>
<div className={s.user} style={{ color }}>
<span className={s.userName}>{displayName}</span>
<div className={styles.user} style={{ color }}>
<span className={styles.userName}>{displayName}</span>
<span>{badgeNodes}</span>
</div>
</Tooltip>
)}
<Tooltip title={formattedTimestamp} mouseEnterDelay={1}>
<Highlight search={highlightString}>
<div className={s.message} dangerouslySetInnerHTML={{ __html: formattedMessage }} />
<div
className={styles.message}
dangerouslySetInnerHTML={{ __html: formattedMessage }}
/>
</Highlight>
</Tooltip>
{showModeratorMenu && (
<div className={s.modMenuWrapper}>
<div className={styles.modMenuWrapper}>
<ChatModerationActionMenu
messageID={messageId}
accessToken={accessToken}
@@ -90,9 +93,9 @@ export default function ChatUserMessage({
/>
</div>
)}
<div className={s.customBorder} style={{ color }} />
<div className={s.background} style={{ color }} />
<div className={styles.customBorder} style={{ color }} />
<div className={styles.background} style={{ color }} />
</div>
</div>
);
}
};

View File

@@ -1 +0,0 @@
export { default } from './ChatUserMessage';

View File

@@ -1,3 +0,0 @@
export { default as ChatContainer } from './ChatContainer';
export { default as ChatUserMessage } from './ChatUserMessage';
export { default as ChatTextField } from './ChatTextField/ChatTextField';