Skip to content

Commit 7df3a3b

Browse files
authored
Improve Instance list panel design (#8573)
- Display Z order (from foreground to background) by default to match how visual tools work (beginners expect front-most object at top of list, matching Figma/Illustrator/Photoshop mental model). - Match the rest of the tokens to the updated brand design.
1 parent e325803 commit 7df3a3b

8 files changed

Lines changed: 210 additions & 117 deletions

File tree

newIDE/app/src/InstancesEditor/InstancesList/index.js

Lines changed: 148 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ import {
99
} from 'react-virtualized';
1010
import IconButton from '../../UI/IconButton';
1111
import KeyboardShortcuts from '../../UI/KeyboardShortcuts';
12-
import GDevelopThemeContext from '../../UI/Theme/GDevelopThemeContext';
1312
import CompactSearchBar from '../../UI/CompactSearchBar';
1413
import RemoveCircle from '../../UI/CustomSvgIcons/RemoveCircle';
1514
import Lock from '../../UI/CustomSvgIcons/Lock';
1615
import LockOpen from '../../UI/CustomSvgIcons/LockOpen';
16+
import RotateZ from '../../UI/CustomSvgIcons/RotateZ';
17+
import Layers from '../../UI/CustomSvgIcons/Layers';
18+
import SortArrowUp from '../../UI/CustomSvgIcons/SortArrowUp';
19+
import SortArrowDown from '../../UI/CustomSvgIcons/SortArrowDown';
1720
import { toFixedWithoutTrailingZeros } from '../../Utils/Mathematics';
1821
import ErrorBoundary from '../../UI/ErrorBoundary';
1922
import useForceUpdate from '../../Utils/UseForceUpdate';
@@ -46,11 +49,15 @@ const styles = {
4649
flexDirection: 'column',
4750
alignItems: 'stretch',
4851
minWidth: 0,
52+
// Search-bar band: matches the column-header band, kept distinct from the
53+
// alternating row colors so it stays stable when the rows change.
54+
backgroundColor: 'var(--table-header-background-color)',
4955
},
5056
tableContainer: {
5157
flex: 1,
5258
overflowX: 'auto',
5359
overflowY: 'hidden',
60+
backgroundColor: 'var(--table-header-background-color)',
5461
},
5562
};
5663

@@ -63,6 +70,40 @@ const compareStrings = (x: string, y: string, direction: number): number => {
6370
return 0;
6471
};
6572

73+
const renderSortableHeader = ({
74+
dataKey,
75+
label,
76+
sortBy,
77+
sortDirection,
78+
}: {
79+
dataKey: string,
80+
label: React.Node,
81+
sortBy: string,
82+
sortDirection: string,
83+
}) => {
84+
const isActive = dataKey === sortBy;
85+
return (
86+
<span
87+
style={{
88+
color: isActive
89+
? 'var(--theme-text-default-color)'
90+
: 'var(--table-text-color-header)',
91+
display: 'flex',
92+
alignItems: 'center',
93+
gap: 4,
94+
}}
95+
>
96+
{label}
97+
{isActive &&
98+
(sortDirection === 'ASC' ? (
99+
<SortArrowUp style={{ width: 12, height: 12, display: 'block' }} />
100+
) : (
101+
<SortArrowDown style={{ width: 12, height: 12, display: 'block' }} />
102+
))}
103+
</span>
104+
);
105+
};
106+
66107
export type InstancesListInterface = {|
67108
forceUpdate: () => void,
68109
|};
@@ -85,8 +126,8 @@ class InstancesList extends Component<Props, State> {
85126
// $FlowFixMe[missing-local-annot]
86127
state = {
87128
searchText: '',
88-
sortBy: '',
89-
sortDirection: SortDirection.ASC,
129+
sortBy: 'zOrder',
130+
sortDirection: SortDirection.DESC,
90131
};
91132
renderedRows: Array<RenderedRowInfo> = [];
92133
instanceRowRenderer: ?typeof gd.InitialInstanceJSFunctor;
@@ -118,7 +159,7 @@ class InstancesList extends Component<Props, State> {
118159
y: toFixedWithoutTrailingZeros(instance.getY(), 2),
119160
angle: toFixedWithoutTrailingZeros(instance.getAngle(), 2),
120161
layer: instance.getLayer(),
121-
zOrder: instance.getZOrder(),
162+
zOrder: String(instance.getZOrder()),
122163
});
123164
}
124165
};
@@ -250,112 +291,112 @@ class InstancesList extends Component<Props, State> {
250291
const tableKey = instances.ptr;
251292

252293
return (
253-
<GDevelopThemeContext.Consumer>
254-
{gdevelopTheme => (
255-
<div style={styles.container}>
256-
<Line>
257-
<Column expand noOverflowParent>
258-
<CompactSearchBar
259-
value={searchText}
260-
onChange={searchText =>
261-
this.setState({
262-
searchText,
263-
})
264-
}
265-
onRequestSearch={this._selectFirstInstance}
266-
placeholder={t`Search instances`}
294+
<div style={styles.container}>
295+
<Line>
296+
<Column expand noOverflowParent>
297+
<CompactSearchBar
298+
value={searchText}
299+
onChange={searchText =>
300+
this.setState({
301+
searchText,
302+
})
303+
}
304+
onRequestSearch={this._selectFirstInstance}
305+
placeholder={t`Search instances`}
306+
/>
307+
</Column>
308+
</Line>
309+
<div
310+
style={styles.tableContainer}
311+
onKeyDown={this._keyboardShortcuts.onKeyDown}
312+
onKeyUp={this._keyboardShortcuts.onKeyUp}
313+
>
314+
<AutoSizer>
315+
{({ height, width }) => (
316+
<RVTable
317+
ref={table => (this.table = table)}
318+
key={tableKey}
319+
headerHeight={30}
320+
height={height}
321+
className={`gd-table`}
322+
headerClassName={'tableHeaderColumn'}
323+
headerStyle={{
324+
backgroundColor: 'var(--table-header-background-color)',
325+
}}
326+
rowCount={this.renderedRows.length}
327+
rowGetter={this._rowGetter}
328+
rowHeight={32}
329+
onRowClick={this._onRowClick}
330+
rowClassName={this._rowClassName}
331+
sort={this._sort}
332+
sortBy={sortBy}
333+
sortDirection={sortDirection}
334+
width={Math.max(width, minimumWidths.table)}
335+
>
336+
<RVColumn
337+
label={<Trans>Object name</Trans>}
338+
dataKey="name"
339+
width={Math.max(width * 0.35, minimumWidths.objectName)}
340+
className={'tableColumn'}
341+
headerRenderer={renderSortableHeader}
267342
/>
268-
</Column>
269-
</Line>
270-
<div
271-
style={styles.tableContainer}
272-
onKeyDown={this._keyboardShortcuts.onKeyDown}
273-
onKeyUp={this._keyboardShortcuts.onKeyUp}
274-
>
275-
<AutoSizer>
276-
{({ height, width }) => (
277-
<RVTable
278-
ref={table => (this.table = table)}
279-
key={tableKey}
280-
headerHeight={30}
281-
height={height}
282-
className={`gd-table`}
283-
headerClassName={'tableHeaderColumn'}
284-
rowCount={this.renderedRows.length}
285-
rowGetter={this._rowGetter}
286-
rowHeight={32}
287-
onRowClick={this._onRowClick}
288-
rowClassName={this._rowClassName}
289-
sort={this._sort}
290-
sortBy={sortBy}
291-
sortDirection={sortDirection}
292-
width={Math.max(width, minimumWidths.table)}
293-
>
294-
<RVColumn
295-
label={<Trans>Object name</Trans>}
296-
dataKey="name"
297-
width={Math.max(width * 0.35, minimumWidths.objectName)}
298-
className={'tableColumn'}
299-
/>
300-
<RVColumn
301-
label=""
302-
dataKey="locked"
303-
width={Math.max(
304-
width * 0.05,
305-
minimumWidths.numberProperty
306-
)}
307-
className={'tableColumn'}
308-
cellRenderer={this._renderLockCell}
309-
/>
310-
<RVColumn
311-
label={<Trans>X</Trans>}
312-
dataKey="x"
313-
width={Math.max(
314-
width * 0.1,
315-
minimumWidths.numberProperty
316-
)}
317-
className={'tableColumn'}
318-
/>
319-
<RVColumn
320-
label={<Trans>Y</Trans>}
321-
dataKey="y"
322-
width={Math.max(
323-
width * 0.1,
324-
minimumWidths.numberProperty
325-
)}
326-
className={'tableColumn'}
327-
/>
328-
<RVColumn
329-
label={<Trans>Angle</Trans>}
330-
dataKey="angle"
331-
width={Math.max(
332-
width * 0.1,
333-
minimumWidths.numberProperty
334-
)}
335-
className={'tableColumn'}
336-
/>
337-
<RVColumn
338-
label={<Trans>Layer</Trans>}
339-
dataKey="layer"
340-
width={Math.max(width * 0.2, minimumWidths.layerName)}
341-
className={'tableColumn'}
343+
<RVColumn
344+
label={<Trans>X</Trans>}
345+
dataKey="x"
346+
width={Math.max(width * 0.1, minimumWidths.numberProperty)}
347+
className={'tableColumn tableColumnSecondary'}
348+
headerRenderer={renderSortableHeader}
349+
/>
350+
<RVColumn
351+
label={<Trans>Y</Trans>}
352+
dataKey="y"
353+
width={Math.max(width * 0.1, minimumWidths.numberProperty)}
354+
className={'tableColumn tableColumnSecondary'}
355+
headerRenderer={renderSortableHeader}
356+
/>
357+
<RVColumn
358+
label={<Trans>Z</Trans>}
359+
dataKey="zOrder"
360+
width={Math.max(width * 0.1, minimumWidths.numberProperty)}
361+
className={'tableColumn tableColumnSecondary'}
362+
headerRenderer={renderSortableHeader}
363+
/>
364+
<RVColumn
365+
label={
366+
<RotateZ
367+
titleAccess="Rotation (Z)"
368+
style={{ width: 18, height: 18, display: 'block' }}
342369
/>
343-
<RVColumn
344-
label={<Trans>Z Order</Trans>}
345-
dataKey="zOrder"
346-
width={Math.max(
347-
width * 0.1,
348-
minimumWidths.numberProperty
349-
)}
350-
className={'tableColumn'}
370+
}
371+
dataKey="angle"
372+
width={Math.max(width * 0.1, minimumWidths.numberProperty)}
373+
className={'tableColumn tableColumnSecondary'}
374+
headerRenderer={renderSortableHeader}
375+
/>
376+
<RVColumn
377+
label={
378+
<Layers
379+
titleAccess="Layer"
380+
style={{ width: 18, height: 18, display: 'block' }}
351381
/>
352-
</RVTable>
353-
)}
354-
</AutoSizer>
355-
</div>
356-
</div>
357-
)}
358-
</GDevelopThemeContext.Consumer>
382+
}
383+
dataKey="layer"
384+
width={Math.max(width * 0.2, minimumWidths.layerName)}
385+
className={'tableColumn tableColumnSecondary'}
386+
headerRenderer={renderSortableHeader}
387+
/>
388+
<RVColumn
389+
label=""
390+
dataKey="locked"
391+
width={Math.max(width * 0.05, minimumWidths.numberProperty)}
392+
className={'tableColumn'}
393+
cellRenderer={this._renderLockCell}
394+
/>
395+
</RVTable>
396+
)}
397+
</AutoSizer>
398+
</div>
399+
</div>
359400
);
360401
}
361402
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
import SvgIcon from '@material-ui/core/SvgIcon';
3+
4+
export default React.memo(props => (
5+
<SvgIcon {...props} width="12" height="12" viewBox="0 0 12 12" fill="none">
6+
<path
7+
d="M5.99996 2C6.20707 2 6.37496 2.16789 6.37496 2.375V8.68848L8.35348 6.61621C8.49642 6.46646 8.73393 6.4607 8.88375 6.60352C9.0335 6.74646 9.03926 6.98397 8.89644 7.13379L6.27144 9.88379C6.20068 9.95792 6.10244 10 5.99996 10C5.89748 10 5.79924 9.95792 5.72848 9.88379L3.10348 7.13379C2.96066 6.98397 2.96642 6.74646 3.11617 6.60352C3.26599 6.46069 3.5035 6.46646 3.64644 6.61621L5.62496 8.68848V2.375C5.62496 2.16789 5.79285 2 5.99996 2Z"
8+
fill="currentColor"
9+
/>
10+
</SvgIcon>
11+
));
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
import SvgIcon from '@material-ui/core/SvgIcon';
3+
4+
export default React.memo(props => (
5+
<SvgIcon {...props} width="12" height="12" viewBox="0 0 12 12" fill="none">
6+
<path
7+
d="M5.99996 10C6.20707 10 6.37496 9.83211 6.37496 9.625V3.31152L8.35348 5.38379C8.49642 5.53354 8.73393 5.5393 8.88375 5.39648C9.0335 5.25354 9.03926 5.01603 8.89644 4.86621L6.27144 2.11621C6.20068 2.04208 6.10244 2 5.99996 2C5.89748 2 5.79924 2.04208 5.72848 2.11621L3.10348 4.86621C2.96066 5.01603 2.96642 5.25354 3.11617 5.39648C3.26599 5.53931 3.5035 5.53354 3.64644 5.38379L5.62496 3.31152V9.625C5.62496 9.83211 5.79285 10 5.99996 10Z"
8+
fill="currentColor"
9+
/>
10+
</SvgIcon>
11+
));

newIDE/app/src/UI/EditorMosaic/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ const EditorMosaic: React.ComponentType<{
474474
<MosaicWindow
475475
path={path}
476476
title={i18n._(editor.title)}
477+
className={`mosaic-editor-${editorName}`}
477478
onDragStart={onDragOrResizedStarted}
478479
onDragEnd={onDragOrResizedEnded}
479480
toolbarControls={

newIDE/app/src/UI/Theme/DefaultDarkTheme/theme.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -959,15 +959,20 @@
959959
"value": "#D6DEEC"
960960
}
961961
},
962+
"header": {
963+
"background-color": {
964+
"value": "#25252E"
965+
}
966+
},
962967
"row": {
963968
"odd": {
964969
"background-color": {
965-
"value": "#282C34"
970+
"value": "#23232A"
966971
}
967972
},
968973
"even": {
969974
"background-color": {
970-
"value": "#21252B"
975+
"value": "#1D1D26"
971976
}
972977
},
973978
"selected": {

0 commit comments

Comments
 (0)