fix/chore: Various style improvements (#2015)

* Update all the icons

* Turn off global tool sync; watch as the world burns

* Shift a bunch of things around so we can start tracking/setting per element

* ToolBarService to initiate one of three different calls; callback passed to all button types

* SplitButton and Toolbar Button to use new `onInteraction` prop and new toolbar state

* Changes to toolbar button interface and config

* Fix broken layout selector

* Update SR viewport to activate tools in viewport component

* Duplicate activation logic in measurement tracking extension

* Add alternative/dashed variants for SR Viewport

* pass through "setToolActive" commands for other viewport types

* fix small overlay bugs (no wwwc or scale info)

* Show SpacingBetweenSlices instead of PixelSpacing in patient information dialog

* Fix prop-types

* Update tracked viewport to have alternative tracked styling

* alt styling for SR viewports

* Update to support isLocked + isRehydratable

* fix broken logic

* fix broken logic

* switch icon style

* fix icon styles

* hover and click to start flow

* expedited workflow when data is not dirty (just after SR hydration)

* fix: setting elliptical roi tool

* fix arrow annotate dialog

* fix: do not show learn more button for now

* remove dead code

* simpler cache invalidation

* simpler cache invalidation part 2

* Fix for unable to spand study cards on separate pages

* fix: viewport grid area top padding should align with sidepanel gap

* fix: don't wrap split button list item text

* fix: cine player moz/chrome styles

* fix: split button arrows

* fix: tighten toolbar and splitbutton styles

* chore: clean up worklist sort logic
This commit is contained in:
Danny Brown 2020-09-21 04:42:53 -04:00 committed by GitHub
parent ba38cebcd7
commit 2fc7169fa4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 101 additions and 63 deletions

View File

@ -163,7 +163,7 @@ function ViewerLayout({
</Header>
<div
className="flex flex-row flex-no-wrap items-stretch w-full overflow-hidden"
style={{ height: 'calc(100vh - 57px' }}
style={{ height: 'calc(100vh - 52px' }}
>
{/* LEFT SIDEPANELS */}
{leftPanelComponents.length && (
@ -177,7 +177,7 @@ function ViewerLayout({
)}
{/* TOOLBAR + GRID */}
<div className="flex flex-col flex-1 h-full">
<div className="flex items-center justify-center flex-1 h-full pt-1 pb-2 overflow-hidden bg-black">
<div className="flex items-center justify-center flex-1 h-full -mt-1 overflow-hidden bg-black">
<ErrorBoundary context="Grid">
<ViewportGridComp
servicesManager={servicesManager}

View File

@ -120,9 +120,9 @@ export default [
),
secondary: {
icon: 'chevron-down',
label: '',
label: 'W/L Manual',
isActive: true,
tooltip: 'More Measure Tools',
tooltip: 'W/L Presets',
},
isAction: true, // ?
renderer: WindowLevelMenuItem,
@ -177,7 +177,7 @@ export default [
icon: 'chevron-down',
label: '',
isActive: true,
tooltip: 'More Measure Tools',
tooltip: 'More Tools',
},
items: [
_createActionButton(

View File

@ -13,7 +13,7 @@ const CinePlayer = ({
frameRate: defaultFrameRate,
onFrameRateChange,
onPlayPauseChange,
onClose
onClose,
}) => {
const [frameRate, setFrameRate] = useState(defaultFrameRate);
const debouncedSetFrameRate = debounce(onFrameRateChange, 300);
@ -28,21 +28,21 @@ const CinePlayer = ({
const action = {
false: { icon: 'old-play' },
true: { icon: 'old-stop' }
true: { icon: 'old-stop' },
};
return (
<div className="CinePlayer flex flex-row h-10 items-center justify-center border border-primary-light rounded-full">
<div className="flex flex-row items-center justify-center h-10 border rounded-full CinePlayer border-primary-light">
<IconButton
variant="text"
color="inherit"
size="initial"
className="mr-3 ml-4 text-primary-active"
className="ml-4 mr-3 text-primary-active"
onClick={onPlayPauseChangeHandler}
>
<Icon width="15px" height="15px" name={action[isPlaying].icon} />
</IconButton>
<div className="flex flex-col h-full justify-center pt-2 mr-3 pl-1 pr-1">
<div className="flex flex-col justify-center h-full pt-2 pl-1 pr-1 mr-3">
<input
type="range"
name="frameRate"
@ -52,12 +52,14 @@ const CinePlayer = ({
value={frameRate}
onChange={onFrameRateChangeHandler}
/>
<p className="mt-1 text-sm text-primary-light">{`${frameRate.toFixed(1)} fps`}</p>
<p className="-mt-2 text-sm text-primary-light">{`${frameRate.toFixed(
1
)} fps`}</p>
</div>
<IconButton
color="inherit"
size="initial"
className="mr-3 text-primary-active border border-primary-active rounded-full"
className="mr-3 border rounded-full text-primary-active border-primary-active"
onClick={onClose}
>
<Icon name="close" width="15px" height="15px" />
@ -66,7 +68,7 @@ const CinePlayer = ({
);
};
const noop = () => { };
const noop = () => {};
CinePlayer.defaultProps = {
isPlaying: false,
@ -76,7 +78,7 @@ CinePlayer.defaultProps = {
frameRate: 24,
onPlayPauseChange: noop,
onFrameRateChange: noop,
onClose: noop
onClose: noop,
};
CinePlayer.propTypes = {

View File

@ -3,17 +3,19 @@
* written in plain CSS with color variables from tailwind
* to avoid complex compatibility configuration.
*/
.CinePlayer input[type=range] {
.CinePlayer input[type='range'] {
-webkit-appearance: none;
background: transparent;
width: 100%;
height: 20px;
z-index: 5;
}
.CinePlayer input[type=range]:focus {
.CinePlayer input[type='range']:focus {
outline: none;
}
.CinePlayer input[type=range]::-webkit-slider-runnable-track {
.CinePlayer input[type='range']::-webkit-slider-runnable-track {
width: 100%;
height: 2px;
cursor: pointer;
@ -24,7 +26,7 @@
border: 0px solid #000000;
}
.CinePlayer input[type=range]::-webkit-slider-thumb {
.CinePlayer input[type='range']::-webkit-slider-thumb {
box-shadow: 0px 0px 0px #000000;
border: 4px solid #000000;
height: 18px;
@ -36,11 +38,11 @@
margin-top: -9px;
}
.CinePlayer input[type=range]:focus::-webkit-slider-runnable-track {
.CinePlayer input[type='range']:focus::-webkit-slider-runnable-track {
@apply bg-primary-light;
}
.CinePlayer input[type=range]::-moz-range-track {
.CinePlayer input[type='range']::-moz-range-track {
width: 100%;
height: 2px;
cursor: pointer;
@ -51,17 +53,17 @@
border: 0px solid #000000;
}
.CinePlayer input[type=range]::-moz-range-thumb {
.CinePlayer input[type='range']::-moz-range-thumb {
box-shadow: 0px 0px 0px #000000;
border: 4px solid #000000;
height: 18px;
width: 17px;
border: 2px solid #000000;
height: 12px;
width: 12px;
border-radius: 50px;
@apply bg-primary-light;
cursor: pointer;
}
.CinePlayer input[type=range]::-ms-track {
.CinePlayer input[type='range']::-ms-track {
width: 100%;
height: 2px;
cursor: pointer;
@ -71,21 +73,21 @@
color: transparent;
}
.CinePlayer input[type=range]::-ms-fill-lower {
.CinePlayer input[type='range']::-ms-fill-lower {
@apply bg-primary-light;
border: 0px solid #000000;
border-radius: 10px;
box-shadow: 0px 0px 0px #000000;
}
.CinePlayer input[type=range]::-ms-fill-upper {
.CinePlayer input[type='range']::-ms-fill-upper {
@apply bg-primary-light;
border: 0px solid #000000;
border-radius: 10px;
box-shadow: 0px 0px 0px #000000;
}
.CinePlayer input[type=range]::-ms-thumb {
.CinePlayer input[type='range']::-ms-thumb {
margin-top: 1px;
box-shadow: 0px 0px 0px #000000;
border: 4px solid #000000;
@ -96,10 +98,10 @@
cursor: pointer;
}
.CinePlayer input[type=range]:focus::-ms-fill-lower {
.CinePlayer input[type='range']:focus::-ms-fill-lower {
@apply bg-primary-light;
}
.CinePlayer input[type=range]:focus::-ms-fill-upper {
.CinePlayer input[type='range']:focus::-ms-fill-upper {
@apply bg-primary-light;
}

View File

@ -62,12 +62,14 @@ const sizeClasses = {
medium: 'py-3 px-3 text-lg',
large: 'py-4 px-4 text-xl',
initial: '',
toolbar: 'text-lg',
};
const iconSizeClasses = {
small: 'w-4 h-4',
medium: 'w-5 h-5',
large: 'w-6 h-6',
toolbar: 'w-5 h-5',
};
const fullWidthClasses = {
@ -106,6 +108,9 @@ const IconButton = ({
disabledClasses[disabled],
className
)}
style={{
padding: size === 'toolbar' ? '10px' : null,
}}
ref={buttonElement}
onClick={handleOnClick}
type={type}

View File

@ -9,11 +9,12 @@ const NavBar = ({ className, children, isSticky }) => {
return (
<div
className={classnames(
'flex flex-row items-center bg-secondary-dark px-3 py-1 min-h-16 border-b-4 border-black z-20',
'flex flex-row items-center bg-secondary-dark px-3 border-b-4 border-black z-20',
isSticky && stickyClasses,
!isSticky && notStickyClasses,
className
)}
style={{ paddingTop: '4px', paddingBottom: '4px', minHeight: '52px' }}
>
{children}
</div>

View File

@ -7,7 +7,7 @@ import { Icon, Tooltip, ListMenu } from '@ohif/ui';
const baseClasses = {
Button:
'h-12 flex items-center rounded-md border-transparent border-2 cursor-pointer',
'flex items-center rounded-md border-transparent border-2 cursor-pointer',
Primary:
'h-full flex flex-1 items-center rounded-md rounded-tr-none rounded-br-none',
Secondary:
@ -15,7 +15,7 @@ const baseClasses = {
PrimaryIcon: 'w-5 h-5',
SecondaryIcon: 'w-4 h-full stroke-1',
Separator: 'border-l pt-2 pb-2',
Content: 'absolute z-10 top-0 mt-16',
Content: 'absolute z-10 top-0 mt-12',
};
const classes = {
@ -154,6 +154,7 @@ const SplitButton = ({
...state,
primary: { isActive: isPrimaryActive },
})}
style={{ height: '40px' }}
onMouseEnter={onMouseEnterHandler}
onMouseLeave={onMouseLeaveHandler}
>
@ -169,7 +170,10 @@ const SplitButton = ({
isDisabled={!state.primary.tooltip}
content={state.primary.tooltip}
>
<div className="flex items-center justify-center w-full h-full p-3">
<div
className="flex items-center justify-center w-full h-full"
style={{ padding: '10px' }}
>
<Icon
name={state.primary.icon}
className={classes.PrimaryIcon({
@ -225,10 +229,12 @@ const DefaultListItemRenderer = ({ icon, label, isActive }) => (
isActive && 'bg-primary-dark'
)}
>
<span className="mr-4 text-base text-common-bright">
<span className="mr-4 text-base whitespace-pre text-common-bright">
<Icon name={icon} className="w-5 h-5 text-common-bright" />
</span>
<span className="mr-5 text-base text-common-bright">{label}</span>
<span className="mr-5 text-base whitespace-pre text-common-bright">
{label}
</span>
</div>
);

View File

@ -24,7 +24,7 @@ import { SplitButton, WindowLevelMenuItem } from '@ohif/ui';
primary: {
tooltip: 'W/L',
icon: 'tool-window-level',
onClick: (args) => console.debug('Primary click!', args)
onClick: args => console.debug('Primary click!', args),
},
secondary: {
icon: 'chevron-down',
@ -33,23 +33,43 @@ import { SplitButton, WindowLevelMenuItem } from '@ohif/ui';
tooltip: 'More Measure Tools',
},
items: [
{ id: '1', icon: 'tool-layout', label: 'Layout', onClick: (args) => console.debug('Item click!', args) },
{ id: '2', icon: 'tool-window-level', label: 'W/L', onClick: (args) => console.debug('Item click!', args) },
{ id: '3', icon: 'tool-length', label: 'Length', onClick: (args) => console.debug('Item click!', args) }
{
id: '1',
icon: 'tool-layout',
label: 'Layout',
onClick: args => console.debug('Item click!', args),
},
{
id: '2',
icon: 'tool-window-level',
label: 'W/L',
onClick: args => console.debug('Item click!', args),
},
{
id: '3',
icon: 'tool-length',
label: 'Length',
onClick: args => console.debug('Item click!', args),
},
],
onClick: (args) => console.debug('Any click!', args)
onClick: args => console.debug('Any click!', args),
};
return (
<div className="mb-2">
<div className="flex flex-row min-h-16 w-full justify-center items-center bg-secondary-dark">
<div className="flex flex-row w-full justify-center items-center bg-secondary-dark">
<SplitButton {...mockedProps} isRadio />
<SplitButton {...mockedProps} isAction renderer={WindowLevelMenuItem} items={[
{ id: '1', value: 1, title: 'Soft tissue', subtitle: '400 / 40' },
{ id: '2', value: 2, title: 'Lung', subtitle: '1500 / -600' },
{ id: '3', value: 3, title: 'Liver', subtitle: '150 / 90' },
{ id: '4', value: 4, title: 'Bone', subtitle: '80 / 40' },
{ id: '5', value: 5, title: 'Brain', subtitle: '2500 / 480' },
]} />
<SplitButton
{...mockedProps}
isAction
renderer={WindowLevelMenuItem}
items={[
{ id: '1', value: 1, title: 'Soft tissue', subtitle: '400 / 40' },
{ id: '2', value: 2, title: 'Lung', subtitle: '1500 / -600' },
{ id: '3', value: 3, title: 'Liver', subtitle: '150 / 90' },
{ id: '4', value: 4, title: 'Bone', subtitle: '80 / 40' },
{ id: '5', value: 5, title: 'Brain', subtitle: '2500 / 480' },
]}
/>
<SplitButton {...mockedProps} />
</div>
</div>

View File

@ -61,7 +61,7 @@ const StudyListFilter = ({
</div>
<div
className="sticky z-10 border-b-4 border-black"
style={{ top: '57px' }}
style={{ top: '52px' }}
>
<div className="pt-3 pb-3 bg-primary-dark ">
<InputGroup

View File

@ -41,6 +41,7 @@ const ToolbarButton = ({
>
<IconButton
variant={isActive ? 'contained' : 'text'}
size="toolbar"
className={classnames('mx-1', classes.type[type])}
onClick={() => {
onInteraction({

View File

@ -11,7 +11,7 @@ const Viewer = () => {
<Header />
<div
className="flex flex-row flex-no-wrap items-stretch flex-1 w-full overflow-hidden"
style={{ height: 'calc(100vh - 57px' }}
style={{ height: 'calc(100vh - 52px' }}
>
<SidePanel
side="left"

View File

@ -57,7 +57,7 @@ import { tabs } from './studyBrowserMockData';
<Header />
<div
className="flex flex-row flex-no-wrap items-stretch overflow-hidden w-full"
style={{ height: 'calc(100vh - 57px' }}
style={{ height: 'calc(100vh - 52px' }}
>
{/* LEFT SIDEPANELS */}
<SidePanel

View File

@ -62,21 +62,21 @@ function WorkList({
* The default sort value keep the filters synchronized with runtime conditional sorting
* Only applied if no other sorting is specified and there are less than 101 studies
*/
let defaultSortValues = {};
const sortedStudies = studies
// TOOD: Move sort to DataSourceWrapper?
// TODO: MOTIVATION, this is triggered on every render, even if list/sort does not change
.sort((s1, s2) => {
const noSortApplied = sortBy === '' || !sortBy;
const sortModifier = sortDirection === 'descending' ? 1 : -1;
const canSort = studiesTotal < STUDIES_LIMIT;
const shouldUseDefaultSort = sortBy === '' || !sortBy;
const sortModifier = sortDirection === 'descending' ? 1 : -1;
const defaultSortValues =
shouldUseDefaultSort && canSort
? { sortBy: 'studyDate', sortDirection: 'ascending' }
: {};
const sortedStudies = studies;
if (noSortApplied && studiesTotal < STUDIES_LIMIT) {
if (canSort) {
studies.sort((s1, s2) => {
if (shouldUseDefaultSort) {
const ascendingSortModifier = -1;
defaultSortValues = { sortBy: 'studyDate', sortDirection: 'ascending' };
return _sortStringDates(s1, s2, ascendingSortModifier);
} else if (noSortApplied) {
return 0;
}
const s1Prop = s1[sortBy];
@ -96,6 +96,7 @@ function WorkList({
return 0;
});
}
// ~ Rows & Studies
const [expandedRows, setExpandedRows] = useState([]);