Refactor layout to integrate right-side stack panel with improved hover and pinning functionality

This commit is contained in:
Ross
2025-09-22 10:26:49 +01:00
parent 6ab976a82b
commit 67329d0468
+106 -17
View File
@@ -3582,25 +3582,114 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer
</div>
{/* Viewport grid (inside main div) */}
<div
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
display: "grid",
margin: 3,
gridTemplateRows: `repeat(${viewportGrid.rows}, 1fr)`,
gridTemplateColumns: `repeat(${viewportGrid.cols}, 1fr)`,
gap: "5px", // Increase gap for better visibility
zIndex: 1,
}}
>
{viewports}
{/* Main content area: viewports and right-side panel in a row so panel pushes content */}
<div style={{ display: 'flex', flexDirection: 'row', height: 'calc(100% - 48px)', gap: 8 }}>
{/* Viewport grid container — flex:1 so it shrinks when panel takes space */}
<div
style={{
flex: 1,
display: 'grid',
margin: 3,
gridTemplateRows: `repeat(${viewportGrid.rows}, 1fr)`,
gridTemplateColumns: `repeat(${viewportGrid.cols}, 1fr)`,
gap: '5px',
minHeight: 0,
minWidth: 0,
zIndex: 1,
position: 'relative',
}}
>
{viewports}
</div>
{/* Right-side panel occupies layout space when visible or pinned */}
<div style={{ width: stackPanelPinned || stackPanelHover ? 320 : 28, transition: 'width 220ms ease', display: 'flex', flexDirection: 'column', pointerEvents: 'none' }}>
{/* Reuse the existing right-side panel markup but ensure pointerEvents are enabled inside */}
<div style={{ pointerEvents: 'auto', width: '100%', height: '100%' }}>
{/* Panel (same content as before) */}
<div
onMouseEnter={() => setStackPanelHover(true)}
onMouseLeave={() => setStackPanelHover(false)}
style={{
height: '100%',
width: '100%',
background: '#1f2428',
color: '#fff',
boxShadow: '0 2px 14px rgba(0,0,0,0.45)',
borderLeft: '1px solid #2f3336',
transform: 'translateX(0)',
transition: 'transform 220ms ease',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
}}
>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 12px', borderBottom: '1px solid #2b2f31' }}>
<div style={{ fontWeight: 700 }}>Stacks</div>
<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
<button
title={stackPanelPinned ? 'Unpin panel' : 'Pin panel'}
onClick={() => setStackPanelPinned(p => !p)}
style={{ background: stackPanelPinned ? '#1976d2' : '#333', color: '#fff', border: 'none', padding: '6px 8px', borderRadius: 4, cursor: 'pointer' }}
>
{stackPanelPinned ? 'Pinned' : 'Pin'}
</button>
<button
title="Close"
onClick={() => { setStackPanelPinned(false); setStackPanelHover(false); }}
style={{ background: 'transparent', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 18 }}
>
×
</button>
</div>
</div>
<div style={{ overflowY: 'auto', padding: 8, flex: 1 }}>
{availableStacks.length === 0 ? (
<div style={{ color: '#999', padding: 12 }}>No stacks available</div>
) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
{availableStacks.map((stack, idx) => {
const imageIds = Array.isArray(stack.imageIds) ? stack.imageIds : [];
const label = stack.name || (stack.caseId ? `Case: ${stack.caseId}` : `Stack ${idx + 1}`);
const count = imageIds.length;
const invalid = !Array.isArray(imageIds) || count === 0;
const isSelected = selectedStackIdx.includes(idx);
return (
<div
key={idx}
draggable={!invalid}
onDragStart={e => {
if (invalid) return;
e.dataTransfer.setData('text/stack-idx', String(idx));
e.dataTransfer.effectAllowed = 'copy';
}}
onClick={() => { if (!invalid) handleLoadStack(0, idx); }}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '8px 10px',
background: isSelected ? '#1976d2' : 'transparent',
color: isSelected ? '#fff' : '#ddd',
borderRadius: 6,
cursor: invalid ? 'not-allowed' : 'pointer',
}}
>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<div style={{ fontWeight: 600 }}>{label}</div>
<div style={{ fontSize: 12, opacity: 0.7 }}>{count} img{count === 1 ? '' : 's'}</div>
</div>
<div style={{ fontSize: 12, opacity: 0.8 }}>{stack.studyId || ''}</div>
</div>
);
})}
</div>
)}
</div>
</div>
</div>
</div>
</div>