mirror of
https://github.com/lukevella/rallly.git
synced 2025-06-06 04:31:50 +02:00
Switch to tRPC (#173)
This commit is contained in:
parent
3d7e7e8a95
commit
2c4157ea24
245 changed files with 1585 additions and 1755 deletions
1
src/components/modal/index.ts
Normal file
1
src/components/modal/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { useModal } from "./use-modal";
|
61
src/components/modal/modal-provider.tsx
Normal file
61
src/components/modal/modal-provider.tsx
Normal file
|
@ -0,0 +1,61 @@
|
|||
import * as React from "react";
|
||||
import { useList } from "react-use";
|
||||
|
||||
import { useRequiredContext } from "../use-required-context";
|
||||
import Modal, { ModalProps } from "./modal";
|
||||
|
||||
export interface ModalProviderProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const ModalContext =
|
||||
React.createContext<{
|
||||
render: (el: ModalProps) => void;
|
||||
} | null>(null);
|
||||
|
||||
ModalContext.displayName = "<ModalProvider />";
|
||||
|
||||
export const useModalContext = () => {
|
||||
return useRequiredContext(ModalContext);
|
||||
};
|
||||
|
||||
const ModalProvider: React.VoidFunctionComponent<ModalProviderProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [modals, { push, removeAt, updateAt }] = useList<ModalProps>([]);
|
||||
|
||||
const removeModalAt = (index: number) => {
|
||||
updateAt(index, { ...modals[index], visible: false });
|
||||
setTimeout(() => {
|
||||
removeAt(index);
|
||||
}, 500);
|
||||
};
|
||||
return (
|
||||
<ModalContext.Provider
|
||||
value={{
|
||||
render: (props) => {
|
||||
push(props);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
{modals.map((props, i) => (
|
||||
<Modal
|
||||
key={i}
|
||||
visible={true}
|
||||
{...props}
|
||||
onOk={() => {
|
||||
props.onOk?.();
|
||||
removeModalAt(i);
|
||||
}}
|
||||
onCancel={() => {
|
||||
props.onCancel?.();
|
||||
removeModalAt(i);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</ModalContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalProvider;
|
126
src/components/modal/modal.tsx
Normal file
126
src/components/modal/modal.tsx
Normal file
|
@ -0,0 +1,126 @@
|
|||
import { Dialog } from "@headlessui/react";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import * as React from "react";
|
||||
|
||||
import X from "@/components/icons/x.svg";
|
||||
|
||||
import Button, { ButtonProps } from "../button";
|
||||
|
||||
export interface ModalProps {
|
||||
description?: React.ReactNode;
|
||||
title?: React.ReactNode;
|
||||
okText?: string;
|
||||
cancelText?: string;
|
||||
okButtonProps?: ButtonProps;
|
||||
onOk?: () => void;
|
||||
onCancel?: () => void;
|
||||
footer?: React.ReactNode;
|
||||
content?: React.ReactNode;
|
||||
overlayClosable?: boolean;
|
||||
visible?: boolean;
|
||||
showClose?: boolean;
|
||||
}
|
||||
|
||||
const Modal: React.VoidFunctionComponent<ModalProps> = ({
|
||||
description,
|
||||
title,
|
||||
okText,
|
||||
cancelText,
|
||||
okButtonProps,
|
||||
footer,
|
||||
content,
|
||||
overlayClosable,
|
||||
onCancel,
|
||||
onOk,
|
||||
visible,
|
||||
showClose,
|
||||
}) => {
|
||||
const initialFocusRef = React.useRef<HTMLButtonElement>(null);
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{visible ? (
|
||||
<Dialog
|
||||
open={visible}
|
||||
className="fixed inset-0 z-40 overflow-y-auto"
|
||||
initialFocus={initialFocusRef}
|
||||
onClose={() => {
|
||||
if (overlayClosable) onCancel?.();
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
transition={{ duration: 0.5 }}
|
||||
className="flex min-h-screen items-center justify-center"
|
||||
>
|
||||
<Dialog.Overlay
|
||||
as={motion.div}
|
||||
transition={{ duration: 0.5 }}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="fixed inset-0 z-0 bg-slate-900 bg-opacity-25"
|
||||
/>
|
||||
<motion.div
|
||||
transition={{ duration: 0.1 }}
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.9 }}
|
||||
className="relative z-50 my-8 inline-block max-w-full transform text-left align-middle"
|
||||
>
|
||||
<div className="mx-4 max-w-full overflow-hidden rounded-xl bg-white shadow-xl xs:rounded-xl">
|
||||
{showClose ? (
|
||||
<button
|
||||
className="absolute right-5 top-1 z-10 rounded-lg p-2 text-slate-400 transition-colors hover:bg-slate-500/10 hover:text-slate-500 active:bg-slate-500/20"
|
||||
onClick={onCancel}
|
||||
>
|
||||
<X className="h-4" />
|
||||
</button>
|
||||
) : null}
|
||||
{content ?? (
|
||||
<div className="max-w-md p-6">
|
||||
{title ? (
|
||||
<Dialog.Title className="mb-2 font-medium">
|
||||
{title}
|
||||
</Dialog.Title>
|
||||
) : null}
|
||||
{description ? (
|
||||
<Dialog.Description className="m-0">
|
||||
{description}
|
||||
</Dialog.Description>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
{footer === undefined ? (
|
||||
<div className="flex h-14 items-center justify-end space-x-3 rounded-br-lg rounded-bl-lg border-t bg-slate-50 px-4">
|
||||
{cancelText ? (
|
||||
<Button
|
||||
onClick={() => {
|
||||
onCancel?.();
|
||||
}}
|
||||
>
|
||||
{cancelText}
|
||||
</Button>
|
||||
) : null}
|
||||
{okText ? (
|
||||
<Button
|
||||
ref={initialFocusRef}
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
onOk?.();
|
||||
}}
|
||||
{...okButtonProps}
|
||||
>
|
||||
{okText}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</Dialog>
|
||||
) : null}
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
||||
|
||||
export default Modal;
|
27
src/components/modal/use-modal.tsx
Normal file
27
src/components/modal/use-modal.tsx
Normal file
|
@ -0,0 +1,27 @@
|
|||
import React from "react";
|
||||
|
||||
import Modal, { ModalProps } from "./modal";
|
||||
|
||||
type OpenModalFn = () => void;
|
||||
type CloseModalFn = () => void;
|
||||
|
||||
export const useModal = (
|
||||
props?: ModalProps,
|
||||
): [React.ReactElement<ModalProps>, OpenModalFn, CloseModalFn] => {
|
||||
const [visible, setVisible] = React.useState(false);
|
||||
const modal = (
|
||||
<Modal
|
||||
{...props}
|
||||
visible={visible}
|
||||
onOk={() => {
|
||||
props?.onOk?.();
|
||||
setVisible(false);
|
||||
}}
|
||||
onCancel={() => {
|
||||
props?.onCancel?.();
|
||||
setVisible(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
return [modal, () => setVisible(true), () => setVisible(false)];
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue