Skip to content

Commit

Permalink
Initial shorts page
Browse files Browse the repository at this point in the history
  • Loading branch information
ikprk committed May 26, 2024
1 parent 5ad4851 commit d572878
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type BackgroundVideoPlayerProps = {
withFade?: boolean
src: string[]
poster: string[]
onMuted?: (newState: boolean) => void
loop?: boolean
customLink?: string
} & Omit<VideoHTMLAttributes<HTMLVideoElement>, 'src' | 'poster'>

Expand All @@ -32,14 +34,16 @@ export const BackgroundVideoPlayer: FC<BackgroundVideoPlayerProps> = ({
handleActions,
videoPlaytime,
videoId,
onMuted,
withFade,
customLink,
loop,
...props
}) => {
const videoRef = useRef<HTMLVideoElement>(null)
const [isPosterVisible, setIsPosterVisible] = useState(true)
const [isPlaying, setIsPlaying] = useState(autoPlay)
const [isMuted, setIsMuted] = useState(true)
const [isMuted, setIsMuted] = useState(props.muted)
const [canPlay, setCanPlay] = useState(false)

const initialRender = useRef(true)
Expand Down Expand Up @@ -76,9 +80,12 @@ export const BackgroundVideoPlayer: FC<BackgroundVideoPlayerProps> = ({
}
}, [canPlay])

console.log('adf', playing, props.muted)

Check warning on line 83 in packages/atlas/src/components/_video/BackgroundVideoPlayer/BackgroundVideoPlayer.tsx

View workflow job for this annotation

GitHub Actions / Tests and Linting (ubuntu-latest, 18.x)

Unexpected console statement

useEffect(() => {
// show poster again when src changes
setIsPosterVisible(true)
console.log('effect')

Check warning on line 88 in packages/atlas/src/components/_video/BackgroundVideoPlayer/BackgroundVideoPlayer.tsx

View workflow job for this annotation

GitHub Actions / Tests and Linting (ubuntu-latest, 18.x)

Unexpected console statement
if (!videoRef.current || playing === undefined || !canPlay) {
return
}
Expand All @@ -97,9 +104,15 @@ export const BackgroundVideoPlayer: FC<BackgroundVideoPlayerProps> = ({
}

const handleEnded = (e: SyntheticEvent<HTMLVideoElement, Event>) => {
onEnded?.(e)

if (loop && videoRef.current) {
console.log('xd')

Check warning on line 110 in packages/atlas/src/components/_video/BackgroundVideoPlayer/BackgroundVideoPlayer.tsx

View workflow job for this annotation

GitHub Actions / Tests and Linting (ubuntu-latest, 18.x)

Unexpected console statement
videoRef.current.currentTime = 0
return
}
setIsPosterVisible(true)
setIsPlaying(false)
onEnded?.(e)
}

return (
Expand All @@ -112,13 +125,18 @@ export const BackgroundVideoPlayer: FC<BackgroundVideoPlayerProps> = ({
variant="tertiary"
/>
<Button
onClick={() => setIsMuted((prev) => !prev)}
onClick={() => {
onMuted?.(!isMuted)
setIsMuted((prev) => !prev)
}}
icon={isMuted ? <SvgActionSoundOff /> : <SvgActionSoundOn />}
variant="tertiary"
/>
</ButtonBox>
)}
{playing && <VideoProgress video={videoRef.current} isPlaying={isPlaying} tick={10} limit={videoPlaytime} />}
{playing && (
<VideoProgress loop={loop} video={videoRef.current} isPlaying={isPlaying} tick={10} limit={videoPlaytime} />
)}
<StyledFade withFade={withFade}>
<StyledVideo
resolvedVideoUrls={src}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,23 @@ export type VideoProgressProps = {
isPlaying?: boolean
// limit in seconds for video play time
limit?: number
loop?: boolean
}

export const VideoProgress = ({ tick, video, isPlaying, limit }: VideoProgressProps) => {
export const VideoProgress = ({ tick, video, isPlaying, limit, loop }: VideoProgressProps) => {
const [progress, setProgress] = useState(0)
const hasVideo = !!video
useEffect(() => {
if ((isPlaying || typeof isPlaying === 'undefined') && video) {
if ((isPlaying || typeof isPlaying === 'undefined') && hasVideo) {
const id = setInterval(() => {
const proccessedLimit = limit ? (limit < video.duration ? limit : video.duration) : video.duration
const proccessedLimit = limit ? Math.min(limit, video.duration) : video.duration
if (limit && video.currentTime > proccessedLimit) {
setProgress(1)
if (loop) {
video.currentTime = 0
video.play()
return
}
video.currentTime = video.duration
clearInterval(id)
return
Expand All @@ -30,7 +37,7 @@ export const VideoProgress = ({ tick, video, isPlaying, limit }: VideoProgressPr
clearInterval(id)
}
}
}, [isPlaying, limit, progress, tick, video, video?.duration])
}, [hasVideo, isPlaying, limit, loop, progress, tick, video, video?.duration])

const width = useMemo(() => (progress ? `${progress * 100}%` : 1), [progress])
return (
Expand Down
1 change: 1 addition & 0 deletions packages/atlas/src/config/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const relativeRoutes = {
video: (id = ':id') => `video/${id}`,
},
viewer: {
shorts: () => 'shorts',
curatorView: () => 'curator-view',
curatorHomepage: () => 'curator-homepage',
index: () => '',
Expand Down
2 changes: 1 addition & 1 deletion packages/atlas/src/views/viewer/HomeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const StyledSection = styled(Section)`
padding: ${sizes(8)} 0;
`

const useHomeVideos = () => {
export const useHomeVideos = () => {
const initialRowsToLoad = useVideoGridRows('main')
const { data, loading } = useGetCuratedHompageVideosQuery({
notifyOnNetworkStatusChange: true,
Expand Down
237 changes: 237 additions & 0 deletions packages/atlas/src/views/viewer/ShortsView/ShortsView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
import styled from '@emotion/styled'
import { useCallback, useEffect, useRef, useState } from 'react'

import { useFullVideo } from '@/api/hooks/video'
import { VideoOrderByInput } from '@/api/queries/__generated__/baseTypes.generated'
import {
GetBasicVideosConnectionLightweightDocument,
useGetCuratedHompageVideosQuery,
} from '@/api/queries/__generated__/videos.generated'
import { SkeletonLoader } from '@/components/_loaders/SkeletonLoader'
import { BackgroundVideoPlayer } from '@/components/_video/BackgroundVideoPlayer'
import { getPublicCryptoVideoFilter } from '@/config/contentFilter'
import { absoluteRoutes } from '@/config/routes'
import { useInfiniteVideoGrid } from '@/hooks/useInfiniteVideoGrid'
import { media } from '@/styles'
import { createPlaceholderData } from '@/utils/data'

export const ShortsView = () => {
const containerRef = useRef<HTMLDivElement>(null)
const [forceMuted, setForceMuted] = useState(false)
const [activeIndex, setActiveIndex] = useState(0)
const [nextSlide, setNextSlide] = useState<Element | null>(null)
const observerRef = useRef<IntersectionObserver | null>(null)
const { fetchMore, tiles, loading, pageInfo } = useHomeVideos()

useEffect(() => {
const options = {
root: containerRef.current,
rootMargin: '0px',
threshold: 0.5, // Adjust as needed to determine what constitutes "on screen"
}

observerRef.current = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const newIndex = Number(entry.target.dataset.index)
setActiveIndex(newIndex)
setNextSlide(entries[newIndex + 1].target)

if (tiles.length - newIndex < 2) {
console.log('try fetch')

Check warning on line 41 in packages/atlas/src/views/viewer/ShortsView/ShortsView.tsx

View workflow job for this annotation

GitHub Actions / Tests and Linting (ubuntu-latest, 18.x)

Unexpected console statement
if (!loading) {
fetchMore({
variables: { first: 4 * 4, after: pageInfo?.endCursor },
})
}
}
}
})
}, options)

const placeholders = containerRef.current?.querySelectorAll('.short-video') ?? []
placeholders.forEach((placeholder) => observerRef.current?.observe(placeholder))

return () => {
placeholders.forEach((placeholder) => observerRef.current?.unobserve(placeholder))
observerRef.current?.disconnect()
}
}, [activeIndex, fetchMore, loading, pageInfo?.endCursor, tiles.length])
console.log('enext', nextSlide)

Check warning on line 60 in packages/atlas/src/views/viewer/ShortsView/ShortsView.tsx

View workflow job for this annotation

GitHub Actions / Tests and Linting (ubuntu-latest, 18.x)

Unexpected console statement
const goNextSlide = useCallback(() => {
console.log(nextSlide, 'scroll')

Check warning on line 62 in packages/atlas/src/views/viewer/ShortsView/ShortsView.tsx

View workflow job for this annotation

GitHub Actions / Tests and Linting (ubuntu-latest, 18.x)

Unexpected console statement
nextSlide?.scrollIntoView({ behavior: 'smooth' })
}, [nextSlide])

return (
<Container ref={containerRef}>
{tiles.map(({ id }, idx) => (
<ShortVideoPlaceholder
key={idx}
data-index={idx}
className={`short-video ${idx === activeIndex ? 'active' : ''} ${
activeIndex > idx && idx > activeIndex - 2 ? 'prev' : ''
} ${activeIndex < idx && idx < activeIndex + 2 ? 'next' : ''}`}
>
{!id || activeIndex - 1 > idx || activeIndex + 2 < idx ? (
<div style={{ height: '100%', background: 'red', width: 400, aspectRatio: '9/16' }} />
) : (
<ShortVideoPlayer
forceMuted={forceMuted}
setForceMuted={setForceMuted}
videoId={id}
isActive={idx === activeIndex}
playNext={goNextSlide}
/>
)}
</ShortVideoPlaceholder>
))}
</Container>
)
}

const Container = styled.div`
display: flex;
flex-direction: column;
overflow-y: auto;
gap: 40px;
height: 100%;
scroll-snap-type: y mandatory;
align-items: center;
scrollbar-width: none;
width: 100%;
::-webkit-scrollbar {
display: none;
}
`

const ShortVideoPlaceholder = styled.div`
display: grid;
place-items: center;
aspect-ratio: 9/16;
/* background-color: green; */
max-height: 90%;
width: 400px;
text-align: center;
vertical-align: middle;
scroll-snap-stop: always;
scroll-snap-align: center;
${media.xxl} {
width: 40vw;
height: 100%;
}
`

const ShortVideoPlayer = ({
videoId,
isActive,
forceMuted,
playNext,
setForceMuted,
}: {
isActive: boolean
videoId: string
forceMuted: boolean
setForceMuted: (val: boolean) => void
playNext: () => void
}) => {
const { video, loading } = useFullVideo(videoId)
const thumbnailUrls: string[] = video?.thumbnailPhoto?.resolvedUrls ?? []

Check warning on line 142 in packages/atlas/src/views/viewer/ShortsView/ShortsView.tsx

View workflow job for this annotation

GitHub Actions / Tests and Linting (ubuntu-latest, 18.x)

'thumbnailUrls' is assigned a value but never used. Allowed unused vars must match /^_+$/u
const mediaUrls: string[] = video?.media?.resolvedUrls ?? []
const isLoading = loading
console.log(loading)

Check warning on line 145 in packages/atlas/src/views/viewer/ShortsView/ShortsView.tsx

View workflow job for this annotation

GitHub Actions / Tests and Linting (ubuntu-latest, 18.x)

Unexpected console statement
return (
<ShortVideoPlayerBox>
{!isLoading ? (
<StyledBackgroundVideoPlayer
videoId={videoId}
playing={isActive}
muted={forceMuted}
onMuted={setForceMuted}
preload="metadata"
withFade
src={mediaUrls ?? undefined}
poster={[] ?? undefined}
handleActions={isActive}
videoPlaytime={10}
loop
onEnded={playNext}
customLink={absoluteRoutes.viewer.video(videoId)}
/>
) : (
<SkeletonLoader height="100%" width={400} />
// <VideoWrapper>
// <VideoPoster resolvedUrls={thumbnailUrls ?? undefined} type="cover" alt="" />
// </VideoWrapper>
)}
</ShortVideoPlayerBox>
)
}

const ShortVideoPlayerBox = styled.div`
aspect-ratio: 9/16;
/* background-color: green; */
min-height: 90%;
max-height: 100%;
width: 100%;
position: relative;
scroll-snap-stop: always;
scroll-snap-align: center;
border: 1px solid red;
overflow: hidden;
${media.xxl} {
width: 40vw;
}
`

const StyledBackgroundVideoPlayer = styled(BackgroundVideoPlayer)``

export const useHomeVideos = () => {
const { data, loading } = useGetCuratedHompageVideosQuery({
notifyOnNetworkStatusChange: true,
variables: {
where: getPublicCryptoVideoFilter({
orionLanguage_in: undefined,
includeInHomeFeed_eq: true,
isShort_not_eq: undefined,
isShortDerived_isNull: undefined,
isShort_eq: true,
}),
skipVideoIds: ['-1'],
},
})
const avoidIds = data?.dumbPublicFeedVideos ? data.dumbPublicFeedVideos?.map((video) => video.id) : undefined
const { columns, fetchMore, pageInfo, tiles } = useInfiniteVideoGrid({
query: GetBasicVideosConnectionLightweightDocument,
variables: {
where: getPublicCryptoVideoFilter({
id_not_in: avoidIds,
isShort_not_eq: undefined,
isShortDerived_isNull: undefined,
isShort_eq: true,
}),
orderBy: VideoOrderByInput.VideoRelevanceDesc,
},
options: {
skip: !avoidIds,
},
})

const firstLoad = !data?.dumbPublicFeedVideos && loading
const firstLoadPlaceholders = firstLoad ? createPlaceholderData(columns * 3) : []

const displayedItems = [...(data?.dumbPublicFeedVideos || []), ...(tiles || [])]

return {
tiles: [...firstLoadPlaceholders, ...displayedItems],
fetchMore,
columns,
loading,
pageInfo,
}
}
1 change: 1 addition & 0 deletions packages/atlas/src/views/viewer/ShortsView/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ShortsView'
2 changes: 2 additions & 0 deletions packages/atlas/src/views/viewer/ViewerLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const SearchView = lazy(() => import('./SearchView').then((module) => ({ default
const CuratorView = lazy(() => import('./CuratorView').then((module) => ({ default: module.CuratorView })))
const CuratorHomepage = lazy(() => import('./CuratorHomepage').then((module) => ({ default: module.CuratorHomepage })))
const VideoView = lazy(() => import('./VideoView').then((module) => ({ default: module.VideoView })))
const ShortsView = lazy(() => import('./ShortsView').then((module) => ({ default: module.ShortsView })))
const PortfolioView = lazy(() => import('./PortfolioView').then((module) => ({ default: module.PortfolioView })))
const ReferralsView = lazy(() =>
import('@/views/global/ReferralsView').then((module) => ({ default: module.ReferralsView }))
Expand All @@ -62,6 +63,7 @@ const viewerRoutes = [
{ path: relativeRoutes.viewer.category(), element: <CategoryView /> },
{ path: relativeRoutes.viewer.memberById(), element: <MemberView /> },
{ path: relativeRoutes.viewer.member(), element: <MemberView /> },
{ path: relativeRoutes.viewer.shorts(), element: <ShortsView /> },
{ path: relativeRoutes.viewer.marketplace(), element: <MarketplaceView /> },
...(atlasConfig.features.ypp.googleConsoleClientId
? [
Expand Down

0 comments on commit d572878

Please sign in to comment.