A small web app for watching movies and shows easily
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

106 lines
2.7 KiB

import { FloatingCardAnchorPosition } from "@/components/popout/positions/FloatingCardAnchorPosition";
import { FloatingCardMobilePosition } from "@/components/popout/positions/FloatingCardMobilePosition";
import { useIsMobile } from "@/hooks/useIsMobile";
import { useSpringValue, animated, easings } from "@react-spring/web";
import { ReactNode, useCallback, useEffect, useRef } from "react";
interface FloatingCardProps {
children?: ReactNode;
onClose?: () => void;
for: string;
}
interface RootFloatingCardProps extends FloatingCardProps {
className?: string;
}
function CardBase(props: { children: ReactNode }) {
const ref = useRef<HTMLDivElement>(null);
const { isMobile } = useIsMobile();
const height = useSpringValue(0, {
config: { easing: easings.easeInOutSine, duration: 300 },
});
const width = useSpringValue(0, {
config: { easing: easings.easeInOutSine, duration: 300 },
});
const getNewHeight = useCallback(() => {
if (!ref.current) return;
const children = ref.current.querySelectorAll(
":scope *[data-floating-page='true']"
);
if (children.length === 0) {
height.start(0);
width.start(0);
return;
}
const lastChild = children[children.length - 1];
const rect = lastChild.getBoundingClientRect();
if (height.get() === 0) {
height.set(rect.height);
width.set(rect.width);
} else {
height.start(rect.height);
width.start(rect.width);
}
}, [height, width]);
useEffect(() => {
if (!ref.current) return;
getNewHeight();
const observer = new MutationObserver(() => {
getNewHeight();
});
observer.observe(ref.current, {
attributes: false,
childList: true,
subtree: true,
});
return () => {
observer.disconnect();
};
}, [getNewHeight]);
return (
<animated.div
ref={ref}
style={{
height,
width: isMobile ? "100%" : width,
}}
className="relative flex items-center justify-center overflow-hidden"
>
{props.children}
</animated.div>
);
}
export function FloatingCard(props: RootFloatingCardProps) {
const { isMobile } = useIsMobile();
const content = <CardBase>{props.children}</CardBase>;
if (isMobile)
return (
<FloatingCardMobilePosition
className={props.className}
onClose={props.onClose}
>
{content}
</FloatingCardMobilePosition>
);
return (
<FloatingCardAnchorPosition id={props.for} className={props.className}>
{content}
</FloatingCardAnchorPosition>
);
}
export function PopoutFloatingCard(props: FloatingCardProps) {
return (
<FloatingCard
className="overflow-hidden rounded-md bg-ash-300"
{...props}
/>
);
}