style upgrades

This commit is contained in:
2026-07-12 21:26:39 -07:00
parent ec334bbed4
commit 4f81f3c0ca
72 changed files with 1541 additions and 471 deletions
+16 -45
View File
@@ -1,17 +1,15 @@
import {
Box,
Container,
Title,
useComputedColorScheme,
} from "@mantine/core";
import { Box, Container, Title, useComputedColorScheme } from "@mantine/core";
import { PropsWithChildren, useEffect, useRef } from "react";
import { Drawer as VaulDrawer } from "vaul";
import { CHROME_COLORS, setThemeColorMeta } from "@/lib/mantine/theme-colors";
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> = ({
@@ -19,55 +17,25 @@ const Drawer: React.FC<DrawerProps> = ({
children,
opened,
onChange,
onExited,
}) => {
const colorScheme = useComputedColorScheme("light");
const contentRef = useRef<HTMLDivElement>(null);
const openedRef = useRef(opened);
useEffect(() => {
openedRef.current = opened;
}, [opened]);
if (!opened) return;
useEffect(() => {
const appElement = document.querySelector(".app") as HTMLElement;
const appElement = document.querySelector<HTMLElement>(".app");
const colors = CHROME_COLORS[colorScheme];
if (!appElement) return;
let themeColorMeta = document.querySelector(
'meta[name="theme-color"]'
) as HTMLMetaElement;
if (!themeColorMeta) {
themeColorMeta = document.createElement("meta");
themeColorMeta.name = "theme-color";
document.head.appendChild(themeColorMeta);
}
const colors = {
light: {
normal: "rgb(255,255,255)",
overlay: "rgb(153,153,153)",
},
dark: {
normal: "rgb(36,36,36)",
overlay: "rgb(22,22,22)",
},
};
const currentColors = colors[colorScheme] || colors.light;
if (opened) {
appElement.classList.add("drawer-scaling");
themeColorMeta.content = currentColors.overlay;
} else {
appElement.classList.remove("drawer-scaling");
themeColorMeta.content = currentColors.normal;
}
appElement?.classList.add("drawer-scaling");
setThemeColorMeta(colors.dimmed);
return () => {
appElement.classList.remove("drawer-scaling");
themeColorMeta.content = currentColors.normal;
appElement?.classList.remove("drawer-scaling");
setThemeColorMeta(colors.base);
};
}, [opened]);
}, [opened, colorScheme]);
useEffect(() => {
if (!opened || !contentRef.current) return;
@@ -109,6 +77,9 @@ const Drawer: React.FC<DrawerProps> = ({
repositionInputs={false}
open={opened}
onOpenChange={onChange}
onAnimationEnd={(open) => {
if (!open) onExited?.();
}}
>
<VaulDrawer.Portal>
<VaulDrawer.Overlay className={styles.drawerOverlay} />
+18 -1
View File
@@ -5,13 +5,30 @@ interface ModalProps extends PropsWithChildren {
title?: string;
opened: boolean;
onClose: () => void;
onChange?: (next: boolean) => void;
onExited?: () => void;
}
const Modal: React.FC<ModalProps> = ({ title, children, opened, onClose }) => (
const Modal: React.FC<ModalProps> = ({
title,
children,
opened,
onClose,
onExited,
}) => (
<MantineModal
opened={opened}
onClose={onClose}
title={<Title order={3}>{title}</Title>}
radius={20}
transitionProps={{
transition: "pop",
duration: 200,
timingFunction: "ease-out",
onExited,
}}
overlayProps={{ backgroundOpacity: 0.4 }}
closeButtonProps={{ "aria-label": "Close" }}
>
<Suspense
fallback={
+32 -2
View File
@@ -1,4 +1,11 @@
import { PropsWithChildren, Suspense, useCallback } from "react";
import {
PropsWithChildren,
Suspense,
useCallback,
useEffect,
useRef,
useState,
} from "react";
import { useIsMobile } from "@/hooks/use-is-mobile";
import Drawer from "./drawer";
import Modal from "./modal";
@@ -10,13 +17,35 @@ interface SheetProps extends PropsWithChildren {
onChange: (next: boolean) => void;
}
const DRAWER_EXIT_MS = 500;
const MODAL_EXIT_MS = 200;
const EXIT_BUFFER_MS = 100;
const Sheet: React.FC<SheetProps> = ({ title, children, opened, onChange }) => {
const isMobile = useIsMobile();
const handleClose = useCallback(() => onChange(false), [onChange]);
const [mounted, setMounted] = useState(opened);
const openedRef = useRef(opened);
openedRef.current = opened;
const handleExited = useCallback(() => {
if (!openedRef.current) setMounted(false);
}, []);
useEffect(() => {
if (opened) {
setMounted(true);
return;
}
const exitDuration =
(isMobile ? DRAWER_EXIT_MS : MODAL_EXIT_MS) + EXIT_BUFFER_MS;
const timer = window.setTimeout(() => setMounted(false), exitDuration);
return () => window.clearTimeout(timer);
}, [opened, isMobile]);
const SheetComponent = isMobile ? Drawer : Modal;
if (!opened) return null;
if (!opened && !mounted) return null;
return (
<SheetComponent
@@ -24,6 +53,7 @@ const Sheet: React.FC<SheetProps> = ({ title, children, opened, onChange }) => {
opened={opened}
onChange={onChange}
onClose={handleClose}
onExited={handleExited}
>
<Suspense fallback={
<Flex justify='center' align='center' w='100%' style={{ minHeight: '25vh' }}>
@@ -150,7 +150,11 @@ const SlidePanel = ({
{panelConfig && (
<>
<Group justify="space-between" p="md" align="center" w="100%">
<ActionIcon variant="transparent" onClick={closePanel}>
<ActionIcon
variant="transparent"
onClick={closePanel}
aria-label="Back"
>
<ArrowLeftIcon size={24} />
</ActionIcon>
<Text fw={500}>{panelConfig.title}</Text>
@@ -158,6 +162,7 @@ const SlidePanel = ({
variant="transparent"
color="green"
onClick={handleConfirm}
aria-label="Confirm"
>
<CheckIcon size={24} />
</ActionIcon>
+6
View File
@@ -20,3 +20,9 @@
outline: none;
transition: height 0.2s ease-out, max-height 0.2s ease-out;
}
@media (prefers-reduced-motion: reduce) {
.drawerContent {
transition: none;
}
}