feat: add files popover in note toolbar (#913)
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/constants';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
import { StreamingFileReader } from '@standardnotes/filepicker';
|
||||
import { SNNote } from '@standardnotes/snjs';
|
||||
import { FunctionComponent } from 'preact';
|
||||
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
|
||||
import { AttachedFilesPopover } from './AttachedFilesPopover';
|
||||
import {
|
||||
PopoverFileItemAction,
|
||||
PopoverFileItemActionType,
|
||||
} from './PopoverFileItemAction';
|
||||
|
||||
export enum PopoverTabs {
|
||||
AttachedFiles,
|
||||
AllFiles,
|
||||
}
|
||||
|
||||
export type PopoverWrapperProps = {
|
||||
application: WebApplication;
|
||||
appState: AppState;
|
||||
note: SNNote;
|
||||
fileActionHandler: (action: PopoverFileItemAction) => Promise<boolean>;
|
||||
};
|
||||
|
||||
export const PopoverDragNDropWrapper: FunctionComponent<
|
||||
PopoverWrapperProps
|
||||
> = ({ fileActionHandler, appState, application, note }) => {
|
||||
const dropzoneRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [currentTab, setCurrentTab] = useState(PopoverTabs.AttachedFiles);
|
||||
const dragCounter = useRef(0);
|
||||
|
||||
const handleDrag = (event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const handleDragIn = (event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
dragCounter.current = dragCounter.current + 1;
|
||||
|
||||
if (event.dataTransfer?.items.length) {
|
||||
setIsDragging(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragOut = (event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
dragCounter.current = dragCounter.current - 1;
|
||||
|
||||
if (dragCounter.current > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
const handleDrop = useCallback(
|
||||
(event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
setIsDragging(false);
|
||||
|
||||
if (event.dataTransfer?.items.length) {
|
||||
Array.from(event.dataTransfer.items).forEach(async (item) => {
|
||||
let fileOrHandle;
|
||||
if (StreamingFileReader.available()) {
|
||||
fileOrHandle =
|
||||
(await item.getAsFileSystemHandle()) as FileSystemFileHandle;
|
||||
} else {
|
||||
fileOrHandle = item.getAsFile();
|
||||
}
|
||||
if (fileOrHandle) {
|
||||
const uploadedFiles = await appState.files.uploadNewFile(
|
||||
fileOrHandle
|
||||
);
|
||||
if (!uploadedFiles) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentTab === PopoverTabs.AttachedFiles) {
|
||||
uploadedFiles.forEach((file) => {
|
||||
fileActionHandler({
|
||||
type: PopoverFileItemActionType.AttachFileToNote,
|
||||
payload: file,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
event.dataTransfer.clearData();
|
||||
dragCounter.current = 0;
|
||||
}
|
||||
},
|
||||
[appState.files, currentTab, fileActionHandler]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const dropzoneElement = dropzoneRef.current;
|
||||
|
||||
if (dropzoneElement) {
|
||||
dropzoneElement.addEventListener('dragenter', handleDragIn);
|
||||
dropzoneElement.addEventListener('dragleave', handleDragOut);
|
||||
dropzoneElement.addEventListener('dragover', handleDrag);
|
||||
dropzoneElement.addEventListener('drop', handleDrop);
|
||||
}
|
||||
|
||||
return () => {
|
||||
dropzoneElement?.removeEventListener('dragenter', handleDragIn);
|
||||
dropzoneElement?.removeEventListener('dragleave', handleDragOut);
|
||||
dropzoneElement?.removeEventListener('dragover', handleDrag);
|
||||
dropzoneElement?.removeEventListener('drop', handleDrop);
|
||||
};
|
||||
}, [handleDrop]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={dropzoneRef}
|
||||
className="focus:shadow-none"
|
||||
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
|
||||
style={{
|
||||
border: isDragging ? '2px dashed var(--sn-stylekit-info-color)' : '',
|
||||
}}
|
||||
>
|
||||
<AttachedFilesPopover
|
||||
application={application}
|
||||
appState={appState}
|
||||
note={note}
|
||||
fileActionHandler={fileActionHandler}
|
||||
currentTab={currentTab}
|
||||
setCurrentTab={setCurrentTab}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user