Skip to content

Commit 79800a8

Browse files
committed
feat: enhance TecanDeckView to support dynamic labware types and improve layout handling
1 parent 35bdadd commit 79800a8

4 files changed

Lines changed: 179 additions & 221 deletions

File tree

src/TecanDeckView/TecanDeckView.tsx

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as React from 'react';
22

3+
import { Plate } from '../Plate';
34
import { PALETTE } from '../theme';
45

56
import { EmptyLabware } from './EmptyLabware';
@@ -13,13 +14,13 @@ import {
1314
LABWARE_METADATA,
1415
} from './labwareMetadata';
1516
import {
17+
Labware,
1618
LabwareConfig,
1719
LabwareKey,
1820
LabwareWithStyle,
1921
TecanLabwares,
2022
} from './types';
2123

22-
// Scaling constants for fit-to-width behavior
2324
const GRID_PADDING = 8;
2425
const GRID_GAP = 8;
2526
const COLUMN_COUNT = 5;
@@ -51,7 +52,6 @@ const LABWARE_ITEM_BASE_STYLE = {
5152
justifySelf: 'center',
5253
} as const;
5354

54-
// Shared style for columns that span all 3 grid rows
5555
const SPANNING_COLUMN_BASE_STYLE = {
5656
display: 'grid',
5757
alignSelf: 'center',
@@ -68,38 +68,27 @@ const RIGHT_COLUMN_STYLE = {
6868
gridArea: 'rightColumn',
6969
} as const;
7070

71-
// Helper functions for dynamic grid sizing
72-
73-
/**
74-
* Calculates dynamic grid-template-columns based on which columns have content.
75-
* Empty columns get minimal width (40-60px), filled columns get proportional sizes
76-
* matching physical Tecan deck dimensions (column 1: 0.5fr, columns 2-3: 1fr).
77-
*/
7871
function calculateGridTemplateColumns(labwares: TecanLabwares): string {
7972
const filledByColumn = getFilledLabwaresByColumn(labwares);
8073

8174
const columnSizes = [
82-
(filledByColumn[0]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)', // Column 0
83-
(filledByColumn[1]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)', // Column 1
84-
(filledByColumn[2]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)', // Column 2
85-
(filledByColumn[3]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)', // Column 3
86-
(filledByColumn[4]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)', // Column 4
75+
(filledByColumn[0]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)',
76+
(filledByColumn[1]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)',
77+
(filledByColumn[2]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)',
78+
(filledByColumn[3]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)',
79+
(filledByColumn[4]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)',
8780
];
8881

8982
return columnSizes.join(' ');
9083
}
9184

92-
/**
93-
* Calculates dynamic grid-template-rows based on which rows have content.
94-
* Empty rows get minimal height (40-60px), filled rows get auto.
95-
*/
9685
function calculateGridTemplateRows(labwares: TecanLabwares): string {
9786
const filledByRow = getFilledLabwaresByRow(labwares);
9887

9988
const rowSizes = [
100-
(filledByRow[0]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)', // Row 0
101-
(filledByRow[1]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)', // Row 1
102-
(filledByRow[2]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)', // Row 2
89+
(filledByRow[0]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)',
90+
(filledByRow[1]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)',
91+
(filledByRow[2]?.length ?? 0) > 0 ? 'auto' : 'minmax(40px, 60px)',
10392
];
10493

10594
return rowSizes.join(' ');
@@ -164,7 +153,7 @@ export function TecanDeckView({ labwares }: { labwares: TecanLabwares }) {
164153
const labware: LabwareWithStyle = {
165154
key,
166155
...metadata,
167-
content: labwares[key]?.content,
156+
labware: labwares[key],
168157
style: {
169158
...LABWARE_ITEM_BASE_STYLE,
170159
gridArea: key,
@@ -190,15 +179,36 @@ export function TecanDeckView({ labwares }: { labwares: TecanLabwares }) {
190179
);
191180
}, [labwares]);
192181

193-
const renderLabware = (labware: LabwareConfig) =>
194-
labware.content ? (
182+
const renderLabwareContent = (
183+
labware: Labware,
184+
coordinateSystem: LabwareConfig['coordinateSystem'],
185+
) => {
186+
if (labware.type === 'custom') {
187+
return labware.content;
188+
}
189+
190+
return (
191+
<Plate
192+
coordinateSystem={coordinateSystem}
193+
data={labware.data}
194+
loading={labware.loading}
195+
wellSizing={labware.wellSizing ?? 'compact'}
196+
/>
197+
);
198+
};
199+
200+
const renderLabware = (labwareConfig: LabwareConfig) =>
201+
labwareConfig.labware ? (
195202
<LabwareDetailItem
196-
shortLabel={labware.shortLabel}
197-
content={labware.content}
198-
backgroundColor={labware.color}
203+
shortLabel={labwareConfig.shortLabel}
204+
content={renderLabwareContent(
205+
labwareConfig.labware,
206+
labwareConfig.coordinateSystem,
207+
)}
208+
backgroundColor={labwareConfig.color}
199209
/>
200210
) : (
201-
<EmptyLabware shortLabel={labware.shortLabel} />
211+
<EmptyLabware shortLabel={labwareConfig.shortLabel} />
202212
);
203213

204214
return (

0 commit comments

Comments
 (0)