mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-08 06:02:49 +00:00
improve dialog animation + move to ui lib
This commit is contained in:
parent
0e66e6a843
commit
34a6e812ad
|
@ -1,11 +1,11 @@
|
|||
import { KeyIcon } from '@heroicons/react/24/outline';
|
||||
import { CogIcon, LockClosedIcon } from '@heroicons/react/24/solid';
|
||||
import { Button } from '@sd/ui';
|
||||
import { Loader } from '@sd/ui';
|
||||
import { Cloud, Desktop, DeviceMobileCamera, DotsSixVertical, Laptop } from 'phosphor-react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import FileItem from '../explorer/FileItem';
|
||||
import Loader from '../primitive/Loader';
|
||||
import ProgressBar from '../primitive/ProgressBar';
|
||||
import { Tooltip } from '../tooltip/Tooltip';
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { useBridgeMutation } from '@sd/client';
|
||||
import { Input } from '@sd/ui';
|
||||
import { Dialog } from '@sd/ui';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { PropsWithChildren, useState } from 'react';
|
||||
|
||||
import Dialog from '../layout/Dialog';
|
||||
|
||||
export default function CreateLibraryDialog({
|
||||
children,
|
||||
onSubmit
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { useBridgeMutation } from '@sd/client';
|
||||
import { Dialog } from '@sd/ui';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useState } from 'react';
|
||||
|
||||
import Dialog from '../layout/Dialog';
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
libraryUuid: string;
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
||||
import { Button } from '@sd/ui';
|
||||
import clsx from 'clsx';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import Loader from '../primitive/Loader';
|
||||
|
||||
export interface DialogProps extends DialogPrimitive.DialogProps {
|
||||
trigger: ReactNode;
|
||||
ctaLabel?: string;
|
||||
ctaDanger?: boolean;
|
||||
ctaAction?: () => void;
|
||||
title?: string;
|
||||
description?: string;
|
||||
children?: ReactNode;
|
||||
loading?: boolean;
|
||||
submitDisabled?: boolean;
|
||||
}
|
||||
|
||||
export default function Dialog(props: DialogProps) {
|
||||
return (
|
||||
<DialogPrimitive.Root open={props.open} onOpenChange={props.onOpenChange}>
|
||||
<DialogPrimitive.Trigger asChild>{props.trigger}</DialogPrimitive.Trigger>
|
||||
<DialogPrimitive.Portal>
|
||||
<DialogPrimitive.Overlay className="fixed top-0 dialog-overlay bottom-0 left-0 right-0 z-50 grid overflow-y-auto bg-black bg-opacity-50 rounded-xl place-items-center m-[1px]">
|
||||
<DialogPrimitive.Content className="min-w-[300px] max-w-[400px] dialog-content rounded-md bg-gray-650 text-white border border-gray-550 shadow-deep">
|
||||
<form onSubmit={(e) => e.preventDefault()}>
|
||||
<div className="p-5">
|
||||
<DialogPrimitive.Title className="mb-2 font-bold">
|
||||
{props.title}
|
||||
</DialogPrimitive.Title>
|
||||
<DialogPrimitive.Description className="text-sm text-gray-300">
|
||||
{props.description}
|
||||
</DialogPrimitive.Description>
|
||||
{props.children}
|
||||
</div>
|
||||
<div className="flex flex-row justify-end px-3 py-3 space-x-2 bg-gray-600 border-t border-gray-550">
|
||||
{props.loading && <Loader />}
|
||||
<div className="flex-grow" />
|
||||
<DialogPrimitive.Close asChild>
|
||||
<Button loading={props.loading} disabled={props.loading} size="sm" variant="gray">
|
||||
Close
|
||||
</Button>
|
||||
</DialogPrimitive.Close>
|
||||
<Button
|
||||
onClick={props.ctaAction}
|
||||
type="submit"
|
||||
size="sm"
|
||||
loading={props.loading}
|
||||
disabled={props.loading || props.submitDisabled}
|
||||
variant={props.ctaDanger ? 'colored' : 'primary'}
|
||||
className={clsx(props.ctaDanger && 'bg-red-500 border-red-500')}
|
||||
>
|
||||
{props.ctaLabel}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPrimitive.Overlay>
|
||||
</DialogPrimitive.Portal>
|
||||
</DialogPrimitive.Root>
|
||||
);
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
import { TrashIcon } from '@heroicons/react/24/solid';
|
||||
import { useLibraryMutation } from '@sd/client';
|
||||
import { Location, Node } from '@sd/client';
|
||||
import { Button } from '@sd/ui';
|
||||
import { Button, Dialog } from '@sd/ui';
|
||||
import clsx from 'clsx';
|
||||
import { Repeat } from 'phosphor-react';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { Folder } from '../icons/Folder';
|
||||
import Dialog from '../layout/Dialog';
|
||||
|
||||
interface LocationListItemProps {
|
||||
location: Location & { node: Node };
|
||||
|
|
|
@ -2,6 +2,7 @@ import { ExclamationCircleIcon, PlusIcon } from '@heroicons/react/24/solid';
|
|||
import { useBridgeQuery, useLibraryQuery, usePlatform } from '@sd/client';
|
||||
import { Statistics } from '@sd/client';
|
||||
import { Button, Input } from '@sd/ui';
|
||||
import { Dialog } from '@sd/ui';
|
||||
import byteSize from 'byte-size';
|
||||
import clsx from 'clsx';
|
||||
import { useEffect } from 'react';
|
||||
|
@ -10,7 +11,6 @@ import 'react-loading-skeleton/dist/skeleton.css';
|
|||
import create from 'zustand';
|
||||
|
||||
import { Device } from '../components/device/Device';
|
||||
import Dialog from '../components/layout/Dialog';
|
||||
import useCounter from '../hooks/useCounter';
|
||||
|
||||
interface StatItemProps {
|
||||
|
|
|
@ -2,13 +2,13 @@ import { TrashIcon } from '@heroicons/react/24/outline';
|
|||
import { Tag, useLibraryMutation, useLibraryQuery } from '@sd/client';
|
||||
import { TagUpdateArgs } from '@sd/client';
|
||||
import { Button, Input } from '@sd/ui';
|
||||
import { Dialog } from '@sd/ui';
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useDebounce } from 'rooks';
|
||||
|
||||
import Card from '../../../components/layout/Card';
|
||||
import Dialog from '../../../components/layout/Dialog';
|
||||
import { Toggle } from '../../../components/primitive';
|
||||
import { InputContainer } from '../../../components/primitive/InputContainer';
|
||||
import { PopoverPicker } from '../../../components/primitive/PopoverPicker';
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
"target": "es2020",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": ["src", "../ui/src/Dialog.tsx", "../ui/src/Loader.tsx"]
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"@headlessui/react": "^1.7.3",
|
||||
"@heroicons/react": "^2.0.12",
|
||||
"@radix-ui/react-context-menu": "^1.0.0",
|
||||
"@radix-ui/react-dialog": "^1.0.0",
|
||||
"@radix-ui/react-dropdown-menu": "^1.0.0",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"class-variance-authority": "^0.2.3",
|
||||
|
@ -28,6 +29,7 @@
|
|||
"postcss": "^8.4.17",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-loading-icons": "^1.1.0",
|
||||
"react-spring": "^9.5.5",
|
||||
"storybook": "^6.5.12",
|
||||
"tailwindcss": "^3.1.8"
|
||||
|
|
99
packages/ui/src/Dialog.tsx
Normal file
99
packages/ui/src/Dialog.tsx
Normal file
|
@ -0,0 +1,99 @@
|
|||
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
||||
import clsx from 'clsx';
|
||||
import { ReactNode, useState } from 'react';
|
||||
import { animated, config, useTransition } from 'react-spring';
|
||||
|
||||
import { Button, Loader } from '../';
|
||||
|
||||
export interface DialogProps extends DialogPrimitive.DialogProps {
|
||||
trigger: ReactNode;
|
||||
ctaLabel?: string;
|
||||
ctaDanger?: boolean;
|
||||
ctaAction?: () => void;
|
||||
title?: string;
|
||||
description?: string;
|
||||
children?: ReactNode;
|
||||
transformOrigin?: string;
|
||||
loading?: boolean;
|
||||
submitDisabled?: boolean;
|
||||
}
|
||||
|
||||
export function Dialog(props: DialogProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const transitions = useTransition(open, {
|
||||
from: {
|
||||
opacity: 0,
|
||||
transform: `translateY(20px)`,
|
||||
transformOrigin: props.transformOrigin || 'bottom'
|
||||
},
|
||||
enter: { opacity: 1, transform: `translateY(0px)` },
|
||||
leave: { opacity: 0, transform: `translateY(20px)` },
|
||||
config: { mass: 0.4, tension: 200, friction: 10 }
|
||||
});
|
||||
|
||||
return (
|
||||
<DialogPrimitive.Root open={open} onOpenChange={setOpen}>
|
||||
<DialogPrimitive.Trigger asChild>{props.trigger}</DialogPrimitive.Trigger>
|
||||
{transitions(
|
||||
(styles, show) =>
|
||||
show && (
|
||||
<DialogPrimitive.Portal forceMount>
|
||||
<DialogPrimitive.Overlay asChild>
|
||||
<animated.div
|
||||
className="fixed top-0 bottom-0 left-0 right-0 z-50 grid overflow-y-auto bg-black bg-opacity-50 rounded-xl place-items-center m-[1px]"
|
||||
style={{
|
||||
opacity: styles.opacity
|
||||
}}
|
||||
>
|
||||
<DialogPrimitive.Content forceMount asChild>
|
||||
<animated.div
|
||||
style={styles}
|
||||
className="min-w-[300px] max-w-[400px] rounded-md bg-gray-650 text-white border border-gray-550 shadow-deep"
|
||||
>
|
||||
<form onSubmit={(e) => e.preventDefault()}>
|
||||
<div className="p-5">
|
||||
<DialogPrimitive.Title className="mb-2 font-bold">
|
||||
{props.title}
|
||||
</DialogPrimitive.Title>
|
||||
<DialogPrimitive.Description className="text-sm text-gray-300">
|
||||
{props.description}
|
||||
</DialogPrimitive.Description>
|
||||
{props.children}
|
||||
</div>
|
||||
<div className="flex flex-row justify-end px-3 py-3 space-x-2 bg-gray-600 border-t border-gray-550">
|
||||
{props.loading && <Loader />}
|
||||
<div className="flex-grow" />
|
||||
<DialogPrimitive.Close asChild>
|
||||
<Button
|
||||
loading={props.loading}
|
||||
disabled={props.loading}
|
||||
size="sm"
|
||||
variant="gray"
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
</DialogPrimitive.Close>
|
||||
<Button
|
||||
onClick={props.ctaAction}
|
||||
type="submit"
|
||||
size="sm"
|
||||
loading={props.loading}
|
||||
disabled={props.loading || props.submitDisabled}
|
||||
variant={props.ctaDanger ? 'colored' : 'primary'}
|
||||
className={clsx(props.ctaDanger && 'bg-red-500 border-red-500')}
|
||||
>
|
||||
{props.ctaLabel}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</animated.div>
|
||||
</DialogPrimitive.Content>
|
||||
</animated.div>
|
||||
</DialogPrimitive.Overlay>
|
||||
</DialogPrimitive.Portal>
|
||||
)
|
||||
)}
|
||||
</DialogPrimitive.Root>
|
||||
);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import clsx from 'clsx';
|
||||
import { Puff } from 'react-loading-icons';
|
||||
|
||||
export default function Loader(props: { className?: string }) {
|
||||
export function Loader(props: { className?: string }) {
|
||||
return (
|
||||
<Puff
|
||||
stroke="#2599FF"
|
|
@ -1,5 +1,7 @@
|
|||
export * from './Button';
|
||||
export * from './Dropdown';
|
||||
export * from './Dialog';
|
||||
export * from './Loader';
|
||||
export * as ContextMenu from './ContextMenu';
|
||||
export * from './OverlayPanel';
|
||||
export * from './Input';
|
||||
|
|
|
@ -485,6 +485,7 @@ importers:
|
|||
'@headlessui/react': ^1.7.3
|
||||
'@heroicons/react': ^2.0.12
|
||||
'@radix-ui/react-context-menu': ^1.0.0
|
||||
'@radix-ui/react-dialog': ^1.0.0
|
||||
'@radix-ui/react-dropdown-menu': ^1.0.0
|
||||
'@sd/config': workspace:*
|
||||
'@storybook/addon-actions': ^6.5.12
|
||||
|
@ -512,6 +513,7 @@ importers:
|
|||
postcss-loader: ^7.0.1
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
react-loading-icons: ^1.1.0
|
||||
react-spring: ^9.5.5
|
||||
sass: ^1.55.0
|
||||
sass-loader: ^13.0.2
|
||||
|
@ -524,6 +526,7 @@ importers:
|
|||
'@headlessui/react': 1.7.3_biqbaboplfbrettd7655fr4n2y
|
||||
'@heroicons/react': 2.0.12_react@18.2.0
|
||||
'@radix-ui/react-context-menu': 1.0.0_rj7ozvcq3uehdlnj3cbwzbi5ce
|
||||
'@radix-ui/react-dialog': 1.0.0_rj7ozvcq3uehdlnj3cbwzbi5ce
|
||||
'@radix-ui/react-dropdown-menu': 1.0.0_rj7ozvcq3uehdlnj3cbwzbi5ce
|
||||
'@tailwindcss/forms': 0.5.3_tailwindcss@3.1.8
|
||||
class-variance-authority: 0.2.3_typescript@4.8.4
|
||||
|
@ -532,6 +535,7 @@ importers:
|
|||
postcss: 8.4.17
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-loading-icons: 1.1.0
|
||||
react-spring: 9.5.5_biqbaboplfbrettd7655fr4n2y
|
||||
storybook: 6.5.12_yalvw3r2waubxycyb7k7qsruca
|
||||
tailwindcss: 3.1.8
|
||||
|
|
Loading…
Reference in a new issue