Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 125 lines 5.1 kB view raw
1import { LockClosedIcon, NoSymbolIcon } from "@heroicons/react/24/outline"; 2import { 3 ArrowsPointingInIcon, 4 ArrowsPointingOutIcon, 5 PauseIcon, 6 PlayIcon, 7 SpeakerWaveIcon, 8 SpeakerXMarkIcon 9} from "@heroicons/react/24/solid"; 10import type { Src } from "@livepeer/react"; 11import * as Player from "@livepeer/react/player"; 12import { memo, type ReactNode } from "react"; 13import { Spinner } from "@/components/Shared/UI"; 14 15const PlayerLoading = () => ( 16 <div className="absolute inset-0 flex flex-col items-center justify-center"> 17 <Spinner size="md" /> 18 </div> 19); 20 21interface PlayerErrorProps { 22 matcher: Player.ErrorIndicatorProps["matcher"]; 23 icon: ReactNode; 24 title: string; 25} 26 27const PlayerError = ({ matcher, icon, title }: PlayerErrorProps) => { 28 return ( 29 <Player.ErrorIndicator 30 className="absolute inset-0 flex flex-col items-center justify-center bg-black" 31 matcher={matcher} 32 > 33 <div className="flex flex-col items-center space-y-2 text-lg text-white"> 34 {icon} 35 <b>{title}</b> 36 </div> 37 </Player.ErrorIndicator> 38 ); 39}; 40 41interface VideoProps { 42 src: Src[] | null; 43 poster?: string; 44} 45 46const Video = ({ src, poster }: VideoProps) => { 47 if (!src) { 48 return null; 49 } 50 51 return ( 52 <Player.Root src={src}> 53 <Player.Container className="size-full overflow-hidden rounded-xl bg-black"> 54 <Player.Video className="size-full" poster={poster} /> 55 <Player.LoadingIndicator> 56 <PlayerLoading /> 57 </Player.LoadingIndicator> 58 <PlayerError 59 icon={<NoSymbolIcon className="size-8" />} 60 matcher="offline" 61 title="Stream is offline" 62 /> 63 <PlayerError 64 icon={<LockClosedIcon className="size-8" />} 65 matcher="access-control" 66 title="Stream is private" 67 /> 68 <Player.Controls className="flex flex-col-reverse gap-1 bg-gradient-to-b from-black/5 via-80% via-black/30 to-black/60 px-3 py-2 duration-1000 md:px-3"> 69 <div className="flex justify-between gap-4"> 70 <div className="flex flex-1 items-center gap-3"> 71 <Player.PlayPauseTrigger className="size-6 flex-shrink-0 transition hover:scale-110"> 72 <Player.PlayingIndicator asChild matcher={false}> 73 <PlayIcon className="size-5 text-white" /> 74 </Player.PlayingIndicator> 75 <Player.PlayingIndicator asChild> 76 <PauseIcon className="size-5 text-white" /> 77 </Player.PlayingIndicator> 78 </Player.PlayPauseTrigger> 79 <Player.LiveIndicator className="flex items-center gap-2"> 80 <div className="size-1.5 rounded-full bg-red-500" /> 81 <b className="text-white text-xs">LIVE</b> 82 </Player.LiveIndicator> 83 <Player.LiveIndicator className="flex" matcher={false}> 84 <Player.Time className="text-white text-xs" /> 85 </Player.LiveIndicator> 86 <Player.MuteTrigger className="size-6 flex-shrink-0 transition hover:scale-110"> 87 <Player.VolumeIndicator asChild matcher={false}> 88 <SpeakerXMarkIcon className="size-5 text-white" /> 89 </Player.VolumeIndicator> 90 <Player.VolumeIndicator asChild matcher={true}> 91 <SpeakerWaveIcon className="size-5 text-white" /> 92 </Player.VolumeIndicator> 93 </Player.MuteTrigger> 94 <Player.Volume className="relative flex max-w-28 flex-1 cursor-pointer items-center"> 95 <Player.Track className="relative h-1 grow rounded-full bg-white/30"> 96 <Player.Range className="absolute h-full rounded-full bg-white" /> 97 </Player.Track> 98 <Player.Thumb className="block size-2.5 rounded-full bg-white outline-hidden" /> 99 </Player.Volume> 100 </div> 101 <div className="flex items-center justify-end gap-2.5 sm:flex-1 md:flex-[1.5]"> 102 <Player.FullscreenTrigger className="size-6 flex-shrink-0 transition hover:scale-110"> 103 <Player.FullscreenIndicator asChild> 104 <ArrowsPointingInIcon className="size-5 text-white" /> 105 </Player.FullscreenIndicator> 106 <Player.FullscreenIndicator asChild matcher={false}> 107 <ArrowsPointingOutIcon className="size-5 text-white" /> 108 </Player.FullscreenIndicator> 109 </Player.FullscreenTrigger> 110 </div> 111 </div> 112 <Player.Seek className="relative flex h-4 w-full cursor-pointer items-center"> 113 <Player.Track className="relative h-1 grow rounded-full bg-white/30"> 114 <Player.SeekBuffer className="absolute h-full rounded-full bg-white/60" /> 115 <Player.Range className="absolute h-full rounded-full bg-white" /> 116 </Player.Track> 117 <Player.Thumb className="block size-2.5 rounded-full bg-white outline-hidden" /> 118 </Player.Seek> 119 </Player.Controls> 120 </Player.Container> 121 </Player.Root> 122 ); 123}; 124 125export default memo(Video);