diff --git a/extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx b/extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx index 6dc0b4af4..19cf891d0 100644 --- a/extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx +++ b/extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import PropTypes from 'prop-types'; -import { ViewportActionArrows } from '@ohif/ui'; +import { ViewportActionArrows } from '@ohif/ui-next'; import { useViewportGrid } from '@ohif/ui-next'; import { utils } from '@ohif/extension-cornerstone'; diff --git a/extensions/cornerstone-dicom-rt/src/viewports/_getStatusComponent.tsx b/extensions/cornerstone-dicom-rt/src/viewports/_getStatusComponent.tsx index 78b36ca63..b2dc2744f 100644 --- a/extensions/cornerstone-dicom-rt/src/viewports/_getStatusComponent.tsx +++ b/extensions/cornerstone-dicom-rt/src/viewports/_getStatusComponent.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; -import { ViewportActionButton } from '@ohif/ui'; +import { ViewportActionButton } from '@ohif/ui-next'; import { Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next'; export default function _getStatusComponent({ isHydrated, onStatusClick }) { @@ -56,4 +56,4 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) { {!ToolTipMessage && } ); -} \ No newline at end of file +} diff --git a/extensions/cornerstone-dicom-seg/src/viewports/OHIFCornerstoneSEGViewport.tsx b/extensions/cornerstone-dicom-seg/src/viewports/OHIFCornerstoneSEGViewport.tsx index cebcf10df..2d7ae9105 100644 --- a/extensions/cornerstone-dicom-seg/src/viewports/OHIFCornerstoneSEGViewport.tsx +++ b/extensions/cornerstone-dicom-seg/src/viewports/OHIFCornerstoneSEGViewport.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { ViewportActionArrows } from '@ohif/ui'; +import { ViewportActionArrows } from '@ohif/ui-next'; import { useViewportGrid } from '@ohif/ui-next'; import createSEGToolGroupAndAddTools from '../utils/initSEGToolGroup'; import promptHydrateSEG from '../utils/promptHydrateSEG'; diff --git a/extensions/cornerstone-dicom-seg/src/viewports/_getStatusComponent.tsx b/extensions/cornerstone-dicom-seg/src/viewports/_getStatusComponent.tsx index 836dca5bb..003b75fb2 100644 --- a/extensions/cornerstone-dicom-seg/src/viewports/_getStatusComponent.tsx +++ b/extensions/cornerstone-dicom-seg/src/viewports/_getStatusComponent.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; -import { ViewportActionButton } from '@ohif/ui'; +import { ViewportActionButton } from '@ohif/ui-next'; import { Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next'; export default function _getStatusComponent({ isHydrated, onStatusClick }) { @@ -56,4 +56,4 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) { {!ToolTipMessage && } ); -} \ No newline at end of file +} diff --git a/extensions/cornerstone-dicom-sr/src/components/OHIFCornerstoneSRMeasurementViewport.tsx b/extensions/cornerstone-dicom-sr/src/components/OHIFCornerstoneSRMeasurementViewport.tsx index 71c5b19ac..a5f7a1ace 100644 --- a/extensions/cornerstone-dicom-sr/src/components/OHIFCornerstoneSRMeasurementViewport.tsx +++ b/extensions/cornerstone-dicom-sr/src/components/OHIFCornerstoneSRMeasurementViewport.tsx @@ -5,7 +5,7 @@ import { ExtensionManager, useToolbar } from '@ohif/core'; import { setTrackingUniqueIdentifiersForElement } from '../tools/modules/dicomSRModule'; -import { ViewportActionArrows } from '@ohif/ui'; +import { ViewportActionArrows } from '@ohif/ui-next'; import createReferencedImageDisplaySet from '../utils/createReferencedImageDisplaySet'; import { usePositionPresentationStore } from '@ohif/extension-cornerstone'; import { useViewportGrid } from '@ohif/ui-next'; diff --git a/extensions/cornerstone-dicom-sr/src/onModeEnter.tsx b/extensions/cornerstone-dicom-sr/src/onModeEnter.tsx index 603e46f9b..fec9efaed 100644 --- a/extensions/cornerstone-dicom-sr/src/onModeEnter.tsx +++ b/extensions/cornerstone-dicom-sr/src/onModeEnter.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { SOPClassHandlerId, SOPClassHandlerId3D } from './id'; -import { ViewportActionButton } from '@ohif/ui'; +import { ViewportActionButton } from '@ohif/ui-next'; import i18n from '@ohif/i18n'; export default function onModeEnter({ servicesManager }) { diff --git a/extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx b/extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx index 7f0c0279c..1faf3ced8 100644 --- a/extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx +++ b/extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx @@ -3,7 +3,8 @@ import { useResizeDetector } from 'react-resize-detector'; import * as cs3DTools from '@cornerstonejs/tools'; import { Enums, eventTarget, getEnabledElement } from '@cornerstonejs/core'; import { MeasurementService } from '@ohif/core'; -import { AllInOneMenu, useViewportDialog } from '@ohif/ui'; +import { AllInOneMenu } from '@ohif/ui-next'; +import { useViewportDialog } from '@ohif/ui'; import type { Types as csTypes } from '@cornerstonejs/core'; import { setEnabledElement } from '../state'; @@ -99,7 +100,7 @@ const OHIFCornerstoneViewport = React.memo( const [viewportDialogState] = useViewportDialog(); // useCallback for scroll bar height calculation const setImageScrollBarHeight = useCallback(() => { - const scrollbarHeight = `${elementRef.current.clientHeight - 40}px`; + const scrollbarHeight = `${elementRef.current.clientHeight - 10}px`; setScrollbarHeight(scrollbarHeight); }, [elementRef]); diff --git a/extensions/cornerstone/src/Viewport/Overlays/CustomizableViewportOverlay.tsx b/extensions/cornerstone/src/Viewport/Overlays/CustomizableViewportOverlay.tsx index 142702032..38da73c99 100644 --- a/extensions/cornerstone/src/Viewport/Overlays/CustomizableViewportOverlay.tsx +++ b/extensions/cornerstone/src/Viewport/Overlays/CustomizableViewportOverlay.tsx @@ -3,7 +3,7 @@ import { vec3 } from 'gl-matrix'; import PropTypes from 'prop-types'; import { metaData, Enums, utilities } from '@cornerstonejs/core'; import type { ImageSliceData } from '@cornerstonejs/core/types'; -import { ViewportOverlay } from '@ohif/ui'; +import { ViewportOverlay } from '@ohif/ui-next'; import type { InstanceMetadata } from '@ohif/core/src/types'; import { formatDICOMDate, formatDICOMTime, formatNumberPrecision } from './utils'; import { utils } from '@ohif/core'; @@ -368,7 +368,7 @@ function OverlayItem(props) { title={title} > {label ? {label} : null} - {value} + {value} ); } @@ -387,10 +387,10 @@ function VOIOverlayItem({ voi, customization }: OverlayItemProps) { className="overlay-item flex flex-row" style={{ color: customization?.color }} > - W: - {windowWidth.toFixed(0)} - L: - {windowCenter.toFixed(0)} + W: + {windowWidth.toFixed(0)} + L: + {windowCenter.toFixed(0)} ); } @@ -404,7 +404,7 @@ function ZoomOverlayItem({ scale, customization }: OverlayItemProps) { className="overlay-item flex flex-row" style={{ color: (customization && customization.color) || undefined }} > - Zoom: + Zoom: {scale.toFixed(2)}x ); @@ -428,7 +428,7 @@ function InstanceNumberOverlayItem({ {instanceNumber !== undefined && instanceNumber !== null ? ( <> - I: + I: {`${instanceNumber} (${imageIndex + 1}/${numberOfSlices})`} ) : ( diff --git a/extensions/cornerstone/src/Viewport/Overlays/ViewportImageScrollbar.tsx b/extensions/cornerstone/src/Viewport/Overlays/ViewportImageScrollbar.tsx index a09e49c9b..2c7f02903 100644 --- a/extensions/cornerstone/src/Viewport/Overlays/ViewportImageScrollbar.tsx +++ b/extensions/cornerstone/src/Viewport/Overlays/ViewportImageScrollbar.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import { Enums, VolumeViewport3D, utilities as csUtils } from '@cornerstonejs/core'; -import { ImageScrollbar } from '@ohif/ui'; +import { ImageScrollbar } from '@ohif/ui-next'; function CornerstoneImageScrollbar({ viewportData, diff --git a/extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.css b/extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.css index 5461f4a95..13958ea60 100644 --- a/extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.css +++ b/extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.css @@ -3,19 +3,18 @@ --marker-height: 100px; --scrollbar-width: 20px; pointer-events: none; - font-size: 15px; line-height: 18px; } .ViewportOrientationMarkers .orientation-marker { position: absolute; } .ViewportOrientationMarkers .top-mid { - top: 0.6rem; + top: 0.38rem; left: 50%; } .ViewportOrientationMarkers .left-mid { top: 47%; - left: 5px; + left: 0.38rem; } .ViewportOrientationMarkers .right-mid { top: 47%; diff --git a/extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.tsx b/extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.tsx index 69be2be75..89e77b963 100644 --- a/extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.tsx +++ b/extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.tsx @@ -119,8 +119,8 @@ function ViewportOrientationMarkers({ className={classNames( 'overlay-text', `${m}-mid orientation-marker`, - 'text-aqua-pale', - 'text-[13px]', + 'text-highlight/65', + 'text-base', 'leading-5' )} key={`${m}-mid orientation-marker`} diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/Colorbar.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/Colorbar.tsx index 298c2ae84..8b42bd15b 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/Colorbar.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/Colorbar.tsx @@ -1,5 +1,5 @@ import React, { ReactElement, useCallback, useEffect, useState } from 'react'; -import { SwitchButton } from '@ohif/ui'; +import { Switch } from '@ohif/ui-next'; import { StackViewport, VolumeViewport } from '@cornerstonejs/core'; import { ColorbarProps } from '../../types/Colorbar'; import { utilities } from '@cornerstonejs/core'; @@ -22,7 +22,7 @@ export function setViewportColorbar( colorbarOptions.ticks = { position: 'left', style: { - font: '12px Arial', + font: '13px Inter', color: '#000000', maxNumTicks: 8, tickSize: 5, @@ -101,12 +101,18 @@ export function Colorbar({ }, [viewportId]); return ( -
-
- { + onSetColorbar(); + }} + > +
+ Display Color bar + { + onCheckedChange={() => { onSetColorbar(); }} /> diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/Colormap.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/Colormap.tsx index 93c2ec481..b6a81eb81 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/Colormap.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/Colormap.tsx @@ -1,5 +1,6 @@ -import React, { ReactElement, useCallback, useEffect, useRef, useState, useMemo } from 'react'; -import { AllInOneMenu, ButtonGroup, SwitchButton } from '@ohif/ui'; +import React, { ReactElement, useCallback, useEffect, useRef, useState } from 'react'; +import { AllInOneMenu, Switch, Tabs, TabsList, TabsTrigger } from '@ohif/ui-next'; + import { StackViewport, Types } from '@cornerstonejs/core'; import { ColormapProps } from '../../types/Colormap'; @@ -26,6 +27,7 @@ export function Colormap({ const onSetColorLUT = useCallback( props => { + debugger; // TODO: Better way to check if it's a fusion const oneOpacityColormaps = ['Grayscale', 'X Ray']; const opacity = @@ -64,20 +66,9 @@ export function Colormap({ return colormap; }; - const buttons = useMemo(() => { - return displaySets.map((displaySet, index) => ({ - children: displaySet.Modality, - key: index, - style: { - minWidth: `calc(100% / ${displaySets.length})`, - fontSize: '0.8rem', - textAlign: 'center', - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - }, - })); - }, [displaySets]); + const activeIndex = displaySets.findIndex( + ds => ds.displaySetInstanceUID === activeDisplaySetRef.current.displaySetInstanceUID + ); useEffect(() => { setActiveDisplaySet(displaySets[displaySets.length - 1]); @@ -85,46 +76,52 @@ export function Colormap({ return ( <> - {buttons.length > 1 && ( -
- { + {displaySets.length > 1 && ( +
+ { + const index = parseInt(val, 10); setActiveDisplaySet(displaySets[index]); setPrePreviewColormap(null); }} - activeIndex={ - displaySets.findIndex( - ds => ds.displaySetInstanceUID === activeDisplaySetRef.current.displaySetInstanceUID - ) || 1 - } - className="w-[70%] text-[10px]" > - {buttons.map(({ children, key, style }) => ( -
- {children} -
- ))} - + + {displaySets.map((ds, i) => ( + + {ds.Modality} + + ))} + +
)} -
- setShowPreview(!showPreview)} + > + Preview in viewport + { + onCheckedChange={checked => { setShowPreview(checked); }} />
- + {colormaps.map((colormap, index) => ( { onSetColorLUT({ viewportId, diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeLighting.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeLighting.tsx index a6c07ddc2..f602f9294 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeLighting.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeLighting.tsx @@ -1,5 +1,6 @@ import React, { ReactElement, useState, useEffect, useCallback } from 'react'; import { VolumeLightingProps } from '../../types/ViewportPresets'; +import { Numeric } from '@ohif/ui-next'; export function VolumeLighting({ servicesManager, @@ -8,135 +9,75 @@ export function VolumeLighting({ hasShade, }: VolumeLightingProps): ReactElement { const { cornerstoneViewportService } = servicesManager.services; - const [ambient, setAmbient] = useState(null); - const [diffuse, setDiffuse] = useState(null); - const [specular, setSpecular] = useState(null); + const [lightingValues, setLightingValues] = useState({ + ambient: null, + diffuse: null, + specular: null, + }); - const onAmbientChange = useCallback(() => { - commandsManager.runCommand('setVolumeLighting', { viewportId, options: { ambient } }); - }, [ambient, commandsManager, viewportId]); - - const onDiffuseChange = useCallback(() => { - commandsManager.runCommand('setVolumeLighting', { viewportId, options: { diffuse } }); - }, [diffuse, commandsManager, viewportId]); - - const onSpecularChange = useCallback(() => { - commandsManager.runCommand('setVolumeLighting', { viewportId, options: { specular } }); - }, [specular, commandsManager, viewportId]); - - const calculateBackground = value => { - const percentage = ((value - 0) / (1 - 0)) * 100; - return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`; - }; + // Single callback to handle all lighting property changes + const onLightingChange = useCallback( + (property, value) => { + commandsManager.runCommand('setVolumeLighting', { + viewportId, + options: { [property]: value }, + }); + setLightingValues(prev => ({ + ...prev, + [property]: value, + })); + }, + [commandsManager, viewportId] + ); useEffect(() => { const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId); const { actor } = viewport.getActors()[0]; - const ambient = actor.getProperty().getAmbient(); - const diffuse = actor.getProperty().getDiffuse(); - const specular = actor.getProperty().getSpecular(); - setAmbient(ambient); - setDiffuse(diffuse); - setSpecular(specular); - }, [viewportId, cornerstoneViewportService]); - const disableOption = hasShade ? '' : 'ohif-disabled !opacity-40'; - const disableSlider = !hasShade; - return ( - <> -
- - {ambient !== null && ( - { - setAmbient(e.target.value); - onAmbientChange(); - }} - id="ambient" - disabled={disableSlider} - max={1} - min={0} - type="range" - step={0.1} - style={{ - background: calculateBackground(ambient), - '--thumb-inner-color': '#5acce6', - '--thumb-outer-color': '#090c29', - }} - /> - )} -
-
- - {diffuse !== null && ( - { - setDiffuse(e.target.value); - onDiffuseChange(); - }} - disabled={disableSlider} - id="diffuse" - max={1} - min={0} - type="range" - step={0.1} - style={{ - background: calculateBackground(diffuse), - '--thumb-inner-color': '#5acce6', - '--thumb-outer-color': '#090c29', - }} - /> - )} -
+ const property = actor.getProperty(); -
- - {specular !== null && ( - { - setSpecular(e.target.value); - onSpecularChange(); - }} - id="specular" - max={1} - min={0} - type="range" - step={0.1} - style={{ - background: calculateBackground(specular), - '--thumb-inner-color': '#5acce6', - '--thumb-outer-color': '#090c29', - }} - /> - )} -
- + const values = { + ambient: property.getAmbient(), + diffuse: property.getDiffuse(), + specular: property.getSpecular(), + }; + + setLightingValues(values); + }, [viewportId, cornerstoneViewportService]); + + const disableOption = hasShade ? '' : 'ohif-disabled !opacity-40'; + + // Configuration for our lighting properties + const lightingProperties = [ + { key: 'ambient', label: 'Ambient' }, + { key: 'diffuse', label: 'Diffuse' }, + { key: 'specular', label: 'Specular' }, + ]; + + return ( +
+ {lightingProperties.map( + ({ key, label }) => + lightingValues[key] !== null && ( +
+ onLightingChange(key, value)} + > +
+ {label} + +
+
+
+ ) + )} +
); } diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingOptions.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingOptions.tsx index af3906332..d87fa1f13 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingOptions.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingOptions.tsx @@ -1,5 +1,5 @@ import React, { ReactElement, useState } from 'react'; -import { AllInOneMenu } from '@ohif/ui'; +import { AllInOneMenu } from '@ohif/ui-next'; import { VolumeRenderingOptionsProps } from '../../types/ViewportPresets'; import { VolumeRenderingQuality } from './VolumeRenderingQuality'; import { VolumeShift } from './VolumeShift'; @@ -26,11 +26,11 @@ export function VolumeRenderingOptions({ commandsManager={commandsManager} servicesManager={servicesManager} /> -
-
LIGHTING
+
+
Lighting
-
-
+
+
{ - const percentage = ((value - 0) / (1 - 0)) * 100; - return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`; - }; - useEffect(() => { const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId); const { actor } = viewport.getActors()[0]; @@ -41,33 +37,26 @@ export function VolumeRenderingQuality({ setQuality(Math.sqrt(averageSpacing / (sampleDistance * 0.5))); } }, [cornerstoneViewportService, viewportId]); + return ( - <> -
- - {quality !== null && ( - + {quality !== null && ( +
+ onChange(parseInt(e.target.value, 10))} - style={{ - background: calculateBackground((quality - min) / (max - min)), - '--thumb-inner-color': '#5acce6', - '--thumb-outer-color': '#090c29', - }} - /> - )} -
- + value={quality} + onChange={onChange} + > +
+ Quality + +
+ +
+ )} +
); } diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShade.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShade.tsx index cc7cee7d0..5be08d3d4 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShade.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShade.tsx @@ -1,5 +1,5 @@ import React, { ReactElement, useCallback, useEffect, useState } from 'react'; -import { SwitchButton } from '@ohif/ui'; +import { Switch } from '@ohif/ui-next'; import { VolumeShadeProps } from '../../types/ViewportPresets'; export function VolumeShade({ @@ -28,15 +28,18 @@ export function VolumeShade({ }, [viewportId, cornerstoneViewportService]); return ( - { - setShade(!shade); - onClickShade(!shade); - onShadeChange(!shade); - }} - /> + <> + Shade + { + setShade(!shade); + onClickShade(!shade); + onShadeChange(!shade); + }} + /> + ); } diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShift.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShift.tsx index 353126901..c6cb4c6f2 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShift.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShift.tsx @@ -1,5 +1,6 @@ import React, { ReactElement, useCallback, useEffect, useState, useRef } from 'react'; import { VolumeShiftProps } from '../../types/ViewportPresets'; +import { Numeric } from '@ohif/ui-next'; export function VolumeShift({ viewportId, @@ -46,48 +47,32 @@ export function VolumeShift({ viewportId, shift: shiftDifference, }); + setShift(newShift); }, [commandsManager, viewportId, viewport] ); - const calculateBackground = value => { - const percentage = ((value - 0) / (1 - 0)) * 100; - return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`; - }; - return ( - <> -
- - {step !== null && ( - + {step !== null && minShift !== null && maxShift !== null && ( +
+ { - const shiftValue = parseInt(e.target.value, 10); - setShift(shiftValue); - onChangeRange(shiftValue); - }} - id="shift" + onChange={onChangeRange} onMouseDown={() => setIsBlocking(true)} onMouseUp={() => setIsBlocking(false)} - max={maxShift} - min={minShift} - type="range" - step={step} - style={{ - background: calculateBackground((shift - minShift) / (maxShift - minShift)), - '--thumb-inner-color': '#5acce6', - '--thumb-outer-color': '#090c29', - }} - /> - )} -
- + > +
+ Shift + +
+ +
+ )} +
); } diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevel.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevel.tsx index eda52d5bb..49152cd69 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevel.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevel.tsx @@ -1,5 +1,5 @@ import React, { ReactElement, useCallback } from 'react'; -import { AllInOneMenu } from '@ohif/ui'; +import { AllInOneMenu } from '@ohif/ui-next'; import { WindowLevelPreset } from '../../types/WindowLevel'; import { CommandsManager } from '@ohif/core'; import { useTranslation } from 'react-i18next'; @@ -45,6 +45,7 @@ export function WindowLevel({ key={`${modality}-${index}`} label={preset.description} secondaryLabel={`${preset.window} / ${preset.level}`} + useIconSpace={false} onClick={() => onSetWindowLevel(preset)} /> ))} diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx index 65804c914..d9e10663a 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx @@ -1,7 +1,7 @@ import React, { ReactElement, useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import classNames from 'classnames'; -import { AllInOneMenu } from '@ohif/ui'; +import { AllInOneMenu } from '@ohif/ui-next'; import { useViewportGrid } from '@ohif/ui-next'; import { Colormap } from './Colormap'; import { Colorbar } from './Colorbar'; @@ -119,8 +119,8 @@ export function WindowLevelActionMenu({ iconClassName={classNames( // Visible on hover and for the active viewport activeViewportId === viewportId ? 'visible' : 'invisible group-hover/pane:visible', - 'flex shrink-0 cursor-pointer rounded active:text-white text-primary-light', - isLight ? ' hover:bg-secondary-dark' : 'hover:bg-secondary-light/60' + 'flex shrink-0 cursor-pointer rounded active:text-foreground text-highlight', + isLight ? ' hover:bg-primary/30' : 'hover:bg-primary/30' )} menuStyle={{ maxHeight: vpHeight - 32, minWidth: 218 }} onVisibilityChange={() => { @@ -144,8 +144,10 @@ export function WindowLevelActionMenu({ key="colorLUTPresets" itemLabel="Color LUT" itemIcon="icon-color-lut" + className="flex h-[calc(100%-32px)] flex-col" > !nonWLModalities.includes(ds.Modality))} diff --git a/extensions/cornerstone/src/contextProviders/ViewportActionCornersProvider.tsx b/extensions/cornerstone/src/contextProviders/ViewportActionCornersProvider.tsx index 28661816c..cdef450ac 100644 --- a/extensions/cornerstone/src/contextProviders/ViewportActionCornersProvider.tsx +++ b/extensions/cornerstone/src/contextProviders/ViewportActionCornersProvider.tsx @@ -8,7 +8,7 @@ import React, { } from 'react'; import PropTypes from 'prop-types'; -import { Types, ViewportActionCornersLocations } from '@ohif/ui'; +import { Types, ViewportActionCornersLocations } from '@ohif/ui-next'; import ViewportActionCornersService, { ActionComponentInfo, } from '../services/ViewportActionCornersService/ViewportActionCornersService'; diff --git a/extensions/cornerstone/src/services/ViewportActionCornersService/ViewportActionCornersService.ts b/extensions/cornerstone/src/services/ViewportActionCornersService/ViewportActionCornersService.ts index 7c677618b..6dc79954f 100644 --- a/extensions/cornerstone/src/services/ViewportActionCornersService/ViewportActionCornersService.ts +++ b/extensions/cornerstone/src/services/ViewportActionCornersService/ViewportActionCornersService.ts @@ -1,5 +1,5 @@ import { PubSubService } from '@ohif/core'; -import { ViewportActionCornersLocations } from '@ohif/ui'; +import { ViewportActionCornersLocations } from '@ohif/ui-next'; import { ReactNode } from 'react'; export type ActionComponentInfo = { diff --git a/extensions/default/src/customizations/viewportActionCornersCustomization.ts b/extensions/default/src/customizations/viewportActionCornersCustomization.ts index 49b28bb21..0e99f9e2d 100644 --- a/extensions/default/src/customizations/viewportActionCornersCustomization.ts +++ b/extensions/default/src/customizations/viewportActionCornersCustomization.ts @@ -1,4 +1,4 @@ -import { ViewportActionCorners } from '@ohif/ui'; +import { ViewportActionCorners } from '@ohif/ui-next'; export default { 'ui.viewportActionCorner': ViewportActionCorners, diff --git a/extensions/measurement-tracking/src/index.tsx b/extensions/measurement-tracking/src/index.tsx index 7f87c7519..0992e71a8 100644 --- a/extensions/measurement-tracking/src/index.tsx +++ b/extensions/measurement-tracking/src/index.tsx @@ -4,7 +4,7 @@ import getContextModule from './getContextModule'; import getPanelModule from './getPanelModule'; import getViewportModule from './getViewportModule'; import { id } from './id.js'; -import { ViewportActionButton } from '@ohif/ui'; +import { ViewportActionButton } from '@ohif/ui-next'; import i18n from '@ohif/i18n'; import { measurementTrackingMode } from './contexts/TrackedMeasurementsContext/promptBeginTracking'; import getCustomizationModule from './getCustomizationModule'; diff --git a/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.tsx b/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.tsx index 50d630ce6..8f2600adc 100644 --- a/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.tsx +++ b/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import PropTypes from 'prop-types'; -import { ViewportActionArrows } from '@ohif/ui'; +import { ViewportActionArrows } from '@ohif/ui-next'; import { useViewportGrid, Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next'; import { annotation } from '@cornerstonejs/tools'; @@ -325,7 +325,7 @@ function _getStatusComponent(isTracked, t) { - + void; +}; + +const BackItem = ({ backLabel, onBackClick }: BackItemProps) => { + return ( + <> +
+ + {backLabel || 'Back to Display Options'} +
+ + + ); +}; + +export default BackItem; diff --git a/platform/ui-next/src/components/AllInOneMenu/DividerItem.tsx b/platform/ui-next/src/components/AllInOneMenu/DividerItem.tsx new file mode 100644 index 000000000..056d68e9c --- /dev/null +++ b/platform/ui-next/src/components/AllInOneMenu/DividerItem.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const DividerItem = () => { + return ( +
+
+
+ ); +}; + +export default DividerItem; diff --git a/platform/ui-next/src/components/AllInOneMenu/HeaderItem.tsx b/platform/ui-next/src/components/AllInOneMenu/HeaderItem.tsx new file mode 100644 index 000000000..bcb1988ad --- /dev/null +++ b/platform/ui-next/src/components/AllInOneMenu/HeaderItem.tsx @@ -0,0 +1,15 @@ +import React, { ReactNode } from 'react'; + +type HeaderItemProps = { + children: ReactNode; +}; + +const HeaderItem = ({ children }: HeaderItemProps) => { + return ( +
+ {children} +
+ ); +}; + +export default HeaderItem; diff --git a/platform/ui-next/src/components/AllInOneMenu/IconMenu.tsx b/platform/ui-next/src/components/AllInOneMenu/IconMenu.tsx new file mode 100644 index 000000000..b1662394a --- /dev/null +++ b/platform/ui-next/src/components/AllInOneMenu/IconMenu.tsx @@ -0,0 +1,83 @@ +import React, { useCallback, useState } from 'react'; +import OutsideClickHandler from 'react-outside-click-handler'; +import { MenuProps } from './Menu'; +import classNames from 'classnames'; +import { AllInOneMenu } from '..'; +import { Icons } from '@ohif/ui-next'; + +export interface IconMenuProps extends MenuProps { + icon: string; + iconClassName?: string; + horizontalDirection?: AllInOneMenu.HorizontalDirection; + verticalDirection?: AllInOneMenu.VerticalDirection; + menuKey?: number | string; +} + +/** + * An IconMenu allows for a div wrapped icon to be clicked to show and hide + * an AllInOneMenu.Menu. Based on the direction(s) specified, the menu is + * positioned relative to the icon. + * + * HorizontalDirection.LeftToRight - the left edges of the icon and menu are aligned + * HorizontalDirection.RightRoLeft - the right edges of the icon and menu are aligned + * VerticalDirection.TopToBottom - the top edge of the menu appears directly below the bottom edge of the icon + * VerticalDirection.BottomToTop - the bottom edge of the menu appears directly above the top edge of the icon + * + * For example, if an IconMenu were situated in the bottom-left corner of a container, + * it would be best to use BottomToTop and LeftToRight directions for it. + */ +export default function IconMenu({ + icon, + iconClassName, + horizontalDirection, + verticalDirection, + children, + backLabel, + menuClassName, + menuStyle, + onVisibilityChange, + menuKey, +}: IconMenuProps) { + const [isMenuVisible, setIsMenuVisible] = useState(false); + + const toggleMenuVisibility = useCallback(() => setIsMenuVisible(isVisible => !isVisible), []); + + return ( + +
+
+ +
+ { + setIsMenuVisible(isVis); + onVisibilityChange?.(isVis); + }} + horizontalDirection={horizontalDirection} + > + {children} + +
+
+ ); +} diff --git a/platform/ui-next/src/components/AllInOneMenu/Item.tsx b/platform/ui-next/src/components/AllInOneMenu/Item.tsx new file mode 100644 index 000000000..437d06a3d --- /dev/null +++ b/platform/ui-next/src/components/AllInOneMenu/Item.tsx @@ -0,0 +1,51 @@ +import React, { ReactNode, useCallback, useContext } from 'react'; +import { MenuContext } from './Menu'; + +type ItemProps = { + label: string; + secondaryLabel?: string; + icon?: ReactNode; + rightIcon?: ReactNode; + onClick?: () => void; + onMouseEnter?: () => void; + onMouseLeave?: () => void; + useIconSpace?: boolean; +}; + +const Item = ({ + label, + secondaryLabel, + icon, + rightIcon, + onClick, + onMouseEnter, + onMouseLeave, + useIconSpace = false, +}: ItemProps) => { + const { hideMenu } = useContext(MenuContext); + + const onClickHandler = useCallback(() => { + hideMenu(); + onClick?.(); + }, [hideMenu, onClick]); + + return ( +
+ {(icon || useIconSpace) && ( +
{icon}
+ )} + {label} + {secondaryLabel && ( + {secondaryLabel} + )} + {rightIcon &&
{rightIcon}
} +
+ ); +}; + +export default Item; diff --git a/platform/ui-next/src/components/AllInOneMenu/ItemPanel.tsx b/platform/ui-next/src/components/AllInOneMenu/ItemPanel.tsx new file mode 100644 index 000000000..15a23484d --- /dev/null +++ b/platform/ui-next/src/components/AllInOneMenu/ItemPanel.tsx @@ -0,0 +1,38 @@ +import React, { ReactNode, useContext, useEffect } from 'react'; +import { MenuContext } from './Menu'; +import { ScrollArea } from '@ohif/ui-next'; + +type ItemPanelProps = { + label?: string; + index?: number; + children: ReactNode; + maxHeight?: string; + className?: string; +}; + +const ItemPanel = ({ + label, + index = 0, + children, + maxHeight = '250px', + className, +}: ItemPanelProps) => { + const { addItemPanel, activePanelIndex } = useContext(MenuContext); + + useEffect(() => { + addItemPanel(index, label); + }, [addItemPanel, index, label]); + + return ( + activePanelIndex === index && ( + + {children} + + ) + ); +}; + +export default ItemPanel; diff --git a/platform/ui-next/src/components/AllInOneMenu/Menu.tsx b/platform/ui-next/src/components/AllInOneMenu/Menu.tsx new file mode 100644 index 000000000..0fe900e55 --- /dev/null +++ b/platform/ui-next/src/components/AllInOneMenu/Menu.tsx @@ -0,0 +1,187 @@ +import React, { createContext, ReactNode, useCallback, useEffect, useState } from 'react'; + +import DividerItem from './DividerItem'; +import PanelSelector from './PanelSelector'; +import classNames from 'classnames'; +import BackItem from './BackItem'; + +/** + * The vertical direction that the menu will be opened/used with. + * + * A TopToBottom menu would be used for cases where the menu is opened "near" + * the top edge of its container. Likewise a BottomToTop menu would be used + * for cases where the menu is opened "near" the bottom edge of its container. + * + * See IconMenu for more information. + */ +export enum VerticalDirection { + TopToBottom, + BottomToTop, +} + +/** + * The horizontal direction that the menu is opened/used with. + * This direction dictates the general direction sub-menus and + * back-to-menus are opened with. For example, a RightToLeft menu + * will have sub-menu items indicated with a left pointing chevron + * and aligned with the left edge of the menu. Similarly back-to items of a + * RightToLeft menu are indicated with a right pointing chevron and + * aligned with the right edge of the menu. + * + * It is also worth noting that a LeftToRight menu would be used for + * cases where a menu is opened "near" the left edge of its container. + * Likewise, a RightToLeft menu would be used for cases where a menu is opened + * "near" the right edge of its container. + * + * See IconMenu for more information. + */ +export enum HorizontalDirection { + LeftToRight, + RightToLeft, +} + +export interface MenuProps { + menuStyle?: unknown; + menuClassName?: string; + isVisible?: boolean; + preventHideMenu?: boolean; + backLabel?: string; + headerComponent?: ReactNode; + showHeaderDivider?: boolean; + activePanelIndex?: number; + onVisibilityChange?: (isVisible: boolean) => void; + horizontalDirection?: HorizontalDirection; + children: ReactNode; +} +type MenuContextProps = { + showSubMenu: (subMenuProps: MenuProps) => void; + hideMenu: () => void; + addItemPanel: (index: number, label: string) => void; + horizontalDirection: HorizontalDirection; + activePanelIndex: number; +}; + +type MenuPathState = { + props: MenuProps; + activePanelIndex: number; +}; + +export const MenuContext = createContext(null); + +const Menu = (props: MenuProps) => { + const { + isVisible, + onVisibilityChange, + activePanelIndex, + preventHideMenu, + menuClassName, + menuStyle, + horizontalDirection = HorizontalDirection.LeftToRight, + } = props; + + const [isMenuVisible, setIsMenuVisible] = useState(isVisible); + + // The menuPath is an array consisting of this top Menu and every SubMenu + // that has been traversed/opened by the user with the last item in the array + // being the current (sub)menu that is currently visible. This allows for the previously + // viewed menus to be returned to via the Back button at the top of the menu. + const [menuPath, setMenuPath] = useState>([ + { props, activePanelIndex: activePanelIndex || 0 }, + ]); + const [itemPanelLabels, setItemPanelLabels] = useState>([]); + + const hideMenu = useCallback(() => { + if (preventHideMenu) { + return; + } + setMenuPath(path => [path[0]]); + setItemPanelLabels([]); + setIsMenuVisible(false); + onVisibilityChange?.(false); + }, [preventHideMenu, onVisibilityChange]); + + useEffect(() => { + if (isVisible) { + setIsMenuVisible(isVisible); + onVisibilityChange?.(isVisible); + } else { + hideMenu(); + } + }, [hideMenu, isVisible, onVisibilityChange]); + + const showSubMenu = useCallback((subMenuProps: MenuProps) => { + setMenuPath(path => { + return [ + ...path, + { props: subMenuProps, activePanelIndex: subMenuProps.activePanelIndex || 0 }, + ]; + }); + setItemPanelLabels([]); + }, []); + + const addItemPanel = useCallback((index, label) => { + setItemPanelLabels(labels => { + return [...labels.slice(0, index), label, ...labels.slice(index + 1, labels.length)]; + }); + }, []); + + const onActivePanelIndexChange = useCallback(index => { + setMenuPath(path => { + return [ + ...path.slice(0, path.length - 1), + { ...path[path.length - 1], activePanelIndex: index }, + ]; + }); + }, []); + + const onBackClick = useCallback(() => { + setMenuPath(path => [...path.slice(0, path.length - 1)]); + setItemPanelLabels([]); + }, []); + + const { props: currentMenuProps, activePanelIndex: currentMenuActivePanelIndex } = + menuPath[menuPath.length - 1]; + + return ( + <> + + {isMenuVisible && ( +
+ {menuPath.length > 1 && ( + + )} + {itemPanelLabels.length > 1 && ( + + )} + {currentMenuProps.headerComponent} + {currentMenuProps.showHeaderDivider && } + {currentMenuProps.children} +
+ )} +
+ + ); +}; + +export default Menu; diff --git a/platform/ui-next/src/components/AllInOneMenu/PanelSelector.tsx b/platform/ui-next/src/components/AllInOneMenu/PanelSelector.tsx new file mode 100644 index 000000000..b7ca846d5 --- /dev/null +++ b/platform/ui-next/src/components/AllInOneMenu/PanelSelector.tsx @@ -0,0 +1,32 @@ +import React, { ReactNode } from 'react'; +import { Tabs, TabsList, TabsTrigger } from '../Tabs'; + +type PanelSelectorProps = { + panelLabels: Array; + onActiveIndexChange: (index: number) => void; + activeIndex: number; +}; + +const PanelSelector = ({ panelLabels, onActiveIndexChange, activeIndex }: PanelSelectorProps) => { + return ( +
+ onActiveIndexChange(parseInt(val, 10))} + > + + {panelLabels.map((panelLabel, index) => ( + + {panelLabel} + + ))} + + +
+ ); +}; + +export default PanelSelector; diff --git a/platform/ui-next/src/components/AllInOneMenu/SubMenu.tsx b/platform/ui-next/src/components/AllInOneMenu/SubMenu.tsx new file mode 100644 index 000000000..ce2a11e13 --- /dev/null +++ b/platform/ui-next/src/components/AllInOneMenu/SubMenu.tsx @@ -0,0 +1,36 @@ +import React, { useCallback, useContext } from 'react'; +import { MenuContext, MenuProps } from './Menu'; +import { Icons } from '@ohif/ui-next'; +export interface SubMenuProps extends MenuProps { + itemLabel: string; + onClick?: () => void; + itemIcon?: string; +} + +const SubMenu = (props: SubMenuProps) => { + const { showSubMenu } = useContext(MenuContext); + + const onClickHandler = useCallback(() => { + showSubMenu(props); + props.onClick?.(); + }, [showSubMenu, props]); + + return ( +
+ {props.itemIcon && ( +
+ +
+ )} + {props.itemLabel} +
+ +
+
+ ); +}; + +export default SubMenu; diff --git a/platform/ui-next/src/components/AllInOneMenu/index.ts b/platform/ui-next/src/components/AllInOneMenu/index.ts new file mode 100644 index 000000000..14bf89925 --- /dev/null +++ b/platform/ui-next/src/components/AllInOneMenu/index.ts @@ -0,0 +1,42 @@ +import Menu, { VerticalDirection, HorizontalDirection } from './Menu'; +import SubMenu from './SubMenu'; +import BackItem from './BackItem'; +import HeaderItem from './HeaderItem'; +import DividerItem from './DividerItem'; +import IconMenu from './IconMenu'; +import ItemPanel from './ItemPanel'; +import PanelSelector from './PanelSelector'; +import Item from './Item'; + +// Export enums +export { VerticalDirection, HorizontalDirection }; + +// Export components +export { + Menu, + SubMenu, + BackItem, + HeaderItem, + DividerItem, + IconMenu, + ItemPanel, + PanelSelector, + Item, +}; + +// Namespace for components and enums +const AllInOneMenu = { + Menu, + SubMenu, + BackItem, + HeaderItem, + DividerItem, + IconMenu, + ItemPanel, + PanelSelector, + Item, + VerticalDirection, + HorizontalDirection, +}; + +export default AllInOneMenu; diff --git a/platform/ui-next/src/components/DropdownMenu/DropdownMenu.tsx b/platform/ui-next/src/components/DropdownMenu/DropdownMenu.tsx index f7ba45360..3d420d333 100644 --- a/platform/ui-next/src/components/DropdownMenu/DropdownMenu.tsx +++ b/platform/ui-next/src/components/DropdownMenu/DropdownMenu.tsx @@ -46,7 +46,7 @@ const DropdownMenuSubContent = React.forwardRef< { /** Flag to show/hide scroll indicator arrows at top and bottom */ showArrows?: boolean; + type?: 'auto' | 'always' | 'scroll'; } /** @@ -56,6 +57,7 @@ const ScrollArea = React.forwardRef< void; + onContextMenu?: (e: React.MouseEvent) => void; + className?: string; +} + +export const ImageScrollbar: React.FC = ({ + value, + max, + height, + onChange, + onContextMenu = e => e.preventDefault(), + className = '', +}) => { + if (max === 0) { + return null; + } + + const style = { + width: height, // This is intentional for the rotation + }; + + const handleChange = useCallback( + (event: React.ChangeEvent) => { + const intValue = parseInt(event.target.value, 10); + onChange(intValue); + }, + [onChange] + ); + + const handleKeyDown = useCallback((event: React.KeyboardEvent) => { + // We don't allow direct keyboard navigation (arrow keys) + const keys = { + DOWN: 40, + UP: 38, + }; + + if (event.which === keys.DOWN || event.which === keys.UP) { + event.preventDefault(); + } + }, []); + + return ( +
+
+ +
+
+ ); +}; \ No newline at end of file diff --git a/platform/ui-next/src/components/Viewport/ViewportActionArrows.tsx b/platform/ui-next/src/components/Viewport/ViewportActionArrows.tsx index 96b41ee44..7313512f5 100644 --- a/platform/ui-next/src/components/Viewport/ViewportActionArrows.tsx +++ b/platform/ui-next/src/components/Viewport/ViewportActionArrows.tsx @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; import { Icons } from '@ohif/ui-next'; const arrowClasses = - 'cursor-pointer flex items-center justify-center shrink-0 text-primary-light active:text-white hover:bg-secondary-light/60 rounded'; + 'cursor-pointer flex items-center justify-center shrink-0 text-highlight active:text-foreground hover:bg-primary/30 rounded'; /** * A small set of left/right arrow icons for stepping through slices or series. diff --git a/platform/ui-next/src/components/Viewport/ViewportActionCorners.tsx b/platform/ui-next/src/components/Viewport/ViewportActionCorners.tsx index f02d4ff70..1acc27738 100644 --- a/platform/ui-next/src/components/Viewport/ViewportActionCorners.tsx +++ b/platform/ui-next/src/components/Viewport/ViewportActionCorners.tsx @@ -13,7 +13,7 @@ export enum ViewportActionCornersLocations { bottomRight, } -const commonClasses = 'pointer-events-auto flex items-center gap-1'; +const commonClasses = 'pointer-events-auto flex items-center'; const locationClasses = { [ViewportActionCornersLocations.topLeft]: classNames( commonClasses, @@ -21,7 +21,7 @@ const locationClasses = { ), [ViewportActionCornersLocations.topRight]: classNames( commonClasses, - 'absolute top-[4px] right-[4px] right-viewport-scrollbar' + 'absolute top-[4px] right-[16px] right-viewport-scrollbar' ), [ViewportActionCornersLocations.bottomLeft]: classNames( commonClasses, @@ -64,4 +64,4 @@ ViewportActionCorners.propTypes = { cornerComponents: PropTypes.object.isRequired, }; -export { ViewportActionCorners }; +export { ViewportActionCorners }; \ No newline at end of file diff --git a/platform/ui-next/src/components/Viewport/ViewportOverlay.css b/platform/ui-next/src/components/Viewport/ViewportOverlay.css index e8aebd0be..5b17f7ad8 100644 --- a/platform/ui-next/src/components/Viewport/ViewportOverlay.css +++ b/platform/ui-next/src/components/Viewport/ViewportOverlay.css @@ -2,7 +2,7 @@ display: none; } .ViewportOverlay { - color: #9ccef9; + color: hsl(var(--highlight)); } .ViewportOverlay .overlay-element { position: absolute; @@ -11,12 +11,12 @@ pointer-events: none; } .overlay-top { - top: 28px; + top: 2.15rem; } .overlay-bottom { - bottom: 3px; + bottom: 1rem; } .overlay-text { - text-shadow: 0.8px 0.8px 0.5px rgba(0, 0, 0, 0.75); + text-shadow: 0.8px 0.8px 0.5px rgba(0, 0, 0, 0.65); } diff --git a/platform/ui-next/src/components/Viewport/ViewportOverlay.tsx b/platform/ui-next/src/components/Viewport/ViewportOverlay.tsx index 5164142ad..a5d3ed1be 100644 --- a/platform/ui-next/src/components/Viewport/ViewportOverlay.tsx +++ b/platform/ui-next/src/components/Viewport/ViewportOverlay.tsx @@ -17,17 +17,11 @@ const classes = { bottomLeft: 'overlay-bottom left-viewport', }; -function ViewportOverlay({ - topLeft, - topRight, - bottomRight, - bottomLeft, - color = 'text-primary-light', -}) { +function ViewportOverlay({ topLeft, topRight, bottomRight, bottomLeft, color = 'text-highlight' }) { const overlay = 'absolute pointer-events-none viewport-overlay'; return ( -
+
{topRight}
{bottomRight}
diff --git a/platform/ui-next/src/components/Viewport/ViewportPane.tsx b/platform/ui-next/src/components/Viewport/ViewportPane.tsx index 4a1e32769..e5c6f4b91 100644 --- a/platform/ui-next/src/components/Viewport/ViewportPane.tsx +++ b/platform/ui-next/src/components/Viewport/ViewportPane.tsx @@ -68,8 +68,8 @@ function ViewportPane({ {/* Border overlay */}
diff --git a/platform/ui-next/src/components/Viewport/index.ts b/platform/ui-next/src/components/Viewport/index.ts index feb9a0a95..f5f1c7642 100644 --- a/platform/ui-next/src/components/Viewport/index.ts +++ b/platform/ui-next/src/components/Viewport/index.ts @@ -6,3 +6,4 @@ export { ViewportPane } from './ViewportPane'; export { ViewportActionCorners, ViewportActionCornersLocations } from './ViewportActionCorners'; export { ViewportOverlay } from './ViewportOverlay'; export { ViewportGrid } from './ViewportGrid'; +export { ImageScrollbar } from './ImageScrollbar'; \ No newline at end of file diff --git a/platform/ui-next/src/components/index.ts b/platform/ui-next/src/components/index.ts index 4accaf0bc..9e660144a 100644 --- a/platform/ui-next/src/components/index.ts +++ b/platform/ui-next/src/components/index.ts @@ -81,8 +81,6 @@ import { } from './DropdownMenu'; import { Onboarding } from './Onboarding'; import { DoubleSlider } from './DoubleSlider'; -export { DataRow } from './DataRow'; -export { MeasurementTable } from './MeasurementTable'; import { SegmentationTable, useSegmentationTableContext, @@ -92,7 +90,6 @@ import { import { Toaster, toast } from './Sonner'; import { StudySummary } from './StudySummary'; import { ErrorBoundary } from './Errorboundary'; -export * from './ColorCircle'; import { Header } from './Header'; import { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } from './Card'; import { @@ -105,6 +102,7 @@ import { ViewportActionCornersLocations, ViewportOverlay, ViewportGrid, + ImageScrollbar, } from './Viewport'; import { ToolButton, @@ -115,6 +113,11 @@ import { ToolButtonListDivider, } from './ToolButton'; import { ToolSettings } from './OHIFToolSettings'; +export { DataRow } from './DataRow'; +export { MeasurementTable } from './MeasurementTable'; +export * from './ColorCircle'; +export { default as AllInOneMenu } from './AllInOneMenu'; +export * from './AllInOneMenu'; // Segmentation Context Exports export { useSegmentationTableContext, useSegmentationExpanded, useSegmentStatistics }; @@ -232,6 +235,7 @@ export { ViewportActionCornersLocations, ViewportOverlay, ViewportGrid, + ImageScrollbar, Clipboard, ToolButton, ToolButtonList, diff --git a/platform/ui-next/src/tailwind.css b/platform/ui-next/src/tailwind.css index 90271c9cf..b27fa0767 100644 --- a/platform/ui-next/src/tailwind.css +++ b/platform/ui-next/src/tailwind.css @@ -26,7 +26,7 @@ --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; --border: 0 0% 14.9%; - --input: 236 45% 21%; + --input: 236 52% 30%; --ring: 214 98% 60%; --chart-1: 220 70% 50%; --chart-2: 160 60% 45%; @@ -69,7 +69,7 @@ --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; --border: 0 0% 14.9%; - --input: 236 45% 21%; + --input: 236 52% 30%; --ring: 214 98% 60%; --chart-1: 220 70% 50%; --chart-2: 160 60% 45%; @@ -252,4 +252,4 @@ input[type='number']::-webkit-outer-spin-button { input[type='number'] { -moz-appearance: textfield; /* For Firefox */ -} +} \ No newline at end of file diff --git a/platform/ui/src/components/AllInOneMenu/DividerItem.tsx b/platform/ui/src/components/AllInOneMenu/DividerItem.tsx index 056d68e9c..fa4307ca6 100644 --- a/platform/ui/src/components/AllInOneMenu/DividerItem.tsx +++ b/platform/ui/src/components/AllInOneMenu/DividerItem.tsx @@ -2,8 +2,8 @@ import React from 'react'; const DividerItem = () => { return ( -
-
+
+
); }; diff --git a/platform/ui/src/tailwind.css b/platform/ui/src/tailwind.css index 8bda44030..1fac7989b 100644 --- a/platform/ui/src/tailwind.css +++ b/platform/ui/src/tailwind.css @@ -11,6 +11,8 @@ } } + + /* Truncate 2 lines utility */ .truncate-2-lines { overflow: hidden; @@ -49,7 +51,7 @@ --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; --border: 0 0% 14.9%; - --input: 236 45% 21%; + --input: 236 52% 30%; --ring: 214 98% 60%; --chart-1: 220 70% 50%; --chart-2: 160 60% 45%; @@ -92,7 +94,7 @@ --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; --border: 0 0% 14.9%; - --input: 236 45% 21%; + --input: 236 52% 30%; --ring: 214 98% 60%; --chart-1: 220 70% 50%; --chart-2: 160 60% 45%; @@ -100,4 +102,4 @@ --chart-4: 280 65% 60%; --chart-5: 340 75% 55%; } -} +} \ No newline at end of file