caption clear + popout math

Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
This commit is contained in:
Jelle van Snik 2023-02-09 20:42:51 +01:00
parent d89bbaef97
commit 056f837dcb
5 changed files with 62 additions and 45 deletions

View File

@ -13,7 +13,6 @@ function makeCaptionId(caption: MWCaption, isLinked: boolean): string {
return isLinked ? `linked-${caption.langIso}` : `external-${caption.langIso}`;
}
// TODO add option to clear captions
export function CaptionSelectionPopout() {
const descriptor = useVideoPlayerDescriptor();
const meta = useMeta(descriptor);
@ -42,10 +41,23 @@ export function CaptionSelectionPopout() {
<div>Captions</div>
</PopoutSection>
<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">
<Icon className="text-base" icon={Icons.LINK} />
<span>Linked captions</span>
</p>
<PopoutSection className="pt-0">
<div>
{linkedCaptions.map((link) => (

View File

@ -18,8 +18,10 @@ export function PopoutAnchor(props: Props) {
if (state.interface.popout !== props.for) return;
let handle = -1;
let cancelled = false;
function render() {
if (cancelled) return;
if (ref.current) {
const current = JSON.stringify(state.interface.popoutBounds);
const newer = ref.current.getBoundingClientRect();
@ -28,12 +30,12 @@ export function PopoutAnchor(props: Props) {
updateInterface(descriptor, state);
}
}
handle = window.requestAnimationFrame(render);
window.requestAnimationFrame(render);
}
handle = window.requestAnimationFrame(render);
window.requestAnimationFrame(render);
return () => {
window.cancelAnimationFrame(handle);
cancelled = true;
};
}, [descriptor, props]);

View File

@ -4,8 +4,11 @@ import { EpisodeSelectionPopout } from "@/video/components/popouts/EpisodeSelect
import { CaptionSelectionPopout } from "@/video/components/popouts/CaptionSelectionPopout";
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls";
import { useInterface } from "@/video/state/logic/interface";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
useInterface,
VideoInterfaceEvent,
} from "@/video/state/logic/interface";
import { useCallback, useEffect, useRef, useState } from "react";
import "./Popouts.css";
@ -22,9 +25,44 @@ function ShowPopout(props: { popoutId: string | null }) {
return null;
}
// TODO bug: coords are sometimes completely broken
export function PopoutProviderAction() {
function PopoutContainer(props: { videoInterface: VideoInterfaceEvent }) {
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 videoInterface = useInterface(descriptor);
const controls = useControls(descriptor);
@ -34,26 +72,6 @@ export function PopoutProviderAction() {
controls.closePopout();
}, [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 (
<Transition
show={!!videoInterface.popout}
@ -62,16 +80,7 @@ export function PopoutProviderAction() {
>
<div className="popout-wrapper pointer-events-auto absolute inset-0">
<div onClick={handleClick} className="absolute inset-0" />
<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: `${distanceFromRight}px`,
bottom: `${distanceFromBottom}px`,
}}
>
<ShowPopout popoutId={videoInterface.popout} />
</div>
<PopoutContainer videoInterface={videoInterface} />
</div>
</Transition>
);

View File

@ -45,11 +45,6 @@ export function ScrollToActive(props: ScrollToActiveProps) {
wrapper?.querySelector(".active");
if (wrapper && active) {
active.scrollIntoView({
block: "nearest",
inline: "nearest",
});
let activeYPositionCentered = 0;
const setActiveYPositionCentered = () => {
activeYPositionCentered =

View File

@ -74,7 +74,6 @@ export function useControls(
},
closePopout() {
state.interface.popout = null;
state.interface.popoutBounds = null;
updateInterface(descriptor, state);
},
setFocused(focused) {