Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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