19 changed files with 256 additions and 115 deletions
@ -1,3 +1,7 @@ |
|||||||
export * from "./atoms"; |
export * from "./atoms"; |
||||||
export * from "./base/Container"; |
export * from "./base/Container"; |
||||||
|
export * from "./base/TopControls"; |
||||||
export * from "./base/BottomControls"; |
export * from "./base/BottomControls"; |
||||||
|
export * from "./base/BlackOverlay"; |
||||||
|
export * from "./base/BackLink"; |
||||||
|
export * from "./internals/BookmarkButton"; |
||||||
|
@ -0,0 +1,23 @@ |
|||||||
|
import { useTranslation } from "react-i18next"; |
||||||
|
|
||||||
|
import { Icon, Icons } from "@/components/Icon"; |
||||||
|
import { useGoBack } from "@/hooks/useGoBack"; |
||||||
|
|
||||||
|
export function BackLink() { |
||||||
|
const { t } = useTranslation(); |
||||||
|
const goBack = useGoBack(); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="flex items-center"> |
||||||
|
<span |
||||||
|
onClick={() => goBack()} |
||||||
|
className="flex items-center cursor-pointer text-type-secondary hover:text-white transition-colors duration-200 font-medium" |
||||||
|
> |
||||||
|
<Icon className="mr-2" icon={Icons.ARROW_LEFT} /> |
||||||
|
<span>{t("videoPlayer.backToHomeShort")}</span> |
||||||
|
</span> |
||||||
|
<span className="text mx-3 text-type-secondary">/</span> |
||||||
|
<span>Mr Jeebaloo's Big Ocean Adventure</span> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
import { Transition } from "@/components/Transition"; |
||||||
|
|
||||||
|
export function BlackOverlay(props: { show?: boolean }) { |
||||||
|
return ( |
||||||
|
<Transition |
||||||
|
animation="fade" |
||||||
|
show={props.show} |
||||||
|
className="absolute inset-0 w-full h-full bg-black bg-opacity-20 pointer-events-none" |
||||||
|
/> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
import { Transition } from "@/components/Transition"; |
||||||
|
|
||||||
|
export function TopControls(props: { |
||||||
|
show?: boolean; |
||||||
|
children: React.ReactNode; |
||||||
|
}) { |
||||||
|
return ( |
||||||
|
<div className="w-full text-white"> |
||||||
|
<Transition |
||||||
|
animation="fade" |
||||||
|
show={props.show} |
||||||
|
className="pointer-events-none flex justify-end pb-32 bg-gradient-to-b from-black to-transparent [margin-bottom:env(safe-area-inset-bottom)] transition-opacity duration-200 absolute top-0 w-full" |
||||||
|
/> |
||||||
|
<Transition |
||||||
|
animation="slide-down" |
||||||
|
show={props.show} |
||||||
|
className="pointer-events-auto px-4 pt-6 absolute top-0 w-full text-white" |
||||||
|
> |
||||||
|
{props.children} |
||||||
|
</Transition> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
import { PlayerHoverState } from "@/stores/player/slices/interface"; |
||||||
|
import { usePlayerStore } from "@/stores/player/store"; |
||||||
|
|
||||||
|
export function useShouldShowControls() { |
||||||
|
const { hovering } = usePlayerStore((s) => s.interface); |
||||||
|
const { isPaused } = usePlayerStore((s) => s.mediaPlaying); |
||||||
|
|
||||||
|
return hovering !== PlayerHoverState.NOT_HOVERING || isPaused; |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
import { Icons } from "@/components/Icon"; |
||||||
|
|
||||||
|
import { VideoPlayerButton } from "./Button"; |
||||||
|
|
||||||
|
export function BookmarkButton() { |
||||||
|
return ( |
||||||
|
<VideoPlayerButton |
||||||
|
onClick={() => window.open("https://youtu.be/TENzstSjsus", "_blank")} |
||||||
|
icon={Icons.BOOKMARK_OUTLINE} |
||||||
|
iconSizeClass="text-base" |
||||||
|
className="p-3" |
||||||
|
/> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
import { PointerEvent, useCallback } from "react"; |
||||||
|
|
||||||
|
import { useShouldShowVideoElement } from "@/components/player/internals/VideoContainer"; |
||||||
|
import { PlayerHoverState } from "@/stores/player/slices/interface"; |
||||||
|
import { usePlayerStore } from "@/stores/player/store"; |
||||||
|
|
||||||
|
export function VideoClickTarget() { |
||||||
|
const show = useShouldShowVideoElement(); |
||||||
|
const display = usePlayerStore((s) => s.display); |
||||||
|
const isPaused = usePlayerStore((s) => s.mediaPlaying.isPaused); |
||||||
|
const updateInterfaceHovering = usePlayerStore( |
||||||
|
(s) => s.updateInterfaceHovering |
||||||
|
); |
||||||
|
const hovering = usePlayerStore((s) => s.interface.hovering); |
||||||
|
|
||||||
|
const toggleFullscreen = useCallback(() => { |
||||||
|
display?.toggleFullscreen(); |
||||||
|
}, [display]); |
||||||
|
|
||||||
|
const togglePause = useCallback( |
||||||
|
(e: PointerEvent<HTMLDivElement>) => { |
||||||
|
// pause on mouse click
|
||||||
|
if (e.pointerType === "mouse") { |
||||||
|
if (e.button !== 0) return; |
||||||
|
if (isPaused) display?.play(); |
||||||
|
else display?.pause(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// toggle on other types of clicks
|
||||||
|
if (hovering !== PlayerHoverState.MOBILE_TAPPED) |
||||||
|
updateInterfaceHovering(PlayerHoverState.MOBILE_TAPPED); |
||||||
|
else updateInterfaceHovering(PlayerHoverState.NOT_HOVERING); |
||||||
|
}, |
||||||
|
[display, isPaused, hovering, updateInterfaceHovering] |
||||||
|
); |
||||||
|
|
||||||
|
if (!show) return null; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div |
||||||
|
className="absolute inset-0" |
||||||
|
onDoubleClick={toggleFullscreen} |
||||||
|
onPointerUp={togglePause} |
||||||
|
/> |
||||||
|
); |
||||||
|
} |
Loading…
Reference in new issue