mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 12:26:40 +07:00
play video in embed instead of new window on desktops
This commit is contained in:
parent
5056047546
commit
06cf7050a9
8 changed files with 184 additions and 44 deletions
|
@ -36,6 +36,7 @@
|
|||
"react-lazyload": "^3.2.0",
|
||||
"react-masonry-css": "^1.0.16",
|
||||
"react-popper": "^2.2.3",
|
||||
"react-resize-detector": "^12.0.2",
|
||||
"react-router": "^5.1.2",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-sticky-box": "^1.0.2",
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import classNames from 'classnames';
|
||||
import { useResizeDetector } from 'react-resize-detector';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
title: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const CommentVideoFrame = ({ id, title, className }: Props) => {
|
||||
const { ref, width = 0, height = 0 } = useResizeDetector();
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.wrap, className)} ref={ref}>
|
||||
<iframe
|
||||
width={width}
|
||||
height={height}
|
||||
src={`https://www.youtube.com/embed/${id}?autoplay=1`}
|
||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||
frameBorder="0"
|
||||
allowFullScreen
|
||||
title={title}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
@import '~/styles/variables';
|
||||
|
||||
.wrap {
|
||||
width: 100%;
|
||||
aspect-ratio: calc(16 / 9);
|
||||
overflow: hidden;
|
||||
border-radius: $radius;
|
||||
}
|
|
@ -1,15 +1,21 @@
|
|||
import { FC, memo, useMemo } from 'react';
|
||||
import { FC, memo, useCallback, useMemo } from 'react';
|
||||
|
||||
import { Icon } from '~/components/common/Icon';
|
||||
import { ICommentBlockProps } from '~/constants/comment';
|
||||
import { useWindowSize } from '~/hooks/dom/useWindowSize';
|
||||
import { useYoutubeMetadata } from '~/hooks/metadata/useYoutubeMetadata';
|
||||
import { getYoutubeThumb } from '~/utils/dom';
|
||||
import { useVideoPlayer } from '~/utils/providers/VideoPlayerProvider';
|
||||
|
||||
import { CommentVideoFrame } from './components/CommentVideoFrame';
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
type Props = ICommentBlockProps & {};
|
||||
|
||||
const CommentEmbedBlock: FC<Props> = memo(({ block }) => {
|
||||
const { isTablet } = useWindowSize();
|
||||
const { url, setUrl } = useVideoPlayer();
|
||||
|
||||
const id = useMemo(() => {
|
||||
const match = block.content.match(
|
||||
/https?:\/\/(?:www\.)?(?:youtube\.com|youtu\.be)\/(?:watch)?(?:\?v=)?([\w\-=]+)/,
|
||||
|
@ -18,7 +24,7 @@ const CommentEmbedBlock: FC<Props> = memo(({ block }) => {
|
|||
return (match && match[1]) || '';
|
||||
}, [block.content]);
|
||||
|
||||
const url = useMemo(() => `https://youtube.com/watch?v=${id}`, [id]);
|
||||
const address = `https://youtube.com/watch?v=${id}`;
|
||||
|
||||
const preview = useMemo(
|
||||
() => getYoutubeThumb(block.content),
|
||||
|
@ -28,11 +34,35 @@ const CommentEmbedBlock: FC<Props> = memo(({ block }) => {
|
|||
const metadata = useYoutubeMetadata(id);
|
||||
const title = metadata?.metadata?.title || '';
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
if (isTablet) {
|
||||
window.open(address, '_blank');
|
||||
return;
|
||||
}
|
||||
|
||||
setUrl(address);
|
||||
}, [isTablet, setUrl, address]);
|
||||
|
||||
const closeVideo = useCallback(() => setUrl(''), [setUrl]);
|
||||
|
||||
return (
|
||||
<div className={styles.embed}>
|
||||
<a href={url} target="_blank" rel="noreferrer" />
|
||||
|
||||
<div className={styles.preview}>
|
||||
{url === address ? (
|
||||
<div className={styles.video}>
|
||||
<div className={styles.close} onClick={closeVideo}>
|
||||
<Icon icon="close" />
|
||||
</div>
|
||||
<div className={styles.animation}>
|
||||
<CommentVideoFrame id={id} title={title} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={styles.preview}
|
||||
role="button"
|
||||
onClick={onClick}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<div style={{ backgroundImage: `url("${preview}")` }}>
|
||||
<div className={styles.backdrop}>
|
||||
<div className={styles.play}>
|
||||
|
@ -43,6 +73,7 @@ const CommentEmbedBlock: FC<Props> = memo(({ block }) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.embed {
|
||||
padding: 0 $gap;
|
||||
height: $comment_height;
|
||||
padding: 0 0;
|
||||
min-height: $comment_height;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: 50% 50% no-repeat;
|
||||
|
@ -69,6 +69,7 @@
|
|||
justify-content: stretch;
|
||||
box-sizing: border-box;
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
|
||||
& > div {
|
||||
width: 100%;
|
||||
|
@ -98,3 +99,47 @@
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@keyframes appear {
|
||||
0% {
|
||||
grid-template-columns: 0fr;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.video {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
padding: $gap / 2;
|
||||
}
|
||||
|
||||
.close {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color_danger);
|
||||
width: 64px;
|
||||
height: 24px;
|
||||
position: absolute;
|
||||
bottom: calc(100% - #{$gap / 2});
|
||||
right: 24px;
|
||||
border-radius: $radius $radius 0 0;
|
||||
z-index: 10;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.animation {
|
||||
background-color: var(--content_bg_darker);
|
||||
display: grid;
|
||||
animation: appear 0.5s forwards;
|
||||
width: 100%;
|
||||
border-radius: $radius;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import { useCommentContext } from '~/utils/context/CommentContextProvider';
|
|||
import { useNodeContext } from '~/utils/context/NodeContextProvider';
|
||||
import { useUserContext } from '~/utils/context/UserContextProvider';
|
||||
import { canEditComment, canLikeComment } from '~/utils/node';
|
||||
import { VideoPlayerProvider } from '~/utils/providers/VideoPlayerProvider';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
|
@ -84,6 +85,7 @@ const NodeComments: FC<Props> = observer(({ order }) => {
|
|||
}, [isLoading]);
|
||||
|
||||
return (
|
||||
<VideoPlayerProvider>
|
||||
<div className={styles.wrap}>
|
||||
{order === 'DESC' && more}
|
||||
|
||||
|
@ -116,6 +118,7 @@ const NodeComments: FC<Props> = observer(({ order }) => {
|
|||
|
||||
{order === 'ASC' && more}
|
||||
</div>
|
||||
</VideoPlayerProvider>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
17
src/utils/providers/VideoPlayerProvider.tsx
Normal file
17
src/utils/providers/VideoPlayerProvider.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { createContext, ReactNode, useContext, useState } from 'react';
|
||||
|
||||
const Context = createContext({
|
||||
url: '',
|
||||
setUrl: (val: string) => {},
|
||||
});
|
||||
|
||||
/** Provides context for comment video playing */
|
||||
export const VideoPlayerProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [url, setUrl] = useState('');
|
||||
|
||||
return (
|
||||
<Context.Provider value={{ url, setUrl }}>{children}</Context.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useVideoPlayer = () => useContext(Context);
|
|
@ -2626,6 +2626,13 @@ react-popper@^2.2.3:
|
|||
react-fast-compare "^3.0.1"
|
||||
warning "^4.0.2"
|
||||
|
||||
react-resize-detector@^12.0.2:
|
||||
version "12.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-12.0.2.tgz#5e65f906a85835d246de57dbf608bf22ab333cad"
|
||||
integrity sha512-aAI4WxWAysWLhA8wKDpsS+PnnxQ0lWCkTlk2t+2ijalWvoSa7vPxmcKRLURkH+PU84QE4KP4dO58oVP3ypWkKA==
|
||||
dependencies:
|
||||
lodash "^4.17.21"
|
||||
|
||||
react-router-dom@^5.1.2:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.0.tgz#da1bfb535a0e89a712a93b97dd76f47ad1f32363"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue