mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-10-14 03:12:30 -04:00
[ENG-1288] Copy, cut, and paste shortcuts (#1591)
* copy paste shortcut * add cut shortcut
This commit is contained in:
1 parent
3d844aeee7
commit
2dd28540f1
3 files changed
+85
-4
No files matched your search
@@ -12,9 +12,9 @@ import {
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useKey, useKeys } from 'rooks';
|
||||
import { getItemObject, useLibraryContext, type Object } from '@sd/client';
|
||||
import { dialogManager, ModifierKeys, toast } from '@sd/ui';
|
||||
import { dialogManager, ModifierKeys } from '@sd/ui';
|
||||
import { Loader } from '~/components';
|
||||
import { useKeyMatcher, useOperatingSystem } from '~/hooks';
|
||||
import { useKeyCopyPaste, useKeyMatcher, useOperatingSystem } from '~/hooks';
|
||||
import { isNonEmpty } from '~/util';
|
||||
import { usePlatform } from '~/util/Platform';
|
||||
|
||||
@@ -63,7 +63,6 @@ export default memo(
|
||||
const quickPreview = useQuickPreviewContext();
|
||||
const quickPreviewStore = useQuickPreviewStore();
|
||||
const os = useOperatingSystem();
|
||||
|
||||
const { doubleClick } = useViewItemDoubleClick();
|
||||
|
||||
const { layoutMode } = explorer.useSettingsSnapshot();
|
||||
@@ -109,6 +108,8 @@ export default memo(
|
||||
doubleClick();
|
||||
});
|
||||
|
||||
useKeyCopyPaste();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -179,7 +180,7 @@ export const EmptyNotice = (props: {
|
||||
if (props.loading) return null;
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col items-center justify-center text-ink-faint">
|
||||
<div className="flex flex-col items-center justify-center h-full text-ink-faint">
|
||||
{props.icon
|
||||
? isValidElement(props.icon)
|
||||
? props.icon
|
||||
|
||||
@@ -21,3 +21,4 @@ export * from './useZodRouteParams';
|
||||
export * from './useZodSearchParams';
|
||||
export * from './useIsTextTruncated';
|
||||
export * from './useKeyMatcher';
|
||||
export * from './useKeyCopyCutPaste';
|
||||
@@ -0,0 +1,79 @@
|
||||
import { getExplorerStore, useExplorerStore } from "~/app/$libraryId/Explorer/store";
|
||||
import { useExplorerSearchParams } from "~/app/$libraryId/Explorer/util";
|
||||
import { useExplorerContext } from "~/app/$libraryId/Explorer/Context";
|
||||
import { useKeyMatcher } from "./useKeyMatcher";
|
||||
import { useKeys } from "rooks";
|
||||
import {useItemsAsFilePaths, useLibraryMutation} from '@sd/client';
|
||||
import {toast} from '@sd/ui';
|
||||
|
||||
|
||||
export const useKeyCopyPaste = () => {
|
||||
const {cutCopyState} = useExplorerStore();
|
||||
const [{ path }] = useExplorerSearchParams();
|
||||
|
||||
const metaCtrlKey = useKeyMatcher('Meta').key;
|
||||
const copyFiles = useLibraryMutation('files.copyFiles');
|
||||
const cutFiles = useLibraryMutation('files.cutFiles');
|
||||
const explorer = useExplorerContext();
|
||||
const selectedFilePaths = useItemsAsFilePaths(Array.from(explorer.selectedItems));
|
||||
|
||||
useKeys([metaCtrlKey, 'KeyC'], (e) => {
|
||||
e.stopPropagation();
|
||||
; if (explorer.parent?.type === 'Location') {
|
||||
getExplorerStore().cutCopyState = {
|
||||
sourceParentPath: path ?? '/',
|
||||
sourceLocationId: explorer.parent.location.id,
|
||||
sourcePathIds: selectedFilePaths.map((p) => p.id),
|
||||
type: 'Copy'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
useKeys([metaCtrlKey, 'KeyX'], (e) => {
|
||||
e.stopPropagation();
|
||||
if (explorer.parent?.type === 'Location') {
|
||||
getExplorerStore().cutCopyState = {
|
||||
sourceParentPath: path ?? '/',
|
||||
sourceLocationId: explorer.parent.location.id,
|
||||
sourcePathIds: selectedFilePaths.map((p) => p.id),
|
||||
type: 'Cut'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
useKeys([metaCtrlKey, 'KeyV'], async (e) => {
|
||||
e.stopPropagation();
|
||||
const parent = explorer.parent;
|
||||
if (parent?.type === 'Location' && cutCopyState.type !== 'Idle' && path) {
|
||||
const { type, sourcePathIds, sourceParentPath, sourceLocationId } = cutCopyState;
|
||||
|
||||
const sameLocation =
|
||||
sourceLocationId === parent.location.id && sourceParentPath === path;
|
||||
|
||||
try {
|
||||
if (type == 'Copy') {
|
||||
await copyFiles.mutateAsync({
|
||||
source_location_id: sourceLocationId,
|
||||
sources_file_path_ids: [...sourcePathIds],
|
||||
target_location_id: parent.location.id,
|
||||
target_location_relative_directory_path: path
|
||||
});
|
||||
} else if (sameLocation) {
|
||||
toast.error('File already exists in this location');
|
||||
} else {
|
||||
await cutFiles.mutateAsync({
|
||||
source_location_id: sourceLocationId,
|
||||
sources_file_path_ids: [...sourcePathIds],
|
||||
target_location_id: parent.location.id,
|
||||
target_location_relative_directory_path: path
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error({
|
||||
title: `Failed to ${type.toLowerCase()} file`,
|
||||
body: `Error: ${error}.`
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user