[ENG-1182] Switch quick preview animation from react-spring to tailwindcss-animate (#1431)

* animate

* radix-state-open
This commit is contained in:
nikec
2023-10-04 11:40:40 +02:00
committed by GitHub
parent ddf3995032
commit 1ca2ea1221

View File

@@ -1,6 +1,5 @@
import { ArrowLeft, ArrowRight, DotsThree, Plus, SidebarSimple, X } from '@phosphor-icons/react';
import * as Dialog from '@radix-ui/react-dialog';
import { animated, useTransition } from '@react-spring/web';
import clsx from 'clsx';
import {
ButtonHTMLAttributes,
@@ -38,9 +37,6 @@ import { FileThumb } from '../FilePath/Thumb';
import { SingleItemMetadata } from '../Inspector';
import { getQuickPreviewStore, useQuickPreviewStore } from './store';
const AnimatedDialogOverlay = animated(Dialog.Overlay);
const AnimatedDialogContent = animated(Dialog.Content);
const iconKinds: ObjectKindKey[] = ['Audio', 'Folder', 'Executable', 'Unknown'];
const textKinds: ObjectKindKey[] = ['Text', 'Config', 'Code'];
const withoutBackgroundKinds: ObjectKindKey[] = [...iconKinds, ...textKinds, 'Document'];
@@ -77,17 +73,6 @@ export const QuickPreview = () => {
const item = useMemo(() => items[itemIndex], [items, itemIndex]);
const transitions = useTransition(open, {
from: {
opacity: 0,
transform: `translateY(20px) scale(0.9)`,
transformOrigin: 'center top'
},
enter: { opacity: 1, transform: `translateY(0px) scale(1)` },
leave: { opacity: 0, immediate: true },
config: { mass: 0.2, tension: 300, friction: 20, bounce: 0 }
});
const renameFile = useLibraryMutation(['files.renameFile'], {
onError: () => setNewName(null),
onSuccess: () => rspc.queryClient.invalidateQueries(['search.paths'])
@@ -181,268 +166,253 @@ export const QuickPreview = () => {
));
});
if (!item) return null;
const { kind, ...itemData } = getExplorerItemData(item);
const name = newName || `${itemData.name}${itemData.extension ? `.${itemData.extension}` : ''}`;
const background = !withoutBackgroundKinds.includes(kind);
const icon = iconKinds.includes(kind);
return (
<Dialog.Root open={open} onOpenChange={(open) => (getQuickPreviewStore().open = open)}>
{transitions((styles, show) => {
if (!show || !item) return null;
<QuickPreviewContext.Provider value={{ background }}>
<Dialog.Portal forceMount>
<Dialog.Overlay
className={clsx(
'absolute inset-0 z-50',
'radix-state-open:animate-in radix-state-open:fade-in-0',
isDark ? 'bg-black/80' : 'bg-black/60'
)}
onContextMenu={(e) => e.preventDefault()}
/>
const { kind, ...itemData } = getExplorerItemData(item);
const name =
newName ||
`${itemData.name}${itemData.extension ? `.${itemData.extension}` : ''}`;
const background = !withoutBackgroundKinds.includes(kind);
const icon = iconKinds.includes(kind);
return (
<QuickPreviewContext.Provider value={{ background }}>
<Dialog.Portal forceMount>
<AnimatedDialogOverlay
className={clsx(
'absolute inset-0 z-50',
isDark ? 'bg-black/80' : 'bg-black/60'
<Dialog.Content
className="fixed inset-[5%] z-50 outline-none radix-state-open:animate-in radix-state-open:fade-in-0 radix-state-open:zoom-in-95"
onOpenAutoFocus={(e) => e.preventDefault()}
onEscapeKeyDown={(e) => isRenaming && e.preventDefault()}
onContextMenu={(e) => e.preventDefault()}
>
<div
className={clsx(
'flex h-full overflow-hidden rounded-md border',
isDark ? 'border-app-line/80' : 'border-app-line/10'
)}
>
<div className="relative flex flex-1 flex-col overflow-hidden bg-app/80 backdrop-blur">
{background && (
<div className="absolute inset-0 overflow-hidden bg-black/90">
<FileThumb
data={item}
cover={true}
childClassName="opacity-75 blur-3xl scale-125"
/>
</div>
)}
style={{ opacity: styles.opacity }}
onContextMenu={(e) => e.preventDefault()}
/>
<AnimatedDialogContent
className="fixed inset-[5%] z-50 outline-none"
style={styles}
onOpenAutoFocus={(e) => e.preventDefault()}
onEscapeKeyDown={(e) => isRenaming && e.preventDefault()}
onContextMenu={(e) => e.preventDefault()}
>
<div
className={clsx(
'flex h-full overflow-hidden rounded-md border',
isDark ? 'border-app-line/80' : 'border-app-line/10'
'z-50 flex items-center p-2',
background ? 'text-white' : 'text-ink'
)}
>
<div className="relative flex flex-1 flex-col overflow-hidden bg-app/80 backdrop-blur">
{background && (
<div className="absolute inset-0 overflow-hidden bg-black/90">
<FileThumb
data={item}
cover={true}
childClassName="opacity-75 blur-3xl scale-125"
/>
</div>
)}
<div className="flex flex-1">
<Tooltip label="Close">
<Dialog.Close asChild>
<IconButton>
<X weight="bold" />
</IconButton>
</Dialog.Close>
</Tooltip>
<div
className={clsx(
'z-50 flex items-center p-2',
background ? 'text-white' : 'text-ink'
)}
>
<div className="flex flex-1">
<Tooltip label="Close">
<Dialog.Close asChild>
<IconButton>
<X weight="bold" />
</IconButton>
</Dialog.Close>
{items.length > 1 && (
<div className="ml-2 flex">
<Tooltip label="Back">
<IconButton
disabled={!items[itemIndex - 1]}
onClick={() =>
changeCurrentItem(itemIndex - 1)
}
className="rounded-r-none"
>
<ArrowLeft weight="bold" />
</IconButton>
</Tooltip>
{items.length > 1 && (
<div className="ml-2 flex">
<Tooltip label="Back">
<IconButton
disabled={!items[itemIndex - 1]}
onClick={() =>
changeCurrentItem(itemIndex - 1)
}
className="rounded-r-none"
>
<ArrowLeft weight="bold" />
</IconButton>
</Tooltip>
<Tooltip label="Forward">
<IconButton
disabled={!items[itemIndex + 1]}
onClick={() =>
changeCurrentItem(itemIndex + 1)
}
className="rounded-l-none"
>
<ArrowRight weight="bold" />
</IconButton>
</Tooltip>
</div>
)}
</div>
<div className="flex w-1/2 items-center justify-center truncate text-sm">
{isRenaming && name ? (
<RenameInput
name={name}
onRename={(newName) => {
setIsRenaming(false);
if (
!('id' in item.item) ||
!newName ||
newName === name
)
return;
const filePathData =
getIndexedItemFilePath(item);
if (!filePathData) return;
const locationId =
filePathData.location_id;
if (locationId === null) return;
renameFile.mutate({
location_id: locationId,
kind: {
One: {
from_file_path_id:
item.item.id,
to: newName
}
}
});
setNewName(newName);
}}
/>
) : (
<Tooltip label={name} className="truncate">
<span
onClick={() =>
name &&
item.type !== 'NonIndexedPath' &&
setIsRenaming(true)
}
className={clsx(
item.type === 'NonIndexedPath'
? 'cursor-default'
: 'cursor-text'
)}
>
{name}
</span>
</Tooltip>
)}
</div>
<div className="flex flex-1 justify-end gap-1">
{item.type !== 'NonIndexedPath' && (
<DropdownMenu.Root
trigger={
<div className="flex">
<Tooltip label="More">
<IconButton>
<DotsThree
size={20}
weight="bold"
/>
</IconButton>
</Tooltip>
</div>
}
onOpenChange={setIsContextMenuOpen}
align="end"
sideOffset={-10}
>
<ExplorerContextMenu items={[item]} custom>
<Conditional
items={[
FilePathItems.OpenOrDownload,
SharedItems.RevealInNativeExplorer
]}
/>
<DropdownMenu.Item
label="Rename"
onClick={() =>
name && setIsRenaming(true)
}
/>
<SeparatedConditional
items={[ObjectItems.AssignTag]}
/>
<Conditional
items={[
FilePathItems.CopyAsPath,
FilePathItems.Crypto,
FilePathItems.Compress,
ObjectItems.ConvertObject,
FilePathItems.SecureDelete
]}
>
{(items) => (
<DropdownMenu.SubMenu
label="More actions..."
icon={Plus}
>
{items}
</DropdownMenu.SubMenu>
)}
</Conditional>
<SeparatedConditional
items={[FilePathItems.Delete]}
/>
</ExplorerContextMenu>
</DropdownMenu.Root>
)}
<Tooltip label="Show details">
<Tooltip label="Forward">
<IconButton
disabled={!items[itemIndex + 1]}
onClick={() =>
setShowMetadata(!showMetadata)
changeCurrentItem(itemIndex + 1)
}
active={showMetadata}
className="rounded-l-none"
>
<SidebarSimple
className="rotate-180"
weight={
showMetadata ? 'fill' : 'regular'
}
/>
<ArrowRight weight="bold" />
</IconButton>
</Tooltip>
</div>
</div>
<FileThumb
data={item}
loadOriginal
mediaControls
className={clsx(
'm-3 !w-auto flex-1 !overflow-hidden rounded',
!background && !icon && 'bg-app-box shadow'
)}
childClassName={clsx(
'rounded',
kind === 'Text' && 'p-3',
!icon && 'h-full',
textKinds.includes(kind) && 'select-text'
)}
/>
)}
</div>
{showMetadata && (
<div className="no-scrollbar w-64 shrink-0 border-l border-app-line bg-app-darkBox py-1">
<SingleItemMetadata item={item} />
</div>
)}
<div className="flex w-1/2 items-center justify-center truncate text-sm">
{isRenaming && name ? (
<RenameInput
name={name}
onRename={(newName) => {
setIsRenaming(false);
if (
!('id' in item.item) ||
!newName ||
newName === name
)
return;
const filePathData =
getIndexedItemFilePath(item);
if (!filePathData) return;
const locationId = filePathData.location_id;
if (locationId === null) return;
renameFile.mutate({
location_id: locationId,
kind: {
One: {
from_file_path_id: item.item.id,
to: newName
}
}
});
setNewName(newName);
}}
/>
) : (
<Tooltip label={name} className="truncate">
<span
onClick={() =>
name &&
item.type !== 'NonIndexedPath' &&
setIsRenaming(true)
}
className={clsx(
item.type === 'NonIndexedPath'
? 'cursor-default'
: 'cursor-text'
)}
>
{name}
</span>
</Tooltip>
)}
</div>
<div className="flex flex-1 justify-end gap-1">
{item.type !== 'NonIndexedPath' && (
<DropdownMenu.Root
trigger={
<div className="flex">
<Tooltip label="More">
<IconButton>
<DotsThree
size={20}
weight="bold"
/>
</IconButton>
</Tooltip>
</div>
}
onOpenChange={setIsContextMenuOpen}
align="end"
sideOffset={-10}
>
<ExplorerContextMenu items={[item]} custom>
<Conditional
items={[
FilePathItems.OpenOrDownload,
SharedItems.RevealInNativeExplorer
]}
/>
<DropdownMenu.Item
label="Rename"
onClick={() => name && setIsRenaming(true)}
/>
<SeparatedConditional
items={[ObjectItems.AssignTag]}
/>
<Conditional
items={[
FilePathItems.CopyAsPath,
FilePathItems.Crypto,
FilePathItems.Compress,
ObjectItems.ConvertObject,
FilePathItems.SecureDelete
]}
>
{(items) => (
<DropdownMenu.SubMenu
label="More actions..."
icon={Plus}
>
{items}
</DropdownMenu.SubMenu>
)}
</Conditional>
<SeparatedConditional
items={[FilePathItems.Delete]}
/>
</ExplorerContextMenu>
</DropdownMenu.Root>
)}
<Tooltip label="Show details">
<IconButton
onClick={() => setShowMetadata(!showMetadata)}
active={showMetadata}
>
<SidebarSimple
className="rotate-180"
weight={showMetadata ? 'fill' : 'regular'}
/>
</IconButton>
</Tooltip>
</div>
</div>
</AnimatedDialogContent>
</Dialog.Portal>
</QuickPreviewContext.Provider>
);
})}
<FileThumb
data={item}
loadOriginal
mediaControls
className={clsx(
'm-3 !w-auto flex-1 !overflow-hidden rounded',
!background && !icon && 'bg-app-box shadow'
)}
childClassName={clsx(
'rounded',
kind === 'Text' && 'p-3',
!icon && 'h-full',
textKinds.includes(kind) && 'select-text'
)}
/>
</div>
{showMetadata && (
<div className="no-scrollbar w-64 shrink-0 border-l border-app-line bg-app-darkBox py-1">
<SingleItemMetadata item={item} />
</div>
)}
</div>
</Dialog.Content>
</Dialog.Portal>
</QuickPreviewContext.Provider>
</Dialog.Root>
);
};