mirror of
https://github.com/movie-web/movie-web.git
synced 2025-01-12 01:39:14 +01:00
caption clear + popout math
Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
This commit is contained in:
parent
d89bbaef97
commit
056f837dcb
@ -13,7 +13,6 @@ function makeCaptionId(caption: MWCaption, isLinked: boolean): string {
|
|||||||
return isLinked ? `linked-${caption.langIso}` : `external-${caption.langIso}`;
|
return isLinked ? `linked-${caption.langIso}` : `external-${caption.langIso}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO add option to clear captions
|
|
||||||
export function CaptionSelectionPopout() {
|
export function CaptionSelectionPopout() {
|
||||||
const descriptor = useVideoPlayerDescriptor();
|
const descriptor = useVideoPlayerDescriptor();
|
||||||
const meta = useMeta(descriptor);
|
const meta = useMeta(descriptor);
|
||||||
@ -42,10 +41,23 @@ export function CaptionSelectionPopout() {
|
|||||||
<div>Captions</div>
|
<div>Captions</div>
|
||||||
</PopoutSection>
|
</PopoutSection>
|
||||||
<div className="relative overflow-y-auto">
|
<div className="relative overflow-y-auto">
|
||||||
|
<PopoutSection>
|
||||||
|
<PopoutListEntry
|
||||||
|
active={!currentCaption}
|
||||||
|
onClick={() => {
|
||||||
|
controls.clearCaption();
|
||||||
|
controls.closePopout();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
No captions
|
||||||
|
</PopoutListEntry>
|
||||||
|
</PopoutSection>
|
||||||
|
|
||||||
<p className="sticky top-0 z-10 flex items-center space-x-1 bg-ash-200 px-5 py-3 text-sm font-bold uppercase">
|
<p className="sticky top-0 z-10 flex items-center space-x-1 bg-ash-200 px-5 py-3 text-sm font-bold uppercase">
|
||||||
<Icon className="text-base" icon={Icons.LINK} />
|
<Icon className="text-base" icon={Icons.LINK} />
|
||||||
<span>Linked captions</span>
|
<span>Linked captions</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<PopoutSection className="pt-0">
|
<PopoutSection className="pt-0">
|
||||||
<div>
|
<div>
|
||||||
{linkedCaptions.map((link) => (
|
{linkedCaptions.map((link) => (
|
||||||
|
@ -18,8 +18,10 @@ export function PopoutAnchor(props: Props) {
|
|||||||
|
|
||||||
if (state.interface.popout !== props.for) return;
|
if (state.interface.popout !== props.for) return;
|
||||||
|
|
||||||
let handle = -1;
|
let cancelled = false;
|
||||||
function render() {
|
function render() {
|
||||||
|
if (cancelled) return;
|
||||||
|
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
const current = JSON.stringify(state.interface.popoutBounds);
|
const current = JSON.stringify(state.interface.popoutBounds);
|
||||||
const newer = ref.current.getBoundingClientRect();
|
const newer = ref.current.getBoundingClientRect();
|
||||||
@ -28,12 +30,12 @@ export function PopoutAnchor(props: Props) {
|
|||||||
updateInterface(descriptor, state);
|
updateInterface(descriptor, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handle = window.requestAnimationFrame(render);
|
window.requestAnimationFrame(render);
|
||||||
}
|
}
|
||||||
|
|
||||||
handle = window.requestAnimationFrame(render);
|
window.requestAnimationFrame(render);
|
||||||
return () => {
|
return () => {
|
||||||
window.cancelAnimationFrame(handle);
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [descriptor, props]);
|
}, [descriptor, props]);
|
||||||
|
|
||||||
|
@ -4,8 +4,11 @@ import { EpisodeSelectionPopout } from "@/video/components/popouts/EpisodeSelect
|
|||||||
import { CaptionSelectionPopout } from "@/video/components/popouts/CaptionSelectionPopout";
|
import { CaptionSelectionPopout } from "@/video/components/popouts/CaptionSelectionPopout";
|
||||||
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
|
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
|
||||||
import { useControls } from "@/video/state/logic/controls";
|
import { useControls } from "@/video/state/logic/controls";
|
||||||
import { useInterface } from "@/video/state/logic/interface";
|
import {
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
useInterface,
|
||||||
|
VideoInterfaceEvent,
|
||||||
|
} from "@/video/state/logic/interface";
|
||||||
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
import "./Popouts.css";
|
import "./Popouts.css";
|
||||||
|
|
||||||
@ -22,9 +25,44 @@ function ShowPopout(props: { popoutId: string | null }) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO bug: coords are sometimes completely broken
|
function PopoutContainer(props: { videoInterface: VideoInterfaceEvent }) {
|
||||||
export function PopoutProviderAction() {
|
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const [right, setRight] = useState<number>(0);
|
||||||
|
const [bottom, setBottom] = useState<number>(0);
|
||||||
|
const [width, setWidth] = useState<number>(0);
|
||||||
|
|
||||||
|
const calculateAndSetCoords = useCallback((rect: DOMRect, w: number) => {
|
||||||
|
const buttonCenter = rect.left + rect.width / 2;
|
||||||
|
|
||||||
|
setBottom(rect ? rect.height + 30 : 30);
|
||||||
|
setRight(Math.max(window.innerWidth - buttonCenter - w / 2, 30));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!props.videoInterface.popoutBounds) return;
|
||||||
|
calculateAndSetCoords(props.videoInterface.popoutBounds, width);
|
||||||
|
}, [props.videoInterface.popoutBounds, calculateAndSetCoords, width]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const rect = ref.current?.getBoundingClientRect();
|
||||||
|
setWidth(rect?.width ?? 0);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className="absolute z-10 grid h-[500px] w-80 grid-rows-[auto,minmax(0,1fr)] overflow-hidden rounded-lg bg-ash-200"
|
||||||
|
style={{
|
||||||
|
right: `${right}px`,
|
||||||
|
bottom: `${bottom}px`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ShowPopout popoutId={props.videoInterface.popout} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PopoutProviderAction() {
|
||||||
const descriptor = useVideoPlayerDescriptor();
|
const descriptor = useVideoPlayerDescriptor();
|
||||||
const videoInterface = useInterface(descriptor);
|
const videoInterface = useInterface(descriptor);
|
||||||
const controls = useControls(descriptor);
|
const controls = useControls(descriptor);
|
||||||
@ -34,26 +72,6 @@ export function PopoutProviderAction() {
|
|||||||
controls.closePopout();
|
controls.closePopout();
|
||||||
}, [controls]);
|
}, [controls]);
|
||||||
|
|
||||||
const distanceFromRight = useMemo(() => {
|
|
||||||
if (!videoInterface.popoutBounds) return 30;
|
|
||||||
|
|
||||||
const buttonCenter =
|
|
||||||
videoInterface.popoutBounds.left + videoInterface.popoutBounds.width / 2;
|
|
||||||
|
|
||||||
return Math.max(
|
|
||||||
window.innerWidth -
|
|
||||||
buttonCenter -
|
|
||||||
(ref.current?.getBoundingClientRect().width ?? 0) / 2,
|
|
||||||
30
|
|
||||||
);
|
|
||||||
}, [videoInterface.popoutBounds]);
|
|
||||||
|
|
||||||
const distanceFromBottom = useMemo(() => {
|
|
||||||
return videoInterface.popoutBounds
|
|
||||||
? videoInterface.popoutBounds.height + 30
|
|
||||||
: 30;
|
|
||||||
}, [videoInterface.popoutBounds]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition
|
<Transition
|
||||||
show={!!videoInterface.popout}
|
show={!!videoInterface.popout}
|
||||||
@ -62,16 +80,7 @@ export function PopoutProviderAction() {
|
|||||||
>
|
>
|
||||||
<div className="popout-wrapper pointer-events-auto absolute inset-0">
|
<div className="popout-wrapper pointer-events-auto absolute inset-0">
|
||||||
<div onClick={handleClick} className="absolute inset-0" />
|
<div onClick={handleClick} className="absolute inset-0" />
|
||||||
<div
|
<PopoutContainer videoInterface={videoInterface} />
|
||||||
ref={ref}
|
|
||||||
className="absolute z-10 grid h-[500px] w-80 grid-rows-[auto,minmax(0,1fr)] overflow-hidden rounded-lg bg-ash-200"
|
|
||||||
style={{
|
|
||||||
right: `${distanceFromRight}px`,
|
|
||||||
bottom: `${distanceFromBottom}px`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ShowPopout popoutId={videoInterface.popout} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
);
|
);
|
||||||
|
@ -45,11 +45,6 @@ export function ScrollToActive(props: ScrollToActiveProps) {
|
|||||||
wrapper?.querySelector(".active");
|
wrapper?.querySelector(".active");
|
||||||
|
|
||||||
if (wrapper && active) {
|
if (wrapper && active) {
|
||||||
active.scrollIntoView({
|
|
||||||
block: "nearest",
|
|
||||||
inline: "nearest",
|
|
||||||
});
|
|
||||||
|
|
||||||
let activeYPositionCentered = 0;
|
let activeYPositionCentered = 0;
|
||||||
const setActiveYPositionCentered = () => {
|
const setActiveYPositionCentered = () => {
|
||||||
activeYPositionCentered =
|
activeYPositionCentered =
|
||||||
|
@ -74,7 +74,6 @@ export function useControls(
|
|||||||
},
|
},
|
||||||
closePopout() {
|
closePopout() {
|
||||||
state.interface.popout = null;
|
state.interface.popout = null;
|
||||||
state.interface.popoutBounds = null;
|
|
||||||
updateInterface(descriptor, state);
|
updateInterface(descriptor, state);
|
||||||
},
|
},
|
||||||
setFocused(focused) {
|
setFocused(focused) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user