feat: Tooltip, ToolbarButton, Toolbar API and misc
This commit is contained in:
parent
3223d6a8a1
commit
9154f36477
@ -28,6 +28,7 @@ export {
|
|||||||
MeasurementTable,
|
MeasurementTable,
|
||||||
NavBar,
|
NavBar,
|
||||||
Notification,
|
Notification,
|
||||||
|
PrimaryToolbar,
|
||||||
Select,
|
Select,
|
||||||
SegmentationTable,
|
SegmentationTable,
|
||||||
SidePanel,
|
SidePanel,
|
||||||
@ -46,6 +47,8 @@ export {
|
|||||||
Thumbnail,
|
Thumbnail,
|
||||||
ThumbnailSR,
|
ThumbnailSR,
|
||||||
ThumbnailList,
|
ThumbnailList,
|
||||||
|
ToolbarButton,
|
||||||
|
Tooltip,
|
||||||
Typography,
|
Typography,
|
||||||
ViewportActionBar,
|
ViewportActionBar,
|
||||||
ViewportGrid,
|
ViewportGrid,
|
||||||
|
|||||||
@ -41,62 +41,6 @@
|
|||||||
@apply hidden;
|
@apply hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
|
||||||
@apply z-10 absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TOOLTIP WORKAROUND FOR ARROW UP */
|
|
||||||
.tooltip.tooltip-up::before {
|
|
||||||
@apply bg-primary-dark absolute z-10;
|
|
||||||
content: '';
|
|
||||||
width: 14px;
|
|
||||||
height: 1px;
|
|
||||||
top: -1px;
|
|
||||||
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.tooltip-top-right::before {
|
|
||||||
@apply bg-primary-dark absolute z-10;
|
|
||||||
content: '';
|
|
||||||
width: 15px;
|
|
||||||
height: 2px;
|
|
||||||
right: 5px;
|
|
||||||
top: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip.tooltip-top-left::before {
|
|
||||||
@apply bg-primary-dark absolute z-10;
|
|
||||||
content: '';
|
|
||||||
width: 15px;
|
|
||||||
height: 2px;
|
|
||||||
left: 5px;
|
|
||||||
top: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TOOLTIP WORKAROUND FOR ARROW */
|
|
||||||
.showTooltipOnHover .tooltip {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.showTooltipOnHover:hover .tooltip {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.showExcludeButtonOnHover .excludeButton {
|
.showExcludeButtonOnHover .excludeButton {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
79
platform/ui/src/components/PrimaryToolbar/PrimaryToolbar.jsx
Normal file
79
platform/ui/src/components/PrimaryToolbar/PrimaryToolbar.jsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
import { ToolbarButton, IconButton, Icon, Tooltip } from '@ohif/ui';
|
||||||
|
|
||||||
|
const PrimaryToolbar = ({ activeTool, tools, moreTools }) => {
|
||||||
|
return (
|
||||||
|
<div className="flex">
|
||||||
|
{tools.map((tool) => {
|
||||||
|
const { id, onClick, icon, label, dropdownContent } = tool;
|
||||||
|
const isActive = activeTool === tool.id;
|
||||||
|
return (
|
||||||
|
<div className="relative flex justify-center" key={tool.id}>
|
||||||
|
<ToolbarButton
|
||||||
|
id={id}
|
||||||
|
isActive={isActive}
|
||||||
|
onClick={onClick}
|
||||||
|
icon={icon}
|
||||||
|
label={label}
|
||||||
|
dropdownContent={dropdownContent}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{!!moreTools.length && (
|
||||||
|
<>
|
||||||
|
<span className="w-1 border-l py-4 mx-2 border-common-dark" />
|
||||||
|
<Tooltip position="bottom" content="More tools">
|
||||||
|
<IconButton
|
||||||
|
className={classnames(
|
||||||
|
'mx-1 text-common-bright hover:bg-primary-dark hover:text-primary-light'
|
||||||
|
)}
|
||||||
|
color="inherit"
|
||||||
|
>
|
||||||
|
<Icon name="tool-more-menu" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
PrimaryToolbar.defaultProps = {
|
||||||
|
activeTool: '',
|
||||||
|
moreTools: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
PrimaryToolbar.propTypes = {
|
||||||
|
activeTool: PropTypes.string,
|
||||||
|
tools: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
id: PropTypes.string,
|
||||||
|
label: PropTypes.string,
|
||||||
|
icon: PropTypes.string,
|
||||||
|
commandName: PropTypes.string,
|
||||||
|
commandOptions: PropTypes.shape({
|
||||||
|
toolName: PropTypes.string,
|
||||||
|
}),
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
dropdownContent: PropTypes.node,
|
||||||
|
})
|
||||||
|
).isRequired,
|
||||||
|
moreTools: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
id: PropTypes.string,
|
||||||
|
label: PropTypes.string,
|
||||||
|
icon: PropTypes.string,
|
||||||
|
commandName: PropTypes.string,
|
||||||
|
commandOptions: PropTypes.shape({
|
||||||
|
toolName: PropTypes.string,
|
||||||
|
}),
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PrimaryToolbar;
|
||||||
127
platform/ui/src/components/PrimaryToolbar/PrimaryToolbar.mdx
Normal file
127
platform/ui/src/components/PrimaryToolbar/PrimaryToolbar.mdx
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
---
|
||||||
|
name: Primary Toolbar
|
||||||
|
menu: Data Display
|
||||||
|
route: components/primaryToolbar
|
||||||
|
---
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { Playground } from 'docz';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { PrimaryToolbar } from '@ohif/ui';
|
||||||
|
|
||||||
|
# Primary Toolbar
|
||||||
|
|
||||||
|
Primary Toolbar is used to create a list of tools.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { PrimaryToolbar } from '@ohif/ui';
|
||||||
|
```
|
||||||
|
|
||||||
|
<Playground>
|
||||||
|
{() => {
|
||||||
|
const [activeTool, setActiveTool] = useState('Zoom');
|
||||||
|
const dropdownContent = [
|
||||||
|
{
|
||||||
|
name: 'Soft tissue',
|
||||||
|
value: '400/40',
|
||||||
|
},
|
||||||
|
{ name: 'Lung', value: '1500 / -600' },
|
||||||
|
{ name: 'Liver', value: '150 / 90' },
|
||||||
|
{ name: 'Bone', value: '2500 / 480' },
|
||||||
|
{ name: 'Brain', value: '80 / 40' },
|
||||||
|
];
|
||||||
|
const tools = [
|
||||||
|
{
|
||||||
|
id: 'Zoom',
|
||||||
|
label: 'Zoom',
|
||||||
|
icon: 'tool-zoom',
|
||||||
|
commandName: 'setToolActive',
|
||||||
|
commandOptions: { toolName: 'Zoom' },
|
||||||
|
onClick: () => setActiveTool('Zoom'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Wwwc',
|
||||||
|
label: 'Levels',
|
||||||
|
icon: 'tool-window-level',
|
||||||
|
commandName: 'setToolActive',
|
||||||
|
commandOptions: { toolName: 'Wwwc' },
|
||||||
|
onClick: () => setActiveTool('Wwwc'),
|
||||||
|
dropdownContent: (
|
||||||
|
<div>
|
||||||
|
{dropdownContent.map((row, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="flex justify-between py-2 px-3 hover:bg-secondary-dark cursor-pointer"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span className="text-base text-white">{row.name}</span>
|
||||||
|
<span className="text-base text-primary-light ml-3">
|
||||||
|
{row.value}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-base text-primary-active ml-4">{i}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Pan',
|
||||||
|
label: 'Pan',
|
||||||
|
icon: 'tool-move',
|
||||||
|
commandName: 'setToolActive',
|
||||||
|
commandOptions: { toolName: 'Pan' },
|
||||||
|
onClick: () => setActiveTool('Pan'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Capture',
|
||||||
|
label: 'Capture',
|
||||||
|
icon: 'tool-capture',
|
||||||
|
commandName: 'setToolActive',
|
||||||
|
commandOptions: { toolName: 'Capture' },
|
||||||
|
onClick: () => setActiveTool('Capture'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Layout',
|
||||||
|
label: 'Layout',
|
||||||
|
icon: 'tool-layout',
|
||||||
|
commandName: 'setToolActive',
|
||||||
|
commandOptions: { toolName: 'Layout' },
|
||||||
|
onClick: () => setActiveTool('Layout'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const moreTools = [
|
||||||
|
{
|
||||||
|
id: 'Zoom 2',
|
||||||
|
label: 'Zoom',
|
||||||
|
icon: 'tool-zoom',
|
||||||
|
commandName: 'setToolActive',
|
||||||
|
commandOptions: { toolName: 'Zoom' },
|
||||||
|
onClick: () => setActiveTool('Zoom 2'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Layout 2',
|
||||||
|
label: 'Layout',
|
||||||
|
icon: 'tool-layout',
|
||||||
|
commandName: 'setToolActive',
|
||||||
|
commandOptions: { toolName: 'Layout' },
|
||||||
|
onClick: () => setActiveTool('Layout 2'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<div className="py-10 flex justify-center">
|
||||||
|
<PrimaryToolbar
|
||||||
|
moreTools={moreTools}
|
||||||
|
activeTool={activeTool}
|
||||||
|
tools={tools}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Playground>
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
<Props of={PrimaryToolbar} />
|
||||||
2
platform/ui/src/components/PrimaryToolbar/index.js
Normal file
2
platform/ui/src/components/PrimaryToolbar/index.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import PrimaryToolbar from './PrimaryToolbar';
|
||||||
|
export default PrimaryToolbar;
|
||||||
53
platform/ui/src/components/ToolbarButton/ToolbarButton.jsx
Normal file
53
platform/ui/src/components/ToolbarButton/ToolbarButton.jsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
import { IconButton, Icon, Tooltip } from '@ohif/ui';
|
||||||
|
|
||||||
|
const ToolbarButton = ({
|
||||||
|
id,
|
||||||
|
isActive,
|
||||||
|
onClick,
|
||||||
|
icon,
|
||||||
|
label,
|
||||||
|
dropdownContent,
|
||||||
|
}) => {
|
||||||
|
const shouldShowDropdown = !!isActive && !!dropdownContent;
|
||||||
|
return (
|
||||||
|
<div key={id}>
|
||||||
|
<Tooltip
|
||||||
|
content={shouldShowDropdown ? dropdownContent : label}
|
||||||
|
tight={shouldShowDropdown}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
variant={isActive ? 'contained' : 'text'}
|
||||||
|
className={classnames('mx-1', {
|
||||||
|
'text-black': isActive,
|
||||||
|
'text-common-bright hover:bg-primary-dark hover:text-primary-light': !isActive,
|
||||||
|
})}
|
||||||
|
onClick={onClick}
|
||||||
|
key={id}
|
||||||
|
>
|
||||||
|
<Icon name={icon} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ToolbarButton.defaultProps = {
|
||||||
|
dropdownContent: null,
|
||||||
|
isActive: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
ToolbarButton.propTypes = {
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
isActive: PropTypes.bool,
|
||||||
|
onClick: PropTypes.func.isRequired,
|
||||||
|
icon: PropTypes.string.isRequired,
|
||||||
|
label: PropTypes.string.isRequired,
|
||||||
|
/** Tooltip content can be replaced for a customized content by passing a node to this value. */
|
||||||
|
dropdownContent: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ToolbarButton;
|
||||||
44
platform/ui/src/components/ToolbarButton/ToolbarButton.mdx
Normal file
44
platform/ui/src/components/ToolbarButton/ToolbarButton.mdx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
name: Toolbar Button
|
||||||
|
menu: General
|
||||||
|
route: components/toolbarButton
|
||||||
|
---
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { Playground, Props } from 'docz';
|
||||||
|
import { ToolbarButton } from '@ohif/ui';
|
||||||
|
|
||||||
|
# Toolbar Button
|
||||||
|
|
||||||
|
Toolbar Buttons are used to populate the Toolbar.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { ToolbarButton } from '@ohif/ui';
|
||||||
|
```
|
||||||
|
|
||||||
|
<Playground>
|
||||||
|
{() => {
|
||||||
|
const [isActive, setIsActive] = useState(false);
|
||||||
|
const tool = {
|
||||||
|
id: 'Zoom',
|
||||||
|
label: 'Zoom',
|
||||||
|
icon: 'tool-zoom',
|
||||||
|
type: null,
|
||||||
|
commandName: 'setToolActive',
|
||||||
|
commandOptions: { toolName: 'Zoom' },
|
||||||
|
onClick: () => setIsActive(true),
|
||||||
|
isActive,
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="py-10 flex justify-center">
|
||||||
|
<ToolbarButton {...tool} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Playground>
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
<Props of={ToolbarButton} />
|
||||||
2
platform/ui/src/components/ToolbarButton/index.js
Normal file
2
platform/ui/src/components/ToolbarButton/index.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import ToolbarButton from './ToolbarButton';
|
||||||
|
export default ToolbarButton;
|
||||||
91
platform/ui/src/components/Tooltip/Tooltip.jsx
Normal file
91
platform/ui/src/components/Tooltip/Tooltip.jsx
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
import './tooltip.css';
|
||||||
|
|
||||||
|
const arrowPositionStyle = {
|
||||||
|
bottom: {
|
||||||
|
top: -15,
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
},
|
||||||
|
'bottom-left': { top: -15, left: 5 },
|
||||||
|
'bottom-right': { top: -15, right: 5 },
|
||||||
|
right: {
|
||||||
|
top: 'calc(50% - 8px)',
|
||||||
|
left: -15,
|
||||||
|
transform: 'rotate(270deg)',
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
top: 'calc(50% - 8px)',
|
||||||
|
right: -15,
|
||||||
|
transform: 'rotate(-270deg)',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Tooltip = ({ position, content, tight, children }) => {
|
||||||
|
const [isActive, setIsActive] = useState(false);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="relative"
|
||||||
|
onMouseOver={() => {
|
||||||
|
if (!isActive) {
|
||||||
|
setIsActive(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseOut={() => {
|
||||||
|
if (isActive) {
|
||||||
|
setIsActive(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<div
|
||||||
|
className={classnames(`tooltip tooltip-${position}`, {
|
||||||
|
block: isActive,
|
||||||
|
hidden: !isActive,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={classnames(
|
||||||
|
'relative tooltip-box bg-primary-dark border border-secondary-main text-white text-base rounded inset-x-auto top-full w-max-content',
|
||||||
|
{
|
||||||
|
'py-1 px-4': !tight,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
<svg
|
||||||
|
className="absolute text-primary-dark h-4 stroke-secondary-main"
|
||||||
|
style={arrowPositionStyle[position]}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path fill="currentColor" d="M24 22h-24l12-20z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Tooltip.defaultProps = {
|
||||||
|
tight: false,
|
||||||
|
position: 'bottom',
|
||||||
|
};
|
||||||
|
|
||||||
|
Tooltip.propTypes = {
|
||||||
|
tight: PropTypes.bool,
|
||||||
|
position: PropTypes.oneOf([
|
||||||
|
'bottom',
|
||||||
|
'bottom-left',
|
||||||
|
'bottom-right',
|
||||||
|
'left',
|
||||||
|
'right',
|
||||||
|
]),
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
content: PropTypes.node.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Tooltip;
|
||||||
40
platform/ui/src/components/Tooltip/Tooltip.mdx
Normal file
40
platform/ui/src/components/Tooltip/Tooltip.mdx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
name: Tooltip
|
||||||
|
menu: Data Display
|
||||||
|
route: components/tooltip
|
||||||
|
---
|
||||||
|
|
||||||
|
import { Playground, Props } from 'docz';
|
||||||
|
import { Tooltip, Typography } from '@ohif/ui';
|
||||||
|
|
||||||
|
# Tooltip
|
||||||
|
|
||||||
|
Tooltips display informative content when users hover over, focus on, or tap an
|
||||||
|
element.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { Tooltip } from '@ohif/ui';
|
||||||
|
```
|
||||||
|
|
||||||
|
<Playground>
|
||||||
|
{() => {
|
||||||
|
const tooltips = ['bottom', 'bottom-left', 'bottom-right', 'left', 'right'];
|
||||||
|
return (
|
||||||
|
<div className="py-10 flex flex-col items-center justify-center">
|
||||||
|
{tooltips.map((tooltip) => (
|
||||||
|
<div className="mb-16">
|
||||||
|
<Tooltip content="Tooltip content" position={tooltip}>
|
||||||
|
<Typography>Tooltip {tooltip}</Typography>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Playground>
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
<Props of={Tooltip} />
|
||||||
2
platform/ui/src/components/Tooltip/index.js
Normal file
2
platform/ui/src/components/Tooltip/index.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import Tooltip from './Tooltip';
|
||||||
|
export default Tooltip;
|
||||||
91
platform/ui/src/components/Tooltip/tooltip.css
Normal file
91
platform/ui/src/components/Tooltip/tooltip.css
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
.tooltip {
|
||||||
|
@apply z-10 absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TOOLTIP WORKAROUND FOR ARROW UP */
|
||||||
|
.tooltip.tooltip-bottom .tooltip-box::before {
|
||||||
|
@apply bg-primary-dark absolute z-10;
|
||||||
|
content: '';
|
||||||
|
width: 14px;
|
||||||
|
height: 1px;
|
||||||
|
top: -1px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip-bottom {
|
||||||
|
@apply pt-2 mt-1;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip-bottom-left {
|
||||||
|
@apply pt-2 mt-1;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip-bottom-right {
|
||||||
|
@apply pt-2 mt-1;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip-left {
|
||||||
|
@apply mr-4;
|
||||||
|
top: 50%;
|
||||||
|
right: calc(100%);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip-right {
|
||||||
|
@apply ml-4;
|
||||||
|
top: 50%;
|
||||||
|
left: calc(100%);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip-right .tooltip-box::before {
|
||||||
|
@apply bg-primary-dark absolute z-10;
|
||||||
|
content: '';
|
||||||
|
width: 2px;
|
||||||
|
height: 15px;
|
||||||
|
left: -1px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip-left .tooltip-box::before {
|
||||||
|
@apply bg-primary-dark absolute z-10;
|
||||||
|
content: '';
|
||||||
|
width: 2px;
|
||||||
|
height: 15px;
|
||||||
|
right: -1px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip-bottom-right .tooltip-box::before {
|
||||||
|
@apply bg-primary-dark absolute z-10;
|
||||||
|
content: '';
|
||||||
|
width: 15px;
|
||||||
|
height: 2px;
|
||||||
|
right: 5px;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip-bottom-left .tooltip-box::before {
|
||||||
|
@apply bg-primary-dark absolute z-10;
|
||||||
|
content: '';
|
||||||
|
width: 15px;
|
||||||
|
height: 2px;
|
||||||
|
left: 5px;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: REMOVE BELOW CLASS "showTooltipOnHover" AFTER TOOLTIP REPLACEMENT */
|
||||||
|
.showTooltipOnHover .tooltip {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.showTooltipOnHover:hover .tooltip {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
@ -15,6 +15,7 @@ import MeasurementTable from './MeasurementTable';
|
|||||||
import NavBar from './NavBar';
|
import NavBar from './NavBar';
|
||||||
import Notification from './Notification';
|
import Notification from './Notification';
|
||||||
import Select from './Select';
|
import Select from './Select';
|
||||||
|
import PrimaryToolbar from './PrimaryToolbar';
|
||||||
import SegmentationTable from './SegmentationTable';
|
import SegmentationTable from './SegmentationTable';
|
||||||
import SidePanel from './SidePanel';
|
import SidePanel from './SidePanel';
|
||||||
import StudyBrowser from './StudyBrowser';
|
import StudyBrowser from './StudyBrowser';
|
||||||
@ -32,6 +33,8 @@ import ThemeWrapper from './ThemeWrapper/';
|
|||||||
import Thumbnail from './Thumbnail';
|
import Thumbnail from './Thumbnail';
|
||||||
import ThumbnailSR from './ThumbnailSR';
|
import ThumbnailSR from './ThumbnailSR';
|
||||||
import ThumbnailList from './ThumbnailList';
|
import ThumbnailList from './ThumbnailList';
|
||||||
|
import ToolbarButton from './ToolbarButton';
|
||||||
|
import Tooltip from './Tooltip';
|
||||||
import Typography from './Typography';
|
import Typography from './Typography';
|
||||||
import ViewportActionBar from './ViewportActionBar';
|
import ViewportActionBar from './ViewportActionBar';
|
||||||
import ViewportGrid from './ViewportGrid';
|
import ViewportGrid from './ViewportGrid';
|
||||||
@ -53,6 +56,7 @@ export {
|
|||||||
MeasurementTable,
|
MeasurementTable,
|
||||||
NavBar,
|
NavBar,
|
||||||
Notification,
|
Notification,
|
||||||
|
PrimaryToolbar,
|
||||||
Select,
|
Select,
|
||||||
SegmentationTable,
|
SegmentationTable,
|
||||||
SidePanel,
|
SidePanel,
|
||||||
@ -71,6 +75,8 @@ export {
|
|||||||
Thumbnail,
|
Thumbnail,
|
||||||
ThumbnailSR,
|
ThumbnailSR,
|
||||||
ThumbnailList,
|
ThumbnailList,
|
||||||
|
ToolbarButton,
|
||||||
|
Tooltip,
|
||||||
Typography,
|
Typography,
|
||||||
ViewportActionBar,
|
ViewportActionBar,
|
||||||
ViewportGrid,
|
ViewportGrid,
|
||||||
|
|||||||
@ -1,166 +0,0 @@
|
|||||||
---
|
|
||||||
name: Toolbar Header
|
|
||||||
menu: Views
|
|
||||||
route: examples/toolbarHeader
|
|
||||||
---
|
|
||||||
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { Playground } from 'docz';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import { NavBar, Typography, Svg, Icon, IconButton } from '@ohif/ui';
|
|
||||||
|
|
||||||
# Toolbar Header
|
|
||||||
|
|
||||||
This example shows you how you can build a Toolbar using the available
|
|
||||||
components.
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
{() => {
|
|
||||||
const [activeTool, setActiveTool] = useState('Zoom');
|
|
||||||
const [showTooltip, setShowTooltip] = useState(null);
|
|
||||||
const tools = [
|
|
||||||
{
|
|
||||||
id: 'Zoom',
|
|
||||||
label: 'Zoom',
|
|
||||||
icon: 'tool-zoom',
|
|
||||||
type: null,
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'Zoom' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Wwwc',
|
|
||||||
label: 'Levels',
|
|
||||||
icon: 'tool-window-level',
|
|
||||||
type: null,
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'Wwwc' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Pan',
|
|
||||||
label: 'Pan',
|
|
||||||
icon: 'tool-move',
|
|
||||||
type: null,
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'Pan' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Capture',
|
|
||||||
label: 'Capture',
|
|
||||||
icon: 'tool-capture',
|
|
||||||
type: null,
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'Capture' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Layout',
|
|
||||||
label: 'Layout',
|
|
||||||
icon: 'tool-layout',
|
|
||||||
type: null,
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'Layout' },
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const renderToolbar = () => {
|
|
||||||
return tools.map((tool, i) => {
|
|
||||||
const isActive = activeTool === tool.id;
|
|
||||||
const shouldShowTooltip = showTooltip === tool.id;
|
|
||||||
return (
|
|
||||||
<div className="relative flex justify-center" key={tool.id}>
|
|
||||||
<IconButton
|
|
||||||
variant={isActive ? 'contained' : 'text'}
|
|
||||||
className={classnames('mx-1', {
|
|
||||||
'text-black': isActive,
|
|
||||||
'text-common-bright hover:bg-primary-dark hover:text-primary-light': !isActive,
|
|
||||||
})}
|
|
||||||
onClick={(e) => {
|
|
||||||
setActiveTool(tool.id);
|
|
||||||
}}
|
|
||||||
onMouseOver={() => setShowTooltip(tool.id)}
|
|
||||||
onMouseOut={() => setShowTooltip(null)}
|
|
||||||
key={tool.id}
|
|
||||||
>
|
|
||||||
<Icon name={tool.icon} />
|
|
||||||
</IconButton>
|
|
||||||
{shouldShowTooltip && (
|
|
||||||
<div
|
|
||||||
className={classnames(
|
|
||||||
'tooltip tooltip-up 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}
|
|
||||||
<svg
|
|
||||||
className="absolute text-primary-dark w-full h-4 left-0 stroke-secondary-main"
|
|
||||||
style={{ top: -15 }}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
|
||||||
<path fill="currentColor" d="M24 22h-24l12-20z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="pb-10">
|
|
||||||
<NavBar className="justify-between border-b-4 border-black">
|
|
||||||
<div className="flex flex-1 justify-between">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<div className="mx-3 inline-flex items-center">
|
|
||||||
<Icon
|
|
||||||
name="chevron-left"
|
|
||||||
className="text-primary-main w-10 h-10 cursor-pointer"
|
|
||||||
onClick={() => alert('Navigate to previous page')}
|
|
||||||
/>
|
|
||||||
<a href="#" className="ml-4">
|
|
||||||
<Svg name="logo-ohif" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<div className="flex items-center">
|
|
||||||
{renderToolbar()}
|
|
||||||
<span className="w-1 border-l py-4 mx-2 border-common-dark" />
|
|
||||||
<IconButton
|
|
||||||
className={classnames(
|
|
||||||
'mx-1 text-common-bright hover:bg-primary-dark hover:text-primary-light'
|
|
||||||
)}
|
|
||||||
color="inherit"
|
|
||||||
onClick={(e) => {
|
|
||||||
alert('Open menu');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon name="tool-more-menu" />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<span className="mr-3 text-common-light text-lg">
|
|
||||||
FOR INVESTIGATIONAL USE ONLY
|
|
||||||
</span>
|
|
||||||
<IconButton
|
|
||||||
variant="text"
|
|
||||||
color="inherit"
|
|
||||||
className="text-primary-active"
|
|
||||||
onClick={() => {}}
|
|
||||||
>
|
|
||||||
<React.Fragment>
|
|
||||||
<Icon name="settings" /> <Icon name="chevron-down" />
|
|
||||||
</React.Fragment>
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</NavBar>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
<Props of={NavBar} />
|
|
||||||
@ -1,96 +1,78 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import classnames from 'classnames';
|
import { NavBar, Svg, Icon, IconButton, PrimaryToolbar } from '@ohif/ui';
|
||||||
import { NavBar, Svg, Icon, IconButton } from '@ohif/ui';
|
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
const [activeTool, setActiveTool] = useState(null);
|
const [activeTool, setActiveTool] = useState('Zoom');
|
||||||
const [showTooltip, setShowTooltip] = useState(null);
|
const dropdownContent = [
|
||||||
|
{
|
||||||
|
name: 'Soft tissue',
|
||||||
|
value: '400/40',
|
||||||
|
},
|
||||||
|
{ name: 'Lung', value: '1500 / -600' },
|
||||||
|
{ name: 'Liver', value: '150 / 90' },
|
||||||
|
{ name: 'Bone', value: '2500 / 480' },
|
||||||
|
{ name: 'Brain', value: '80 / 40' },
|
||||||
|
];
|
||||||
const tools = [
|
const tools = [
|
||||||
{
|
{
|
||||||
id: 'Zoom',
|
id: 'Zoom',
|
||||||
label: 'Zoom',
|
label: 'Zoom',
|
||||||
icon: 'tool-zoom',
|
icon: 'tool-zoom',
|
||||||
type: null,
|
|
||||||
commandName: 'setToolActive',
|
commandName: 'setToolActive',
|
||||||
commandOptions: { toolName: 'Zoom' },
|
commandOptions: { toolName: 'Zoom' },
|
||||||
|
onClick: () => setActiveTool('Zoom'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'Wwwc',
|
id: 'Wwwc',
|
||||||
label: 'Levels',
|
label: 'Levels',
|
||||||
icon: 'tool-window-level',
|
icon: 'tool-window-level',
|
||||||
type: null,
|
|
||||||
commandName: 'setToolActive',
|
commandName: 'setToolActive',
|
||||||
commandOptions: { toolName: 'Wwwc' },
|
commandOptions: { toolName: 'Wwwc' },
|
||||||
|
onClick: () => setActiveTool('Wwwc'),
|
||||||
|
dropdownContent: (
|
||||||
|
<div>
|
||||||
|
{dropdownContent.map((row, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="flex justify-between py-2 px-3 hover:bg-secondary-dark cursor-pointer"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span className="text-base text-white">{row.name}</span>
|
||||||
|
<span className="text-base text-primary-light ml-3">
|
||||||
|
{row.value}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-base text-primary-active ml-4">{i}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'Pan',
|
id: 'Pan',
|
||||||
label: 'Pan',
|
label: 'Pan',
|
||||||
icon: 'tool-move',
|
icon: 'tool-move',
|
||||||
type: null,
|
|
||||||
commandName: 'setToolActive',
|
commandName: 'setToolActive',
|
||||||
commandOptions: { toolName: 'Pan' },
|
commandOptions: { toolName: 'Pan' },
|
||||||
|
onClick: () => setActiveTool('Pan'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'Capture',
|
id: 'Capture',
|
||||||
label: 'Capture',
|
label: 'Capture',
|
||||||
icon: 'tool-capture',
|
icon: 'tool-capture',
|
||||||
type: null,
|
|
||||||
commandName: 'setToolActive',
|
commandName: 'setToolActive',
|
||||||
commandOptions: { toolName: 'Capture' },
|
commandOptions: { toolName: 'Capture' },
|
||||||
|
onClick: () => setActiveTool('Capture'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'Layout',
|
id: 'Layout',
|
||||||
label: 'Layout',
|
label: 'Layout',
|
||||||
icon: 'tool-layout',
|
icon: 'tool-layout',
|
||||||
type: null,
|
|
||||||
commandName: 'setToolActive',
|
commandName: 'setToolActive',
|
||||||
commandOptions: { toolName: 'Layout' },
|
commandOptions: { toolName: 'Layout' },
|
||||||
|
onClick: () => setActiveTool('Layout'),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const renderToolbar = () => {
|
|
||||||
return tools.map((tool, i) => {
|
|
||||||
const isActive = activeTool === tool.id;
|
|
||||||
const shouldShowTooltip = showTooltip === tool.id;
|
|
||||||
return (
|
|
||||||
<div className="relative flex justify-center" key={tool.id}>
|
|
||||||
<IconButton
|
|
||||||
variant={isActive ? 'contained' : 'text'}
|
|
||||||
className={classnames('mx-1', {
|
|
||||||
'text-black': isActive,
|
|
||||||
'text-common-bright hover:bg-primary-dark hover:text-primary-light': !isActive,
|
|
||||||
})}
|
|
||||||
onClick={(e) => {
|
|
||||||
setActiveTool(tool.id);
|
|
||||||
}}
|
|
||||||
onMouseOver={() => setShowTooltip(tool.id)}
|
|
||||||
onMouseOut={() => setShowTooltip(null)}
|
|
||||||
key={tool.id}
|
|
||||||
>
|
|
||||||
<Icon name={tool.icon} />
|
|
||||||
</IconButton>
|
|
||||||
{shouldShowTooltip && (
|
|
||||||
<div
|
|
||||||
className={classnames(
|
|
||||||
'tooltip tooltip-up 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}
|
|
||||||
<svg
|
|
||||||
className="absolute text-primary-dark w-full h-4 left-0 stroke-secondary-main"
|
|
||||||
style={{ top: -15 }}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
|
||||||
<path fill="currentColor" d="M24 22h-24l12-20z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<NavBar className="justify-between border-b-4 border-black">
|
<NavBar className="justify-between border-b-4 border-black">
|
||||||
<div className="flex flex-1 justify-between">
|
<div className="flex flex-1 justify-between">
|
||||||
@ -107,21 +89,11 @@ const Header = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="flex items-center">
|
<PrimaryToolbar
|
||||||
{renderToolbar()}
|
tools={tools}
|
||||||
<span className="w-1 border-l py-4 mx-2 border-common-dark" />
|
activeTool={activeTool}
|
||||||
<IconButton
|
moreTools={tools}
|
||||||
className={classnames(
|
/>
|
||||||
'mx-1 text-common-bright hover:bg-primary-dark hover:text-primary-light'
|
|
||||||
)}
|
|
||||||
color="inherit"
|
|
||||||
onClick={(e) => {
|
|
||||||
alert('Open menu');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon name="tool-more-menu" />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="mr-3 text-common-light text-lg">
|
<span className="mr-3 text-common-light text-lg">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user