OHIF with Cornerstone3D 2.0 (#4347)
This commit is contained in:
1 parent
8981a61b8c
commit
7ce7127d7c
803 files changed
+32760
-15893
No files matched your search
@@ -69,7 +69,9 @@ const ProgressItemDetail = ({ option }: { option: ProgressDropdownOption }): Rea
|
||||
)}
|
||||
{!info && iconContent}
|
||||
|
||||
<div className="grow text-base leading-6">{label}</div>
|
||||
<div className="grow overflow-hidden text-ellipsis whitespace-nowrap text-base leading-6">
|
||||
{label}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -161,7 +161,7 @@ const SegmentationConfig = ({
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="h-[6px] bg-black "></div>
|
||||
<div className="h-[6px] bg-black"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -98,7 +98,7 @@ function SegmentationDropDownRow({
|
||||
],
|
||||
]}
|
||||
>
|
||||
<div className="hover:bg-secondary-dark grid h-[28px] w-[28px] cursor-pointer place-items-center rounded-[4px]">
|
||||
<div className="hover:bg-secondary-dark grid h-[28px] w-[28px] cursor-pointer place-items-center rounded-[4px]">
|
||||
<Icon name="icon-more-menu"></Icon>
|
||||
</div>
|
||||
</Dropdown>
|
||||
@@ -138,7 +138,7 @@ function SegmentationDropDownRow({
|
||||
/>
|
||||
</Tooltip>
|
||||
<div
|
||||
className="hover:bg-secondary-dark mr-1 grid h-[28px] w-[28px] cursor-pointer place-items-center rounded-[4px]"
|
||||
className="hover:bg-secondary-dark mr-1 grid h-[28px] w-[28px] cursor-pointer place-items-center rounded-[4px]"
|
||||
onClick={() => onToggleSegmentationVisibility(activeSegmentation.id)}
|
||||
>
|
||||
{activeSegmentation.isVisible ? (
|
||||
|
||||
@@ -94,7 +94,7 @@ const SegmentationGroupTable = ({
|
||||
segmentationConfig={segmentationConfig}
|
||||
/>
|
||||
)}
|
||||
<div className="bg-primary-dark ">
|
||||
<div className="bg-primary-dark">
|
||||
{segmentations?.length === 0 ? (
|
||||
<div className="select-none bg-black py-[3px]">
|
||||
{showAddSegmentation && !disableEditing && (
|
||||
|
||||
@@ -49,7 +49,7 @@ const StudyItem = ({
|
||||
<div className="flex-2 flex">
|
||||
<div
|
||||
className={classnames(
|
||||
'bg-secondary-main mt-2 flex flex-row py-1 pl-2 pr-4 text-base text-white ',
|
||||
'bg-secondary-main mt-2 flex flex-row py-1 pl-2 pr-4 text-base text-white',
|
||||
isActive
|
||||
? 'border-secondary-light flex-1 justify-center border-t'
|
||||
: 'mx-4 mb-4 rounded-sm'
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const StudySummary = ({ date, modality, description }) => {
|
||||
interface StudySummaryProps {
|
||||
date: string;
|
||||
modality: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
const StudySummary: React.FC<StudySummaryProps> = ({ date, modality, description }) => {
|
||||
return (
|
||||
<div className="p-2">
|
||||
<div className="leading-none">
|
||||
@@ -17,10 +22,4 @@ const StudySummary = ({ date, modality, description }) => {
|
||||
);
|
||||
};
|
||||
|
||||
StudySummary.propTypes = {
|
||||
date: PropTypes.string.isRequired,
|
||||
modality: PropTypes.string.isRequired,
|
||||
description: PropTypes.string,
|
||||
};
|
||||
|
||||
export default StudySummary;
|
||||
@@ -64,7 +64,7 @@ function ViewportPane({
|
||||
onScroll={onInteractionHandler}
|
||||
onWheel={onInteractionHandler}
|
||||
className={classnames(
|
||||
'group h-full w-full overflow-hidden rounded-md transition duration-300',
|
||||
'group/pane h-full w-full overflow-hidden rounded-md transition duration-300',
|
||||
{
|
||||
'border-primary-light border-2': isActive,
|
||||
'border-2 border-transparent': !isActive,
|
||||
@@ -80,7 +80,7 @@ function ViewportPane({
|
||||
'h-full w-full overflow-hidden rounded-md',
|
||||
{
|
||||
'border border-transparent': isActive,
|
||||
'border-secondary-light group-hover:border-primary-light/70 border': !isActive,
|
||||
'border-secondary-light group-hover/pane:border-primary-light/70 border': !isActive,
|
||||
},
|
||||
className
|
||||
)}
|
||||
|
||||
@@ -143,11 +143,12 @@ const WindowLevel = ({
|
||||
inputClassName="grow"
|
||||
maxValue={1}
|
||||
minValue={0}
|
||||
step={0.1}
|
||||
step={0.05}
|
||||
value={opacity}
|
||||
showLabel={true}
|
||||
allowNumberEdit={true}
|
||||
onChange={handleOpacityChange}
|
||||
showAdjustmentArrows={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -93,6 +93,9 @@ export default function CineProvider({ children, service }) {
|
||||
setIsCineEnabled: isCineEnabled => service.setIsCineEnabled(isCineEnabled),
|
||||
playClip: (element, playClipOptions) => service.playClip(element, playClipOptions),
|
||||
stopClip: (element, stopClipOptions) => service.stopClip(element, stopClipOptions),
|
||||
setViewportCineClosed: viewportId => service.setViewportCineClosed(viewportId),
|
||||
clearViewportCineClosed: viewportId => service.clearViewportCineClosed(viewportId),
|
||||
isViewportCineClosed: viewportId => service.isViewportCineClosed(viewportId),
|
||||
};
|
||||
|
||||
return <CineContext.Provider value={[state, api]}>{children}</CineContext.Provider>;
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import React, { useState, createContext, useContext, useCallback, useEffect, useRef } from 'react';
|
||||
import React, {
|
||||
useState,
|
||||
createContext,
|
||||
useContext,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import Draggable from 'react-draggable';
|
||||
@@ -268,8 +276,13 @@ const DialogProvider = ({ children, service = null }) => {
|
||||
|
||||
const validCallback = callback => callback && typeof callback === 'function';
|
||||
|
||||
const contextValue = useMemo(
|
||||
() => ({ create, dismiss, dismissAll, isEmpty }),
|
||||
[create, dismiss, dismissAll, isEmpty]
|
||||
);
|
||||
|
||||
return (
|
||||
<DialogContext.Provider value={{ create, dismiss, dismissAll, isEmpty }}>
|
||||
<DialogContext.Provider value={contextValue}>
|
||||
{!isEmpty() && (
|
||||
<div
|
||||
className="absolute h-full w-full"
|
||||
|
||||
@@ -2,7 +2,6 @@ export function toolboxReducer(state, action) {
|
||||
let newState = { ...state };
|
||||
|
||||
const { payload } = action;
|
||||
const { stateSyncService, buttonSectionId } = payload || {};
|
||||
|
||||
switch (action.type) {
|
||||
case 'SET_ACTIVE_TOOL':
|
||||
@@ -49,18 +48,5 @@ export function toolboxReducer(state, action) {
|
||||
break;
|
||||
}
|
||||
|
||||
// store the state in the stateSyncService
|
||||
if (payload?.stateSyncService) {
|
||||
const prevState = stateSyncService.getState()?.['uiStateStore']?.[buttonSectionId];
|
||||
stateSyncService.store({
|
||||
uiStateStore: {
|
||||
...stateSyncService.getState()?.['uiStateStore'],
|
||||
[buttonSectionId]: {
|
||||
...prevState,
|
||||
...newState,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
@@ -1,38 +1,18 @@
|
||||
import React, { createContext, useCallback, useContext, useEffect, useReducer } from 'react';
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useReducer,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import merge from 'lodash.merge';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import { ViewportGridService, utils } from '@ohif/core';
|
||||
import viewportLabels from '../utils/viewportLabels';
|
||||
|
||||
interface Viewport {
|
||||
viewportId: string;
|
||||
displaySetInstanceUIDs: string[];
|
||||
viewportOptions: any;
|
||||
displaySetSelectors: any[];
|
||||
displaySetOptions: any[];
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
viewportLabel: any;
|
||||
isReady: boolean;
|
||||
}
|
||||
|
||||
interface Layout {
|
||||
numRows: number;
|
||||
numCols: number;
|
||||
layoutType: string;
|
||||
}
|
||||
|
||||
interface DefaultState {
|
||||
activeViewportId: string | null;
|
||||
layout: Layout;
|
||||
isHangingProtocolLayout: boolean;
|
||||
viewports: Map<string, Viewport>;
|
||||
}
|
||||
|
||||
const DEFAULT_STATE: DefaultState = {
|
||||
const DEFAULT_STATE: AppTypes.ViewportGrid.State = {
|
||||
activeViewportId: null,
|
||||
layout: {
|
||||
numRows: 0,
|
||||
@@ -78,7 +58,10 @@ const getViewportLabel = (viewports, viewportId) => {
|
||||
return viewportLabels[viewportIds.indexOf(viewportId)];
|
||||
};
|
||||
|
||||
const determineActiveViewportId = (state: DefaultState, newViewports: Map) => {
|
||||
const determineActiveViewportId = (
|
||||
state: AppTypes.ViewportGrid.State,
|
||||
newViewports: Map<string, AppTypes.ViewportGrid.Viewport>
|
||||
) => {
|
||||
const { activeViewportId } = state;
|
||||
const currentActiveViewport = state.viewports.get(activeViewportId);
|
||||
|
||||
@@ -132,10 +115,37 @@ const determineActiveViewportId = (state: DefaultState, newViewports: Map) => {
|
||||
return sortedViewports[0].viewportId;
|
||||
};
|
||||
|
||||
export const ViewportGridContext = createContext(DEFAULT_STATE);
|
||||
// Define the API interface
|
||||
interface ViewportGridApi {
|
||||
getState: () => AppTypes.ViewportGrid.State;
|
||||
setActiveViewportId: (index: string) => void;
|
||||
setDisplaySetsForViewport: (props: any) => void;
|
||||
setDisplaySetsForViewports: (props: any[]) => void;
|
||||
setLayout: (layout: AppTypes.ViewportGrid.Layout) => void;
|
||||
reset: () => void;
|
||||
set: (gridLayoutState: Partial<AppTypes.ViewportGrid.State>) => void;
|
||||
getNumViewportPanes: () => number;
|
||||
setViewportIsReady: (viewportId: string, isReady: boolean) => void;
|
||||
getGridViewportsReady: () => boolean;
|
||||
getActiveViewportOptionByKey: (key: string) => any;
|
||||
setViewportGridSizeChanged: (props: any) => void;
|
||||
publishViewportsReady: () => void;
|
||||
}
|
||||
|
||||
export function ViewportGridProvider({ children, service }) {
|
||||
const viewportGridReducer = (state: DefaultState, action) => {
|
||||
// Update the context type
|
||||
export const ViewportGridContext = createContext<[AppTypes.ViewportGrid.State, ViewportGridApi]>([
|
||||
DEFAULT_STATE,
|
||||
{} as ViewportGridApi,
|
||||
]);
|
||||
|
||||
// Update the provider props type
|
||||
interface ViewportGridProviderProps {
|
||||
children: ReactNode;
|
||||
service: ViewportGridService;
|
||||
}
|
||||
|
||||
export function ViewportGridProvider({ children, service }: ViewportGridProviderProps) {
|
||||
const viewportGridReducer = (state: AppTypes.ViewportGrid.State, action) => {
|
||||
switch (action.type) {
|
||||
case 'SET_ACTIVE_VIEWPORT_ID': {
|
||||
return { ...state, ...{ activeViewportId: action.payload } };
|
||||
@@ -207,10 +217,10 @@ export function ViewportGridProvider({ children, service }) {
|
||||
// viewportLabel: getViewportLabel(viewports, viewportId),
|
||||
};
|
||||
|
||||
viewportOptions.presentationIds = ViewportGridService.getPresentationIds(
|
||||
newViewport,
|
||||
viewports
|
||||
);
|
||||
viewportOptions.presentationIds = service.getPresentationIds({
|
||||
viewport: newViewport,
|
||||
viewports,
|
||||
});
|
||||
|
||||
viewports.set(viewportId, {
|
||||
...viewports.get(viewportId),
|
||||
@@ -233,7 +243,7 @@ export function ViewportGridProvider({ children, service }) {
|
||||
|
||||
// If empty viewportOptions, we use numRow and numCols to calculate number of viewports
|
||||
const hasOptions = layoutOptions?.length;
|
||||
const viewports = new Map<string, Viewport>();
|
||||
const viewports = new Map<string, AppTypes.ViewportGrid.Viewport>();
|
||||
// Options is a temporary state store which can be used by the
|
||||
// findOrCreate to store state about already found viewports. Typically,
|
||||
// it will be used to store the display set UID's which are already
|
||||
@@ -298,10 +308,11 @@ export function ViewportGridProvider({ children, service }) {
|
||||
viewport.isReady = false;
|
||||
|
||||
if (!viewport.viewportOptions.presentationIds) {
|
||||
viewport.viewportOptions.presentationIds = ViewportGridService.getPresentationIds(
|
||||
const presentationIds = service.getPresentationIds({
|
||||
viewport,
|
||||
viewports
|
||||
);
|
||||
viewports,
|
||||
});
|
||||
viewport.viewportOptions.presentationIds = presentationIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -513,4 +524,6 @@ ViewportGridProvider.propTypes = {
|
||||
service: PropTypes.instanceOf(ViewportGridService).isRequired,
|
||||
};
|
||||
|
||||
export const useViewportGrid = () => useContext(ViewportGridContext);
|
||||
// Update the useViewportGrid hook
|
||||
export const useViewportGrid = (): [AppTypes.ViewportGrid.State, ViewportGridApi] =>
|
||||
useContext(ViewportGridContext);
|
||||
@@ -5,6 +5,10 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
* {
|
||||
min-height: 0 !important;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
html {
|
||||
font-family: 'Inter', sans-serif;
|
||||
@@ -28,3 +32,76 @@
|
||||
user-select: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--highlight: 191 74% 63%;
|
||||
--background: 236 62% 5%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 236 62% 5%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 219 90% 15%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 214 98% 60%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 214 66% 48%;
|
||||
--secondary-foreground: 200 50% 84%;
|
||||
--muted: 234 64% 10%;
|
||||
--muted-foreground: 200 46% 65%;
|
||||
--accent: 217 79% 24%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 14.9%;
|
||||
--input: 236 45% 21%;
|
||||
--ring: 214 98% 60%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
--radius: 0.5rem;
|
||||
--success-bg: hsl(143, 85%, 96%);
|
||||
--success-border: hsl(145, 92%, 91%);
|
||||
--success-text: hsl(140, 100%, 27%);
|
||||
|
||||
--info-bg: hsl(208, 100%, 97%);
|
||||
--info-border: hsl(221, 91%, 91%);
|
||||
--info-text: hsl(210, 92%, 45%);
|
||||
|
||||
--warning-bg: hsl(49, 100%, 97%);
|
||||
--warning-border: hsl(49, 91%, 91%);
|
||||
--warning-text: hsl(31, 92%, 45%);
|
||||
|
||||
--error-bg: hsl(359, 100%, 97%);
|
||||
--error-border: hsl(359, 100%, 94%);
|
||||
--error-text: hsl(360, 100%, 45%);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 0 0% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 0 0% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 0 0% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 214 98% 60%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 0 0% 14.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 14.9%;
|
||||
--muted-foreground: 0 0% 63.9%;
|
||||
--accent: 0 0% 14.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 14.9%;
|
||||
--input: 236 45% 21%;
|
||||
--ring: 214 98% 60%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
}
|
||||
}
|
||||
@@ -253,6 +253,18 @@ module.exports = {
|
||||
fill: {
|
||||
current: 'currentColor',
|
||||
},
|
||||
fontSize: {
|
||||
xxs: '0.6875rem', // 11px
|
||||
xs: '0.75rem', // 12px
|
||||
sm: '0.8125rem', // 13px
|
||||
base: '0.875rem', // 14px
|
||||
lg: '1rem', // 16px
|
||||
xl: '1.125rem', // 18px
|
||||
'2xl': '1.25rem', // 20px
|
||||
'3xl': '1.375rem', // 22px
|
||||
'4xl': '1.5rem', // 24px
|
||||
'5xl': '1.875rem', // 30px
|
||||
},
|
||||
flex: {
|
||||
1: '1 1 0%',
|
||||
0.3: '0.3 0.3 0%',
|
||||
|
||||
Reference in new issue
Block a user