add video theater mode button
This commit is contained in:
parent
b43593a996
commit
d43c4d053e
19 changed files with 206 additions and 24 deletions
|
@ -26,6 +26,7 @@ const select = (state, props) => {
|
||||||
streamingUrl: makeSelectStreamingUrlForUri(uri)(state),
|
streamingUrl: makeSelectStreamingUrlForUri(uri)(state),
|
||||||
floatingPlayerEnabled: makeSelectClientSetting(SETTINGS.FLOATING_PLAYER)(state),
|
floatingPlayerEnabled: makeSelectClientSetting(SETTINGS.FLOATING_PLAYER)(state),
|
||||||
renderMode: makeSelectFileRenderModeForUri(uri)(state),
|
renderMode: makeSelectFileRenderModeForUri(uri)(state),
|
||||||
|
videoTheaterMode: makeSelectClientSetting(SETTINGS.VIDEO_THEATER_MODE)(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ type Props = {
|
||||||
renderMode: string,
|
renderMode: string,
|
||||||
playingUri: ?PlayingUri,
|
playingUri: ?PlayingUri,
|
||||||
primaryUri: ?string,
|
primaryUri: ?string,
|
||||||
|
videoTheaterMode: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function FileRenderFloating(props: Props) {
|
export default function FileRenderFloating(props: Props) {
|
||||||
|
@ -45,6 +46,7 @@ export default function FileRenderFloating(props: Props) {
|
||||||
renderMode,
|
renderMode,
|
||||||
playingUri,
|
playingUri,
|
||||||
primaryUri,
|
primaryUri,
|
||||||
|
videoTheaterMode,
|
||||||
} = props;
|
} = props;
|
||||||
const {
|
const {
|
||||||
location: { pathname },
|
location: { pathname },
|
||||||
|
@ -187,7 +189,7 @@ export default function FileRenderFloating(props: Props) {
|
||||||
window.removeEventListener('resize', handleResize);
|
window.removeEventListener('resize', handleResize);
|
||||||
onFullscreenChange(window, 'remove', handleResize);
|
onFullscreenChange(window, 'remove', handleResize);
|
||||||
};
|
};
|
||||||
}, [setFileViewerRect, isFloating, playingUriSource, mainFilePlaying]);
|
}, [setFileViewerRect, isFloating, playingUriSource, mainFilePlaying, videoTheaterMode]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// @if TARGET='app'
|
// @if TARGET='app'
|
||||||
|
@ -248,6 +250,7 @@ export default function FileRenderFloating(props: Props) {
|
||||||
className={classnames('content__viewer', {
|
className={classnames('content__viewer', {
|
||||||
'content__viewer--floating': isFloating,
|
'content__viewer--floating': isFloating,
|
||||||
'content__viewer--inline': !isFloating,
|
'content__viewer--inline': !isFloating,
|
||||||
|
'content__viewer--theater-mode': !isFloating && videoTheaterMode,
|
||||||
})}
|
})}
|
||||||
style={
|
style={
|
||||||
!isFloating && fileViewerRect
|
!isFloating && fileViewerRect
|
||||||
|
|
|
@ -32,6 +32,7 @@ type Props = {
|
||||||
claim: StreamClaim,
|
claim: StreamClaim,
|
||||||
claimWasPurchased: boolean,
|
claimWasPurchased: boolean,
|
||||||
authenticated: boolean,
|
authenticated: boolean,
|
||||||
|
videoTheaterMode: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function FileRenderInitiator(props: Props) {
|
export default function FileRenderInitiator(props: Props) {
|
||||||
|
@ -51,6 +52,7 @@ export default function FileRenderInitiator(props: Props) {
|
||||||
costInfo,
|
costInfo,
|
||||||
claimWasPurchased,
|
claimWasPurchased,
|
||||||
authenticated,
|
authenticated,
|
||||||
|
videoTheaterMode,
|
||||||
} = props;
|
} = props;
|
||||||
const cost = costInfo && costInfo.cost;
|
const cost = costInfo && costInfo.cost;
|
||||||
const isFree = hasCostInfo && cost === 0;
|
const isFree = hasCostInfo && cost === 0;
|
||||||
|
@ -118,6 +120,7 @@ export default function FileRenderInitiator(props: Props) {
|
||||||
style={thumbnail && !obscurePreview ? { backgroundImage: `url("${thumbnail}")` } : {}}
|
style={thumbnail && !obscurePreview ? { backgroundImage: `url("${thumbnail}")` } : {}}
|
||||||
className={classnames('content__cover', {
|
className={classnames('content__cover', {
|
||||||
'content__cover--disabled': disabled,
|
'content__cover--disabled': disabled,
|
||||||
|
'content__cover--theater-mode': videoTheaterMode,
|
||||||
'card__media--nsfw': obscurePreview,
|
'card__media--nsfw': obscurePreview,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
|
import { SETTINGS } from 'lbry-redux';
|
||||||
import Page from './view';
|
import Page from './view';
|
||||||
|
|
||||||
export default connect()(Page);
|
const select = (state, props) => ({
|
||||||
|
videoTheaterMode: makeSelectClientSetting(SETTINGS.VIDEO_THEATER_MODE)(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select)(Page);
|
||||||
|
|
|
@ -26,6 +26,7 @@ type Props = {
|
||||||
noFooter: boolean,
|
noFooter: boolean,
|
||||||
noSideNavigation: boolean,
|
noSideNavigation: boolean,
|
||||||
fullWidthPage: boolean,
|
fullWidthPage: boolean,
|
||||||
|
videoTheaterMode: boolean,
|
||||||
backout: {
|
backout: {
|
||||||
backLabel?: string,
|
backLabel?: string,
|
||||||
backNavDefault?: string,
|
backNavDefault?: string,
|
||||||
|
@ -45,7 +46,9 @@ function Page(props: Props) {
|
||||||
noFooter = false,
|
noFooter = false,
|
||||||
noSideNavigation = false,
|
noSideNavigation = false,
|
||||||
backout,
|
backout,
|
||||||
|
videoTheaterMode,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
location: { pathname },
|
location: { pathname },
|
||||||
} = useHistory();
|
} = useHistory();
|
||||||
|
@ -82,7 +85,12 @@ function Page(props: Props) {
|
||||||
setSidebarOpen={setSidebarOpen}
|
setSidebarOpen={setSidebarOpen}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className={classnames('main-wrapper__inner', { 'main-wrapper__inner--filepage': isOnFilePage })}>
|
<div
|
||||||
|
className={classnames('main-wrapper__inner', {
|
||||||
|
'main-wrapper__inner--filepage': isOnFilePage,
|
||||||
|
'main-wrapper__inner--theater-mode': isOnFilePage && videoTheaterMode,
|
||||||
|
})}
|
||||||
|
>
|
||||||
{!authPage && !noSideNavigation && (
|
{!authPage && !noSideNavigation && (
|
||||||
<SideNavigation
|
<SideNavigation
|
||||||
sidebarOpen={sidebarOpen}
|
sidebarOpen={sidebarOpen}
|
||||||
|
@ -96,6 +104,7 @@ function Page(props: Props) {
|
||||||
'main--full-width': fullWidthPage,
|
'main--full-width': fullWidthPage,
|
||||||
'main--auth-page': authPage,
|
'main--auth-page': authPage,
|
||||||
'main--file-page': filePage,
|
'main--file-page': filePage,
|
||||||
|
'main--theater-mode': isOnFilePage && videoTheaterMode,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -55,7 +55,6 @@ export default function RecommendedContent(props: Props) {
|
||||||
title={__('Related')}
|
title={__('Related')}
|
||||||
body={
|
body={
|
||||||
<ClaimList
|
<ClaimList
|
||||||
isCardBody
|
|
||||||
type="small"
|
type="small"
|
||||||
loading={isSearching}
|
loading={isSearching}
|
||||||
uris={recommendedContent}
|
uris={recommendedContent}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import VideoViewer from './view';
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
|
import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
|
import { toggleVideoTheaterMode } from 'redux/actions/settings';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const { search } = props.location;
|
const { search } = props.location;
|
||||||
|
@ -35,6 +36,7 @@ const perform = dispatch => ({
|
||||||
doAnalyticsView: (uri, timeToStart) => dispatch(doAnalyticsView(uri, timeToStart)),
|
doAnalyticsView: (uri, timeToStart) => dispatch(doAnalyticsView(uri, timeToStart)),
|
||||||
doAnalyticsBuffer: (uri, bufferData) => dispatch(doAnalyticsBuffer(uri, bufferData)),
|
doAnalyticsBuffer: (uri, bufferData) => dispatch(doAnalyticsBuffer(uri, bufferData)),
|
||||||
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
|
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
|
||||||
|
toggleVideoTheaterMode: () => dispatch(toggleVideoTheaterMode()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default withRouter(connect(select, perform)(VideoViewer));
|
export default withRouter(connect(select, perform)(VideoViewer));
|
||||||
|
|
16
ui/component/viewers/videoViewer/internal/theater-mode.js
Normal file
16
ui/component/viewers/videoViewer/internal/theater-mode.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// @flow
|
||||||
|
import type { Player } from './videojs';
|
||||||
|
|
||||||
|
export function addTheaterModeButton(player: Player, toggleVideoTheaterMode: () => void) {
|
||||||
|
var myButton = player.controlBar.addChild('button', {
|
||||||
|
text: __('Theater mode'),
|
||||||
|
clickHandler: () => {
|
||||||
|
toggleVideoTheaterMode();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
myButton.addClass('vjs-button--theater-mode');
|
||||||
|
// $FlowFixMe
|
||||||
|
myButton.setAttribute('title', __('Theater mode'));
|
||||||
|
}
|
|
@ -31,6 +31,9 @@ export type Player = {
|
||||||
userActive: (?boolean) => boolean,
|
userActive: (?boolean) => boolean,
|
||||||
overlay: any => void,
|
overlay: any => void,
|
||||||
mobileUi: any => void,
|
mobileUi: any => void,
|
||||||
|
controlBar: {
|
||||||
|
addChild: (string, any) => void,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -3,7 +3,6 @@ import React, { useEffect, useState, useContext, useCallback } from 'react';
|
||||||
import { stopContextMenu } from 'util/context-menu';
|
import { stopContextMenu } from 'util/context-menu';
|
||||||
import type { Player } from './internal/videojs';
|
import type { Player } from './internal/videojs';
|
||||||
import VideoJs from './internal/videojs';
|
import VideoJs from './internal/videojs';
|
||||||
|
|
||||||
import analytics from 'analytics';
|
import analytics from 'analytics';
|
||||||
import { EmbedContext } from 'page/embedWrapper/view';
|
import { EmbedContext } from 'page/embedWrapper/view';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
@ -13,6 +12,7 @@ import usePrevious from 'effects/use-previous';
|
||||||
import FileViewerEmbeddedEnded from 'web/component/fileViewerEmbeddedEnded';
|
import FileViewerEmbeddedEnded from 'web/component/fileViewerEmbeddedEnded';
|
||||||
import FileViewerEmbeddedTitle from 'component/fileViewerEmbeddedTitle';
|
import FileViewerEmbeddedTitle from 'component/fileViewerEmbeddedTitle';
|
||||||
import LoadingScreen from 'component/common/loading-screen';
|
import LoadingScreen from 'component/common/loading-screen';
|
||||||
|
import { addTheaterModeButton } from './internal/theater-mode';
|
||||||
|
|
||||||
const PLAY_TIMEOUT_ERROR = 'play_timeout_error';
|
const PLAY_TIMEOUT_ERROR = 'play_timeout_error';
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ type Props = {
|
||||||
claimRewards: () => void,
|
claimRewards: () => void,
|
||||||
savePosition: (string, number) => void,
|
savePosition: (string, number) => void,
|
||||||
clearPosition: string => void,
|
clearPosition: string => void,
|
||||||
|
toggleVideoTheaterMode: () => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -62,6 +63,7 @@ function VideoViewer(props: Props) {
|
||||||
savePosition,
|
savePosition,
|
||||||
clearPosition,
|
clearPosition,
|
||||||
desktopPlayStartTime,
|
desktopPlayStartTime,
|
||||||
|
toggleVideoTheaterMode,
|
||||||
} = props;
|
} = props;
|
||||||
const claimId = claim && claim.claim_id;
|
const claimId = claim && claim.claim_id;
|
||||||
const isAudio = contentType.includes('audio');
|
const isAudio = contentType.includes('audio');
|
||||||
|
@ -135,6 +137,8 @@ function VideoViewer(props: Props) {
|
||||||
if (!embedded) {
|
if (!embedded) {
|
||||||
player.muted(muted);
|
player.muted(muted);
|
||||||
player.volume(volume);
|
player.volume(volume);
|
||||||
|
|
||||||
|
addTheaterModeButton(player, toggleVideoTheaterMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldPlay = !embedded || autoplayIfEmbedded;
|
const shouldPlay = !embedded || autoplayIfEmbedded;
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doSetContentHistoryItem, doSetPrimaryUri } from 'redux/actions/content';
|
import { doSetContentHistoryItem, doSetPrimaryUri } from 'redux/actions/content';
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
import { doFetchFileInfo, makeSelectFileInfoForUri, makeSelectMetadataForUri, makeSelectClaimIsNsfw } from 'lbry-redux';
|
import {
|
||||||
|
doFetchFileInfo,
|
||||||
|
makeSelectFileInfoForUri,
|
||||||
|
makeSelectMetadataForUri,
|
||||||
|
makeSelectClaimIsNsfw,
|
||||||
|
SETTINGS,
|
||||||
|
} from 'lbry-redux';
|
||||||
import { makeSelectCostInfoForUri, doFetchCostInfoForUri } from 'lbryinc';
|
import { makeSelectCostInfoForUri, doFetchCostInfoForUri } from 'lbryinc';
|
||||||
import { selectShowMatureContent } from 'redux/selectors/settings';
|
import { selectShowMatureContent, makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import { makeSelectFileRenderModeForUri } from 'redux/selectors/content';
|
import { makeSelectFileRenderModeForUri } from 'redux/selectors/content';
|
||||||
import { makeSelectCommentForCommentId } from 'redux/selectors/comments';
|
import { makeSelectCommentForCommentId } from 'redux/selectors/comments';
|
||||||
import FilePage from './view';
|
import FilePage from './view';
|
||||||
|
@ -21,6 +27,7 @@ const select = (state, props) => {
|
||||||
isMature: makeSelectClaimIsNsfw(props.uri)(state),
|
isMature: makeSelectClaimIsNsfw(props.uri)(state),
|
||||||
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
||||||
renderMode: makeSelectFileRenderModeForUri(props.uri)(state),
|
renderMode: makeSelectFileRenderModeForUri(props.uri)(state),
|
||||||
|
videoTheaterMode: makeSelectClientSetting(SETTINGS.VIDEO_THEATER_MODE)(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ type Props = {
|
||||||
isMature: boolean,
|
isMature: boolean,
|
||||||
linkedComment: any,
|
linkedComment: any,
|
||||||
setPrimaryUri: (?string) => void,
|
setPrimaryUri: (?string) => void,
|
||||||
|
videoTheaterMode: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function FilePage(props: Props) {
|
function FilePage(props: Props) {
|
||||||
|
@ -39,6 +40,7 @@ function FilePage(props: Props) {
|
||||||
costInfo,
|
costInfo,
|
||||||
linkedComment,
|
linkedComment,
|
||||||
setPrimaryUri,
|
setPrimaryUri,
|
||||||
|
videoTheaterMode,
|
||||||
} = props;
|
} = props;
|
||||||
const cost = costInfo ? costInfo.cost : null;
|
const cost = costInfo ? costInfo.cost : null;
|
||||||
const hasFileInfo = fileInfo !== undefined;
|
const hasFileInfo = fileInfo !== undefined;
|
||||||
|
@ -67,10 +69,9 @@ function FilePage(props: Props) {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className={PRIMARY_PLAYER_WRAPPER_CLASS}>
|
<div className={PRIMARY_PLAYER_WRAPPER_CLASS}>
|
||||||
<FileRenderInitiator uri={uri} />
|
<FileRenderInitiator uri={uri} videoTheaterMode={videoTheaterMode} />
|
||||||
</div>
|
</div>
|
||||||
{/* playables will be rendered and injected by <FileRenderFloating> */}
|
{/* playables will be rendered and injected by <FileRenderFloating> */}
|
||||||
<FileTitle uri={uri} />
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -96,14 +97,14 @@ function FilePage(props: Props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<FileRenderInitiator uri={uri} />
|
<FileRenderInitiator uri={uri} videoTheaterMode={videoTheaterMode} />
|
||||||
<FileRenderInline uri={uri} />
|
<FileRenderInline uri={uri} />
|
||||||
<FileTitle uri={uri} />
|
<FileTitle uri={uri} />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderBlockedPage() {
|
if (obscureNsfw && isMature) {
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<FileTitle uri={uri} isNsfwBlocked />
|
<FileTitle uri={uri} isNsfwBlocked />
|
||||||
|
@ -111,19 +112,21 @@ function FilePage(props: Props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obscureNsfw && isMature) {
|
|
||||||
return renderBlockedPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page className="file-page" filePage>
|
<Page className="file-page" filePage>
|
||||||
<div className={classnames('section card-stack', `file-page__${renderMode}`)}>
|
<div className={classnames('section card-stack', `file-page__${renderMode}`)}>
|
||||||
{renderFilePageLayout()}
|
{renderFilePageLayout()}
|
||||||
|
|
||||||
<CommentsList uri={uri} linkedComment={linkedComment} />
|
<div className="file-page__secondary-content">
|
||||||
|
<div>
|
||||||
|
{RENDER_MODES.FLOATING_MODES.includes(renderMode) && <FileTitle uri={uri} />}
|
||||||
|
<CommentsList uri={uri} linkedComment={linkedComment} />
|
||||||
|
</div>
|
||||||
|
{videoTheaterMode && <RecommendedContent uri={uri} />}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<RecommendedContent uri={uri} />
|
{!videoTheaterMode && <RecommendedContent uri={uri} />}
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -414,3 +414,12 @@ export function doSetAppToTrayWhenClosed(value) {
|
||||||
dispatch(doSetClientSetting(SETTINGS.TO_TRAY_WHEN_CLOSED, value));
|
dispatch(doSetClientSetting(SETTINGS.TO_TRAY_WHEN_CLOSED, value));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toggleVideoTheaterMode() {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const state = getState();
|
||||||
|
const videoTheaterMode = makeSelectClientSetting(SETTINGS.VIDEO_THEATER_MODE)(state);
|
||||||
|
|
||||||
|
dispatch(doSetClientSetting(SETTINGS.VIDEO_THEATER_MODE, !videoTheaterMode));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ const defaultState = {
|
||||||
[SETTINGS.OS_NOTIFICATIONS_ENABLED]: true,
|
[SETTINGS.OS_NOTIFICATIONS_ENABLED]: true,
|
||||||
[SETTINGS.AUTOMATIC_DARK_MODE_ENABLED]: false,
|
[SETTINGS.AUTOMATIC_DARK_MODE_ENABLED]: false,
|
||||||
[SETTINGS.TILE_LAYOUT]: true,
|
[SETTINGS.TILE_LAYOUT]: true,
|
||||||
|
[SETTINGS.VIDEO_THEATER_MODE]: false,
|
||||||
|
|
||||||
[SETTINGS.DARK_MODE_TIMES]: {
|
[SETTINGS.DARK_MODE_TIMES]: {
|
||||||
from: { hour: '21', min: '00', formattedTime: '21:00' },
|
from: { hour: '21', min: '00', formattedTime: '21:00' },
|
||||||
|
|
|
@ -94,6 +94,42 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vjs-control-bar {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1 !important;
|
||||||
|
transition: visibility 1s, opacity 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-fullscreen-control {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-button--theater-mode.vjs-button {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
@media (min-width: $breakpoint-medium) {
|
||||||
|
display: block;
|
||||||
|
order: 1;
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
margin-top: 0.3rem;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='14' viewBox='0 -2 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-monitor'%3E%3Crect x='2' y='3' width='20' height='14' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='8' y1='21' x2='16' y2='21'%3E%3C/line%3E%3Cline x1='12' y1='17' x2='12' y2='21'%3E%3C/line%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus:not(:focus-visible) {
|
||||||
|
// Need to repeat these styles because of videojs weirdness
|
||||||
|
background: black
|
||||||
|
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='14' viewBox='0 -2 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-monitor'%3E%3Crect x='2' y='3' width='20' height='14' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='8' y1='21' x2='16' y2='21'%3E%3C/line%3E%3Cline x1='12' y1='17' x2='12' y2='21'%3E%3C/line%3E%3C/svg%3E")
|
||||||
|
no-repeat center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-icon-placeholder {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.button--link {
|
.button--link {
|
||||||
color: var(--color-link);
|
color: var(--color-link);
|
||||||
transition: color 0.2s;
|
transition: color 0.2s;
|
||||||
|
|
|
@ -24,6 +24,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content__viewer--theater-mode {
|
||||||
|
top: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
.content__wrapper {
|
.content__wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -33,6 +39,10 @@
|
||||||
.content__wrapper--floating {
|
.content__wrapper--floating {
|
||||||
height: var(--floating-viewer-height);
|
height: var(--floating-viewer-height);
|
||||||
width: var(--floating-viewer-width);
|
width: var(--floating-viewer-width);
|
||||||
|
|
||||||
|
.vjs-button--theater-mode {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content__actions {
|
.content__actions {
|
||||||
|
@ -107,6 +117,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content__cover--theater-mode {
|
||||||
|
@extend .content__cover;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.content__cover--none {
|
.content__cover--none {
|
||||||
@include thumbnail;
|
@include thumbnail;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|
|
@ -39,6 +39,10 @@
|
||||||
padding-top: var(--spacing-s);
|
padding-top: var(--spacing-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main-wrapper__inner--theater-mode {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: calc(100% - var(--side-nav-width) - var(--spacing-l));
|
width: calc(100% - var(--side-nav-width) - var(--spacing-l));
|
||||||
|
@ -65,15 +69,43 @@
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
padding-left: var(--spacing-m);
|
padding-left: var(--spacing-m);
|
||||||
padding-right: var(--spacing-m);
|
padding-right: var(--spacing-m);
|
||||||
|
position: relative;
|
||||||
|
|
||||||
> :first-child {
|
> :first-child {
|
||||||
flex: 1;
|
flex-grow: 2;
|
||||||
margin-right: var(--spacing-m);
|
}
|
||||||
|
|
||||||
|
.file-page__secondary-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: var(--spacing-m);
|
||||||
|
max-width: var(--page-max-width--filepage);
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
|
||||||
|
> :first-child {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $breakpoint-medium) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-page__info {
|
||||||
|
margin-top: var(--spacing-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-page__recommended {
|
.file-page__recommended {
|
||||||
width: 25rem;
|
|
||||||
height: 0%;
|
height: 0%;
|
||||||
|
width: 35rem;
|
||||||
|
margin-left: var(--spacing-m);
|
||||||
|
|
||||||
|
@media (max-width: $breakpoint-small) {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: $breakpoint-medium) {
|
@media (max-width: $breakpoint-medium) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -82,8 +114,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $breakpoint-medium) {
|
@media (max-width: $breakpoint-medium) {
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
> :first-child {
|
> :first-child {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
@ -95,13 +125,48 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main--theater-mode {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
width: 100vw;
|
||||||
|
max-width: none;
|
||||||
|
|
||||||
|
> :first-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-page__info {
|
||||||
|
padding: 0 var(--spacing-m);
|
||||||
|
margin-top: var(--spacing-m);
|
||||||
|
max-width: var(--page-max-width--filepage);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-page__recommended {
|
||||||
|
width: 25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-page__secondary-content {
|
||||||
|
padding: 0 var(--spacing-s);
|
||||||
|
|
||||||
|
@media (min-width: $breakpoint-medium) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.main--full-width {
|
.main--full-width {
|
||||||
@extend .main;
|
@extend .main;
|
||||||
|
|
||||||
@media (min-width: $breakpoint-large) {
|
@media (min-width: $breakpoint-large) {
|
||||||
max-width: none;
|
max-width: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 var(--spacing-l);
|
margin: 0 var(--spacing-l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: var(--spacing-l);
|
margin-top: var(--spacing-l);
|
||||||
|
margin-right: var(--spacing-s);
|
||||||
|
|
||||||
~ .section {
|
~ .section {
|
||||||
margin-top: var(--spacing-l);
|
margin-top: var(--spacing-l);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
:root {
|
:root {
|
||||||
// Button
|
|
||||||
--color-navigation-icon: var(--color-gray-5);
|
--color-navigation-icon: var(--color-gray-5);
|
||||||
--color-link-active: var(--color-primary);
|
--color-link-active: var(--color-primary);
|
||||||
--color-navigation-link: var(--color-gray-5);
|
--color-navigation-link: var(--color-gray-5);
|
||||||
|
|
Loading…
Reference in a new issue