From 297ebd89e21f92c4fc2cd285cb0dc58d5f527a3b Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Fri, 20 Feb 2026 15:29:51 -0300 Subject: [PATCH 1/2] Add new ui --- craco.config.js | 1 + src/App.dark.less | 28 ++ src/App.light.less | 28 ++ src/App.tsx | 89 ++--- src/components/ClusteringSettings.tsx | 79 ---- src/components/Header.tsx | 8 +- src/components/SlideItem.tsx | 17 +- src/components/SlideViewer.tsx | 349 +++++++++++++----- src/components/SlideViewer/SettingsPanel.css | 55 +++ .../SlideViewer/SlideViewerSidebar.css | 1 + .../SlideViewer/SlideViewerSidebar.tsx | 15 +- src/components/SlideViewer/types.ts | 1 + src/contexts/SettingsContext.tsx | 95 +++++ src/data/slides.tsx | 12 + 14 files changed, 544 insertions(+), 234 deletions(-) delete mode 100644 src/components/ClusteringSettings.tsx create mode 100644 src/components/SlideViewer/SettingsPanel.css create mode 100644 src/components/SlideViewer/SlideViewerSidebar.css create mode 100644 src/contexts/SettingsContext.tsx diff --git a/craco.config.js b/craco.config.js index 20780932..1039d728 100644 --- a/craco.config.js +++ b/craco.config.js @@ -11,6 +11,7 @@ module.exports = { modifyVars: { '@layout-header-background': '#007ea3', '@primary-color': '#007ea3', + '@collapse-header-bg': '#e0f2f7', '@processing-color': '#8cb8c6', '@success-color': '#3f9c35', '@warning-color': '#eeaf30', diff --git a/src/App.dark.less b/src/App.dark.less index 5346afc4..baa7f518 100644 --- a/src/App.dark.less +++ b/src/App.dark.less @@ -28,8 +28,36 @@ overflow: visible; } +.ant-collapse-header { + font-weight: 600; + border-top: 1px solid rgba(0, 126, 163, 0.5); + border-bottom: 1px solid rgba(0, 126, 163, 0.5); +} + +.ant-collapse-item + .ant-collapse-item .ant-collapse-header { + margin-top: -1px; +} + .ant-menu-submenu-title { font-size: 'medium'; + background-color: rgba(0, 126, 163, 0.25); + font-weight: 600; + border-top: 1px solid rgba(0, 126, 163, 0.5); + border-bottom: 1px solid rgba(0, 126, 163, 0.5); +} + +.ant-menu-submenu + .ant-menu-submenu .ant-menu-submenu-title { + margin-top: -1px; +} + +/* First section in sidebar has no top border */ +.ant-layout-sider .ant-menu-inline > .ant-menu-submenu:first-child > .ant-menu-submenu-title { + border-top: none; +} + +/* Remove gap between submenu header and list content */ +.ant-layout-sider .ant-list-item { + padding: 0; } .ol-overviewmap-box { diff --git a/src/App.light.less b/src/App.light.less index 59e618ff..bc077372 100644 --- a/src/App.light.less +++ b/src/App.light.less @@ -28,8 +28,36 @@ overflow: visible; } +.ant-collapse-header { + font-weight: 600; + border-top: 1px solid rgba(0, 126, 163, 0.3); + border-bottom: 1px solid rgba(0, 126, 163, 0.3); +} + +.ant-collapse-item + .ant-collapse-item .ant-collapse-header { + margin-top: -1px; +} + .ant-menu-submenu-title { font-size: 'medium'; + background-color: #e0f2f7; + font-weight: 600; + border-top: 1px solid rgba(0, 126, 163, 0.3); + border-bottom: 1px solid rgba(0, 126, 163, 0.3); +} + +.ant-menu-submenu + .ant-menu-submenu .ant-menu-submenu-title { + margin-top: -1px; +} + +/* First section in sidebar has no top border */ +.ant-layout-sider .ant-menu-inline > .ant-menu-submenu:first-child > .ant-menu-submenu-title { + border-top: none; +} + +/* Remove gap between submenu header and list content */ +.ant-layout-sider .ant-list-item { + padding: 0; } .ol-overviewmap-box { diff --git a/src/App.tsx b/src/App.tsx index 2962f194..1557ae6a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -20,6 +20,7 @@ import Header from './components/Header' import InfoPage from './components/InfoPage' import MemoryFooter from './components/MemoryFooter' import Worklist from './components/Worklist' +import { SettingsProvider } from './contexts/SettingsContext' import { ValidationProvider } from './contexts/ValidationContext' import DicomWebManager from './DicomWebManager' import { StorageClasses } from './data/uids' @@ -558,57 +559,61 @@ class App extends React.Component { -
- - + +
- - {enableMemoryMonitoring && ( - - )} - + + + + {enableMemoryMonitoring && ( + + )} + + } /> -
- - + +
- - {enableMemoryMonitoring && ( - - )} - + + + + {enableMemoryMonitoring && ( + + )} + + } /> void - onThresholdChange: (value: number | null) => void -} - -/** - * Clustering settings menu items for annotation groups. - * Extracted to reduce JSX nesting depth. - */ -const ClusteringSettings = ({ - isClusteringEnabled, - clusteringPixelSizeThreshold, - onClusteringToggle, - onThresholdChange, -}: ClusteringSettingsProps): JSX.Element => { - const toggleStyle = { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - marginBottom: '0.5rem', - } - - const helpTextStyle = { - fontSize: '0.75rem', - color: '#8c8c8c', - marginTop: '0.5rem', - } - - return ( - <> - -
- Enable Clustering - -
-
- - {isClusteringEnabled && ( - -
- Clustering Pixel Size Threshold (mm) -
- -
- When pixel size ≤ threshold, clustering is disabled. Leave empty for - zoom-based detection. -
-
- )} - - ) -} - -export default ClusteringSettings diff --git a/src/components/Header.tsx b/src/components/Header.tsx index c6607c0e..b16e0608 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,9 +1,9 @@ import { ApiOutlined, + BugOutlined, CheckOutlined, FileSearchOutlined, InfoOutlined, - SettingOutlined, StopOutlined, UnorderedListOutlined, UserOutlined, @@ -29,6 +29,7 @@ import { NavLink } from 'react-router-dom' import { v4 as uuidv4 } from 'uuid' import appPackageJson from '../../package.json' import type { User } from '../auth' +import { SettingsButton } from '../contexts/SettingsContext' import type DicomWebManager from '../DicomWebManager' import NotificationMiddleware, { NotificationMiddlewareEvents, @@ -602,7 +603,7 @@ class Header extends React.Component { style={{ zIndex: 1001 }} >