OHIF-79: Study Browser side panel (#1614)
* Initial code changes for StudyBrowser * StudyItem component basic strucure * Adding new icon * Updates to get StudyItem working * Small fix on side panel open header * Adding new icons * Thumbnail List * ThumbnailSR WIP * Thumanil WIP * Export new components into ohif/ui * Updates on style * Update ThumbnailSR style * Margin updates * MAke it scrollable * Make it scrollable * Style updates * Fixing tooltip * Tunning the mock data and testing scenarios * Update mock data * make all studies collapsed * small fix on tooltip * Removing empty mdx files * Updating viewer docz page * Style updates * Update button font-size * Fix: Make cancel button only visible on hover * Fixing callouts * Fix eslint
This commit is contained in:
parent
51750c6ede
commit
eda99a0bac
@ -30,6 +30,8 @@ export {
|
||||
Select,
|
||||
SegmentationTable,
|
||||
SidePanel,
|
||||
StudyBrowser,
|
||||
StudyItem,
|
||||
StudyListExpandedRow,
|
||||
StudyListPagination,
|
||||
StudyListTable,
|
||||
@ -40,6 +42,9 @@ export {
|
||||
TableHead,
|
||||
TableRow,
|
||||
ThemeWrapper,
|
||||
Thumbnail,
|
||||
ThumbnailSR,
|
||||
ThumbnailList,
|
||||
Typography,
|
||||
} from './src/components';
|
||||
|
||||
|
||||
6
platform/ui/src/assets/icons/circled-checkmark.svg
Normal file
6
platform/ui/src/assets/icons/circled-checkmark.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<circle cx="8" cy="8" r="8" fill="currentColor"/>
|
||||
<path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.556 5.333L7.824 11.11c-.168.259-.424.42-.703.444-.278.023-.552-.095-.75-.324L4.444 8.993"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 366 B |
3
platform/ui/src/assets/icons/dotted-circle.svg
Normal file
3
platform/ui/src/assets/icons/dotted-circle.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<path fill="none" fill-rule="evenodd" stroke="currentColor" stroke-dasharray="1.5 3.8" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M8 15c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 295 B |
6
platform/ui/src/assets/icons/tracked.svg
Normal file
6
platform/ui/src/assets/icons/tracked.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<circle cx="8" cy="8" r="8" fill="currentColor"/>
|
||||
<path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.556 5.333L7.824 11.11c-.168.259-.424.42-.703.444-.278.023-.552-.095-.75-.324L4.444 8.993"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 366 B |
@ -16,25 +16,12 @@
|
||||
@apply bg-primary-main;
|
||||
}
|
||||
|
||||
/* INVISIBLE SCROLLBAR */
|
||||
.invisible-scrollbar::-webkit-scrollbar {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.invisible-scrollbar::-webkit-scrollbar-track {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.invisible-scrollbar::-webkit-scrollbar-thumb {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.invisible-scrollbar::-webkit-scrollbar-thumb:window-inactive {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
/* TOOLTIP WORKAROUND FOR ARROW UP */
|
||||
.tooltip::before {
|
||||
.tooltip.tooltip-up::before {
|
||||
@apply bg-primary-dark absolute z-10;
|
||||
content: '';
|
||||
width: 14px;
|
||||
@ -43,3 +30,34 @@
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.tooltip.tooltip-right {
|
||||
left: calc(100% + 15px);
|
||||
}
|
||||
|
||||
.tooltip.tooltip-right::before {
|
||||
@apply bg-black absolute z-10;
|
||||
content: '';
|
||||
width: 2px;
|
||||
height: 15px;
|
||||
left: -1px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
/* TOOLTIP WORKAROUND FOR ARROW */
|
||||
.showTooltipOnHover .tooltip {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.showTooltipOnHover:hover .tooltip {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.showExcludeButtonOnHover .excludeButton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.showExcludeButtonOnHover:hover .excludeButton {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@ import React from 'react';
|
||||
import arrowDown from './../../assets/icons/arrow-down.svg';
|
||||
import calendar from './../../assets/icons/calendar.svg';
|
||||
import cancel from './../../assets/icons/cancel.svg';
|
||||
import dottedCircle from './../../assets/icons/dotted-circle.svg';
|
||||
import circledCheckmark from './../../assets/icons/circled-checkmark.svg';
|
||||
import chevronDown from './../../assets/icons/chevron-down.svg';
|
||||
import chevronLeft from './../../assets/icons/chevron-left.svg';
|
||||
import chevronRight from './../../assets/icons/chevron-right.svg';
|
||||
@ -24,6 +26,7 @@ import settings from './../../assets/icons/settings.svg';
|
||||
import sorting from './../../assets/icons/sorting.svg';
|
||||
import sortingActiveDown from './../../assets/icons/sorting-active-down.svg';
|
||||
import sortingActiveUp from './../../assets/icons/sorting-active-up.svg';
|
||||
import tracked from './../../assets/icons/tracked.svg';
|
||||
|
||||
/** Tools */
|
||||
import toolZoom from './../../assets/icons/tool-zoom.svg';
|
||||
@ -41,6 +44,8 @@ const ICONS = {
|
||||
'arrow-down': arrowDown,
|
||||
calendar: calendar,
|
||||
cancel: cancel,
|
||||
'dotted-circle': dottedCircle,
|
||||
'circled-checkmark': circledCheckmark,
|
||||
'chevron-down': chevronDown,
|
||||
'chevron-left': chevronLeft,
|
||||
'chevron-right': chevronRight,
|
||||
@ -61,6 +66,7 @@ const ICONS = {
|
||||
'sorting-active-down': sortingActiveDown,
|
||||
'sorting-active-up': sortingActiveUp,
|
||||
sorting: sorting,
|
||||
tracked: tracked,
|
||||
|
||||
/** Tools */
|
||||
'tool-zoom': toolZoom,
|
||||
|
||||
@ -77,7 +77,7 @@ const SidePanel = ({
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
className="flex flex-row items-center border-b-2 border-secondary-main h-12 relative"
|
||||
className="flex flex-row items-center border-b-2 border-secondary-light px-3 h-12"
|
||||
>
|
||||
<Icon
|
||||
name={openIconName[side]}
|
||||
|
||||
87
platform/ui/src/components/StudyBrowser/StudyBrowser.jsx
Normal file
87
platform/ui/src/components/StudyBrowser/StudyBrowser.jsx
Normal file
@ -0,0 +1,87 @@
|
||||
import React, { useState } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { ButtonGroup, Button, StudyItem, ThumbnailList } from '@ohif/ui';
|
||||
|
||||
import { studyWithSR, studySimple } from './mockData';
|
||||
const studyGroupTypes = ['Primary', 'Recent', 'All'];
|
||||
const studyGroup = {
|
||||
Primary: [studySimple],
|
||||
Recent: [studyWithSR, studySimple],
|
||||
All: [studySimple, studyWithSR],
|
||||
};
|
||||
|
||||
const buttonClasses = 'text-white text-base border-none bg-black';
|
||||
const activeButtonClasses = 'bg-primary-main';
|
||||
|
||||
const StudyBrowser = () => {
|
||||
const [studyGroupSelected, setStudyGroupSelected] = useState('Recent');
|
||||
const [studyActive, setStudyActive] = useState(null);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="flex flex-row items-center justify-center border-b-2 w-100 h-16 border-secondary-light p-4 bg-primary-dark">
|
||||
<ButtonGroup
|
||||
variant="outlined"
|
||||
color="inherit"
|
||||
className="border border-secondary-light rounded-md"
|
||||
>
|
||||
{studyGroupTypes.map((studyGroup) => {
|
||||
const isActive = studyGroupSelected === studyGroup;
|
||||
return (
|
||||
<Button
|
||||
key={studyGroup}
|
||||
className={classnames(
|
||||
buttonClasses,
|
||||
isActive && activeButtonClasses
|
||||
)}
|
||||
size="small"
|
||||
onClick={() => {
|
||||
setStudyGroupSelected(studyGroup);
|
||||
setStudyActive(null);
|
||||
}}
|
||||
>
|
||||
{studyGroup}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
<div className="flex flex-col flex-1 overflow-auto invisible-scrollbar">
|
||||
{studyGroup[studyGroupSelected].map(
|
||||
({
|
||||
studyInstanceUid,
|
||||
studyDate,
|
||||
studyDescription,
|
||||
instances,
|
||||
modalities,
|
||||
trackedSeries,
|
||||
thumbnails,
|
||||
}) => {
|
||||
const isActive = studyActive === studyInstanceUid;
|
||||
return (
|
||||
<React.Fragment key={studyInstanceUid}>
|
||||
<StudyItem
|
||||
studyDate={studyDate}
|
||||
studyDescription={studyDescription}
|
||||
instances={instances}
|
||||
modalities={modalities}
|
||||
trackedSeries={trackedSeries}
|
||||
isActive={isActive}
|
||||
onClick={() => {
|
||||
setStudyActive(isActive ? null : studyInstanceUid);
|
||||
}}
|
||||
/>
|
||||
{isActive && thumbnails && (
|
||||
<ThumbnailList thumbnails={thumbnails} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default StudyBrowser;
|
||||
26
platform/ui/src/components/StudyBrowser/StudyBrowser.mdx
Normal file
26
platform/ui/src/components/StudyBrowser/StudyBrowser.mdx
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
name: StudyBrowser
|
||||
menu: General
|
||||
route: components/studyBrowser
|
||||
---
|
||||
|
||||
import { Playground, Props } from 'docz';
|
||||
import { StudyBrowser } from '@ohif/ui';
|
||||
|
||||
# StudyBrowser
|
||||
|
||||
## Import
|
||||
|
||||
```javascript
|
||||
import { StudyBrowser } from '@ohif/ui';
|
||||
```
|
||||
|
||||
## Basic usage
|
||||
|
||||
<Playground>
|
||||
<StudyBrowser />
|
||||
</Playground>
|
||||
|
||||
## Properties
|
||||
|
||||
<Props of={StudyBrowser} />
|
||||
2
platform/ui/src/components/StudyBrowser/index.js
Normal file
2
platform/ui/src/components/StudyBrowser/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import StudyBrowser from './StudyBrowser';
|
||||
export default StudyBrowser;
|
||||
56
platform/ui/src/components/StudyBrowser/mockData.js
Normal file
56
platform/ui/src/components/StudyBrowser/mockData.js
Normal file
@ -0,0 +1,56 @@
|
||||
const studyWithSR = {
|
||||
studyInstanceUid: '1',
|
||||
studyDate: '07-Sept-2010',
|
||||
studyDescription: 'CHEST/ABD/PELVIS W/CONTRAST',
|
||||
instances: 902,
|
||||
modalities: 'CT,SR',
|
||||
trackedSeries: 1,
|
||||
thumbnails: [
|
||||
{
|
||||
displaySetInstanceUid: 'f69f6asdasd48c-223e-db7f-c4af-b8906641a66e',
|
||||
seriesDescription: 'Multiple line image series description lorem sit',
|
||||
seriesNumber: 1,
|
||||
instanceNumber: 68,
|
||||
viewportIdentificator: 'A',
|
||||
isTracked: true,
|
||||
},
|
||||
{
|
||||
displaySetInstanceUid: 'f69f648c-223e-db7f-c4asdasdaf-b8906641a66e',
|
||||
seriesDescription: 'Multiple line image series description lorem sit',
|
||||
seriesNumber: 1,
|
||||
instanceNumber: 68,
|
||||
viewportIdentificator: 'B',
|
||||
},
|
||||
{
|
||||
displaySetInstanceUid: 'f69f648c-223e-dasdasdb7f-c4af-b8906641a66e',
|
||||
seriesDescription: 'Multiple line image series description lorem sit',
|
||||
seriesNumber: 1,
|
||||
instanceNumber: 68,
|
||||
},
|
||||
{
|
||||
displaySetInstanceUid: 'f69f648c-223e-db7f-c4afas-b8906asd641a66e',
|
||||
seriesDescription: 'Multiple line description lorem ipsum dolor sit amet',
|
||||
modality: 'SR',
|
||||
seriesDate: '07-Sept-2010',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const studySimple = {
|
||||
studyInstanceUid: '2',
|
||||
studyDate: '07-Sept-2010',
|
||||
studyDescription: 'CHEST/ABD/PELVIS W/CONTRAST',
|
||||
instances: 902,
|
||||
modalities: 'CT',
|
||||
trackedSeries: 0,
|
||||
thumbnails: [
|
||||
{
|
||||
displaySetInstanceUid: 'f69f648c-223e-db7f-c4af-b8906641a66e',
|
||||
seriesDescription: 'Multiple line image series description lorem sit',
|
||||
seriesNumber: 1,
|
||||
instanceNumber: 68,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export { studyWithSR, studySimple };
|
||||
72
platform/ui/src/components/StudyItem/StudyItem.jsx
Normal file
72
platform/ui/src/components/StudyItem/StudyItem.jsx
Normal file
@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { Icon } from '@ohif/ui';
|
||||
|
||||
const baseClasses =
|
||||
'first:border-0 border-t border-secondary-light cursor-pointer';
|
||||
|
||||
const StudyItem = ({
|
||||
studyDate,
|
||||
studyDescription,
|
||||
instances,
|
||||
modalities,
|
||||
trackedSeries,
|
||||
isActive,
|
||||
onClick,
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
isActive ? 'bg-secondary-dark' : 'bg-black hover:bg-secondary-main',
|
||||
baseClasses
|
||||
)}
|
||||
onClick={onClick}
|
||||
onKeyDown={onClick}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
<div className="flex flex-col flex-1 px-4 pb-2">
|
||||
<div className="flex flex-row items-center justify-between pb-2 pt-2 pb-2">
|
||||
<div className="text-white text-base">{studyDate}</div>
|
||||
<div className="flex flex-row items-center text-blue-300 text-base">
|
||||
<Icon name="group-layers" className="text-blue-300 mx-2 w-4" />
|
||||
{instances}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row py-1">
|
||||
<div className="text-blue-300 pr-5 text-xl">{modalities}</div>
|
||||
<div className="text-blue-300 text-base">{studyDescription}</div>
|
||||
</div>
|
||||
</div>
|
||||
{!!trackedSeries && (
|
||||
<div className="flex flex-2">
|
||||
<div
|
||||
className={classnames(
|
||||
'flex flex-row bg-secondary-main text-base text-white py-1 pl-2 pr-4 mt-2 ',
|
||||
isActive
|
||||
? 'flex-1 border-t border-secondary-light justify-center'
|
||||
: 'rounded-sm mx-4 mb-4'
|
||||
)}
|
||||
>
|
||||
<Icon name="tracked" className="text-primary-light w-4 mr-2" />
|
||||
{trackedSeries} Tracked Series
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
StudyItem.propTypes = {
|
||||
studyDate: PropTypes.any,
|
||||
studyDescription: PropTypes.any,
|
||||
modalities: PropTypes.any,
|
||||
instances: PropTypes.any,
|
||||
trackedSeries: PropTypes.any,
|
||||
isActive: PropTypes.any,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default StudyItem;
|
||||
2
platform/ui/src/components/StudyItem/index.js
Normal file
2
platform/ui/src/components/StudyItem/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import StudyItem from './StudyItem';
|
||||
export default StudyItem;
|
||||
117
platform/ui/src/components/Thumbnail/Thumbnail.jsx
Normal file
117
platform/ui/src/components/Thumbnail/Thumbnail.jsx
Normal file
@ -0,0 +1,117 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { Icon } from '@ohif/ui';
|
||||
|
||||
const Thumbnail = ({
|
||||
seriesDescription,
|
||||
seriesNumber,
|
||||
instanceNumber,
|
||||
viewportIdentificator,
|
||||
isTracked,
|
||||
isActive,
|
||||
onClick,
|
||||
}) => {
|
||||
const trackedIcon = isTracked ? 'circled-checkmark' : 'dotted-circle';
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex flex-row flex-1 px-4 py-2 showExcludeButtonOnHover cursor-pointer"
|
||||
onClick={onClick}
|
||||
onKeyDown={onClick}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
<div className="flex flex-col flex-2 px-2 items-center">
|
||||
<div
|
||||
className={classnames(
|
||||
'flex flex-col items-center justify-start p-2 mb-2 relative cursor-pointer',
|
||||
isTracked && 'rounded-sm hover:bg-gray-900 showTooltipOnHover'
|
||||
)}
|
||||
>
|
||||
<Icon name={trackedIcon} className="text-primary-light mb-2 w-5" />
|
||||
<div className="text-white text-xl leading-tight h-5">
|
||||
{viewportIdentificator}
|
||||
</div>
|
||||
<div
|
||||
className={classnames(
|
||||
'tooltip tooltip-right absolute bg-black border border-secondary-main text-common-light text-base rounded py-2 px-4 top-0 w-max-content hidden'
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-row flex-1">
|
||||
<div className="flex flex-col flex-1 pr-4">
|
||||
<span>
|
||||
Series is <span className="text-white">tracked</span>
|
||||
</span>
|
||||
{viewportIdentificator && (
|
||||
<span>
|
||||
in viewport
|
||||
<span className="ml-1 text-white">
|
||||
{viewportIdentificator}
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-2 items-center justify-center">
|
||||
<Icon name="info-link" className="text-primary-active" />
|
||||
</div>
|
||||
</div>
|
||||
<svg
|
||||
className="absolute text-black stroke-secondary-main stroke-2"
|
||||
style={{
|
||||
top: 'calc(50% - 8px)',
|
||||
left: -15,
|
||||
transform: 'rotate(270deg)',
|
||||
}}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path fill="currentColor" d="M24 22h-24l12-20z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
{isTracked && (
|
||||
<Icon name="cancel" className="text-primary-active excludeButton" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col flex-1 px-4">
|
||||
<div
|
||||
className={classnames(
|
||||
'flex flex-1 items-center justify-center rounded-md bg-black text-white mb-2',
|
||||
isActive
|
||||
? 'border-2 border-primary-light'
|
||||
: 'border border-secondary-light hover:border-blue-300'
|
||||
)}
|
||||
style={{ minHeight: '120px' }}
|
||||
>
|
||||
{'Thumbnail img'}
|
||||
</div>
|
||||
<div className="flex flex-row flex-1 text-blue-300 text-base">
|
||||
<div className="mr-4">
|
||||
<span className="text-primary-main font-bold">{'S: '}</span>
|
||||
{seriesNumber}
|
||||
</div>
|
||||
<div className="flex flex-row items-centerflex-1">
|
||||
<Icon name="group-layers" className="w-3 mr-2" /> {instanceNumber}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-white text-base">{seriesDescription}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Thumbnail.propTypes = {
|
||||
seriesDescription: PropTypes.string.isRequired,
|
||||
seriesNumber: PropTypes.number.isRequired,
|
||||
instanceNumber: PropTypes.number.isRequired,
|
||||
isActive: PropTypes.bool.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
isTracked: PropTypes.bool,
|
||||
viewportIdentificator: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Thumbnail;
|
||||
2
platform/ui/src/components/Thumbnail/index.js
Normal file
2
platform/ui/src/components/Thumbnail/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import Thumbnail from './Thumbnail';
|
||||
export default Thumbnail;
|
||||
73
platform/ui/src/components/ThumbnailList/ThumbnailList.jsx
Normal file
73
platform/ui/src/components/ThumbnailList/ThumbnailList.jsx
Normal file
@ -0,0 +1,73 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { Thumbnail, ThumbnailSR } from '@ohif/ui';
|
||||
|
||||
const ThumbnailList = ({ thumbnails }) => {
|
||||
const [thumbnailActive, setThumbnailActive] = useState(null);
|
||||
|
||||
return (
|
||||
<div className="bg-black py-3">
|
||||
{thumbnails.map(
|
||||
({
|
||||
displaySetInstanceUid,
|
||||
seriesDescription,
|
||||
seriesNumber,
|
||||
instanceNumber,
|
||||
modality,
|
||||
seriesDate,
|
||||
viewportIdentificator,
|
||||
isTracked,
|
||||
}) => {
|
||||
const isSR = modality && modality.toLowerCase() === 'sr';
|
||||
const isActive = thumbnailActive === displaySetInstanceUid;
|
||||
|
||||
if (isSR) {
|
||||
return (
|
||||
<ThumbnailSR
|
||||
key={displaySetInstanceUid}
|
||||
modality={modality}
|
||||
seriesDate={seriesDate}
|
||||
seriesDescription={seriesDescription}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Thumbnail
|
||||
key={displaySetInstanceUid}
|
||||
seriesDescription={seriesDescription}
|
||||
seriesNumber={seriesNumber}
|
||||
instanceNumber={instanceNumber}
|
||||
viewportIdentificator={viewportIdentificator}
|
||||
isTracked={isTracked}
|
||||
isActive={isActive}
|
||||
onClick={() => {
|
||||
setThumbnailActive(
|
||||
thumbnailActive === displaySetInstanceUid
|
||||
? null
|
||||
: displaySetInstanceUid
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ThumbnailList.propTypes = {
|
||||
thumbnails: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
displaySetInstanceUid: PropTypes.string,
|
||||
seriesDescription: PropTypes.string,
|
||||
seriesNumber: PropTypes.number,
|
||||
instanceNumber: PropTypes.number,
|
||||
modality: PropTypes.string,
|
||||
seriesDate: PropTypes.string,
|
||||
})
|
||||
),
|
||||
};
|
||||
|
||||
export default ThumbnailList;
|
||||
2
platform/ui/src/components/ThumbnailList/index.js
Normal file
2
platform/ui/src/components/ThumbnailList/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import ThumbnailList from './ThumbnailList';
|
||||
export default ThumbnailList;
|
||||
31
platform/ui/src/components/ThumbnailSR/ThumbnailSR.jsx
Normal file
31
platform/ui/src/components/ThumbnailSR/ThumbnailSR.jsx
Normal file
@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { Icon } from '@ohif/ui';
|
||||
|
||||
const ThumbnailSR = ({ seriesDescription, seriesDate }) => {
|
||||
return (
|
||||
<div className="flex flex-row flex-1 px-4 py-3">
|
||||
<div className="flex flex-2 pl-4 pr-6">
|
||||
<Icon name="list-bullets" className="text-secondary-light" />
|
||||
</div>
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="flex flex-row flex-1 items-center mb-2">
|
||||
<div className="px-4 bg-primary-main rounded-sm mr-4 text-xl text-white">
|
||||
SR
|
||||
</div>
|
||||
<span className="text-blue-300 text-base">{seriesDate}</span>
|
||||
</div>
|
||||
<div className="text-white text-base">{seriesDescription}</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ThumbnailSR.propTypes = {
|
||||
seriesDescription: PropTypes.string,
|
||||
seriesDate: PropTypes.string,
|
||||
};
|
||||
|
||||
export default ThumbnailSR;
|
||||
2
platform/ui/src/components/ThumbnailSR/index.js
Normal file
2
platform/ui/src/components/ThumbnailSR/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import ThumbnailSR from './ThumbnailSR';
|
||||
export default ThumbnailSR;
|
||||
@ -16,16 +16,21 @@ import NavBar from './NavBar';
|
||||
import Select from './Select';
|
||||
import SegmentationTable from './SegmentationTable';
|
||||
import SidePanel from './SidePanel';
|
||||
import Svg from './Svg';
|
||||
import StudyBrowser from './StudyBrowser';
|
||||
import StudyListExpandedRow from './StudyListExpandedRow';
|
||||
import StudyListPagination from './StudyListPagination';
|
||||
import StudyListTable from './StudyListTable';
|
||||
import Svg from './Svg';
|
||||
import StudyItem from './StudyItem';
|
||||
import Table from './Table';
|
||||
import TableBody from './TableBody';
|
||||
import TableCell from './TableCell';
|
||||
import TableHead from './TableHead';
|
||||
import TableRow from './TableRow';
|
||||
import ThemeWrapper from './ThemeWrapper/';
|
||||
import Thumbnail from './Thumbnail';
|
||||
import ThumbnailSR from './ThumbnailSR';
|
||||
import ThumbnailList from './ThumbnailList';
|
||||
import Typography from './Typography';
|
||||
|
||||
export {
|
||||
@ -47,15 +52,20 @@ export {
|
||||
Select,
|
||||
SegmentationTable,
|
||||
SidePanel,
|
||||
Svg,
|
||||
StudyBrowser,
|
||||
StudyItem,
|
||||
StudyListExpandedRow,
|
||||
StudyListPagination,
|
||||
StudyListTable,
|
||||
Svg,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableRow,
|
||||
ThemeWrapper,
|
||||
Thumbnail,
|
||||
ThumbnailSR,
|
||||
ThumbnailList,
|
||||
Typography,
|
||||
};
|
||||
|
||||
@ -86,7 +86,7 @@ components.
|
||||
{shouldShowTooltip && (
|
||||
<div
|
||||
className={classnames(
|
||||
'tooltip absolute bg-primary-dark border border-secondary-main text-white text-base rounded py-1 px-4 inset-x-auto top-full mt-2 w-max-content'
|
||||
'tooltip tooltip-up absolute bg-primary-dark border border-secondary-main text-white text-base rounded py-1 px-4 inset-x-auto top-full mt-2 w-max-content'
|
||||
)}
|
||||
>
|
||||
{tool.label}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { NavBar, SidePanel, Svg } from '@ohif/ui';
|
||||
import { NavBar, SidePanel, Svg, StudyBrowser } from '@ohif/ui';
|
||||
|
||||
const Viewer = () => {
|
||||
return (
|
||||
@ -18,11 +18,9 @@ const Viewer = () => {
|
||||
iconName="group-layers"
|
||||
iconLabel="Studies"
|
||||
componentLabel="Studies"
|
||||
defaultIsOpen={false}
|
||||
defaultIsOpen={true}
|
||||
>
|
||||
<div className="flex justify-center text-white p-2">
|
||||
panel placeholder
|
||||
</div>
|
||||
<StudyBrowser />
|
||||
</SidePanel>
|
||||
<div className="flex flex-1 h-100 overflow-hidden bg-primary-main items-center justify-center text-white">
|
||||
CONTENT
|
||||
|
||||
@ -5,110 +5,32 @@ route: examples/viewer
|
||||
---
|
||||
|
||||
import { Playground, Props } from 'docz';
|
||||
import {
|
||||
NavBar,
|
||||
SidePanel,
|
||||
Svg,
|
||||
MeasurementTable,
|
||||
SegmentationTable,
|
||||
ButtonGroup,
|
||||
Button,
|
||||
Icon,
|
||||
IconButton,
|
||||
} from '@ohif/ui';
|
||||
import { NavBar, SidePanel, Svg, StudyBrowser } from '@ohif/ui';
|
||||
|
||||
# Viewer
|
||||
|
||||
<Playground>
|
||||
{() => {
|
||||
const measurementTableData = {
|
||||
title: 'Measurements',
|
||||
amount: 10,
|
||||
data: new Array(10).fill(''),
|
||||
};
|
||||
const segmentationTableData = {
|
||||
title: 'Segments',
|
||||
amount: 12,
|
||||
data: new Array(12).fill(''),
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<NavBar className="justify-start">
|
||||
<div className="m-3">
|
||||
<Svg name="logo-ohif" />
|
||||
</div>
|
||||
</NavBar>
|
||||
<div
|
||||
className="flex flex-row flex-no-wrap flex-1 items-stretch overflow-hidden w-full"
|
||||
style={{ height: 'calc(100vh - 57px' }}
|
||||
>
|
||||
<SidePanel
|
||||
side="left"
|
||||
iconName="group-layers"
|
||||
iconLabel="Studies"
|
||||
componentLabel="Studies"
|
||||
defaultIsOpen={false}
|
||||
>
|
||||
<div className="flex justify-center text-white p-2">
|
||||
panel placeholder
|
||||
</div>
|
||||
</SidePanel>
|
||||
<div className="flex flex-1 h-100 overflow-hidden bg-primary-main items-center justify-center text-white">
|
||||
CONTENT
|
||||
</div>
|
||||
<SidePanel
|
||||
side="right"
|
||||
iconName="list-bullets"
|
||||
iconLabel="Measure"
|
||||
componentLabel="Measurements"
|
||||
defaultIsOpen={false}
|
||||
>
|
||||
<div className="overflow-y-auto overflow-x-hidden invisible-scrollbar">
|
||||
<div className="p-2">
|
||||
<div className="leading-none">
|
||||
<span className="text-white text-base mr-2">07-Sep-2010</span>
|
||||
<span className="px-1 text-black bg-common-bright text-base rounded-sm font-bold">
|
||||
CT
|
||||
</span>
|
||||
</div>
|
||||
<div className="leading-none">
|
||||
<span className="text-base text-primary-light">
|
||||
CHEST/ABD/PELVIS W CONTRAST
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<MeasurementTable {...measurementTableData} />
|
||||
<SegmentationTable {...segmentationTableData} />
|
||||
</div>
|
||||
<div className="p-4 flex justify-center">
|
||||
<ButtonGroup onClick={() => alert('Export')}>
|
||||
<Button
|
||||
className="text-white border-primary-main bg-black text-base py-2 px-2"
|
||||
size="initial"
|
||||
color="inherit"
|
||||
>
|
||||
Export
|
||||
</Button>
|
||||
<IconButton
|
||||
className="bg-black border-primary-main px-2 text-white px-2"
|
||||
color="inherit"
|
||||
size="initial"
|
||||
>
|
||||
<Icon name="arrow-down" />
|
||||
</IconButton>
|
||||
</ButtonGroup>
|
||||
<Button
|
||||
className="text-white border border-primary-main bg-black text-base py-2 px-2 ml-2"
|
||||
variant="outlined"
|
||||
size="initial"
|
||||
color="inherit"
|
||||
onClick={() => alert('Create Report')}
|
||||
>
|
||||
Create Report
|
||||
</Button>
|
||||
</div>
|
||||
</SidePanel>
|
||||
</div>
|
||||
<div>
|
||||
<NavBar className="justify-start">
|
||||
<div className="m-3">
|
||||
<Svg name="logo-ohif" />
|
||||
</div>
|
||||
</NavBar>
|
||||
<div
|
||||
className="flex flex-row flex-no-wrap flex-1 items-stretch overflow-hidden w-full"
|
||||
style={{ height: 'calc(100vh - 57px' }}
|
||||
>
|
||||
<SidePanel
|
||||
side="left"
|
||||
iconName="group-layers"
|
||||
iconLabel="Studies"
|
||||
componentLabel="Studies"
|
||||
defaultIsOpen={false}
|
||||
>
|
||||
<StudyBrowser />
|
||||
</SidePanel>
|
||||
<div className="flex flex-1 h-100 overflow-hidden bg-primary-main items-center justify-center text-white">
|
||||
CONTENT
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user