mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-24 18:51:53 +01:00
popout transitions
This commit is contained in:
parent
5d5a727663
commit
5e433266ee
@ -1,12 +1,14 @@
|
|||||||
import { ReactNode, useRef } from "react";
|
import { ReactNode } from "react";
|
||||||
import { CSSTransition } from "react-transition-group";
|
import {
|
||||||
import { CSSTransitionClassNames } from "react-transition-group/CSSTransition";
|
Transition as HeadlessTransition,
|
||||||
|
TransitionClasses,
|
||||||
|
} from "@headlessui/react";
|
||||||
|
|
||||||
type TransitionAnimations = "slide-down" | "slide-up" | "fade" | "fade-inverse";
|
type TransitionAnimations = "slide-down" | "slide-up" | "fade";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
durationClass?: string;
|
durationClass?: "duration-200" | string; // default is specified so tailwind doesnt remove the class in prod builds
|
||||||
animation: TransitionAnimations;
|
animation: TransitionAnimations;
|
||||||
className?: string;
|
className?: string;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
@ -15,44 +17,37 @@ interface Props {
|
|||||||
function getClasses(
|
function getClasses(
|
||||||
animation: TransitionAnimations,
|
animation: TransitionAnimations,
|
||||||
duration: number
|
duration: number
|
||||||
): CSSTransitionClassNames {
|
): TransitionClasses {
|
||||||
if (animation === "slide-down") {
|
if (animation === "slide-down") {
|
||||||
return {
|
return {
|
||||||
exit: `transition-[transform,opacity] translate-y-0 duration-${duration} opacity-100`,
|
leave: `transition-[transform,opacity] duration-${duration}`,
|
||||||
exitActive: "!-translate-y-4 !opacity-0",
|
leaveFrom: "opacity-100 translate-y-0",
|
||||||
exitDone: "hidden",
|
leaveTo: "-translate-y-4 opacity-0",
|
||||||
enter: `transition-[transform,opacity] -translate-y-4 duration-${duration} opacity-0`,
|
enter: `transition-[transform,opacity] duration-${duration}`,
|
||||||
enterActive: "!translate-y-0 !opacity-100",
|
enterFrom: "opacity-0 -translate-y-4",
|
||||||
|
enterTo: "translate-y-0 opacity-100",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animation === "slide-up") {
|
if (animation === "slide-up") {
|
||||||
return {
|
return {
|
||||||
exit: `transition-[transform,opacity] translate-y-0 duration-${duration} opacity-100`,
|
leave: `transition-[transform,opacity] duration-${duration}`,
|
||||||
exitActive: "!translate-y-4 !opacity-0",
|
leaveFrom: "opacity-100 translate-y-0",
|
||||||
exitDone: "hidden",
|
leaveTo: "translate-y-4 opacity-0",
|
||||||
enter: `transition-[transform,opacity] translate-y-4 duration-${duration} opacity-0`,
|
enter: `transition-[transform,opacity] duration-${duration}`,
|
||||||
enterActive: "!translate-y-0 !opacity-100",
|
enterFrom: "opacity-0 translate-y-4",
|
||||||
|
enterTo: "translate-y-0 opacity-100",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animation === "fade") {
|
if (animation === "fade") {
|
||||||
return {
|
return {
|
||||||
exit: `transition-[transform,opacity] duration-${duration} opacity-100`,
|
leave: `transition-[transform,opacity] duration-${duration}`,
|
||||||
exitActive: "!opacity-0",
|
leaveFrom: "opacity-100",
|
||||||
exitDone: "hidden",
|
leaveTo: "opacity-0",
|
||||||
enter: `transition-[transform,opacity] duration-${duration} opacity-0`,
|
enter: `transition-[transform,opacity] duration-${duration}`,
|
||||||
enterActive: "!opacity-100",
|
enterFrom: "opacity-0",
|
||||||
};
|
enterTo: "opacity-100",
|
||||||
}
|
|
||||||
|
|
||||||
if (animation === "fade-inverse") {
|
|
||||||
return {
|
|
||||||
enter: `transition-[transform,opacity] duration-${duration} opacity-100`,
|
|
||||||
enterActive: "!opacity-0",
|
|
||||||
exit: `transition-[transform,opacity] duration-${duration} opacity-0`,
|
|
||||||
exitActive: "!opacity-100",
|
|
||||||
enterDone: "hidden",
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,25 +55,16 @@ function getClasses(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Transition(props: Props) {
|
export function Transition(props: Props) {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
|
||||||
const duration = props.durationClass
|
const duration = props.durationClass
|
||||||
? parseInt(props.durationClass.split("-")[1], 10)
|
? parseInt(props.durationClass.split("-")[1], 10)
|
||||||
: 200;
|
: 200;
|
||||||
const classes = getClasses(props.animation, duration);
|
const classes = getClasses(props.animation, duration);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CSSTransition
|
<div className={props.className}>
|
||||||
nodeRef={ref}
|
<HeadlessTransition show={props.show} {...classes}>
|
||||||
in={props.show}
|
|
||||||
timeout={duration}
|
|
||||||
classNames={classes}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
ref={ref}
|
|
||||||
className={[props.className ?? "", classes.enter ?? ""].join(" ")}
|
|
||||||
>
|
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</HeadlessTransition>
|
||||||
</CSSTransition>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Transition } from "@/components/Transition";
|
||||||
import { EpisodeSelectionPopout } from "@/video/components/popouts/EpisodeSelectionPopout";
|
import { EpisodeSelectionPopout } from "@/video/components/popouts/EpisodeSelectionPopout";
|
||||||
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";
|
||||||
@ -6,7 +7,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
|||||||
|
|
||||||
import "./Popouts.css";
|
import "./Popouts.css";
|
||||||
|
|
||||||
function ShowPopout(props: { popoutId: string }) {
|
function ShowPopout(props: { popoutId: string | null }) {
|
||||||
// only updates popout id when a new one is set, so transitions look good
|
// only updates popout id when a new one is set, so transitions look good
|
||||||
const [popoutId, setPopoutId] = useState<string | null>(props.popoutId);
|
const [popoutId, setPopoutId] = useState<string | null>(props.popoutId);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -20,7 +21,6 @@ function ShowPopout(props: { popoutId: string }) {
|
|||||||
|
|
||||||
// TODO use new design for popouts
|
// TODO use new design for popouts
|
||||||
// TODO improve anti offscreen math
|
// TODO improve anti offscreen math
|
||||||
// TODO in and out transition
|
|
||||||
// TODO attach router history to popout state, so you can use back button to remove popout
|
// TODO attach router history to popout state, so you can use back button to remove popout
|
||||||
export function PopoutProviderAction() {
|
export function PopoutProviderAction() {
|
||||||
const descriptor = useVideoPlayerDescriptor();
|
const descriptor = useVideoPlayerDescriptor();
|
||||||
@ -51,20 +51,20 @@ export function PopoutProviderAction() {
|
|||||||
: "30px";
|
: "30px";
|
||||||
}, [videoInterface]);
|
}, [videoInterface]);
|
||||||
|
|
||||||
if (!videoInterface.popout) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="popout-wrapper pointer-events-auto absolute inset-0">
|
<Transition show={!!videoInterface.popout} animation="fade">
|
||||||
<div onClick={handleClick} className="absolute inset-0" />
|
<div className="popout-wrapper pointer-events-auto absolute inset-0">
|
||||||
<div
|
<div onClick={handleClick} className="absolute inset-0" />
|
||||||
className="grid-template-rows-[auto,minmax(0px,1fr)] absolute z-10 grid h-[500px] w-72 rounded-lg bg-denim-300"
|
<div
|
||||||
style={{
|
className="grid-template-rows-[auto,minmax(0px,1fr)] absolute z-10 grid h-[500px] w-72 rounded-lg bg-denim-300"
|
||||||
right: distanceFromRight,
|
style={{
|
||||||
bottom: distanceFromBottom,
|
right: distanceFromRight,
|
||||||
}}
|
bottom: distanceFromBottom,
|
||||||
>
|
}}
|
||||||
<ShowPopout popoutId={videoInterface.popout ?? ""} />
|
>
|
||||||
|
<ShowPopout popoutId={videoInterface.popout} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Transition>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user