SwipeableDrawer improvements

Fix css stuf

Split mobile and small popout window styles

Fix failed logic that broke desktop player
This commit is contained in:
Rafael 2022-02-02 09:48:24 -03:00 committed by Thomas Zarebczan
parent 55e0a7effe
commit b3ed0027ff
19 changed files with 489 additions and 250 deletions

View file

@ -33,6 +33,7 @@ import ClaimPreviewHidden from './claim-preview-no-mature';
import ClaimPreviewNoContent from './claim-preview-no-content'; import ClaimPreviewNoContent from './claim-preview-no-content';
import { ENABLE_NO_SOURCE_CLAIMS } from 'config'; import { ENABLE_NO_SOURCE_CLAIMS } from 'config';
import CollectionEditButtons from 'component/collectionEditButtons'; import CollectionEditButtons from 'component/collectionEditButtons';
import { useIsMobile } from 'effects/use-screensize';
const AbandonedChannelPreview = lazyImport(() => const AbandonedChannelPreview = lazyImport(() =>
import('component/abandonedChannelPreview' /* webpackChunkName: "abandonedChannelPreview" */) import('component/abandonedChannelPreview' /* webpackChunkName: "abandonedChannelPreview" */)
@ -153,6 +154,8 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
unavailableUris, unavailableUris,
} = props; } = props;
const isMobile = useIsMobile();
const isCollection = claim && claim.value_type === 'collection'; const isCollection = claim && claim.value_type === 'collection';
const collectionClaimId = isCollection && claim && claim.claim_id; const collectionClaimId = isCollection && claim && claim.claim_id;
const listId = collectionId || collectionClaimId; const listId = collectionId || collectionClaimId;
@ -434,13 +437,11 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
)} )}
{claim && ( {claim && (
<React.Fragment> <React.Fragment>
{typeof properties === 'function' ? ( {typeof properties === 'function'
properties(claim) ? properties(claim)
) : properties !== undefined ? ( : properties !== undefined
properties ? properties
) : ( : !isMobile && <ClaimTags uri={uri} type={type} />}
<ClaimTags uri={uri} type={type} />
)}
</React.Fragment> </React.Fragment>
)} )}
</div> </div>

View file

@ -308,8 +308,8 @@ function CommentList(props: Props) {
<ul <ul
className={classnames({ className={classnames({
comments: isMediumScreen || expandedComments, comments: !isMediumScreen || expandedComments,
'comments--contracted': !isMediumScreen && !expandedComments, 'comments--contracted': isMediumScreen && !expandedComments,
})} })}
> >
{readyToDisplayComments && pinnedComments && getCommentElems(pinnedComments)} {readyToDisplayComments && pinnedComments && getCommentElems(pinnedComments)}

View file

@ -9,6 +9,7 @@ import {
selectSuperChatTotalAmountForUri, selectSuperChatTotalAmountForUri,
selectPinnedCommentsForUri, selectPinnedCommentsForUri,
} from 'redux/selectors/comments'; } from 'redux/selectors/comments';
import { selectThemePath } from 'redux/selectors/settings';
import LivestreamChatLayout from './view'; import LivestreamChatLayout from './view';
const select = (state, props) => { const select = (state, props) => {
@ -20,6 +21,7 @@ const select = (state, props) => {
pinnedComments: selectPinnedCommentsForUri(state, uri), pinnedComments: selectPinnedCommentsForUri(state, uri),
superChats: selectSuperChatsForUri(state, uri), superChats: selectSuperChatsForUri(state, uri),
superChatsTotalAmount: selectSuperChatTotalAmountForUri(state, uri), superChatsTotalAmount: selectSuperChatTotalAmountForUri(state, uri),
theme: selectThemePath(state),
}; };
}; };

View file

@ -4,7 +4,6 @@ import { Global } from '@emotion/react';
import { Menu, MenuButton, MenuList, MenuItem } from '@reach/menu-button'; import { Menu, MenuButton, MenuList, MenuItem } from '@reach/menu-button';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { useIsMobile } from 'effects/use-screensize';
import usePersistedState from 'effects/use-persisted-state'; import usePersistedState from 'effects/use-persisted-state';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
@ -14,20 +13,27 @@ type Props = {
isPopoutWindow?: boolean, isPopoutWindow?: boolean,
superchatsHidden?: boolean, superchatsHidden?: boolean,
noSuperchats?: boolean, noSuperchats?: boolean,
isMobile?: boolean,
hideChat?: () => void, hideChat?: () => void,
setPopoutWindow?: (any) => void, setPopoutWindow?: (any) => void,
toggleSuperchats?: () => void, toggleSuperchats?: () => void,
}; };
export default function LivestreamMenu(props: Props) { export default function LivestreamMenu(props: Props) {
const { isPopoutWindow, superchatsHidden, noSuperchats, hideChat, setPopoutWindow, toggleSuperchats } = props; const {
isPopoutWindow,
superchatsHidden,
noSuperchats,
isMobile,
hideChat,
setPopoutWindow,
toggleSuperchats,
} = props;
const { const {
location: { pathname }, location: { pathname },
} = useHistory(); } = useHistory();
const isMobile = useIsMobile();
const [showTimestamps, setShowTimestamps] = usePersistedState('live-timestamps', false); const [showTimestamps, setShowTimestamps] = usePersistedState('live-timestamps', false);
function handlePopout() { function handlePopout() {
@ -42,19 +48,9 @@ export default function LivestreamMenu(props: Props) {
} }
} }
const MenuGlobalStyles = () => (
<Global
styles={{
':root': {
'--live-timestamp-opacity': showTimestamps ? '0.5' : '0',
},
}}
/>
);
return ( return (
<> <>
<MenuGlobalStyles /> <MenuGlobalStyles showTimestamps={showTimestamps} />
<Menu> <Menu>
<MenuButton className="menu__button"> <MenuButton className="menu__button">
@ -103,3 +99,21 @@ export default function LivestreamMenu(props: Props) {
</> </>
); );
} }
type GlobalStylesProps = {
showTimestamps?: boolean,
};
const MenuGlobalStyles = (globalStylesProps: GlobalStylesProps) => {
const { showTimestamps } = globalStylesProps;
return (
<Global
styles={{
':root': {
'--live-timestamp-opacity': showTimestamps ? '0.5' : '0',
},
}}
/>
);
};

View file

@ -11,14 +11,17 @@ import OptimizedImage from 'component/optimizedImage';
import React from 'react'; import React from 'react';
import Tooltip from 'component/common/tooltip'; import Tooltip from 'component/common/tooltip';
import UriIndicator from 'component/uriIndicator'; import UriIndicator from 'component/uriIndicator';
import Slide from '@mui/material/Slide';
type Props = { type Props = {
superChats: Array<Comment>, superChats: Array<Comment>,
superchatsHidden?: boolean,
isMobile?: boolean,
toggleSuperChat: () => void, toggleSuperChat: () => void,
}; };
export default function LivestreamSuperchats(props: Props) { export default function LivestreamSuperchats(props: Props) {
const { superChats: superChatsByAmount, toggleSuperChat } = props; const { superChats: superChatsByAmount, superchatsHidden, isMobile, toggleSuperChat } = props;
const superChatTopTen = React.useMemo(() => { const superChatTopTen = React.useMemo(() => {
return superChatsByAmount ? superChatsByAmount.slice(0, 10) : superChatsByAmount; return superChatsByAmount ? superChatsByAmount.slice(0, 10) : superChatsByAmount;
@ -29,8 +32,13 @@ export default function LivestreamSuperchats(props: Props) {
const showMore = superChatTopTen && superChatsByAmount && superChatTopTen.length < superChatsByAmount.length; const showMore = superChatTopTen && superChatsByAmount && superChatTopTen.length < superChatsByAmount.length;
return !superChatTopTen ? null : ( return !superChatTopTen ? null : (
<div className="livestreamSuperchats__wrapper"> <Slider isMobile={isMobile} superchatsHidden={superchatsHidden}>
<div className="livestreamSuperchats__inner"> <div
className={classnames('livestream-superchats__wrapper', {
'livestream-superchats__wrapper--mobile': isMobile,
})}
>
<div className="livestream-superchats">
{superChatTopTen.map((superChat: Comment) => { {superChatTopTen.map((superChat: Comment) => {
const { comment, comment_id, channel_url, support_amount, is_fiat } = superChat; const { comment, comment_id, channel_url, support_amount, is_fiat } = superChat;
const isSticker = stickerSuperChats && stickerSuperChats.includes(superChat); const isSticker = stickerSuperChats && stickerSuperChats.includes(superChat);
@ -38,7 +46,11 @@ export default function LivestreamSuperchats(props: Props) {
return ( return (
<Tooltip title={isSticker ? stickerImg : comment} key={comment_id}> <Tooltip title={isSticker ? stickerImg : comment} key={comment_id}>
<div className="livestream__superchat"> <div
className={classnames('livestream-superchat', {
'livestream-superchat--mobile': isMobile,
})}
>
<ChannelThumbnail uri={channel_url} xsmall /> <ChannelThumbnail uri={channel_url} xsmall />
<div <div
@ -72,11 +84,30 @@ export default function LivestreamSuperchats(props: Props) {
label={__('Show More')} label={__('Show More')}
button="inverse" button="inverse"
className="close-button" className="close-button"
onClick={toggleSuperChat} onClick={() => toggleSuperChat()}
iconRight={ICONS.MORE} iconRight={ICONS.MORE}
/> />
)} )}
</div> </div>
</div> </div>
</Slider>
); );
} }
type SliderProps = {
superchatsHidden?: boolean,
isMobile?: boolean,
children: any,
};
const Slider = (sliderProps: SliderProps) => {
const { superchatsHidden, isMobile, children } = sliderProps;
return isMobile ? (
<Slide direction="left" in={!superchatsHidden} mountOnEnter unmountOnExit>
{children}
</Slide>
) : (
<>{children}</>
);
};

View file

@ -1,6 +1,11 @@
// @flow // @flow
import 'scss/component/_livestream-chat.scss'; import 'scss/component/_livestream-chat.scss';
// $FlowFixMe
import { Global } from '@emotion/react';
// $FlowFixMe
import { grey } from '@mui/material/colors';
import { formatLbryUrlForWeb } from 'util/url'; import { formatLbryUrlForWeb } from 'util/url';
import { useIsMobile } from 'effects/use-screensize'; import { useIsMobile } from 'effects/use-screensize';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
@ -16,6 +21,7 @@ import React from 'react';
import Spinner from 'component/spinner'; import Spinner from 'component/spinner';
import Yrbl from 'component/yrbl'; import Yrbl from 'component/yrbl';
import { getTipValues } from 'util/livestream'; import { getTipValues } from 'util/livestream';
import Slide from '@mui/material/Slide';
const VIEW_MODES = { const VIEW_MODES = {
CHAT: 'chat', CHAT: 'chat',
@ -35,6 +41,7 @@ type Props = {
hideHeader?: boolean, hideHeader?: boolean,
superchatsHidden?: boolean, superchatsHidden?: boolean,
customViewMode?: string, customViewMode?: string,
theme: string,
doCommentList: (string, string, number, number) => void, doCommentList: (string, string, number, number) => void,
doResolveUris: (Array<string>, boolean) => void, doResolveUris: (Array<string>, boolean) => void,
doSuperChatList: (string) => void, doSuperChatList: (string) => void,
@ -52,12 +59,13 @@ export default function LivestreamChatLayout(props: Props) {
hideHeader, hideHeader,
superchatsHidden, superchatsHidden,
customViewMode, customViewMode,
theme,
doCommentList, doCommentList,
doResolveUris, doResolveUris,
doSuperChatList, doSuperChatList,
} = props; } = props;
const isMobile = useIsMobile(); const isMobile = useIsMobile() && !isPopoutWindow;
const discussionElement = document.querySelector('.livestream__comments'); const discussionElement = document.querySelector('.livestream__comments');
@ -225,6 +233,7 @@ export default function LivestreamChatLayout(props: Props) {
isPopoutWindow={isPopoutWindow} isPopoutWindow={isPopoutWindow}
hideChat={() => setChatHidden(true)} hideChat={() => setChatHidden(true)}
setPopoutWindow={(v) => setPopoutWindow(v)} setPopoutWindow={(v) => setPopoutWindow(v)}
isMobile={isMobile}
/> />
</div> </div>
@ -247,13 +256,42 @@ export default function LivestreamChatLayout(props: Props) {
)} )}
<div ref={commentsRef} className="livestreamComments__wrapper"> <div ref={commentsRef} className="livestreamComments__wrapper">
<div className="livestream-comments__top-actions"> <div
{viewMode === VIEW_MODES.CHAT && superChatsByAmount && !superchatsHidden && ( className={classnames('livestream-comments__top-actions', {
<LivestreamSuperchats superChats={superChatsByAmount} toggleSuperChat={toggleSuperChat} /> 'livestream-comments__top-actions--mobile': isMobile,
})}
>
{isMobile && ((pinnedComment && showPinned) || (superChatsByAmount && !superchatsHidden)) && (
<MobileDrawerTopGradient theme={theme} />
)} )}
{pinnedComment && showPinned && viewMode === VIEW_MODES.CHAT && ( {viewMode === VIEW_MODES.CHAT && superChatsByAmount && (
<div className="livestreamPinned__wrapper"> <LivestreamSuperchats
superChats={superChatsByAmount}
toggleSuperChat={toggleSuperChat}
superchatsHidden={superchatsHidden}
isMobile={isMobile}
/>
)}
{pinnedComment &&
viewMode === VIEW_MODES.CHAT &&
(isMobile ? (
<Slide direction="left" in={showPinned} mountOnEnter unmountOnExit>
<div className="livestream-pinned__wrapper--mobile">
<LivestreamComment
comment={pinnedComment}
key={pinnedComment.comment_id}
uri={uri}
pushMention={setMention}
handleDismissPin={() => setShowPinned(false)}
isMobile
/>
</div>
</Slide>
) : (
showPinned && (
<div className="livestream-pinned__wrapper">
<LivestreamComment <LivestreamComment
comment={pinnedComment} comment={pinnedComment}
key={pinnedComment.comment_id} key={pinnedComment.comment_id}
@ -262,7 +300,6 @@ export default function LivestreamChatLayout(props: Props) {
handleDismissPin={() => setShowPinned(false)} handleDismissPin={() => setShowPinned(false)}
/> />
{!isMobile && (
<Button <Button
title={__('Dismiss pinned comment')} title={__('Dismiss pinned comment')}
button="inverse" button="inverse"
@ -270,9 +307,9 @@ export default function LivestreamChatLayout(props: Props) {
onClick={() => setShowPinned(false)} onClick={() => setShowPinned(false)}
icon={ICONS.REMOVE} icon={ICONS.REMOVE}
/> />
)}
</div> </div>
)} )
))}
</div> </div>
{viewMode === VIEW_MODES.SUPERCHAT && resolvingSuperChats ? ( {viewMode === VIEW_MODES.SUPERCHAT && resolvingSuperChats ? (
@ -280,7 +317,12 @@ export default function LivestreamChatLayout(props: Props) {
<Spinner /> <Spinner />
</div> </div>
) : ( ) : (
<LivestreamComments uri={uri} commentsToDisplay={commentsToDisplay} pushMention={setMention} /> <LivestreamComments
uri={uri}
commentsToDisplay={commentsToDisplay}
pushMention={setMention}
isMobile={isMobile}
/>
)} )}
{scrollPos < 0 && ( {scrollPos < 0 && (
@ -308,3 +350,28 @@ export default function LivestreamChatLayout(props: Props) {
</div> </div>
); );
} }
type GradientProps = {
theme: string,
};
const MobileDrawerTopGradient = (gradientProps: GradientProps) => {
const { theme } = gradientProps;
const DrawerGlobalStyles = () => (
<Global
styles={{
'.livestream__top-gradient::after': {
background: `linear-gradient(180deg, ${theme === 'light' ? grey[300] : grey[900]} 0, transparent 65%)`,
},
}}
/>
);
return (
<>
<DrawerGlobalStyles />
<div className="livestream__top-gradient" />
</>
);
};

View file

@ -26,11 +26,12 @@ type Props = {
claim: StreamClaim, claim: StreamClaim,
myChannelIds: ?Array<string>, myChannelIds: ?Array<string>,
stakedLevel: number, stakedLevel: number,
isMobile?: boolean,
handleDismissPin?: () => void, handleDismissPin?: () => void,
}; };
export default function LivestreamComment(props: Props) { export default function LivestreamComment(props: Props) {
const { comment, forceUpdate, uri, claim, myChannelIds, stakedLevel, handleDismissPin } = props; const { comment, forceUpdate, uri, claim, myChannelIds, stakedLevel, isMobile, handleDismissPin } = props;
const { const {
channel_url: authorUri, channel_url: authorUri,
@ -65,6 +66,7 @@ export default function LivestreamComment(props: Props) {
'livestream__comment--superchat': supportAmount > 0, 'livestream__comment--superchat': supportAmount > 0,
'livestream__comment--sticker': isSticker, 'livestream__comment--sticker': isSticker,
'livestream__comment--mentioned': hasUserMention, 'livestream__comment--mentioned': hasUserMention,
'livestream__comment--mobile': isMobile,
})} })}
> >
{supportAmount > 0 && ( {supportAmount > 0 && (

View file

@ -11,10 +11,11 @@ type Props = {
commentsToDisplay: Array<Comment>, commentsToDisplay: Array<Comment>,
fetchingComments: boolean, fetchingComments: boolean,
uri: string, uri: string,
isMobile?: boolean,
}; };
export default function LivestreamComments(props: Props) { export default function LivestreamComments(props: Props) {
const { commentsToDisplay, fetchingComments, uri } = props; const { commentsToDisplay, fetchingComments, uri, isMobile } = props;
const [forceUpdate, setForceUpdate] = React.useState(0); const [forceUpdate, setForceUpdate] = React.useState(0);
@ -49,7 +50,13 @@ export default function LivestreamComments(props: Props) {
.slice(0) .slice(0)
.reverse() .reverse()
.map((comment) => ( .map((comment) => (
<LivestreamComment comment={comment} key={comment.comment_id} uri={uri} forceUpdate={forceUpdate} /> <LivestreamComment
comment={comment}
key={comment.comment_id}
uri={uri}
forceUpdate={forceUpdate}
isMobile={isMobile}
/>
))} ))}
</div> </div>
); );

View file

@ -1,4 +1,6 @@
// @flow // @flow
import 'scss/component/_swipeable-drawer.scss';
import { lazyImport } from 'util/lazyImport'; import { lazyImport } from 'util/lazyImport';
import { useIsMobile } from 'effects/use-screensize'; import { useIsMobile } from 'effects/use-screensize';
import { Menu, MenuList, MenuButton, MenuItem } from '@reach/menu-button'; import { Menu, MenuList, MenuButton, MenuItem } from '@reach/menu-button';
@ -8,9 +10,9 @@ import React from 'react';
import { PRIMARY_PLAYER_WRAPPER_CLASS } from 'page/file/view'; import { PRIMARY_PLAYER_WRAPPER_CLASS } from 'page/file/view';
import FileRenderInitiator from 'component/fileRenderInitiator'; import FileRenderInitiator from 'component/fileRenderInitiator';
import LivestreamIframeRender from './iframe-render'; import LivestreamIframeRender from './iframe-render';
import Button from 'component/button';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import SwipeableDrawer from 'component/swipeableDrawer'; import SwipeableDrawer from 'component/swipeableDrawer';
import { DrawerExpandButton } from 'component/swipeableDrawer/view';
import LivestreamMenu from 'component/livestreamChatLayout/livestream-menu'; import LivestreamMenu from 'component/livestreamChatLayout/livestream-menu';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import CreditAmount from 'component/common/credit-amount'; import CreditAmount from 'component/common/credit-amount';
@ -57,31 +59,6 @@ export default function LivestreamLayout(props: Props) {
if (!claim || !claim.signing_channel) return null; if (!claim || !claim.signing_channel) return null;
const { name: channelName, claim_id: channelClaimId } = claim.signing_channel; const { name: channelName, claim_id: channelClaimId } = claim.signing_channel;
const { superChatsFiatAmount, superChatsLBCAmount } = getTipValues(superChats);
const ChatModeSelector = () => (
<Menu>
<MenuButton>
<span className="swipeable-drawer__title-menu">
{chatViewMode === VIEW_MODES.CHAT ? __('Live Chat') : __('Super Chats')}
<Icon icon={ICONS.DOWN} />
</span>
</MenuButton>
<MenuList className="menu__list--header">
<MenuItem className="menu__link" onSelect={() => setChatViewMode(VIEW_MODES.CHAT)}>
{__('Live Chat')}
</MenuItem>
<MenuItem className="menu__link" onSelect={() => setChatViewMode(VIEW_MODES.SUPERCHAT)}>
<div className="recommended-content__toggles">
<CreditAmount amount={superChatsLBCAmount || 0} size={8} /> /
<CreditAmount amount={superChatsFiatAmount || 0} size={8} isFiat /> {__('Tipped')}
</div>
</MenuItem>
</MenuList>
</Menu>
);
return ( return (
<> <>
@ -132,12 +109,19 @@ export default function LivestreamLayout(props: Props) {
<SwipeableDrawer <SwipeableDrawer
open={Boolean(showChat)} open={Boolean(showChat)}
toggleDrawer={() => setShowChat(!showChat)} toggleDrawer={() => setShowChat(!showChat)}
title={<ChatModeSelector />} title={
<ChatModeSelector
superChats={superChats}
chatViewMode={chatViewMode}
setChatViewMode={(mode) => setChatViewMode(mode)}
/>
}
actions={ actions={
<LivestreamMenu <LivestreamMenu
noSuperchats={!superChats || superChats.length === 0} noSuperchats={!superChats || superChats.length === 0}
superchatsHidden={superchatsHidden} superchatsHidden={superchatsHidden}
toggleSuperchats={() => setSuperchatsHidden(!superchatsHidden)} toggleSuperchats={() => setSuperchatsHidden(!superchatsHidden)}
isMobile
/> />
} }
> >
@ -148,17 +132,9 @@ export default function LivestreamLayout(props: Props) {
customViewMode={chatViewMode} customViewMode={chatViewMode}
/> />
</SwipeableDrawer> </SwipeableDrawer>
</React.Suspense>
)}
{isMobile && ( <DrawerExpandButton label={__('Open Live Chat')} toggleDrawer={() => setShowChat(!showChat)} />
<Button </React.Suspense>
className="swipeable-drawer__expand-button"
label="Open Live Chat"
button="primary"
icon={ICONS.CHAT}
onClick={() => setShowChat(!showChat)}
/>
)} )}
<FileTitleSection uri={uri} livestream isLive={showLivestream} /> <FileTitleSection uri={uri} livestream isLive={showLivestream} />
@ -166,3 +142,36 @@ export default function LivestreamLayout(props: Props) {
</> </>
); );
} }
const ChatModeSelector = (chatSelectorProps: any) => {
const { superChats, chatViewMode, setChatViewMode } = chatSelectorProps;
const { superChatsFiatAmount, superChatsLBCAmount } = getTipValues(superChats);
if (!superChats) {
return __('Live Chat');
}
return (
<Menu>
<MenuButton>
<span className="swipeable-drawer__title-menu">
{chatViewMode === VIEW_MODES.CHAT ? __('Live Chat') : __('Super Chats')}
<Icon icon={ICONS.DOWN} />
</span>
</MenuButton>
<MenuList className="menu__list--header">
<MenuItem className="menu__link" onSelect={() => setChatViewMode(VIEW_MODES.CHAT)}>
{__('Live Chat')}
</MenuItem>
<MenuItem className="menu__link" onSelect={() => setChatViewMode(VIEW_MODES.SUPERCHAT)}>
<div className="recommended-content__toggles">
<CreditAmount amount={superChatsLBCAmount || 0} size={8} /> /
<CreditAmount amount={superChatsFiatAmount || 0} size={8} isFiat /> {__('Tipped')}
</div>
</MenuItem>
</MenuList>
</Menu>
);
};

View file

@ -1,4 +1,6 @@
// @flow // @flow
import 'scss/component/_swipeable-drawer.scss';
// $FlowFixMe // $FlowFixMe
import { Global } from '@emotion/react'; import { Global } from '@emotion/react';
// $FlowFixMe // $FlowFixMe
@ -14,7 +16,7 @@ const DRAWER_PULLER_HEIGHT = 42;
type Props = { type Props = {
children: Node, children: Node,
open: Boolean, open: boolean,
theme: string, theme: string,
mobilePlayerDimensions?: { height: number }, mobilePlayerDimensions?: { height: number },
title: any, title: any,
@ -60,22 +62,6 @@ export default function SwipeableDrawer(props: Props) {
/> />
); );
const Puller = () => (
<span className="swipeable-drawer__puller" style={{ backgroundColor: theme === 'light' ? grey[300] : grey[800] }} />
);
const HeaderContents = () => (
<div className="swipeable-drawer__header-content">
{title}
<div className="swipeable-drawer__header-actions">
{actions}
<Button icon={ICONS.REMOVE} iconSize={16} onClick={toggleDrawer} />
</div>
</div>
);
return ( return (
<> <>
<DrawerGlobalStyles /> <DrawerGlobalStyles />
@ -93,8 +79,8 @@ export default function SwipeableDrawer(props: Props) {
> >
{open && ( {open && (
<div className="swipeable-drawer__header" style={{ top: -DRAWER_PULLER_HEIGHT }}> <div className="swipeable-drawer__header" style={{ top: -DRAWER_PULLER_HEIGHT }}>
<Puller /> <Puller theme={theme} />
<HeaderContents /> <HeaderContents title={title} actions={actions} toggleDrawer={toggleDrawer} />
</div> </div>
)} )}
@ -103,3 +89,56 @@ export default function SwipeableDrawer(props: Props) {
</> </>
); );
} }
type PullerProps = {
theme: string,
};
const Puller = (pullerProps: PullerProps) => {
const { theme } = pullerProps;
return (
<span className="swipeable-drawer__puller" style={{ backgroundColor: theme === 'light' ? grey[300] : grey[800] }} />
);
};
type HeaderProps = {
title: any,
actions?: any,
toggleDrawer: () => void,
};
const HeaderContents = (headerProps: HeaderProps) => {
const { title, actions, toggleDrawer } = headerProps;
return (
<div className="swipeable-drawer__header-content">
{title}
<div className="swipeable-drawer__header-actions">
{actions}
<Button icon={ICONS.REMOVE} iconSize={16} onClick={toggleDrawer} />
</div>
</div>
);
};
type ExpandButtonProps = {
label: any,
toggleDrawer: () => void,
};
export const DrawerExpandButton = (expandButtonProps: ExpandButtonProps) => {
const { label, toggleDrawer } = expandButtonProps;
return (
<Button
className="swipeable-drawer__expand-button"
label={label}
button="primary"
icon={ICONS.CHAT}
onClick={toggleDrawer}
/>
);
};

View file

@ -16,7 +16,7 @@ import Button from 'component/button';
import I18nMessage from 'component/i18nMessage'; import I18nMessage from 'component/i18nMessage';
import Empty from 'component/common/empty'; import Empty from 'component/common/empty';
import SwipeableDrawer from 'component/swipeableDrawer'; import SwipeableDrawer from 'component/swipeableDrawer';
import * as ICONS from 'constants/icons'; import { DrawerExpandButton } from 'component/swipeableDrawer/view';
import { useIsMobile } from 'effects/use-screensize'; import { useIsMobile } from 'effects/use-screensize';
const CommentsList = lazyImport(() => import('component/commentsList' /* webpackChunkName: "comments" */)); const CommentsList = lazyImport(() => import('component/commentsList' /* webpackChunkName: "comments" */));
@ -199,7 +199,7 @@ export default function FilePage(props: Props) {
{!isMarkdown && ( {!isMarkdown && (
<div className="file-page__secondary-content"> <div className="file-page__secondary-content">
<> <section className="file-page__media-actions">
{claimIsMine && isLivestream && ( {claimIsMine && isLivestream && (
<div className="livestream__creator-message"> <div className="livestream__creator-message">
<h4>{__('Only visible to you')}</h4> <h4>{__('Only visible to you')}</h4>
@ -215,7 +215,9 @@ export default function FilePage(props: Props) {
{RENDER_MODES.FLOATING_MODES.includes(renderMode) && <FileTitleSection uri={uri} />} {RENDER_MODES.FLOATING_MODES.includes(renderMode) && <FileTitleSection uri={uri} />}
<React.Suspense fallback={null}>
{isMobile ? ( {isMobile ? (
<>
<SwipeableDrawer <SwipeableDrawer
open={Boolean(showComments)} open={Boolean(showComments)}
toggleDrawer={() => setShowComments(!showComments)} toggleDrawer={() => setShowComments(!showComments)}
@ -223,20 +225,14 @@ export default function FilePage(props: Props) {
> >
{commentsListElement} {commentsListElement}
</SwipeableDrawer> </SwipeableDrawer>
<DrawerExpandButton label={commentsListTitle} toggleDrawer={() => setShowComments(!showComments)} />
</>
) : ( ) : (
commentsListElement commentsListElement
)} )}
</> </React.Suspense>
</section>
{isMobile && (
<Button
className="swipeable-drawer__expand-button"
label={commentsListTitle}
button="primary"
icon={ICONS.CHAT}
onClick={() => setShowComments(!showComments)}
/>
)}
{!isMarkdown && videoTheaterMode && <RightSideContent {...rightSideProps} />} {!isMarkdown && videoTheaterMode && <RightSideContent {...rightSideProps} />}
</div> </div>

View file

@ -68,5 +68,4 @@
@import 'component/stripe-card'; @import 'component/stripe-card';
@import 'component/wallet-tip-send'; @import 'component/wallet-tip-send';
@import 'component/swipe-list'; @import 'component/swipe-list';
@import 'component/swipeable-drawer';
@import 'component/utils'; @import 'component/utils';

View file

@ -293,11 +293,36 @@
padding-bottom: 0; padding-bottom: 0;
margin: 0; margin: 0;
.card__title-section {
padding: 0px;
}
h1 { h1 {
font-size: 1.2rem; font-size: 1.2rem;
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
line-height: 1.25; line-height: 1.25;
} }
h2 {
font-size: 1.2rem;
line-height: 1.25;
}
.recommended-content__toggles {
button {
height: unset;
padding: 2px var(--spacing-xxs);
.button__content {
height: unset;
span {
font-size: var(--font-small);
line-height: 1.25;
}
}
}
}
} }
} }

View file

@ -43,11 +43,11 @@ $recent-msg-button__height: 2rem;
height: 95vh !important; height: 95vh !important;
} }
.livestreamSuperchats__wrapper { .livestream-superchats__wrapper {
width: 100%; width: 100%;
} }
.livestreamPinned__wrapper { .livestream-pinned__wrapper {
width: 100%; width: 100%;
} }
} }
@ -168,7 +168,7 @@ $recent-msg-button__height: 2rem;
} }
} }
.livestreamSuperchats__wrapper { .livestream-superchats__wrapper {
flex-shrink: 0; flex-shrink: 0;
position: relative; position: relative;
overflow-x: scroll; overflow-x: scroll;
@ -181,8 +181,11 @@ $recent-msg-button__height: 2rem;
padding: var(--spacing-xs); padding: var(--spacing-xs);
width: var(--livestream-comments-width); width: var(--livestream-comments-width);
} }
}
.livestream-superchats__wrapper--mobile {
@extend .livestream-superchats__wrapper;
@media (max-width: $breakpoint-small) {
z-index: 1300; z-index: 1300;
width: 100%; width: 100%;
background-color: transparent; background-color: transparent;
@ -194,11 +197,10 @@ $recent-msg-button__height: 2rem;
width: 0px; width: 0px;
height: 0px; height: 0px;
} }
}
} }
.livestream-comments__top-actions { .livestream-comments__top-actions--mobile {
@media (max-width: $breakpoint-small) { width: 100%;
position: absolute; position: absolute;
display: grid; display: grid;
padding: var(--spacing-xxs); padding: var(--spacing-xxs);
@ -207,10 +209,26 @@ $recent-msg-button__height: 2rem;
> div:not(:first-child) { > div:not(:first-child) {
margin-top: var(--spacing-xxs); margin-top: var(--spacing-xxs);
} }
.livestream__top-gradient {
width: 100%;
height: 100%;
position: absolute;
&:after {
position: absolute;
bottom: 0;
opacity: 1;
content: '';
height: 100%;
left: 0;
right: 0;
width: 100%;
}
} }
} }
.livestreamPinned__wrapper { .livestream-pinned__wrapper {
display: flex; display: flex;
flex-shrink: 0; flex-shrink: 0;
position: relative; position: relative;
@ -237,8 +255,11 @@ $recent-msg-button__height: 2rem;
padding: var(--spacing-xs); padding: var(--spacing-xs);
width: var(--livestream-comments-width); width: var(--livestream-comments-width);
} }
}
.livestream-pinned__wrapper--mobile {
@extend .livestream-pinned__wrapper;
@media (max-width: $breakpoint-small) {
z-index: 1300; z-index: 1300;
max-width: 100%; max-width: 100%;
padding: 0; padding: 0;
@ -277,7 +298,6 @@ $recent-msg-button__height: 2rem;
padding: 0; padding: 0;
padding-left: var(--spacing-xxs); padding-left: var(--spacing-xxs);
} }
}
} }
.livestreamSuperchat__amount--large { .livestreamSuperchat__amount--large {
@ -288,7 +308,7 @@ $recent-msg-button__height: 2rem;
} }
} }
.livestreamSuperchats__inner { .livestream-superchats {
display: flex; display: flex;
.close-button { .close-button {
@ -296,7 +316,7 @@ $recent-msg-button__height: 2rem;
} }
} }
.livestream__superchat { .livestream-superchat {
display: flex; display: flex;
margin-right: var(--spacing-xs); margin-right: var(--spacing-xs);
padding: var(--spacing-xxs); padding: var(--spacing-xxs);
@ -347,8 +367,11 @@ $recent-msg-button__height: 2rem;
.channel-name { .channel-name {
max-width: 5rem; max-width: 5rem;
} }
}
.livestream-superchat--mobile {
@extend .livestream-superchat;
@media (max-width: $breakpoint-small) {
background-color: #fff; background-color: #fff;
padding: 5px; padding: 5px;
padding-bottom: 2px; padding-bottom: 2px;
@ -356,7 +379,6 @@ $recent-msg-button__height: 2rem;
span { span {
font-size: var(--font-xxsmall); font-size: var(--font-xxsmall);
} }
}
} }
.livestreamSuperchat__info { .livestreamSuperchat__info {

View file

@ -30,8 +30,11 @@
.channel-name { .channel-name {
font-size: var(--font-xsmall); font-size: var(--font-xsmall);
} }
}
.livestream__comment--mobile {
@extend .livestream__comment;
@media (max-width: $breakpoint-small) {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -45,7 +48,6 @@
p { p {
font-size: var(--font-xxsmall) !important; font-size: var(--font-xxsmall) !important;
} }
}
} }
.livestream__comment--mentioned { .livestream__comment--mentioned {

View file

@ -169,6 +169,12 @@
margin-left: 0; margin-left: 0;
margin-top: var(--spacing-l); margin-top: var(--spacing-l);
} }
@media (max-width: $breakpoint-small) {
.card__header--between {
padding: var(--spacing-xxs);
}
}
} }
.file-page__recommended-collection { .file-page__recommended-collection {

View file

@ -160,6 +160,10 @@
width: unset; width: unset;
height: 2rem; height: 2rem;
} }
.icon--Plus {
top: -2px;
}
} }
} }

View file

@ -9,6 +9,10 @@
top: 2px !important; top: 2px !important;
right: 2px !important; right: 2px !important;
} }
span {
color: var(--color-text);
}
} }
.swipeable-drawer__puller { .swipeable-drawer__puller {
@ -40,6 +44,10 @@
.swipeable-drawer__header-actions { .swipeable-drawer__header-actions {
display: flex; display: flex;
button {
padding: 0.3rem;
}
button:not(:last-child) { button:not(:last-child) {
margin-right: var(--spacing-xxs); margin-right: var(--spacing-xxs);
} }
@ -48,7 +56,7 @@
.swipeable-drawer__expand-button { .swipeable-drawer__expand-button {
width: 100%; width: 100%;
margin: var(--spacing-xxs) 0; margin: var(--spacing-xxs) 0;
border-radius: 0; border-radius: 0 !important;
} }
.swipeable-drawer__expand { .swipeable-drawer__expand {

View file

@ -24,6 +24,7 @@
.MuiOutlinedInput-root { .MuiOutlinedInput-root {
font-size: var(--font-xsmall) !important; font-size: var(--font-xsmall) !important;
flex-wrap: nowrap !important; flex-wrap: nowrap !important;
color: var(--color-text) !important;
textarea { textarea {
border: none; border: none;
@ -38,6 +39,10 @@
height: unset; height: unset;
} }
} }
span {
color: var(--color-text) !important;
}
} }
} }