feat: enhanced notifications and toolbar hover states (#3032)

* fix: button hover state and overlay colors in tmtv

* fix: styles for notificaionts
This commit is contained in:
Alireza 2022-11-21 22:35:25 -05:00 committed by GitHub
parent be6b8629be
commit bbfdda7fe7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 185 additions and 88 deletions

View File

@ -4,7 +4,6 @@
--scrollbar-width: 20px;
pointer-events: none;
font-size: 15px;
color: #ccc;
line-height: 18px;
}
.ViewportOrientationMarkers .orientation-marker {

View File

@ -1,4 +1,5 @@
import React, { useEffect, useState, useMemo } from 'react';
import classNames from 'classnames';
import {
metaData,
Enums,
@ -119,13 +120,18 @@ function ViewportOrientationMarkers({
const backgroundColor = ohifViewport.getViewportOptions().background;
// Todo: probably this can be done in a better way in which we identify bright
// background
const isLight = backgroundColor
? csUtils.isEqual(backgroundColor, [1, 1, 1])
: false;
return orientationMarkers.map((m, index) => (
<div
className={`${m}-mid orientation-marker`}
className={classNames(
`${m}-mid orientation-marker`,
isLight ? 'text-[#726F7E]' : 'text-[#ccc]'
)}
key={`${m}-mid orientation-marker`}
>
<div className="orientation-marker-value">{markers[m]}</div>

View File

@ -188,10 +188,27 @@ function CornerstoneViewportOverlay({
return null;
}
const ohifViewport = CornerstoneViewportService.getViewportInfoByIndex(
viewportIndex
);
if (!ohifViewport) {
return null;
}
const backgroundColor = ohifViewport.getViewportOptions().background;
// Todo: probably this can be done in a better way in which we identify bright
// background
const isLight = backgroundColor
? utilities.isEqual(backgroundColor, [1, 1, 1])
: false;
return (
<ViewportOverlay
topLeft={getTopLeftContent()}
topRight={getTopRightContent()}
color={isLight && 'text-[#0944B3]'}
/>
);
}

View File

@ -74,12 +74,9 @@ export default async function init({
CornerstoneViewportService,
HangingProtocolService,
ToolGroupService,
SegmentationService,
ViewportGridService,
} = servicesManager.services;
window.SegmentationService = SegmentationService;
window.DisplaySetService = DisplaySetService;
window.services = servicesManager.services;
if (cornerstone.getShouldUseCPURendering()) {

View File

@ -2,6 +2,6 @@ import React from 'react';
export default function ToolbarDivider() {
return (
<span className="self-center w-1 h-8 mx-2 border-l border-common-dark" />
<span className="self-center w-4 h-8 mx-2 border-l border-common-dark" />
);
}

View File

@ -64,6 +64,6 @@
"postcss": "^8.3.5",
"postcss-loader": "^6.1.1",
"prop-types": "15.7.2",
"tailwindcss": "3.1.8"
"tailwindcss": "3.2.4"
}
}

View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<path d="M24 11.794c.017 6.667-5.333 12.108-12 12.205a11.823 11.823 0 0 1-12-11.79C-.019 5.541 5.331.1 12 .001a11.824 11.824 0 0 1 12 11.793z" fill="#B70D11"/>
<g stroke="#FFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
<path d="M11.494 17.158a.245.245 0 0 0-.241.255.254.254 0 0 0 .253.245h0a.246.246 0 0 0 .241-.255.253.253 0 0 0-.244-.245h-.005M11.503 13V6"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 566 B

View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<circle fill="#0944B3" cx="12" cy="12" r="12"/>
<g stroke="#FFF" stroke-linecap="round" stroke-linejoin="round">
<path d="M12.538 17.423V11.5a.846.846 0 0 0-.846-.846H10M11.27 6.423a.423.423 0 1 1 0 .846.423.423 0 0 1 0-.846M10 17.425h5.077"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 425 B

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<path d="M24 11.794c.017 6.667-5.333 12.108-12 12.205a11.823 11.823 0 0 1-12-11.79C-.019 5.541 5.331.1 12 .001a11.824 11.824 0 0 1 12 11.793z" fill="#61C840"/>
<path d="m17.5 7.5-7 9.5-5-4" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 428 B

View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<path d="M24 11.794c.017 6.667-5.333 12.108-12 12.205a11.823 11.823 0 0 1-12-11.79C-.019 5.541 5.331.1 12 .001a11.824 11.824 0 0 1 12 11.793z" fill="#F1CC1B"/>
<g stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
<path d="M11.494 17.158a.245.245 0 0 0-.241.255.254.254 0 0 0 .253.245h0a.246.246 0 0 0 .241-.255.253.253 0 0 0-.244-.245h-.005M11.503 13V6"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 566 B

View File

@ -53,6 +53,10 @@ import tabSegmentation from './../../assets/icons/tab-segmentation.svg';
import uiArrowDown from './../../assets/icons/ui-arrow-down.svg';
import uiArrowUp from './../../assets/icons/ui-arrow-up.svg';
import loadingOHIFMark from './../../assets/icons/loading-ohif-mark.svg';
import notificationsInfo from './../../assets/icons/notifications-info.svg';
import notificationsWarning from './../../assets/icons/notifications-warning.svg';
import notificationsError from './../../assets/icons/notifications-error.svg';
import notificationsSuccess from './../../assets/icons/notifications-success.svg';
/** Tools */
import toolZoom from './../../assets/icons/tool-zoom.svg';
@ -152,6 +156,10 @@ const ICONS = {
'checkbox-checked': checkboxChecked,
'checkbox-unchecked': checkboxUnchecked,
'loading-ohif-mark': loadingOHIFMark,
'notifications-info': notificationsInfo,
'notifications-error': notificationsError,
'notifications-success': notificationsSuccess,
'notifications-warning': notificationsWarning,
/** Tools */
'tool-zoom': toolZoom,

View File

@ -42,19 +42,11 @@
background: #fff;
}
.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;
@apply relative p-3 text-white overflow-hidden rounded-md transition-height ease-in-out duration-300;
}
@keyframes fadein {

View File

@ -1,5 +1,5 @@
import React from 'react';
import SnackbarItem from './SnackbarItem'
import SnackbarItem from './SnackbarItem';
import { useSnackbar } from '../../contextProviders/SnackbarProvider';
import './Snackbar.css';
@ -8,11 +8,7 @@ const SnackbarContainer = () => {
const { snackbarItems, hide } = useSnackbar();
const renderItem = item => (
<SnackbarItem
key={item.itemId}
options={item}
onClose={hide}
/>
<SnackbarItem key={item.itemId} options={item} onClose={hide} />
);
const renderItems = () => {
@ -26,23 +22,27 @@ const SnackbarContainer = () => {
};
snackbarItems.forEach(item => items[item.position].push(item));
return (
snackbarItems && (
<div>
{Object.keys(items).map(pos => {
if (!items[pos].length) {
return null;
}
return snackbarItems && (
<div>
{Object.keys(items).map(pos => {
if (!items[pos].length) {
return null;
}
return (
<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>
))}
</div>
);
})}
</div>
return (
<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>
))}
</div>
);
})}
</div>
)
);
};

View File

@ -1,10 +1,16 @@
import React, { useEffect } from 'react';
import classNames from 'classnames';
import Icon from '../Icon';
import IconButton from '../IconButton';
import SnackbarTypes from './SnackbarTypes';
const iconClasses = {
[SnackbarTypes.INFO]: 'notifications-info',
[SnackbarTypes.WARNING]: 'notifications-warning',
[SnackbarTypes.SUCCESS]: 'notifications-success',
[SnackbarTypes.ERROR]: 'notifications-error',
};
const SnackbarItem = ({ options, onClose }) => {
const handleClose = () => onClose(options.id);
@ -15,10 +21,10 @@ const SnackbarItem = ({ options, onClose }) => {
}, []);
const typeClasses = {
[SnackbarTypes.INFO]: 'bg-primary-active',
[SnackbarTypes.WARNING]: 'bg-yellow-600',
[SnackbarTypes.SUCCESS]: 'bg-green-600',
[SnackbarTypes.ERROR]: 'bg-red-600',
[SnackbarTypes.INFO]: 'bg-[#bed1db]',
[SnackbarTypes.WARNING]: 'bg-[#ebe5c4]',
[SnackbarTypes.SUCCESS]: 'bg-[#c6d9bf]',
[SnackbarTypes.ERROR]: 'bg-[#dabdbe]',
};
const hidden =
@ -31,17 +37,28 @@ const SnackbarItem = ({ options, onClose }) => {
typeClasses[options.type]
)}
>
{/* <span className="sb-closeBtn" onClick={handleClose}> */}
{/* <span className="sb-closeIcon">x</span> */}
<div
onClick={handleClose}
className="w-5 h-5 rounded-full absolute bg-white flex items-center justify-center right-0 top-0 mr-2 mt-2"
>
<Icon name="close" className="w-4 text-black" />
<div className="flex ">
<div
onClick={handleClose}
className="w-5 h-5 rounded-full absolute flex items-center justify-center right-0 top-0 mr-2 mt-2 text-[#0944b3]"
>
<Icon name="close" className="w-5 h-5 text-black" />
</div>
<Icon name={iconClasses[options.type]} className="w-5 h-5 mt-[1px]" />
<div className="flex-col ml-2">
{/* </span> */}
{options.title && (
<div className="break-normal text-lg font-bold text-black">
{options.title}
</div>
)}
{options.message && (
<div className="break-normal text-base text-black">
{options.message}
</div>
)}
</div>
</div>
{/* </span> */}
{options.title && <div className="sb-title">{options.title}</div>}
{options.message && <div className="sb-message">{options.message}</div>}
</div>
);
};

View File

@ -8,14 +8,14 @@ import { Icon, Tooltip, ListMenu } from '../';
const baseClasses = {
Button:
'flex items-center rounded-md border-transparent border-2 cursor-pointer',
'flex items-center rounded-md border-transparent border-2 cursor-pointer group/button',
Primary:
'h-full flex flex-1 items-center rounded-md rounded-tr-none rounded-br-none',
'h-full flex flex-1 items-center rounded-md rounded-tr-none rounded-br-none group/primary',
Secondary:
'h-full flex items-center justify-center rounded-tr-md rounded-br-md w-4',
'h-full flex items-center justify-center rounded-tr-md rounded-br-md w-4 group/secondary',
PrimaryIcon: 'w-5 h-5',
SecondaryIcon: 'w-4 h-full stroke-1',
Separator: 'border-l pt-2 pb-2',
Separator: 'border-l py-2.5',
Content: 'absolute z-10 top-0 mt-12',
};
@ -49,8 +49,10 @@ const classes = {
PrimaryIcon: ({ primary, isExpanded }) =>
classNames(
baseClasses.PrimaryIcon,
!primary.isActive &&
'group-hover/primary:text-primary-light group-hover/secondary:text-primary-light group-hover/button:text-primary-light',
primary.isActive && !isExpanded
? 'text-primary-dark'
? 'text-primary-dark '
: 'text-common-bright'
),
SecondaryIcon: ({ isExpanded }) =>
@ -58,7 +60,7 @@ const classes = {
baseClasses.SecondaryIcon,
isExpanded
? 'text-primary-dark'
: 'text-primary-active hover:text-common-bright'
: 'text-[#348cfd] group-hover/secondary:text-primary-light'
),
Separator: ({ primary, isExpanded, isHovering }) =>
classNames(

View File

@ -3,38 +3,46 @@ import classnames from 'classnames';
import './ViewportOverlay.css';
const ViewportOverlay = props => {
const topLeft = 'top-viewport left-viewport';
const topRight = 'top-viewport right-viewport-scrollbar';
const bottomRight = 'bottom-viewport right-viewport-scrollbar';
const bottomLeft = 'bottom-viewport left-viewport';
const overlay = 'absolute pointer-events-none';
const classes = {
topLeft: 'top-viewport left-viewport',
topRight: 'top-viewport right-viewport-scrollbar',
bottomRight: 'bottom-viewport right-viewport-scrollbar',
bottomLeft: 'bottom-viewport left-viewport',
};
const ViewportOverlay = ({
topLeft,
topRight,
bottomRight,
bottomLeft,
color,
}) => {
const overlay = 'absolute pointer-events-none';
return (
<div className="text-primary-light">
<div className={classnames(color ? color : 'text-primary-light')}>
<div
data-cy={'viewport-overlay-top-left'}
className={classnames(overlay, topLeft)}
className={classnames(overlay, classes.topLeft)}
>
{props.topLeft}
{topLeft}
</div>
<div
data-cy={'viewport-overlay-top-right'}
className={classnames(overlay, topRight)}
className={classnames(overlay, classes.topRight)}
>
{props.topRight}
{topRight}
</div>
<div
data-cy={'viewport-overlay-bottom-right'}
className={classnames(overlay, bottomRight)}
className={classnames(overlay, classes.bottomRight)}
>
{props.bottomRight}
{bottomRight}
</div>
<div
data-cy={'viewport-overlay-bottom-left'}
className={classnames(overlay, bottomLeft)}
className={classnames(overlay, classes.bottomLeft)}
>
{props.bottomLeft}
{bottomLeft}
</div>
</div>
);

View File

@ -92,7 +92,7 @@
"identity-obj-proxy": "3.0.x",
"lodash": "4.17.15",
"glob": "^8.0.3",
"tailwindcss": "3.1.8",
"tailwindcss": "3.2.4",
"terser-webpack-plugin": "^5.1.1",
"webpack": "^5.50.0",
"webpack-bundle-analyzer": "^4.4.2",

View File

@ -11963,6 +11963,17 @@ fast-glob@^3.0.3, fast-glob@^3.2.11, fast-glob@^3.2.7, fast-glob@^3.2.9:
merge2 "^1.3.0"
micromatch "^4.0.4"
fast-glob@^3.2.12:
version "3.2.12"
resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.2"
merge2 "^1.3.0"
micromatch "^4.0.4"
fast-json-parse@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/fast-json-parse/-/fast-json-parse-1.0.3.tgz#43e5c61ee4efa9265633046b770fb682a7577c4d"
@ -18374,12 +18385,12 @@ postcss-modules-values@^4.0.0:
dependencies:
icss-utils "^5.0.0"
postcss-nested@5.0.6:
version "5.0.6"
resolved "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc"
integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==
postcss-nested@6.0.0:
version "6.0.0"
resolved "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz#1572f1984736578f360cffc7eb7dca69e30d1735"
integrity sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==
dependencies:
postcss-selector-parser "^6.0.6"
postcss-selector-parser "^6.0.10"
postcss-nesting@^10.1.7:
version "10.1.7"
@ -18695,7 +18706,7 @@ postcss-selector-parser@^3.0.0:
indexes-of "^1.0.1"
uniq "^1.0.1"
postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.9:
postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9:
version "6.0.10"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
@ -18784,6 +18795,15 @@ postcss@^8.4.14:
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@^8.4.18:
version "8.4.19"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc"
integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==
dependencies:
nanoid "^3.3.4"
picocolors "^1.0.0"
source-map-js "^1.0.2"
prebuild-install@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45"
@ -21907,10 +21927,10 @@ table@^6.0.9:
string-width "^4.2.3"
strip-ansi "^6.0.1"
tailwindcss@3.1.8:
version "3.1.8"
resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.8.tgz#4f8520550d67a835d32f2f4021580f9fddb7b741"
integrity sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==
tailwindcss@3.2.4:
version "3.2.4"
resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz#afe3477e7a19f3ceafb48e4b083e292ce0dc0250"
integrity sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==
dependencies:
arg "^5.0.2"
chokidar "^3.5.3"
@ -21918,18 +21938,19 @@ tailwindcss@3.1.8:
detective "^5.2.1"
didyoumean "^1.2.2"
dlv "^1.1.3"
fast-glob "^3.2.11"
fast-glob "^3.2.12"
glob-parent "^6.0.2"
is-glob "^4.0.3"
lilconfig "^2.0.6"
micromatch "^4.0.5"
normalize-path "^3.0.0"
object-hash "^3.0.0"
picocolors "^1.0.0"
postcss "^8.4.14"
postcss "^8.4.18"
postcss-import "^14.1.0"
postcss-js "^4.0.0"
postcss-load-config "^3.1.4"
postcss-nested "5.0.6"
postcss-nested "6.0.0"
postcss-selector-parser "^6.0.10"
postcss-value-parser "^4.2.0"
quick-lru "^5.1.1"