Skip to content

Commit c68d888

Browse files
interim17frasercl
andauthored
enable drag and drop on load file modal (#651)
* allow file drop while load file modal is open * raise z index of drag and drop overlay * streamline file load modal drag and drop handles * update load file modal styling for drag and drop * Update src/components/FileUploadModal/index.tsx Co-authored-by: Cameron Fraser <[email protected]> * Update src/components/FileUploadModal/style.css Co-authored-by: Cameron Fraser <[email protected]> * push lockfile * Merge branch 'main' of https://github.com/simularium/simularium-website into feature/drop-on-modal * update ci/cd to use jest experimental config * use node 16 in CI * reduce statement coverage threshold * remove global coverage thresholds * revert lockfile --------- Co-authored-by: Cameron Fraser <[email protected]>
1 parent 3479013 commit c68d888

File tree

11 files changed

+88
-10
lines changed

11 files changed

+88
-10
lines changed

.github/workflows/test-coverage.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@ jobs:
99
if: ${{ github.actor != 'dependabot[bot]' }}
1010
steps:
1111
- uses: actions/checkout@v3
12+
- uses: actions/setup-node@v4
13+
with:
14+
node-version: 16
15+
cache: 'npm'
16+
- run: npm ci
1217
- uses: ArtiomTr/[email protected]
1318
with:
1419
github-token: ${{ secrets.GITHUB_TOKEN }}
1520
annotations: failed-tests
21+
skip-step: install
22+
env:
23+
NODE_OPTIONS: --experimental-vm-modules

jest.config.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ module.exports = {
1717
"^lodash/(.*)$": "lodash-es/$1",
1818
},
1919
coverageThreshold: {
20-
global: {
21-
lines: 25,
22-
statements: 50,
23-
},
2420
"./src/state/*/selectors/index.ts": {
2521
branches: 100,
2622
functions: 100,

src/components/CustomModal/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ interface CustomModalProps extends Omit<ModalProps, OmittedProps> {
1919
titleText?: string;
2020
footerButtons?: React.ReactNode;
2121
divider?: boolean;
22+
wrapProps?: { onDragOver: (e: DragEvent) => void };
23+
wrapClassName?: string;
2224
}
2325

2426
/** Wrapper to keep styling of modals consistent:
@@ -31,6 +33,8 @@ const CustomModal: React.FC<CustomModalProps> = ({
3133
titleText,
3234
footerButtons,
3335
divider,
36+
wrapProps,
37+
wrapClassName,
3438
...props
3539
}) => {
3640
const title = (
@@ -66,6 +70,8 @@ const CustomModal: React.FC<CustomModalProps> = ({
6670
footer={footer}
6771
open
6872
centered
73+
wrapClassName={wrapClassName}
74+
wrapProps={wrapProps}
6975
/>
7076
);
7177
};

src/components/FileUploadModal/index.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Form, Tabs } from "antd";
22
import { RcFile } from "antd/lib/upload";
3-
import React, { useState } from "react";
3+
import React, { useEffect, useState } from "react";
44
import { ActionCreator } from "redux";
5+
import classNames from "classnames";
56

67
import {
78
ClearSimFileDataAction,
@@ -33,6 +34,8 @@ interface FileUploadModalProps {
3334
setViewerStatus: ActionCreator<SetViewerStatusAction>;
3435
clearSimulariumFile: ActionCreator<ClearSimFileDataAction>;
3536
setError: ActionCreator<SetErrorAction>;
37+
fileIsDraggedOverViewer: boolean;
38+
handleDragOver: (e: DragEvent) => void;
3639
}
3740

3841
const FileUploadModal: React.FC<FileUploadModalProps> = ({
@@ -41,6 +44,8 @@ const FileUploadModal: React.FC<FileUploadModalProps> = ({
4144
loadLocalFile,
4245
setViewerStatus,
4346
setError,
47+
fileIsDraggedOverViewer,
48+
handleDragOver,
4449
}) => {
4550
const [openTab, setOpenTab] = useState<string>(UploadTab.Device);
4651
const [noUrlInput, setNoUrlInput] = useState(true);
@@ -51,6 +56,17 @@ const FileUploadModal: React.FC<FileUploadModalProps> = ({
5156
setIsModalVisible(false);
5257
};
5358

59+
useEffect(() => {
60+
if (!fileIsDraggedOverViewer) return;
61+
62+
window.addEventListener("drop", closeModal);
63+
return () => window.removeEventListener("drop", closeModal);
64+
}, [fileIsDraggedOverViewer]);
65+
66+
const fileDragClass = fileIsDraggedOverViewer
67+
? styles.fileDragged
68+
: undefined;
69+
5470
const onUrlInput = (event: React.ChangeEvent<HTMLInputElement>) => {
5571
// Form subcomponent takes care of its own submit behavior
5672
// all we care about is if input is present or not
@@ -118,10 +134,15 @@ const FileUploadModal: React.FC<FileUploadModalProps> = ({
118134
return (
119135
<CustomModal
120136
closeHandler={closeModal}
121-
className={styles.uploadModal}
137+
className={classNames(styles.uploadModal, fileDragClass)}
122138
titleText="Choose a Simularium file to load"
123139
footerButtons={footerButtons}
124-
width={525}
140+
width={603}
141+
wrapClassName={fileDragClass}
142+
wrapProps={{
143+
onDragOver: (e: DragEvent) => handleDragOver(e),
144+
}}
145+
divider
125146
>
126147
<Tabs
127148
items={tabItems}

src/components/FileUploadModal/style.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@
3333
.upload-modal :global(.ant-tabs .ant-tabs-tab-active) {
3434
font-weight: 400;
3535
}
36+
37+
.file-dragged:global(.ant-modal-wrap), .file-dragged :global(.ant-modal-content) {
38+
pointer-events: none;
39+
}

src/components/Icons/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
FullscreenExitOutlined,
2020
FullscreenOutlined,
2121
RightOutlined,
22+
DragOutlined,
2223
} from "@ant-design/icons";
2324

2425
import PurpleArrowPointingRight from "../../assets/open-arrow.svg";
@@ -44,6 +45,7 @@ export const Link = <LinkOutlined />;
4445
export const Download = <DownloadOutlined size={32} />;
4546
export const LoopOutlined = <RetweetOutlined />;
4647
export const Exclamation = <ExclamationCircleFilled />;
48+
export const Drag = <DragOutlined />;
4749

4850
export const PurpleArrow = <img src={PurpleArrowPointingRight} />;
4951
export const AicsLogo = <img src={AicsLogoWhite} style={{ width: "140px" }} />;

src/components/LoadFileMenu/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ interface LoadFileMenuProps {
3535
setError: ActionCreator<SetErrorAction>;
3636
conversionStatus: ConversionStatus;
3737
setConversionStatus: ActionCreator<SetConversionStatusAction>;
38+
fileIsDraggedOverViewer: boolean;
39+
handleDragOver: (e: DragEvent) => void;
3840
}
3941

4042
const LoadFileMenu = ({
@@ -46,6 +48,8 @@ const LoadFileMenu = ({
4648
setError,
4749
conversionStatus,
4850
setConversionStatus,
51+
fileIsDraggedOverViewer,
52+
handleDragOver,
4953
}: LoadFileMenuProps): JSX.Element => {
5054
const [isModalVisible, setIsModalVisible] = useState(false);
5155
const location = useLocation();
@@ -142,6 +146,8 @@ const LoadFileMenu = ({
142146
loadLocalFile={loadLocalFile}
143147
setViewerStatus={setViewerStatus}
144148
setError={setError}
149+
handleDragOver={handleDragOver}
150+
fileIsDraggedOverViewer={fileIsDraggedOverViewer}
145151
/>
146152
)}
147153
</>

src/components/LocalFileUpload/index.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import { Link } from "react-router-dom";
33
import { message, Upload, UploadProps } from "antd";
44
import { CloseOutlined } from "@ant-design/icons";
55
import { RcFile } from "antd/lib/upload";
6+
import classNames from "classnames";
67

78
import { ButtonClass } from "../../constants/interfaces";
89
import { VIEWER_PATHNAME } from "../../routes";
910
import { CustomButton } from "../CustomButton";
11+
import { Drag } from "../Icons";
1012

1113
import styles from "./style.css";
1214

@@ -35,7 +37,9 @@ const LocalFileUpload: React.FC<FileUploadProps> = ({
3537
...uploadConfigProps
3638
}) => {
3739
const uploadPresetProps: UploadProps = {
38-
className: styles.fileUpload,
40+
className: classNames(styles.fileUpload, {
41+
[styles.listEmpty]: fileList.length === 0,
42+
}),
3943
showUploadList: {
4044
removeIcon: <CloseOutlined />,
4145
},
@@ -64,6 +68,11 @@ const LocalFileUpload: React.FC<FileUploadProps> = ({
6468

6569
return (
6670
<Upload {...uploadPresetProps} {...uploadConfigProps}>
71+
<div className={styles.drag}>
72+
{" "}
73+
{Drag} Drag and drop a .simularium file anywhere in this window
74+
or browse to a location.{" "}
75+
</div>
6776
<Link
6877
// Redirect to /viewer if necessary and/or clear out viewer
6978
to={{
@@ -73,7 +82,7 @@ const LocalFileUpload: React.FC<FileUploadProps> = ({
7382
>
7483
{children || (
7584
<CustomButton variant={ButtonClass.LightPrimary}>
76-
Select file
85+
Browse
7786
</CustomButton>
7887
)}
7988
</Link>

src/components/LocalFileUpload/style.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1+
.file-upload :global(.ant-upload){
2+
display: flex;
3+
flex-direction: column;
4+
gap: 26px;
5+
}
6+
17
.file-upload :global(.ant-upload-list) {
28
min-height: 30px;
39
}
10+
11+
.file-upload.list-empty :global(.ant-upload-list) {
12+
display: none;
13+
}
14+
415
.file-upload :global(.ant-upload-list-item):hover,
516
.file-upload :global(.ant-upload-list-item-list-type-text):focus,
617
.file-upload :global(.ant-upload-list-item-list-type-text) :global(.ant-upload-list-item-info):hover {
@@ -28,3 +39,8 @@
2839
width: max-content;
2940
}
3041

42+
.file-upload .drag {
43+
border: 1px dashed var(--heather);
44+
font-size: 14px;
45+
padding: 20px 16px;
46+
}

src/components/ViewerOverlayTarget/style.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
position: absolute;
33
height: 100%;
44
width: 100%;
5-
z-index: 300;
5+
z-index: 1001;
66
background-color: rgba(181, 159, 246, 0.7);
77
}
88

0 commit comments

Comments
 (0)