mirror of
https://github.com/owncast/owncast.git
synced 2024-10-24 05:25:58 +03:00
change chat from a sidebar to a column (#3113)
* change chat from a sidebar to a column Using a 2-column layout prevents the chat scrollbar from overlapping the page scrollbar. Also, it no longer needs to calculate extra padding for elements. * remove unused Sidebar.tsx * fix css for chat column * re-center "Go to last message" button * main content column always uses maximum height * lint * re-hide scrollbars in mainContent on chromium * fix chat column width when input is over-full * chat is only fixed-width in desktop --------- Co-authored-by: janWilejan <>
This commit is contained in:
parent
60d6cda3a6
commit
2d72935564
11 changed files with 114 additions and 196 deletions
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
// The button that is displayed to scroll to the bottom of the chat.
|
// The button that is displayed to scroll to the bottom of the chat.
|
||||||
.toBottomWrap {
|
.toBottomWrap {
|
||||||
|
align-self: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 75px;
|
bottom: 75px;
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatContainer {
|
.chatContainer {
|
||||||
|
flex: 0 0 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background-color: var(--theme-color-components-chat-background);
|
background-color: var(--theme-color-components-chat-background);
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
// this margin is for fixed header
|
// this margin is for fixed header
|
||||||
padding-top: var(--header-height);
|
padding-top: var(--header-height);
|
||||||
background-color: var(--theme-color-main-background);
|
background-color: var(--theme-color-main-background);
|
||||||
min-height: 100vh;
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
// add some spacing between the last row of content and the footer
|
// add some spacing between the last row of content and the footer
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { Layout } from 'antd';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
import { ErrorBoundary } from 'react-error-boundary';
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
import { Footer } from '../../ui/Footer/Footer';
|
|
||||||
import {
|
import {
|
||||||
ClientConfigStore,
|
ClientConfigStore,
|
||||||
isChatAvailableSelector,
|
isChatAvailableSelector,
|
||||||
|
@ -16,9 +15,6 @@ import {
|
||||||
fatalErrorStateAtom,
|
fatalErrorStateAtom,
|
||||||
appStateAtom,
|
appStateAtom,
|
||||||
serverStatusState,
|
serverStatusState,
|
||||||
isMobileAtom,
|
|
||||||
ChatState,
|
|
||||||
chatStateAtom,
|
|
||||||
} from '../../stores/ClientConfigStore';
|
} from '../../stores/ClientConfigStore';
|
||||||
import { Content } from '../../ui/Content/Content';
|
import { Content } from '../../ui/Content/Content';
|
||||||
import { Header } from '../../ui/Header/Header';
|
import { Header } from '../../ui/Header/Header';
|
||||||
|
@ -33,7 +29,6 @@ import { PushNotificationServiceWorker } from '../../workers/PushNotificationSer
|
||||||
import { AppStateOptions } from '../../stores/application-state';
|
import { AppStateOptions } from '../../stores/application-state';
|
||||||
import { Noscript } from '../../ui/Noscript/Noscript';
|
import { Noscript } from '../../ui/Noscript/Noscript';
|
||||||
import { ServerStatus } from '../../../interfaces/server-status.model';
|
import { ServerStatus } from '../../../interfaces/server-status.model';
|
||||||
import { DYNAMIC_PADDING_VALUE } from '../../../utils/constants';
|
|
||||||
|
|
||||||
// Lazy loaded components
|
// Lazy loaded components
|
||||||
|
|
||||||
|
@ -54,17 +49,11 @@ export const Main: FC = () => {
|
||||||
const isChatAvailable = useRecoilValue<boolean>(isChatAvailableSelector);
|
const isChatAvailable = useRecoilValue<boolean>(isChatAvailableSelector);
|
||||||
const fatalError = useRecoilValue<DisplayableError>(fatalErrorStateAtom);
|
const fatalError = useRecoilValue<DisplayableError>(fatalErrorStateAtom);
|
||||||
const appState = useRecoilValue<AppStateOptions>(appStateAtom);
|
const appState = useRecoilValue<AppStateOptions>(appStateAtom);
|
||||||
const isMobile = useRecoilValue<boolean | undefined>(isMobileAtom);
|
|
||||||
const chatState = useRecoilValue<ChatState>(chatStateAtom);
|
|
||||||
const layoutRef = useRef<HTMLDivElement>(null);
|
const layoutRef = useRef<HTMLDivElement>(null);
|
||||||
const { chatDisabled } = clientConfig;
|
const { chatDisabled } = clientConfig;
|
||||||
const { videoAvailable } = appState;
|
const { videoAvailable } = appState;
|
||||||
const { online, streamTitle } = clientStatus;
|
const { online, streamTitle } = clientStatus;
|
||||||
|
|
||||||
// accounts for sidebar width when online in desktop
|
|
||||||
const showChat = online && !chatDisabled && chatState === ChatState.VISIBLE;
|
|
||||||
const dynamicFooterPadding = showChat && !isMobile ? DYNAMIC_PADDING_VALUE : '';
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setupNoLinkReferrer(layoutRef.current);
|
setupNoLinkReferrer(layoutRef.current);
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -171,10 +160,6 @@ export const Main: FC = () => {
|
||||||
{fatalError && (
|
{fatalError && (
|
||||||
<FatalErrorStateModal title={fatalError.title} message={fatalError.message} />
|
<FatalErrorStateModal title={fatalError.title} message={fatalError.message} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className={styles.footerContainer}>
|
|
||||||
<Footer dynamicPaddingValue={dynamicFooterPadding} />
|
|
||||||
</div>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
<Noscript />
|
<Noscript />
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,5 +1,28 @@
|
||||||
@import '../../../styles/mixins';
|
@import '../../../styles/mixins';
|
||||||
|
|
||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
// I'm not quite sure why, but sass ignores `#chat-container` here
|
||||||
|
[id="chat-container"] {
|
||||||
|
width: var(--chat-col-width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainColumn {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainColumn::-webkit-scrollbar, .mainColumn::-webkit-scrollbar-thumb {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.lowerSection {
|
.lowerSection {
|
||||||
padding: var(--content-padding);
|
padding: var(--content-padding);
|
||||||
}
|
}
|
||||||
|
@ -59,6 +82,7 @@
|
||||||
|
|
||||||
.desktopActionButtons {
|
.desktopActionButtons {
|
||||||
display: block;
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
@include screen(tablet) {
|
@include screen(tablet) {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
import { Skeleton, Col, Row, Button, Spin } from 'antd';
|
import { Skeleton, Row, Button, Spin } from 'antd';
|
||||||
import MessageFilled from '@ant-design/icons/MessageFilled';
|
import MessageFilled from '@ant-design/icons/MessageFilled';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
|
@ -24,7 +24,6 @@ import { ClientConfig } from '../../../interfaces/client-config.model';
|
||||||
|
|
||||||
import styles from './Content.module.scss';
|
import styles from './Content.module.scss';
|
||||||
import desktopStyles from './DesktopContent.module.scss';
|
import desktopStyles from './DesktopContent.module.scss';
|
||||||
import { Sidebar } from '../Sidebar/Sidebar';
|
|
||||||
import { OfflineBanner } from '../OfflineBanner/OfflineBanner';
|
import { OfflineBanner } from '../OfflineBanner/OfflineBanner';
|
||||||
import { AppStateOptions } from '../../stores/application-state';
|
import { AppStateOptions } from '../../stores/application-state';
|
||||||
import { ServerStatus } from '../../../interfaces/server-status.model';
|
import { ServerStatus } from '../../../interfaces/server-status.model';
|
||||||
|
@ -35,8 +34,15 @@ import { Modal } from '../Modal/Modal';
|
||||||
import { DesktopContent } from './DesktopContent';
|
import { DesktopContent } from './DesktopContent';
|
||||||
import { MobileContent } from './MobileContent';
|
import { MobileContent } from './MobileContent';
|
||||||
import { ChatModal } from '../../modals/ChatModal/ChatModal';
|
import { ChatModal } from '../../modals/ChatModal/ChatModal';
|
||||||
|
import { Footer } from '../Footer/Footer';
|
||||||
|
|
||||||
// Lazy loaded components
|
// Lazy loaded components
|
||||||
|
const ChatContainer = dynamic(
|
||||||
|
() => import('../../chat/ChatContainer/ChatContainer').then(mod => mod.ChatContainer),
|
||||||
|
{
|
||||||
|
ssr: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const FollowModal = dynamic(
|
const FollowModal = dynamic(
|
||||||
() => import('../../modals/FollowModal/FollowModal').then(mod => mod.FollowModal),
|
() => import('../../modals/FollowModal/FollowModal').then(mod => mod.FollowModal),
|
||||||
|
@ -208,12 +214,9 @@ export const Content: FC = () => {
|
||||||
|
|
||||||
const showChat = isChatAvailable && !chatDisabled && chatState === ChatState.VISIBLE;
|
const showChat = isChatAvailable && !chatDisabled && chatState === ChatState.VISIBLE;
|
||||||
|
|
||||||
// accounts for sidebar width when online in desktop
|
|
||||||
const dynamicPadding = showChat && !isMobile ? '320px' : '0px';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className={styles.main}>
|
||||||
<>
|
<div className={styles.mainColumn}>
|
||||||
{appState.appLoading && (
|
{appState.appLoading && (
|
||||||
<div
|
<div
|
||||||
className={classnames([styles.topSectionElement, styles.centerSpinner])}
|
className={classnames([styles.topSectionElement, styles.centerSpinner])}
|
||||||
|
@ -222,61 +225,54 @@ export const Content: FC = () => {
|
||||||
<Spin delay={2} size="large" tip="One moment..." />
|
<Spin delay={2} size="large" tip="One moment..." />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{showChat && !isMobile && <Sidebar />}
|
|
||||||
<Row>
|
<Row>
|
||||||
<Col span={24} style={{ paddingRight: dynamicPadding }}>
|
{online && (
|
||||||
{online && (
|
<OwncastPlayer
|
||||||
<OwncastPlayer
|
source="/hls/stream.m3u8"
|
||||||
source="/hls/stream.m3u8"
|
online={online}
|
||||||
online={online}
|
title={streamTitle || name}
|
||||||
title={streamTitle || name}
|
className={styles.topSectionElement}
|
||||||
className={styles.topSectionElement}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!online && !appState.appLoading && (
|
|
||||||
<div id="offline-message">
|
|
||||||
<OfflineBanner
|
|
||||||
showsHeader={false}
|
|
||||||
streamName={name}
|
|
||||||
customText={offlineMessage}
|
|
||||||
notificationsEnabled={supportsBrowserNotifications}
|
|
||||||
fediverseAccount={fediverseAccount}
|
|
||||||
lastLive={lastDisconnectTime}
|
|
||||||
onNotifyClick={() => setShowNotifyModal(true)}
|
|
||||||
onFollowClick={() => setShowFollowModal(true)}
|
|
||||||
className={classnames([styles.topSectionElement, styles.offlineBanner])}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<Col span={24} style={{ paddingRight: dynamicPadding }}>
|
|
||||||
{isStreamLive && (
|
|
||||||
<Statusbar
|
|
||||||
online={online}
|
|
||||||
lastConnectTime={lastConnectTime}
|
|
||||||
lastDisconnectTime={lastDisconnectTime}
|
|
||||||
viewerCount={viewerCount}
|
|
||||||
className={classnames(styles.topSectionElement, styles.statusBar)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<Col span={24} style={{ paddingRight: dynamicPadding }}>
|
|
||||||
<ActionButtons
|
|
||||||
supportFediverseFeatures={supportFediverseFeatures}
|
|
||||||
supportsBrowserNotifications={supportsBrowserNotifications}
|
|
||||||
showNotifyReminder={showNotifyReminder}
|
|
||||||
setShowNotifyModal={setShowNotifyModal}
|
|
||||||
disableNotifyReminderPopup={disableNotifyReminderPopup}
|
|
||||||
externalActions={externalActions || []}
|
|
||||||
setExternalActionToDisplay={setExternalActionToDisplay}
|
|
||||||
setShowFollowModal={setShowFollowModal}
|
|
||||||
externalActionSelected={externalActionSelected}
|
|
||||||
/>
|
/>
|
||||||
</Col>
|
)}
|
||||||
|
{!online && !appState.appLoading && (
|
||||||
|
<div id="offline-message" style={{ width: '100%' }}>
|
||||||
|
<OfflineBanner
|
||||||
|
showsHeader={false}
|
||||||
|
streamName={name}
|
||||||
|
customText={offlineMessage}
|
||||||
|
notificationsEnabled={supportsBrowserNotifications}
|
||||||
|
fediverseAccount={fediverseAccount}
|
||||||
|
lastLive={lastDisconnectTime}
|
||||||
|
onNotifyClick={() => setShowNotifyModal(true)}
|
||||||
|
onFollowClick={() => setShowFollowModal(true)}
|
||||||
|
className={classnames([styles.topSectionElement, styles.offlineBanner])}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
{isStreamLive && (
|
||||||
|
<Statusbar
|
||||||
|
online={online}
|
||||||
|
lastConnectTime={lastConnectTime}
|
||||||
|
lastDisconnectTime={lastDisconnectTime}
|
||||||
|
viewerCount={viewerCount}
|
||||||
|
className={classnames(styles.topSectionElement, styles.statusBar)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<ActionButtons
|
||||||
|
supportFediverseFeatures={supportFediverseFeatures}
|
||||||
|
supportsBrowserNotifications={supportsBrowserNotifications}
|
||||||
|
showNotifyReminder={showNotifyReminder}
|
||||||
|
setShowNotifyModal={setShowNotifyModal}
|
||||||
|
disableNotifyReminderPopup={disableNotifyReminderPopup}
|
||||||
|
externalActions={externalActions || []}
|
||||||
|
setExternalActionToDisplay={setExternalActionToDisplay}
|
||||||
|
setShowFollowModal={setShowFollowModal}
|
||||||
|
externalActionSelected={externalActionSelected}
|
||||||
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -290,8 +286,19 @@ export const Content: FC = () => {
|
||||||
<Row>
|
<Row>
|
||||||
{!name && <Skeleton active loading style={{ marginLeft: '10vw', marginRight: '10vw' }} />}
|
{!name && <Skeleton active loading style={{ marginLeft: '10vw', marginRight: '10vw' }} />}
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<Col span={24}>
|
<MobileContent
|
||||||
<MobileContent
|
name={name}
|
||||||
|
summary={summary}
|
||||||
|
tags={tags}
|
||||||
|
socialHandles={socialHandles}
|
||||||
|
extraPageContent={extraPageContent}
|
||||||
|
setShowFollowModal={setShowFollowModal}
|
||||||
|
supportFediverseFeatures={supportFediverseFeatures}
|
||||||
|
online={online}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className={desktopStyles.bottomSectionContent}>
|
||||||
|
<DesktopContent
|
||||||
name={name}
|
name={name}
|
||||||
summary={summary}
|
summary={summary}
|
||||||
tags={tags}
|
tags={tags}
|
||||||
|
@ -299,26 +306,23 @@ export const Content: FC = () => {
|
||||||
extraPageContent={extraPageContent}
|
extraPageContent={extraPageContent}
|
||||||
setShowFollowModal={setShowFollowModal}
|
setShowFollowModal={setShowFollowModal}
|
||||||
supportFediverseFeatures={supportFediverseFeatures}
|
supportFediverseFeatures={supportFediverseFeatures}
|
||||||
online={online}
|
|
||||||
/>
|
/>
|
||||||
</Col>
|
</div>
|
||||||
) : (
|
|
||||||
<Col span={24} style={{ paddingRight: dynamicPadding }}>
|
|
||||||
<div className={desktopStyles.bottomSectionContent}>
|
|
||||||
<DesktopContent
|
|
||||||
name={name}
|
|
||||||
summary={summary}
|
|
||||||
tags={tags}
|
|
||||||
socialHandles={socialHandles}
|
|
||||||
extraPageContent={extraPageContent}
|
|
||||||
setShowFollowModal={setShowFollowModal}
|
|
||||||
supportFediverseFeatures={supportFediverseFeatures}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
)}
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
</>
|
<div style={{ flex: '1 1' }} />
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
{showChat && !isMobile && currentUser && (
|
||||||
|
<ChatContainer
|
||||||
|
messages={messages}
|
||||||
|
usernameToHighlight={currentUser.displayName}
|
||||||
|
chatUserId={currentUser.id}
|
||||||
|
isModerator={currentUser.isModerator}
|
||||||
|
chatAvailable={isChatAvailable}
|
||||||
|
showInput={!!currentUser}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{externalActionToDisplay && (
|
{externalActionToDisplay && (
|
||||||
<ExternalModal
|
<ExternalModal
|
||||||
externalActionToDisplay={externalActionToDisplay}
|
externalActionToDisplay={externalActionToDisplay}
|
||||||
|
@ -354,6 +358,6 @@ export const Content: FC = () => {
|
||||||
Chat <MessageFilled />
|
Chat <MessageFilled />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
@import '../../../styles/mixins';
|
@import '../../../styles/mixins';
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
|
|
|
@ -4,18 +4,11 @@ import styles from './Footer.module.scss';
|
||||||
import { ServerStatus } from '../../../interfaces/server-status.model';
|
import { ServerStatus } from '../../../interfaces/server-status.model';
|
||||||
import { serverStatusState } from '../../stores/ClientConfigStore';
|
import { serverStatusState } from '../../stores/ClientConfigStore';
|
||||||
|
|
||||||
export type FooterProps = {
|
export const Footer: FC = () => {
|
||||||
dynamicPaddingValue?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Footer: FC<FooterProps> = ({ dynamicPaddingValue }) => {
|
|
||||||
const clientStatus = useRecoilValue<ServerStatus>(serverStatusState);
|
const clientStatus = useRecoilValue<ServerStatus>(serverStatusState);
|
||||||
const { versionNumber } = clientStatus;
|
const { versionNumber } = clientStatus;
|
||||||
const dynamicPaddingStyle = dynamicPaddingValue
|
|
||||||
? { paddingRight: `calc(${dynamicPaddingValue} + var(--footer-padding-x)` }
|
|
||||||
: null;
|
|
||||||
return (
|
return (
|
||||||
<footer className={styles.footer} id="footer" style={dynamicPaddingStyle}>
|
<footer className={styles.footer} id="footer">
|
||||||
<span>
|
<span>
|
||||||
Powered by <a href="https://owncast.online">Owncast v{versionNumber}</a>
|
Powered by <a href="https://owncast.online">Owncast v{versionNumber}</a>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
@import '../../../styles/mixins';
|
|
||||||
|
|
||||||
.root {
|
|
||||||
background-color: var(--theme-color-components-chat-background);
|
|
||||||
|
|
||||||
@include screen(desktop) {
|
|
||||||
position: fixed;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
top: 69px;
|
|
||||||
z-index:100;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (width <= 1120px) and (width >= 768px) {
|
|
||||||
top: 65px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
First div is .ant-layout-sider-children
|
|
||||||
Only way to target it apparently
|
|
||||||
*/
|
|
||||||
.root > div {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column nowrap;
|
|
||||||
-moz-box-flex: 1 !important;
|
|
||||||
flex-grow: 1 !important;
|
|
||||||
height: 100% !important;
|
|
||||||
width: 100%!important;
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
import Sider from 'antd/lib/layout/Sider';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
import { FC } from 'react';
|
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
import { Spin } from 'antd';
|
|
||||||
import { ChatMessage } from '../../../interfaces/chat-message.model';
|
|
||||||
import styles from './Sidebar.module.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
currentUserAtom,
|
|
||||||
visibleChatMessagesSelector,
|
|
||||||
isChatAvailableSelector,
|
|
||||||
} from '../../stores/ClientConfigStore';
|
|
||||||
|
|
||||||
// Lazy loaded components
|
|
||||||
const ChatContainer = dynamic(
|
|
||||||
() => import('../../chat/ChatContainer/ChatContainer').then(mod => mod.ChatContainer),
|
|
||||||
{
|
|
||||||
ssr: false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export const Sidebar: FC = () => {
|
|
||||||
const currentUser = useRecoilValue(currentUserAtom);
|
|
||||||
const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector);
|
|
||||||
const isChatAvailable = useRecoilValue(isChatAvailableSelector);
|
|
||||||
|
|
||||||
if (!currentUser) {
|
|
||||||
return (
|
|
||||||
<Sider className={styles.root} collapsedWidth={0} width={320}>
|
|
||||||
<Spin spinning size="large" style={{ position: 'relative', top: '40vh' }} />
|
|
||||||
</Sider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { id, isModerator, displayName } = currentUser;
|
|
||||||
return (
|
|
||||||
<Sider className={styles.root} collapsedWidth={0} width={320}>
|
|
||||||
<ChatContainer
|
|
||||||
messages={messages}
|
|
||||||
usernameToHighlight={displayName}
|
|
||||||
chatUserId={id}
|
|
||||||
isModerator={isModerator}
|
|
||||||
chatAvailable={isChatAvailable}
|
|
||||||
showInput={!!currentUser}
|
|
||||||
/>
|
|
||||||
</Sider>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -133,11 +133,3 @@ body {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
body::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body::-webkit-scrollbar-thumb {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export const DYNAMIC_PADDING_VALUE = '320px';
|
|
Loading…
Reference in a new issue