123 lines
3.3 KiB
TypeScript
123 lines
3.3 KiB
TypeScript
import { Box, Container, Title, useComputedColorScheme } from "@mantine/core";
|
|
import { PropsWithChildren, useEffect, useRef } from "react";
|
|
import { Drawer as VaulDrawer } from "vaul";
|
|
import {
|
|
pushDimmedThemeColor,
|
|
popDimmedThemeColor,
|
|
} from "@/lib/mantine/theme-colors";
|
|
import { getTheme } from "@/themes/registry";
|
|
import { resolveChromeColors } from "@/themes/chrome";
|
|
import { useAuth } from "@/contexts/auth-context";
|
|
import styles from "./styles.module.css";
|
|
|
|
interface DrawerProps extends PropsWithChildren {
|
|
title?: string;
|
|
opened: boolean;
|
|
onChange: (next: boolean) => void;
|
|
onClose?: () => void;
|
|
onExited?: () => void;
|
|
}
|
|
|
|
const Drawer: React.FC<DrawerProps> = ({
|
|
title,
|
|
children,
|
|
opened,
|
|
onChange,
|
|
onExited,
|
|
}) => {
|
|
const colorScheme = useComputedColorScheme("light");
|
|
const { metadata } = useAuth();
|
|
const contentRef = useRef<HTMLDivElement>(null);
|
|
const themeId = metadata.theme;
|
|
|
|
useEffect(() => {
|
|
if (!opened) return;
|
|
|
|
const appElement = document.querySelector<HTMLElement>(".app");
|
|
const colors = resolveChromeColors(getTheme(themeId))[colorScheme];
|
|
|
|
appElement?.classList.add("drawer-scaling");
|
|
pushDimmedThemeColor(colors.dimmed);
|
|
|
|
return () => {
|
|
appElement?.classList.remove("drawer-scaling");
|
|
popDimmedThemeColor(colors.base);
|
|
};
|
|
}, [opened, colorScheme, themeId]);
|
|
|
|
useEffect(() => {
|
|
if (!opened || !contentRef.current) return;
|
|
|
|
const updateDrawerHeight = () => {
|
|
if (contentRef.current) {
|
|
const drawerContent = contentRef.current;
|
|
const visualViewport = window.visualViewport;
|
|
|
|
if (visualViewport) {
|
|
const availableHeight = visualViewport.height;
|
|
const maxDrawerHeight = Math.min(
|
|
availableHeight * 0.75,
|
|
window.innerHeight * 0.75
|
|
);
|
|
|
|
drawerContent.style.maxHeight = `${maxDrawerHeight}px`;
|
|
} else {
|
|
drawerContent.style.maxHeight = "75vh";
|
|
}
|
|
}
|
|
};
|
|
|
|
updateDrawerHeight();
|
|
|
|
if (window.visualViewport) {
|
|
window.visualViewport.addEventListener("resize", updateDrawerHeight);
|
|
}
|
|
|
|
return () => {
|
|
if (window.visualViewport) {
|
|
window.visualViewport.removeEventListener("resize", updateDrawerHeight);
|
|
}
|
|
};
|
|
}, [opened]);
|
|
|
|
return (
|
|
<VaulDrawer.Root
|
|
repositionInputs={false}
|
|
open={opened}
|
|
onOpenChange={onChange}
|
|
onAnimationEnd={(open) => {
|
|
if (!open) onExited?.();
|
|
}}
|
|
>
|
|
<VaulDrawer.Portal>
|
|
<VaulDrawer.Overlay className={styles.drawerOverlay} />
|
|
<VaulDrawer.Content
|
|
className={styles.drawerContent}
|
|
aria-describedby="drawer"
|
|
ref={contentRef}
|
|
>
|
|
<Container flex={1} p="md">
|
|
<Box
|
|
mb="sm"
|
|
bg="var(--mantine-color-gray-4)"
|
|
w="3rem"
|
|
h="0.375rem"
|
|
ml="auto"
|
|
mr="auto"
|
|
style={{ borderRadius: "9999px" }}
|
|
/>
|
|
<Container mx="auto" maw="28rem" px={0}>
|
|
<VaulDrawer.Title>
|
|
<Title order={2}>{title}</Title>
|
|
</VaulDrawer.Title>
|
|
{children}
|
|
</Container>
|
|
</Container>
|
|
</VaulDrawer.Content>
|
|
</VaulDrawer.Portal>
|
|
</VaulDrawer.Root>
|
|
);
|
|
};
|
|
|
|
export default Drawer;
|