mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-20 14:37:43 +01:00
add top bar and improve ui feel
This commit is contained in:
parent
024325f640
commit
351b35ef98
6 changed files with 52 additions and 11 deletions
|
@ -5,8 +5,11 @@ import { PauseControl } from "./controls/PauseControl";
|
||||||
import { ProgressControl } from "./controls/ProgressControl";
|
import { ProgressControl } from "./controls/ProgressControl";
|
||||||
import { TimeControl } from "./controls/TimeControl";
|
import { TimeControl } from "./controls/TimeControl";
|
||||||
import { VolumeControl } from "./controls/VolumeControl";
|
import { VolumeControl } from "./controls/VolumeControl";
|
||||||
|
import { VideoPlayerHeader } from "./parts/VideoPlayerHeader";
|
||||||
import { VideoPlayer, VideoPlayerProps } from "./VideoPlayer";
|
import { VideoPlayer, VideoPlayerProps } from "./VideoPlayer";
|
||||||
|
|
||||||
|
// TODO animate items away when hidden
|
||||||
|
|
||||||
export function DecoratedVideoPlayer(props: VideoPlayerProps) {
|
export function DecoratedVideoPlayer(props: VideoPlayerProps) {
|
||||||
return (
|
return (
|
||||||
<VideoPlayer autoPlay={props.autoPlay}>
|
<VideoPlayer autoPlay={props.autoPlay}>
|
||||||
|
@ -14,9 +17,9 @@ export function DecoratedVideoPlayer(props: VideoPlayerProps) {
|
||||||
<div className="absolute inset-0 flex items-center justify-center">
|
<div className="absolute inset-0 flex items-center justify-center">
|
||||||
<LoadingControl />
|
<LoadingControl />
|
||||||
</div>
|
</div>
|
||||||
<div className="pointer-events-auto absolute inset-x-0 bottom-0 mb-4 flex flex-col px-6">
|
<div className="pointer-events-auto absolute inset-x-0 bottom-0 flex flex-col px-4 pb-2">
|
||||||
<ProgressControl />
|
<ProgressControl />
|
||||||
<div className="flex items-center">
|
<div className="flex items-center px-2">
|
||||||
<PauseControl />
|
<PauseControl />
|
||||||
<VolumeControl className="mr-2" />
|
<VolumeControl className="mr-2" />
|
||||||
<TimeControl />
|
<TimeControl />
|
||||||
|
@ -24,6 +27,9 @@ export function DecoratedVideoPlayer(props: VideoPlayerProps) {
|
||||||
<FullscreenControl />
|
<FullscreenControl />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="pointer-events-auto absolute inset-x-0 top-0 flex flex-col py-6 px-8 pb-2">
|
||||||
|
<VideoPlayerHeader title="Spiderman: Coming House" />
|
||||||
|
</div>
|
||||||
</BackdropControl>
|
</BackdropControl>
|
||||||
{props.children}
|
{props.children}
|
||||||
</VideoPlayer>
|
</VideoPlayer>
|
||||||
|
|
|
@ -5,6 +5,8 @@ interface BackdropControlProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO add double click to toggle fullscreen
|
||||||
|
|
||||||
export function BackdropControl(props: BackdropControlProps) {
|
export function BackdropControl(props: BackdropControlProps) {
|
||||||
const { videoState } = useVideoPlayerState();
|
const { videoState } = useVideoPlayerState();
|
||||||
const [moved, setMoved] = useState(false);
|
const [moved, setMoved] = useState(false);
|
||||||
|
@ -50,12 +52,12 @@ export function BackdropControl(props: BackdropControlProps) {
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={`pointer-events-none absolute inset-x-0 bottom-0 h-[30%] bg-gradient-to-t from-black to-transparent opacity-75 transition-opacity duration-200 ${
|
className={`pointer-events-none absolute inset-x-0 bottom-0 h-[20%] bg-gradient-to-t from-black to-transparent transition-opacity duration-200 ${
|
||||||
!showUI ? "!opacity-0" : ""
|
!showUI ? "!opacity-0" : ""
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={`pointer-events-none absolute inset-x-0 top-0 h-[30%] bg-gradient-to-b from-black to-transparent opacity-75 transition-opacity duration-200 ${
|
className={`pointer-events-none absolute inset-x-0 top-0 h-[20%] bg-gradient-to-b from-black to-transparent transition-opacity duration-200 ${
|
||||||
!showUI ? "!opacity-0" : ""
|
!showUI ? "!opacity-0" : ""
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -44,13 +44,13 @@ export function ProgressControl() {
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="absolute inset-y-0 left-0 flex items-center justify-end rounded-full bg-gray-300 bg-opacity-50"
|
className="absolute inset-y-0 left-0 flex items-center justify-end rounded-full bg-gray-300 bg-opacity-20"
|
||||||
style={{
|
style={{
|
||||||
width: bufferProgress,
|
width: bufferProgress,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="absolute inset-y-0 left-0 flex items-center justify-end rounded-full bg-bink-500"
|
className="absolute inset-y-0 left-0 flex items-center justify-end rounded-full bg-bink-600"
|
||||||
style={{
|
style={{
|
||||||
width: watchProgress,
|
width: watchProgress,
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -60,12 +60,12 @@ export function VolumeControl(props: Props) {
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`-ml-2 w-0 overflow-hidden transition-[width,opacity] duration-300 ease-in ${
|
className={`-ml-2 w-0 overflow-hidden transition-[width,opacity] duration-300 ease-in ${
|
||||||
hoveredOnce ? "!w-20 opacity-100" : "w-4 opacity-0"
|
hoveredOnce ? "!w-24 opacity-100" : "w-4 opacity-0"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className="flex h-10 w-16 items-center px-2"
|
className="flex h-10 w-20 items-center px-2"
|
||||||
onMouseDown={dragMouseDown}
|
onMouseDown={dragMouseDown}
|
||||||
>
|
>
|
||||||
<div className="relative h-1 flex-1 rounded-full bg-gray-500 bg-opacity-50">
|
<div className="relative h-1 flex-1 rounded-full bg-gray-500 bg-opacity-50">
|
||||||
|
|
28
src/components/video/parts/VideoPlayerHeader.tsx
Normal file
28
src/components/video/parts/VideoPlayerHeader.tsx
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { Icon, Icons } from "@/components/Icon";
|
||||||
|
import { BrandPill } from "@/components/layout/BrandPill";
|
||||||
|
|
||||||
|
interface VideoPlayerHeaderProps {
|
||||||
|
title: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VideoPlayerHeader(props: VideoPlayerHeaderProps) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center">
|
||||||
|
<div className="flex flex-1 items-center">
|
||||||
|
<p className="flex items-center">
|
||||||
|
<span
|
||||||
|
onClick={props.onClick}
|
||||||
|
className="flex cursor-pointer items-center py-1 text-white opacity-50 transition-opacity hover:opacity-100"
|
||||||
|
>
|
||||||
|
<Icon className="mr-2" icon={Icons.ARROW_LEFT} />
|
||||||
|
<span>Back to home</span>
|
||||||
|
</span>
|
||||||
|
<span className="mx-4 h-6 w-[1.5px] rotate-[30deg] bg-white opacity-50" />
|
||||||
|
<span className="text-white">{props.title}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<BrandPill />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -5,13 +5,18 @@ import { useCallback, useState } from "react";
|
||||||
// test videos: https://gist.github.com/jsturgis/3b19447b304616f18657
|
// test videos: https://gist.github.com/jsturgis/3b19447b304616f18657
|
||||||
|
|
||||||
// TODO video todos:
|
// TODO video todos:
|
||||||
// - make pretty
|
// - improve seekables (if possible)
|
||||||
// - improve seekables
|
|
||||||
// - error handling
|
// - error handling
|
||||||
// - middle pause button
|
// - middle pause button
|
||||||
|
// - double click backdrop to toggle fullscreen
|
||||||
|
// - make volume bar collapse when hovering away from left control section
|
||||||
|
// - animate UI when showing/hiding
|
||||||
|
// - shortcuts when player is active
|
||||||
|
// - save volume in localstorage so persists between page reloads
|
||||||
// - improve pausing while seeking/buffering
|
// - improve pausing while seeking/buffering
|
||||||
|
// - volume control flashes old value when updating
|
||||||
|
// - progress control flashes old value when updating
|
||||||
// - captions
|
// - captions
|
||||||
// - backdrop better click handling
|
|
||||||
// - IOS support: (no volume, fullscreen video element instead of wrapper)
|
// - IOS support: (no volume, fullscreen video element instead of wrapper)
|
||||||
// - IpadOS support: (fullscreen video wrapper should work, see (lookmovie.io) )
|
// - IpadOS support: (fullscreen video wrapper should work, see (lookmovie.io) )
|
||||||
// - HLS support: feature detection otherwise use HLS.js
|
// - HLS support: feature detection otherwise use HLS.js
|
||||||
|
|
Loading…
Reference in a new issue