Merge branch 'feat/v2-main' of https://github.com/OHIF/Viewers into fix/OHIF-37-thumbnailDoubleClick

This commit is contained in:
Rodrigo Antinarelli committed 2020-06-30 17:59:57 -03:00
commit 4b8dcef956
48 files changed
+1156 -363

No files matched your search

@@ -113,7 +113,7 @@ const IconButton = ({
};
IconButton.defaultProps = {
onClick: () => {},
onClick: () => { },
color: 'default',
disabled: false,
fullWidth: false,
@@ -1,16 +1,35 @@
import React from 'react';
import React, { useEffect, useRef } from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import { Button, Icon } from '@ohif/ui';
const Notification = ({ type, message, actions, onSubmit }) => {
const Notification = ({ type, message, actions, onSubmit, onOutsideClick }) => {
const notificationRef = useRef(null);
useEffect(() => {
const notificationElement = notificationRef.current;
const handleClick = function(event) {
const isClickInside = notificationElement.contains(event.target);
if (!isClickInside) {
onOutsideClick();
}
};
document.addEventListener('mousedown', handleClick);
return () => {
document.removeEventListener('mousedown', handleClick);
};
}, [onOutsideClick]);
const iconsByType = {
error: {
icon: 'info',
color: 'text-red-700',
},
warning: {
icon: 'info',
icon: 'notificationwarning-diamond',
color: 'text-yellow-500',
},
info: {
@@ -35,7 +54,10 @@ const Notification = ({ type, message, actions, onSubmit }) => {
const { icon, color } = getIconData();
return (
<div className="flex flex-col p-2 mx-2 mt-2 rounded bg-common-bright">
<div
ref={notificationRef}
className="flex flex-col p-2 mx-2 mt-2 rounded bg-common-bright"
>
<div className="flex flex-grow">
<Icon name={icon} className={classnames('w-5', color)} />
<span className="ml-2 text-base text-black">{message}</span>
@@ -65,6 +87,7 @@ const Notification = ({ type, message, actions, onSubmit }) => {
Notification.defaultProps = {
type: 'info',
onOutsideClick: () => {},
};
Notification.propTypes = {
@@ -78,6 +101,8 @@ Notification.propTypes = {
})
).isRequired,
onSubmit: PropTypes.func.isRequired,
/** Can be used as a callback to dismiss the notification for clicks that occur outside of it */
onOutsideClick: PropTypes.func,
};
export default Notification;
@@ -0,0 +1,115 @@
/* TODO: Create tailwind styles for this component */
.sb-topLeft {
@apply top-0 left-0 bottom-auto right-auto;
}
.sb-topCenter {
transform: translateX(-50%);
@apply top-0 bottom-auto left-1/2;
}
.sb-topRight {
@apply right-0 top-0 left-auto bottom-auto;
}
.sb-bottomLeft {
@apply right-auto left-0 bottom-0 top-auto;
}
.sb-bottomCenter {
@apply top-auto bottom-0 left-1/2;
transform: translateX(-50%);
}
.sb-bottomRight {
margin: 10px 0 0;
@apply top-auto bottom-0 left-auto right-0;
}
.sb-topLeft .sb-item,
.sb-topCenter .sb-item,
.sb-topRight .sb-item {
margin: 10px 0 0;
}
.sb-bottomLeft .sb-item,
.sb-bottomCenter .sb-item,
.sb-bottomRight .sb-item {
margin: 0 0 10px;
}
.sb-closeBtn {
text-shadow: none;
width: 20px;
height: 20px;
right: 5px;
top: 5px;
@apply overflow-hidden opacity-100 rounded-full p-1 bg-white cursor-pointer absolute text-center duration-300 transition-all ease-in-out;
}
.sb-closeBtn:hover {
background: #fff;
}
.sb-closeIcon {
@apply w-full relative overflow-hidden h-full block leading-none;
}
.sb-closeIcon:after,
.sb-closeIcon:before {
content: ' ';
height: 2px;
width: 12px;
@apply duration-300 transition-all ease-in-out block bg-black opacity-100 absolute;
}
.sb-closeIcon:before {
left: 4px;
top: 3px;
transform: rotate(45deg);
transform-origin: 0px 50%;
}
.sb-closeIcon:after {
right: 3px;
top: 5px;
transform: rotate(-45deg);
transform-origin: calc(100% - 3px) 50%;
}
.sb-title {
@apply break-normal text-lg font-bold;
}
.sb-message {
@apply break-normal text-base;
}
.sb-item {
animation: fadein 1s;
box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.2), 0 1px 18px 0 rgba(0, 0, 0, 0.12),
0 3px 5px -1px rgba(0, 0, 0, 0.14);
@apply relative p-5 text-white overflow-hidden rounded-md transition-height ease-in-out duration-300;
}
@keyframes fadein {
from {
top: 30px;
@apply opacity-0;
}
to {
@apply opacity-100 top-0;
}
}
/* Internet Explorer */
@-ms-keyframes fadein {
from {
top: 30px;
@apply opacity-0;
}
to {
@apply opacity-100;
top: 0;
}
}
@@ -2,16 +2,18 @@ import React from 'react';
import SnackbarItem from './SnackbarItem';
import { useSnackbar } from '../../contextProviders';
import './Snackbar.css';
const SnackbarContainer = () => {
const { snackbarItems, hide } = useSnackbar();
const renderItem = item => {
return <SnackbarItem key={item.itemId} options={item} onClose={hide} />;
};
if (!snackbarItems) {
return null;
}
const renderItem = item => (
<SnackbarItem
key={item.itemId}
options={item}
onClose={hide}
/>
);
const renderItems = () => {
const items = {
@@ -23,11 +25,9 @@ const SnackbarContainer = () => {
bottomRight: [],
};
snackbarItems.map(item => {
items[item.position].push(item);
});
snackbarItems.forEach(item => items[item.position].push(item));
return (
return snackbarItems && (
<div>
{Object.keys(items).map(pos => {
if (!items[pos].length) {
@@ -35,7 +35,7 @@ const SnackbarContainer = () => {
}
return (
<div key={pos} className={`sb-container sb-${pos}`}>
<div key={pos} className={`fixed z-50 p-6 box-border h-auto sb-${pos}`}>
{items[pos].map((item, index) => (
<div key={item.id + index}>{renderItem(item)}</div>
))}
@@ -1,25 +1,38 @@
import React, { useEffect } from 'react';
import classNames from 'classnames';
import SnackbarTypes from './SnackbarTypes';
const SnackbarItem = ({ options, onClose }) => {
const handleClose = () => {
onClose(options.id);
};
const handleClose = () => onClose(options.id);
useEffect(() => {
if (options.autoClose) {
setTimeout(() => {
handleClose();
}, options.duration);
setTimeout(() => handleClose(), options.duration);
}
}, []);
const typeClasses = {
[SnackbarTypes.INFO]: 'bg-primary-active',
[SnackbarTypes.WARNING]: 'bg-yellow-600',
[SnackbarTypes.SUCCESS]: 'bg-green-600',
[SnackbarTypes.ERROR]: 'bg-red-600'
};
const hidden = 'duration-300 transition-all ease-in-out h-0 opacity-0 pt-0 mb-0 pb-0';
return (
<div>
<span onClick={handleClose}>
<span>x</span>
<div
className={classNames(
`${options.visible ? '' : hidden} sb-item`,
typeClasses[options.type]
)}
>
<span className="sb-closeBtn" onClick={handleClose}>
<span className="sb-closeIcon">x</span>
</span>
{options.title && <div>{options.title}</div>}
{options.message && <div>{options.message}</div>}
{options.title && <div className="sb-title">{options.title}</div>}
{options.message && <div className="sb-message">{options.message}</div>}
</div>
);
};
@@ -10,6 +10,7 @@ import blurHandlerListener from '../../utils/blurHandlerListener';
*
*/
const Thumbnail = ({
displaySetInstanceUID,
className,
imageSrc,
imageAltText,
@@ -40,6 +41,7 @@ const Thumbnail = ({
className,
'flex flex-col flex-1 px-3 mb-8 cursor-pointer outline-none group'
)}
id={`thumbnail-${displaySetInstanceUID}`}
onDoubleClick={onClick}
role="button"
tabIndex="0"
@@ -79,6 +81,7 @@ const Thumbnail = ({
};
Thumbnail.propTypes = {
displaySetInstanceUID: PropTypes.string.isRequired,
className: PropTypes.string,
imageSrc: PropTypes.string,
/**
@@ -34,6 +34,7 @@ const ThumbnailList = ({
return (
<Thumbnail
key={displaySetInstanceUID}
displaySetInstanceUID={displaySetInstanceUID}
dragData={dragData}
description={description}
seriesNumber={seriesNumber}
@@ -49,6 +50,7 @@ const ThumbnailList = ({
return (
<ThumbnailTracked
key={displaySetInstanceUID}
displaySetInstanceUID={displaySetInstanceUID}
dragData={dragData}
description={description}
seriesNumber={seriesNumber}
@@ -67,6 +69,7 @@ const ThumbnailList = ({
<ThumbnailNoImage
isActive={isActive}
key={displaySetInstanceUID}
displaySetInstanceUID={displaySetInstanceUID}
dragData={dragData}
modality={modality}
seriesDate={seriesDate}
@@ -1,12 +1,14 @@
import React, { useRef } from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { useDrag } from 'react-dnd';
import { Icon } from '@ohif/ui';
import blurHandlerListener from '../../utils/blurHandlerListener';
const ThumbnailNoImage = ({
displaySetInstanceUID,
description,
seriesDate,
modality,
@@ -31,6 +33,7 @@ const ThumbnailNoImage = ({
'flex flex-row flex-1 px-4 py-3 cursor-pointer outline-none border-transparent hover:border-blue-300 focus:border-blue-300 rounded',
isActive ? 'border-2 border-primary-light' : 'border'
)}
id={`thumbnail-${displaySetInstanceUID}`}
onDoubleClick={onClick}
role="button"
tabIndex="0"
@@ -54,6 +57,7 @@ const ThumbnailNoImage = ({
};
ThumbnailNoImage.propTypes = {
displaySetInstanceUID: PropTypes.string.isRequired,
/**
* Data the thumbnail should expose to a receiving drop target. Use a matching
* `dragData.type` to identify which targets can receive this draggable item.
@@ -5,6 +5,7 @@ import classnames from 'classnames';
import { Icon, Thumbnail, Tooltip } from '@ohif/ui';
const ThumbnailTracked = ({
displaySetInstanceUID,
className,
imageSrc,
imageAltText,
@@ -26,6 +27,7 @@ const ThumbnailTracked = ({
'flex flex-row flex-1 px-3 py-2 cursor-pointer outline-none',
className
)}
id={`thumbnail-${displaySetInstanceUID}`}
>
<div className="flex flex-col items-center flex-2">
<div
@@ -39,7 +39,7 @@ const ViewportActionBar = ({
scanner,
} = patientInformation;
const onPatientInfoClick = () => setShowPatientInfo(!showPatientInfo)
const onPatientInfoClick = () => setShowPatientInfo(!showPatientInfo);
const renderIconStatus = () => {
if (modality === 'SR') {
@@ -64,26 +64,26 @@ const ViewportActionBar = ({
{!isTracked ? (
<Icon name="dotted-circle" className="w-6 text-primary-light" />
) : (
<Tooltip
position="bottom-left"
content={
<div className="flex py-2">
<div className="flex pt-1">
<Icon name="info-link" className="w-4 text-primary-main" />
</div>
<div className="flex ml-4">
<span className="text-base text-common-light">
Series is
<Tooltip
position="bottom-left"
content={
<div className="flex py-2">
<div className="flex pt-1">
<Icon name="info-link" className="w-4 text-primary-main" />
</div>
<div className="flex ml-4">
<span className="text-base text-common-light">
Series is
<span className="font-bold text-white"> tracked</span> and
can be viewed <br /> in the measurement panel
</span>
</div>
</div>
}
>
<Icon name="tracked" className="w-6 text-primary-light" />
</Tooltip>
)}
</div>
}
>
<Icon name="tracked" className="w-6 text-primary-light" />
</Tooltip>
)}
</div>
);
};
@@ -196,54 +196,64 @@ function PatientInfo({
isSticky
isDisabled={!isOpen}
position="bottom-right"
content={isOpen && (
<div className="flex py-2">
<div className="flex pt-1">
<Icon name="info-link" className="w-4 text-primary-main" />
</div>
<div className="flex flex-col ml-2">
<span className="text-base font-bold text-white">
{patientName}
</span>
<div className="flex pb-4 mt-4 mb-4 border-b border-secondary-main">
<div className={classnames(classes.firstRow)}>
<span className={classnames(classes.infoHeader)}>Sex</span>
<span className={classnames(classes.infoText)}>
{patientSex}
</span>
</div>
<div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}>Age</span>
<span className={classnames(classes.infoText)}>
{patientAge}
</span>
</div>
<div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}>MRN</span>
<span className={classnames(classes.infoText)}>{MRN}</span>
</div>
content={
isOpen && (
<div className="flex py-2">
<div className="flex pt-1">
<Icon name="info-link" className="w-4 text-primary-main" />
</div>
<div className="flex">
<div className={classnames(classes.firstRow)}>
<span className={classnames(classes.infoHeader)}>
Thickness
</span>
<span className={classnames(classes.infoText)}>
{thickness}
</span>
<div className="flex flex-col ml-2">
<span className="text-base font-bold text-white">
{patientName}
</span>
<div className="flex pb-4 mt-4 mb-4 border-b border-secondary-main">
<div className={classnames(classes.firstRow)}>
<span className={classnames(classes.infoHeader)}>Sex</span>
<span className={classnames(classes.infoText)}>
{patientSex}
</span>
</div>
<div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}>Age</span>
<span className={classnames(classes.infoText)}>
{patientAge}
</span>
</div>
<div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}>MRN</span>
<span className={classnames(classes.infoText)}>{MRN}</span>
</div>
</div>
<div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}>Spacing</span>
<span className={classnames(classes.infoText)}>{spacing}</span>
</div>
<div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}>Scanner</span>
<span className={classnames(classes.infoText)}>{scanner}</span>
<div className="flex">
<div className={classnames(classes.firstRow)}>
<span className={classnames(classes.infoHeader)}>
Thickness
</span>
<span className={classnames(classes.infoText)}>
{thickness ? thickness : 'N/A'}
</span>
</div>
<div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}>
Spacing
</span>
<span className={classnames(classes.infoText)}>
{spacing}
</span>
</div>
<div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}>
Scanner
</span>
<span className={classnames(classes.infoText)}>
{scanner}
</span>
</div>
</div>
</div>
</div>
</div>
)}
)
}
>
<div className="relative flex justify-end cursor-pointer">
<div className="relative">