Skip to content

Commit 41606f6

Browse files
authored
Media view modes package (#1120)
1 parent 8fd3a11 commit 41606f6

File tree

35 files changed

+141
-162
lines changed

35 files changed

+141
-162
lines changed

web_ui/packages/ui/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ export { VirtualizedHorizontalGrid } from './src/virtualized-horizontal-grid/vir
149149
export { ToggleButtons } from './src/toggle-buttons/toggle-buttons.component';
150150
export { PhotoPlaceholder } from './src/photo-placeholder/photo-placeholder.component';
151151
export { FullscreenAction } from './src/fullscreen-action/fullscreen-action.component';
152+
export { MediaViewModes } from './src/view-modes/media-view-modes.component';
153+
export { ViewModes, INITIAL_VIEW_MODE, VIEW_MODE_LABEL } from './src/view-modes/utils';
154+
export { useViewMode } from './src/view-modes/use-view-mode.hook';
152155

153156
export {
154157
ListBox as AriaComponentsListBox,
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (C) 2022-2025 Intel Corporation
2+
// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
3+
4+
import { Dispatch, Key, SetStateAction } from 'react';
5+
6+
import { Item, Menu, MenuTrigger, Tooltip, TooltipTrigger } from '@adobe/react-spectrum';
7+
import { capitalize } from 'lodash-es';
8+
9+
import { Grid, GridMedium, GridSmall, List } from '../../icons';
10+
import { ActionButton } from '../button/button.component';
11+
import { VIEW_MODE_LABEL, ViewModes } from './utils';
12+
13+
const ITEMS = [ViewModes.LARGE, ViewModes.MEDIUM, ViewModes.SMALL, ViewModes.DETAILS];
14+
15+
const ICON_PER_MODE: Record<ViewModes, JSX.Element> = {
16+
[ViewModes.DETAILS]: <List />,
17+
[ViewModes.SMALL]: <GridSmall />,
18+
[ViewModes.MEDIUM]: <GridMedium />,
19+
[ViewModes.LARGE]: <Grid />,
20+
};
21+
22+
interface MediaViewModesProps {
23+
items?: ViewModes[];
24+
isDisabled?: boolean;
25+
viewMode: ViewModes;
26+
setViewMode: Dispatch<SetStateAction<ViewModes>>;
27+
}
28+
29+
export const MediaViewModes = ({ items = ITEMS, isDisabled = false, viewMode, setViewMode }: MediaViewModesProps) => {
30+
const handleAction = (key: Key): void => {
31+
const convertedKeyToViewMode = capitalize(String(key));
32+
33+
if (convertedKeyToViewMode === viewMode) {
34+
return;
35+
}
36+
37+
setViewMode(convertedKeyToViewMode as ViewModes);
38+
};
39+
40+
return (
41+
<MenuTrigger>
42+
<TooltipTrigger placement='bottom'>
43+
<ActionButton isQuiet isDisabled={isDisabled} aria-label='View mode'>
44+
{ICON_PER_MODE[viewMode]}
45+
</ActionButton>
46+
<Tooltip>{VIEW_MODE_LABEL}</Tooltip>
47+
</TooltipTrigger>
48+
<Menu
49+
items={items}
50+
selectionMode='single'
51+
onAction={handleAction}
52+
selectedKeys={[viewMode.toLocaleLowerCase()]}
53+
>
54+
{items.map((item: string) => (
55+
<Item key={item.toLocaleLowerCase()} aria-label={item.toLocaleLowerCase()} textValue={item}>
56+
{item}
57+
</Item>
58+
))}
59+
</Menu>
60+
</MenuTrigger>
61+
);
62+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (C) 2022-2025 Intel Corporation
2+
// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
3+
4+
import { useLocalStorage } from 'usehooks-ts';
5+
6+
import { INITIAL_VIEW_MODE, VIEW_MODE_KEY } from './utils';
7+
8+
const getMediaViewModeKey = (suffix: string) => {
9+
return `${VIEW_MODE_KEY}-${suffix}`;
10+
};
11+
12+
export const useViewMode = (suffix: string, defaultViewMode = INITIAL_VIEW_MODE) => {
13+
return useLocalStorage(getMediaViewModeKey(suffix), defaultViewMode);
14+
};

web_ui/src/shared/components/media-view-modes/utils.ts renamed to web_ui/packages/ui/src/view-modes/utils.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,4 @@ export enum ViewModes {
1010

1111
export const INITIAL_VIEW_MODE = ViewModes.MEDIUM;
1212
export const VIEW_MODE_LABEL = 'View mode';
13-
14-
export const VIEW_MODE_SETTINGS = {
15-
[ViewModes.LARGE]: { minItemSize: 300, gap: 12, maxColumns: 4 },
16-
[ViewModes.MEDIUM]: { minItemSize: 150, gap: 8, maxColumns: 8 },
17-
[ViewModes.SMALL]: { minItemSize: 112, gap: 4, maxColumns: 11 },
18-
[ViewModes.DETAILS]: { size: 81, gap: 0 },
19-
};
13+
export const VIEW_MODE_KEY = 'view-mode';

web_ui/src/hooks/use-view-mode/use-view-mode.hook.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

web_ui/src/pages/annotator/components/sidebar/dataset/annotator-dataset-list.component.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// Copyright (C) 2022-2025 Intel Corporation
22
// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
33

4+
import { ViewModes } from '@geti/ui';
5+
46
import { usePrevious } from '../../../../../hooks/use-previous/use-previous.hook';
5-
import { ViewModes } from '../../../../../shared/components/media-view-modes/utils';
67
import { useDataset } from '../../../providers/dataset-provider/dataset-provider.component';
78
import { useSelectedMediaItem } from '../../../providers/selected-media-item-provider/selected-media-item-provider.component';
89
import { useSelectMediaItemWithSaveConfirmation } from '../../../providers/submit-annotations-provider/use-select-media-item-with-save-confirmation.hook';

web_ui/src/pages/annotator/components/sidebar/dataset/dataset-accordion.component.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
44
import { CSSProperties, Dispatch, SetStateAction } from 'react';
55

66
import QUERY_KEYS from '@geti/core/src/requests/query-keys';
7-
import { Flex, View } from '@geti/ui';
7+
import { Flex, MediaViewModes, View, ViewModes } from '@geti/ui';
88
import { useQueryClient } from '@tanstack/react-query';
99

1010
import { isAnomalyDomain, isKeypointDetection } from '../../../../../core/projects/domains';
1111
import { TUTORIAL_CARD_KEYS } from '../../../../../core/user-settings/dtos/user-settings.interface';
1212
import { useSortingParams } from '../../../../../hooks/use-sorting-params/use-sorting-params.hook';
1313
import { Accordion } from '../../../../../shared/components/accordion/accordion.component';
14-
import { MediaViewModes } from '../../../../../shared/components/media-view-modes/media-view-modes.component';
15-
import { ViewModes } from '../../../../../shared/components/media-view-modes/utils';
1614
import { RefreshButton } from '../../../../../shared/components/refresh-button/refresh-button.component';
1715
import { TutorialCardBuilder } from '../../../../../shared/components/tutorial-card/tutorial-card-builder.component';
1816
import { MediaFilterChips } from '../../../../media/components/media-filter-chips.component';

web_ui/src/pages/annotator/components/sidebar/dataset/dataset-item-factory.component.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
// Copyright (C) 2022-2025 Intel Corporation
22
// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
33

4-
import { PressableElement, Tooltip, TooltipTrigger } from '@geti/ui';
4+
import { PressableElement, Tooltip, TooltipTrigger, ViewModes } from '@geti/ui';
55

66
import { MediaItem } from '../../../../../core/media/media.interface';
7-
import { ViewModes } from '../../../../../shared/components/media-view-modes/utils';
87
import { DatasetItemGridMenu } from './dataset-item-grid-menu.component';
98
import { DatasetItemMenu } from './dataset-item-menu.component';
109
import { DatasetListItemDetails } from './dataset-list-item-details.component';

web_ui/src/pages/annotator/components/sidebar/dataset/dataset-list.component.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33

44
import { useMemo } from 'react';
55

6-
import { Flex, Loading } from '@geti/ui';
6+
import { Flex, Loading, ViewModes } from '@geti/ui';
77
import { InfiniteData, UseInfiniteQueryResult } from '@tanstack/react-query';
88
import { isEmpty } from 'lodash-es';
99

1010
import { MediaAdvancedFilterResponse, MediaItem, MediaItemResponse } from '../../../../../core/media/media.interface';
1111
import { MediaItemsList } from '../../../../../shared/components/media-items-list/media-items-list.component';
12-
import { ViewModes } from '../../../../../shared/components/media-view-modes/utils';
1312
import { NotFound } from '../../../../../shared/components/not-found/not-found.component';
1413
import { useGroupedMediaItems } from '../../../../../shared/hooks/use-grouped-media-items.hook';
1514
import { useSelectedMediaItemIndex } from '../../../../../shared/hooks/use-selected-media-item-index.hook';

web_ui/src/pages/annotator/components/sidebar/dataset/dataset-list.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { screen, waitFor } from '@testing-library/react';
55

66
import { MEDIA_TYPE } from '../../../../../core/media/base-media.interface';
77
import { createInMemoryMediaService } from '../../../../../core/media/services/in-memory-media-service/in-memory-media-service';
8-
import { ViewModes } from '../../../../../shared/components/media-view-modes/utils';
98
import {
109
getMockedImageMediaItem,
1110
getMockedVideoFrameMediaItem,
@@ -15,6 +14,8 @@ import { annotatorRender as render } from '../../../test-utils/annotator-render'
1514

1615
import './../../../../../test-utils/mock-resize-observer';
1716

17+
import { ViewModes } from '@geti/ui';
18+
1819
import { AnnotatorDatasetList } from './annotator-dataset-list.component';
1920

2021
describe('AnnotatorDatasetList', () => {

0 commit comments

Comments
 (0)