Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/components/CustomModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ interface CustomModalProps extends Omit<ModalProps, OmittedProps> {
titleText?: string;
footerButtons?: React.ReactNode;
divider?: boolean;
wrapProps?: { onDragOver: (e: DragEvent) => void };
wrapClassName?: string;
}

/** Wrapper to keep styling of modals consistent:
Expand All @@ -31,6 +33,8 @@ const CustomModal: React.FC<CustomModalProps> = ({
titleText,
footerButtons,
divider,
wrapProps,
wrapClassName,
...props
}) => {
const title = (
Expand Down Expand Up @@ -66,6 +70,8 @@ const CustomModal: React.FC<CustomModalProps> = ({
footer={footer}
open
centered
wrapClassName={wrapClassName}
wrapProps={wrapProps}
/>
);
};
Expand Down
27 changes: 24 additions & 3 deletions src/components/FileUploadModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Form, Tabs } from "antd";
import { RcFile } from "antd/lib/upload";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { ActionCreator } from "redux";
import classNames from "classnames";

import {
ClearSimFileDataAction,
Expand Down Expand Up @@ -33,6 +34,8 @@ interface FileUploadModalProps {
setViewerStatus: ActionCreator<SetViewerStatusAction>;
clearSimulariumFile: ActionCreator<ClearSimFileDataAction>;
setError: ActionCreator<SetErrorAction>;
fileIsDraggedOverViewer: boolean;
handleDragOver: (e: DragEvent) => void;
}

const FileUploadModal: React.FC<FileUploadModalProps> = ({
Expand All @@ -41,6 +44,8 @@ const FileUploadModal: React.FC<FileUploadModalProps> = ({
loadLocalFile,
setViewerStatus,
setError,
fileIsDraggedOverViewer,
handleDragOver,
}) => {
const [openTab, setOpenTab] = useState<string>(UploadTab.Device);
const [noUrlInput, setNoUrlInput] = useState(true);
Expand All @@ -51,6 +56,17 @@ const FileUploadModal: React.FC<FileUploadModalProps> = ({
setIsModalVisible(false);
};

useEffect(() => {
if (!fileIsDraggedOverViewer) return;

window.addEventListener("drop", closeModal);
return () => window.removeEventListener("drop", closeModal);
}, [fileIsDraggedOverViewer]);

const fileDragClass = fileIsDraggedOverViewer
? styles.fileDragged
: undefined;

const onUrlInput = (event: React.ChangeEvent<HTMLInputElement>) => {
// Form subcomponent takes care of its own submit behavior
// all we care about is if input is present or not
Expand Down Expand Up @@ -118,10 +134,15 @@ const FileUploadModal: React.FC<FileUploadModalProps> = ({
return (
<CustomModal
closeHandler={closeModal}
className={styles.uploadModal}
className={classNames(styles.uploadModal, fileDragClass)}
titleText="Choose a Simularium file to load"
footerButtons={footerButtons}
width={525}
width={603}
wrapClassName={fileDragClass}
wrapProps={{
onDragOver: (e: DragEvent) => handleDragOver(e),
}}
divider
>
<Tabs
items={tabItems}
Expand Down
4 changes: 4 additions & 0 deletions src/components/FileUploadModal/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@
.upload-modal :global(.ant-tabs .ant-tabs-tab-active) {
font-weight: 400;
}

.file-dragged:global(.ant-modal-wrap), .file-dragged :global(.ant-modal-content) {
pointer-events: none;
}
2 changes: 2 additions & 0 deletions src/components/Icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
FullscreenExitOutlined,
FullscreenOutlined,
RightOutlined,
DragOutlined,
} from "@ant-design/icons";

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

export const PurpleArrow = <img src={PurpleArrowPointingRight} />;
export const AicsLogo = <img src={AicsLogoWhite} style={{ width: "140px" }} />;
Expand Down
6 changes: 6 additions & 0 deletions src/components/LoadFileMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ interface LoadFileMenuProps {
setError: ActionCreator<SetErrorAction>;
conversionStatus: ConversionStatus;
setConversionStatus: ActionCreator<SetConversionStatusAction>;
fileIsDraggedOverViewer: boolean;
handleDragOver: (e: DragEvent) => void;
}

const LoadFileMenu = ({
Expand All @@ -46,6 +48,8 @@ const LoadFileMenu = ({
setError,
conversionStatus,
setConversionStatus,
fileIsDraggedOverViewer,
handleDragOver,
}: LoadFileMenuProps): JSX.Element => {
const [isModalVisible, setIsModalVisible] = useState(false);
const location = useLocation();
Expand Down Expand Up @@ -142,6 +146,8 @@ const LoadFileMenu = ({
loadLocalFile={loadLocalFile}
setViewerStatus={setViewerStatus}
setError={setError}
handleDragOver={handleDragOver}
fileIsDraggedOverViewer={fileIsDraggedOverViewer}
/>
)}
</>
Expand Down
13 changes: 11 additions & 2 deletions src/components/LocalFileUpload/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { Link } from "react-router-dom";
import { message, Upload, UploadProps } from "antd";
import { CloseOutlined } from "@ant-design/icons";
import { RcFile } from "antd/lib/upload";
import classNames from "classnames";

import { ButtonClass } from "../../constants/interfaces";
import { VIEWER_PATHNAME } from "../../routes";
import { CustomButton } from "../CustomButton";
import { Drag } from "../Icons";

import styles from "./style.css";

Expand Down Expand Up @@ -35,7 +37,9 @@ const LocalFileUpload: React.FC<FileUploadProps> = ({
...uploadConfigProps
}) => {
const uploadPresetProps: UploadProps = {
className: styles.fileUpload,
className: classNames(styles.fileUpload, {
[styles.listEmpty]: fileList.length === 0,
}),
showUploadList: {
removeIcon: <CloseOutlined />,
},
Expand Down Expand Up @@ -64,6 +68,11 @@ const LocalFileUpload: React.FC<FileUploadProps> = ({

return (
<Upload {...uploadPresetProps} {...uploadConfigProps}>
<div className={styles.drag}>
{" "}
{Drag} Drag and drop a .simularium file anywhere in this window
or browse to a location.{" "}
</div>
<Link
// Redirect to /viewer if necessary and/or clear out viewer
to={{
Expand All @@ -73,7 +82,7 @@ const LocalFileUpload: React.FC<FileUploadProps> = ({
>
{children || (
<CustomButton variant={ButtonClass.LightPrimary}>
Select file
Browse
</CustomButton>
)}
</Link>
Expand Down
16 changes: 16 additions & 0 deletions src/components/LocalFileUpload/style.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
.file-upload :global(.ant-upload){
display: flex;
flex-direction: column;
gap: 26px;
}

.file-upload :global(.ant-upload-list) {
min-height: 30px;
}

.file-upload.list-empty :global(.ant-upload-list) {
display: none;
}

.file-upload :global(.ant-upload-list-item):hover,
.file-upload :global(.ant-upload-list-item-list-type-text):focus,
.file-upload :global(.ant-upload-list-item-list-type-text) :global(.ant-upload-list-item-info):hover {
Expand Down Expand Up @@ -28,3 +39,8 @@
width: max-content;
}

.file-upload .drag {
border: 1px dashed var(--heather);
font-size: 14px;
padding: 20px 16px;
}
2 changes: 1 addition & 1 deletion src/components/ViewerOverlayTarget/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
position: absolute;
height: 100%;
width: 100%;
z-index: 300;
z-index: 1001;
background-color: rgba(181, 159, 246, 0.7);
}

Expand Down
10 changes: 10 additions & 0 deletions src/containers/AppHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import viewerStateBranch from "../../state/viewer";
import {
SetViewerStatusAction,
SetErrorAction,
DragOverViewerAction,
} from "../../state/viewer/types";
import { ButtonClass } from "../../constants/interfaces";
import ShareTrajectoryButton from "../../components/ShareTrajectoryButton";
Expand All @@ -43,6 +44,8 @@ interface AppHeaderProps {
setError: ActionCreator<SetErrorAction>;
conversionStatus: ConversionStatus;
setConversionStatus: ActionCreator<SetConversionStatusAction>;
fileIsDraggedOverViewer: boolean;
dragOverViewer: ActionCreator<DragOverViewerAction>;
}

const AppHeader: React.FC<AppHeaderProps> = ({
Expand All @@ -56,6 +59,8 @@ const AppHeader: React.FC<AppHeaderProps> = ({
isNetworkedFile,
conversionStatus,
setConversionStatus,
fileIsDraggedOverViewer,
dragOverViewer,
}) => {
const history = useHistory();

Expand Down Expand Up @@ -113,6 +118,8 @@ const AppHeader: React.FC<AppHeaderProps> = ({
setError={setError}
conversionStatus={conversionStatus}
setConversionStatus={setConversionStatus}
handleDragOver={dragOverViewer}
fileIsDraggedOverViewer={fileIsDraggedOverViewer}
/>
<HelpMenu />
</div>
Expand All @@ -129,6 +136,8 @@ function mapStateToProps(state: State) {
trajectoryStateBranch.selectors.getIsNetworkedFile(state),
conversionStatus:
trajectoryStateBranch.selectors.getConversionStatus(state),
fileIsDraggedOverViewer:
viewerStateBranch.selectors.getFileDraggedOver(state),
};
}

Expand All @@ -140,6 +149,7 @@ const dispatchToPropsMap = {
setViewerStatus: viewerStateBranch.actions.setStatus,
setError: viewerStateBranch.actions.setError,
setConversionStatus: trajectoryStateBranch.actions.setConversionStatus,
dragOverViewer: viewerStateBranch.actions.dragOverViewer,
};

export default connect(mapStateToProps, dispatchToPropsMap)(AppHeader);
Loading