@griddo/ax 11.4.24 → 11.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/package.json +2 -2
  2. package/src/__tests__/components/Fields/ImageField/ImageField.test.tsx +52 -34
  3. package/src/api/folders.tsx +62 -0
  4. package/src/api/images.tsx +159 -1
  5. package/src/api/index.tsx +2 -0
  6. package/src/api/sites.tsx +1 -1
  7. package/src/components/Fields/ImageField/index.tsx +7 -6
  8. package/src/components/Fields/Wysiwyg/index.tsx +5 -3
  9. package/src/components/FileGallery/index.tsx +22 -16
  10. package/src/components/FileGallery/style.tsx +18 -4
  11. package/src/components/Gallery/FolderItem/index.tsx +39 -0
  12. package/src/components/Gallery/FolderItem/style.tsx +31 -0
  13. package/src/components/Gallery/GalleryPanel/DetailPanel/index.tsx +112 -237
  14. package/src/components/Gallery/GalleryPanel/DetailPanel/style.tsx +77 -61
  15. package/src/components/Gallery/GalleryPanel/index.tsx +37 -32
  16. package/src/components/Gallery/GalleryPanel/style.tsx +1 -0
  17. package/src/components/Gallery/index.tsx +267 -163
  18. package/src/components/Gallery/style.tsx +200 -135
  19. package/src/components/Loading/index.tsx +7 -2
  20. package/src/components/Loading/style.tsx +2 -2
  21. package/src/components/TableFilters/StateFilter/index.tsx +1 -1
  22. package/src/containers/FileDrive/actions.tsx +1 -2
  23. package/src/containers/FileDrive/interfaces.tsx +3 -3
  24. package/src/containers/Gallery/actions.tsx +359 -13
  25. package/src/containers/Gallery/constants.tsx +12 -0
  26. package/src/containers/Gallery/interfaces.tsx +44 -1
  27. package/src/containers/Gallery/reducer.tsx +27 -3
  28. package/src/containers/Sites/actions.tsx +2 -2
  29. package/src/containers/Users/actions.tsx +9 -6
  30. package/src/helpers/files.tsx +37 -1
  31. package/src/helpers/index.tsx +3 -1
  32. package/src/modules/App/Routing/NavMenu/NavItem/NavSubItem/style.tsx +7 -2
  33. package/src/modules/App/Routing/NavMenu/index.tsx +2 -1
  34. package/src/modules/FileDrive/FileFilters/SortBy/style.tsx +3 -0
  35. package/src/modules/FileDrive/FileModal/DetailPanel/UsageContent/index.tsx +1 -1
  36. package/src/modules/FileDrive/FolderTree/MenuItem/index.tsx +14 -10
  37. package/src/modules/FileDrive/FolderTree/MenuItem/style.tsx +8 -1
  38. package/src/modules/FileDrive/FolderTree/MenuList/index.tsx +9 -2
  39. package/src/modules/FileDrive/index.tsx +45 -28
  40. package/src/modules/FileDrive/style.tsx +7 -6
  41. package/src/modules/GlobalEditor/index.tsx +1 -1
  42. package/src/modules/MediaGallery/Breadcrumb/index.tsx +42 -0
  43. package/src/modules/MediaGallery/Breadcrumb/style.tsx +18 -0
  44. package/src/modules/MediaGallery/BulkGridHeader/GridHeader/index.tsx +37 -0
  45. package/src/modules/MediaGallery/BulkGridHeader/GridHeader/style.tsx +19 -0
  46. package/src/modules/MediaGallery/BulkGridHeader/index.tsx +35 -0
  47. package/src/modules/MediaGallery/BulkGridHeader/style.tsx +17 -0
  48. package/src/modules/MediaGallery/BulkListHeader/TableHeader/index.tsx +46 -0
  49. package/src/modules/MediaGallery/BulkListHeader/TableHeader/style.tsx +53 -0
  50. package/src/modules/MediaGallery/BulkListHeader/index.tsx +42 -0
  51. package/src/modules/MediaGallery/BulkListHeader/style.tsx +17 -0
  52. package/src/modules/MediaGallery/FolderItem/index.tsx +191 -0
  53. package/src/modules/MediaGallery/FolderItem/style.tsx +39 -0
  54. package/src/modules/MediaGallery/FolderTree/MenuItem/index.tsx +87 -0
  55. package/src/modules/MediaGallery/FolderTree/MenuItem/style.tsx +76 -0
  56. package/src/modules/MediaGallery/FolderTree/MenuList/index.tsx +34 -0
  57. package/src/modules/MediaGallery/FolderTree/index.tsx +62 -0
  58. package/src/modules/MediaGallery/FolderTree/style.tsx +49 -0
  59. package/src/modules/MediaGallery/GridItem/index.tsx +149 -0
  60. package/src/modules/MediaGallery/GridItem/style.tsx +74 -0
  61. package/src/modules/MediaGallery/ImageDragAndDrop/index.tsx +299 -0
  62. package/src/{components/Gallery/GalleryPanel/GalleryDragAndDrop → modules/MediaGallery/ImageDragAndDrop}/style.tsx +114 -33
  63. package/src/{components/Gallery/GalleryFilters → modules/MediaGallery/ImageFilters}/Orientation/style.tsx +2 -1
  64. package/src/{components/Gallery/GalleryFilters → modules/MediaGallery/ImageFilters}/SortBy/style.tsx +3 -0
  65. package/src/{components/Gallery/GalleryFilters → modules/MediaGallery/ImageFilters}/Type/style.tsx +1 -0
  66. package/src/modules/MediaGallery/ImageFilters/Usage/index.tsx +75 -0
  67. package/src/modules/MediaGallery/ImageFilters/Usage/style.tsx +30 -0
  68. package/src/modules/MediaGallery/ImageModal/DetailPanel/UsageContent/Item/index.tsx +35 -0
  69. package/src/modules/MediaGallery/ImageModal/DetailPanel/UsageContent/Item/style.tsx +43 -0
  70. package/src/modules/MediaGallery/ImageModal/DetailPanel/UsageContent/ItemGroup/index.tsx +44 -0
  71. package/src/modules/MediaGallery/ImageModal/DetailPanel/UsageContent/ItemGroup/style.tsx +34 -0
  72. package/src/modules/MediaGallery/ImageModal/DetailPanel/UsageContent/index.tsx +233 -0
  73. package/src/modules/MediaGallery/ImageModal/DetailPanel/UsageContent/style.tsx +21 -0
  74. package/src/modules/MediaGallery/ImageModal/DetailPanel/index.tsx +209 -0
  75. package/src/modules/MediaGallery/ImageModal/DetailPanel/style.tsx +81 -0
  76. package/src/modules/MediaGallery/ImageModal/index.tsx +168 -0
  77. package/src/modules/MediaGallery/ImageModal/style.tsx +106 -0
  78. package/src/modules/MediaGallery/ListItem/index.tsx +181 -0
  79. package/src/modules/MediaGallery/ListItem/style.tsx +100 -0
  80. package/src/modules/MediaGallery/UploadItem/index.tsx +32 -0
  81. package/src/modules/MediaGallery/UploadItem/style.tsx +42 -0
  82. package/src/modules/MediaGallery/atoms.tsx +196 -0
  83. package/src/{components/Gallery → modules/MediaGallery}/hooks.tsx +10 -4
  84. package/src/modules/MediaGallery/index.tsx +892 -0
  85. package/src/modules/MediaGallery/style.tsx +216 -0
  86. package/src/{components/Gallery → modules/MediaGallery}/utils.tsx +1 -1
  87. package/src/modules/StructuredData/Form/index.tsx +2 -2
  88. package/src/routes/multisite.tsx +24 -4
  89. package/src/routes/site.tsx +24 -4
  90. package/src/types/files.tsx +98 -0
  91. package/src/types/index.tsx +33 -91
  92. package/src/__tests__/components/Gallery/Gallery.test.tsx +0 -559
  93. package/src/__tests__/components/Gallery/GalleryFilters/Orientation/Orientation.test.tsx +0 -54
  94. package/src/__tests__/components/Gallery/GalleryFilters/SortBy/SortBy.test.tsx +0 -118
  95. package/src/__tests__/components/Gallery/GalleryFilters/Type/Type.test.tsx +0 -54
  96. package/src/__tests__/components/Gallery/GalleryPanel/DetailPanel/DetailPanel.test.tsx +0 -869
  97. package/src/__tests__/components/Gallery/GalleryPanel/GalleryDragAndDrop/GalleryDragAndDrop.test.tsx +0 -249
  98. package/src/__tests__/components/Gallery/GalleryPanel/GalleryPanel.test.tsx +0 -55
  99. package/src/components/Gallery/GalleryPanel/GalleryDragAndDrop/index.tsx +0 -239
  100. package/src/containers/FileDrive/utils.tsx +0 -37
  101. /package/src/{components/Gallery/GalleryFilters → modules/MediaGallery/ImageFilters}/Orientation/index.tsx +0 -0
  102. /package/src/{components/Gallery/GalleryFilters → modules/MediaGallery/ImageFilters}/SortBy/index.tsx +0 -0
  103. /package/src/{components/Gallery/GalleryFilters → modules/MediaGallery/ImageFilters}/Type/index.tsx +0 -0
@@ -0,0 +1,42 @@
1
+ import React from "react";
2
+ import { IBulkAction } from "@ax/types";
3
+
4
+ import TableHeader from "./TableHeader";
5
+
6
+ import * as S from "./style";
7
+
8
+ const BulkListHeader = (props: IBulkHeaderProps): JSX.Element => {
9
+ const { showBulk, checkState, selectItems, selectAllItems, totalItems, bulkActions, setHoverCheck } = props;
10
+
11
+ return showBulk ? (
12
+ <S.BulkWrapper>
13
+ <S.StyledBulkSelectionOptions
14
+ isScrolling={false}
15
+ checkState={checkState}
16
+ actions={bulkActions}
17
+ selectItems={selectItems}
18
+ totalItems={totalItems}
19
+ />
20
+ </S.BulkWrapper>
21
+ ) : (
22
+ <TableHeader
23
+ isScrolling={false}
24
+ selectAllItems={selectAllItems}
25
+ checkState={checkState}
26
+ totalItems={totalItems}
27
+ setHoverCheck={setHoverCheck}
28
+ />
29
+ );
30
+ };
31
+
32
+ export interface IBulkHeaderProps {
33
+ showBulk: boolean;
34
+ checkState: any;
35
+ selectItems: () => void;
36
+ selectAllItems: () => void;
37
+ totalItems: number;
38
+ bulkActions: IBulkAction[];
39
+ setHoverCheck: (state: boolean) => void;
40
+ }
41
+
42
+ export default BulkListHeader;
@@ -0,0 +1,17 @@
1
+ import styled from "styled-components";
2
+ import { BulkSelectionOptions } from "@ax/components";
3
+
4
+ const BulkWrapper = styled.div`
5
+ width: 100%;
6
+ span {
7
+ margin-left: ${(p) => p.theme.spacing.xs};
8
+ }
9
+ `;
10
+
11
+ const StyledBulkSelectionOptions = styled(BulkSelectionOptions)`
12
+ padding: ${(p) => `0 0 ${p.theme.spacing.m} 0`};
13
+ margin-top: ${(p) => `-${p.theme.spacing.xs}`};
14
+ margin-bottom: ${(p) => `-${p.theme.spacing.xs}`};
15
+ `;
16
+
17
+ export { BulkWrapper, StyledBulkSelectionOptions }
@@ -0,0 +1,191 @@
1
+ import React, { useState } from "react";
2
+ import { connect } from "react-redux";
3
+
4
+ import { IActionMenuOption, IFolder, IGetFolderParams } from "@ax/types";
5
+ import { Icon, Tooltip } from "@ax/components";
6
+ import { useModal } from "@ax/hooks";
7
+ import { galleryActions } from "@ax/containers/Gallery";
8
+ import { DeleteFolderModal, MoveItemModal, RenameFolderModal } from "../atoms";
9
+ import { trimText } from "@ax/helpers";
10
+
11
+ import * as S from "./style";
12
+
13
+ const FolderItem = (props: IProps) => {
14
+ const {
15
+ folder,
16
+ isAllowedToDelete,
17
+ isAllowedToEdit,
18
+ isAllowedToMove,
19
+ onClick,
20
+ onDelete,
21
+ toggleToast,
22
+ getParams,
23
+ updateFolder,
24
+ } = props;
25
+ const { id, folderName, parentId } = folder;
26
+
27
+ const initState = { folderName, parentId };
28
+ const [folderForm, setFolderForm] = useState(initState);
29
+ const { isOpen: isDeleteOpen, toggleModal: toggleDeleteModal } = useModal();
30
+ const { isOpen: isRenameOpen, toggleModal: toggleRenameModal } = useModal();
31
+ const { isOpen: isMoveOpen, toggleModal: toggleMoveModal } = useModal();
32
+
33
+ const setName = (name: string) => setFolderForm({ ...folderForm, folderName: name });
34
+ const setParent = (folderID: number) => setFolderForm({ ...folderForm, parentId: folderID });
35
+
36
+ let menuOptions: IActionMenuOption[] = [];
37
+
38
+ if (isAllowedToEdit) {
39
+ menuOptions = [
40
+ {
41
+ label: "Rename",
42
+ icon: "edit",
43
+ action: () => toggleRenameModal(),
44
+ },
45
+ ];
46
+
47
+ if (isAllowedToMove) {
48
+ menuOptions = [
49
+ ...menuOptions,
50
+ {
51
+ label: "Move to...",
52
+ icon: "change",
53
+ action: () => toggleMoveModal(),
54
+ },
55
+ ];
56
+ }
57
+ }
58
+
59
+ if (isAllowedToDelete) {
60
+ menuOptions = [
61
+ ...menuOptions,
62
+ {
63
+ label: "Delete",
64
+ icon: "delete",
65
+ action: () => toggleDeleteModal(),
66
+ },
67
+ ];
68
+ }
69
+
70
+ const handleClick = () => onClick(id);
71
+
72
+ const handleDeleteFolder = () => {
73
+ onDelete(folder);
74
+ isDeleteOpen && toggleDeleteModal();
75
+ };
76
+
77
+ const handleUpdateFolder = async (toast = false) => {
78
+ const params = getParams();
79
+ const updated = await updateFolder(
80
+ id,
81
+ { parentId: folderForm.parentId, folderName: folderForm.folderName },
82
+ params
83
+ );
84
+ if (updated) {
85
+ isRenameOpen && toggleRenameModal();
86
+ toast && toggleToast("1 Folder moved to another folder");
87
+ }
88
+ };
89
+
90
+ const handleModalClose = () => {
91
+ setFolderForm(initState);
92
+ isMoveOpen && toggleMoveModal();
93
+ isRenameOpen && toggleRenameModal();
94
+ };
95
+
96
+ const mainDeleteModalAction = {
97
+ title: "Delete Folder",
98
+ onClick: () => handleDeleteFolder(),
99
+ };
100
+
101
+ const secondaryDeleteModalAction = { title: "Cancel", onClick: toggleDeleteModal };
102
+
103
+ const mainRenameModalAction = {
104
+ title: "Rename Folder",
105
+ onClick: () => handleUpdateFolder(),
106
+ disabled: folderForm.folderName.trim().length === 0,
107
+ };
108
+
109
+ const secondaryRenameModalAction = { title: "Cancel", onClick: handleModalClose };
110
+
111
+ const mainMoveModalAction = {
112
+ title: "Move",
113
+ onClick: () => handleUpdateFolder(true),
114
+ };
115
+
116
+ const secondaryMoveModalAction = { title: "Cancel", onClick: handleModalClose };
117
+
118
+ const FolderTitle = () =>
119
+ folderName.length > 15 ? (
120
+ <Tooltip content={folderName}>
121
+ <S.Title>{trimText(folderName, 15)}</S.Title>
122
+ </Tooltip>
123
+ ) : (
124
+ <S.Title>{folderName}</S.Title>
125
+ );
126
+
127
+ return (
128
+ <>
129
+ <S.Wrapper onClick={handleClick}>
130
+ <S.IconWrapper>
131
+ <Icon name="project" size="24" />
132
+ </S.IconWrapper>
133
+ <FolderTitle />
134
+ <S.StyledActionMenu icon="more" options={menuOptions} tooltip="File actions" />
135
+ </S.Wrapper>
136
+ {isDeleteOpen && (
137
+ <DeleteFolderModal
138
+ isOpen={isDeleteOpen}
139
+ toggleModal={toggleDeleteModal}
140
+ mainModalAction={mainDeleteModalAction}
141
+ secondaryModalAction={secondaryDeleteModalAction}
142
+ title={folderName}
143
+ />
144
+ )}
145
+ {isRenameOpen && (
146
+ <RenameFolderModal
147
+ isOpen={isRenameOpen}
148
+ toggleModal={handleModalClose}
149
+ mainModalAction={mainRenameModalAction}
150
+ secondaryModalAction={secondaryRenameModalAction}
151
+ value={folderForm.folderName}
152
+ setValue={setName}
153
+ />
154
+ )}
155
+ {isMoveOpen && (
156
+ <MoveItemModal
157
+ isOpen={isMoveOpen}
158
+ toggleModal={handleModalClose}
159
+ mainModalAction={mainMoveModalAction}
160
+ secondaryModalAction={secondaryMoveModalAction}
161
+ folder={folderForm.parentId}
162
+ setFolder={setParent}
163
+ hidden={[folder.id]}
164
+ hideRoot={!parentId}
165
+ />
166
+ )}
167
+ </>
168
+ );
169
+ };
170
+
171
+ interface IProps {
172
+ folder: IFolder;
173
+ isAllowedToEdit: boolean;
174
+ isAllowedToDelete: boolean;
175
+ isAllowedToMove: boolean;
176
+ onClick(folderID: number): void;
177
+ onDelete(folder: IFolder): void;
178
+ toggleToast(state: string): void;
179
+ getParams(): IGetFolderParams;
180
+ updateFolder(
181
+ folderID: number,
182
+ data: { parentId?: number; folderName: string },
183
+ params: IGetFolderParams
184
+ ): Promise<boolean>;
185
+ }
186
+
187
+ const mapDispatchToProps = {
188
+ updateFolder: galleryActions.updateFolder,
189
+ };
190
+
191
+ export default connect(null, mapDispatchToProps)(FolderItem);
@@ -0,0 +1,39 @@
1
+ import styled from "styled-components";
2
+ import { ActionMenu } from "@ax/components";
3
+
4
+ const Wrapper = styled.div`
5
+ position: relative;
6
+ background-color: ${(p) => p.theme.color.uiBackground02};
7
+ border: ${(p) => `1px solid ${p.theme.color.uiLine}`};
8
+ border-radius: ${p => p.theme.radii.s};
9
+ display: flex;
10
+ align-items: center;
11
+ min-width: 220px;
12
+ max-width: 280px;
13
+ height: 64px;
14
+ cursor: pointer;
15
+ &:hover {
16
+ background-color: ${(p) => p.theme.color.overlayHoverPrimary};
17
+ }
18
+ `;
19
+
20
+ const IconWrapper = styled.div`
21
+ width: 24px;
22
+ height: 24px;
23
+ margin-left: ${(p) => p.theme.spacing.m};
24
+ `;
25
+
26
+ const Title = styled.div`
27
+ ${(p) => p.theme.textStyle.uiL};
28
+ color: ${(p) => p.theme.colors.textHighEmphasis};
29
+ margin-left: ${(p) => p.theme.spacing.xs};
30
+ `;
31
+
32
+ const StyledActionMenu = styled(ActionMenu)`
33
+ width: 32px;
34
+ display: flex;
35
+ margin-left: auto;
36
+ margin-right: ${(p) => p.theme.spacing.xs};
37
+ `;
38
+
39
+ export { Wrapper, IconWrapper, Title, StyledActionMenu };
@@ -0,0 +1,87 @@
1
+ import React, { useState } from "react";
2
+ import MenuList from "../MenuList";
3
+ import { IFolderTree } from "@ax/types";
4
+ import { Icon } from "@ax/components";
5
+ import { trimText } from "@ax/helpers";
6
+
7
+ import * as S from "./style";
8
+
9
+ const MenuItem = (props: IMenuItem) => {
10
+ const { item, trimNames, folderID, hidden, createAction, onClick } = props;
11
+ const { id, name } = item;
12
+
13
+ const [isExpanded, setIsExpanded] = useState(true);
14
+
15
+ const hasChildren =
16
+ item.children &&
17
+ item.children.filter((listItem) => !hidden || (hidden && !hidden.includes(listItem.id))).length > 0;
18
+
19
+ const handleToggle = (e: React.MouseEvent<HTMLDivElement>) => {
20
+ e.stopPropagation();
21
+ setIsExpanded((prev) => !prev);
22
+ };
23
+
24
+ const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
25
+ e.stopPropagation();
26
+ onClick(id);
27
+ };
28
+
29
+ const getIcon = (item: IFolderTree) => {
30
+ if (item.children && item.children.length > 0) {
31
+ return isExpanded ? <Icon name="DownArrow" size="16" /> : <Icon name="RightArrow" size="16" />;
32
+ } else {
33
+ return <></>;
34
+ }
35
+ };
36
+
37
+ const NewFolderButton = () =>
38
+ createAction ? (
39
+ <S.NewIconWrapper onClick={createAction}>
40
+ <Icon name="newFolder" size="16" />
41
+ </S.NewIconWrapper>
42
+ ) : (
43
+ <></>
44
+ );
45
+
46
+ if (hidden?.includes(id)) {
47
+ return <></>;
48
+ }
49
+
50
+ return (
51
+ <li>
52
+ <S.ItemWrapper>
53
+ <S.Item onClick={handleClick} selected={folderID === item.id}>
54
+ {hasChildren && <S.ArrowWrapper onClick={handleToggle}>{getIcon(item)}</S.ArrowWrapper>}
55
+ <S.IconWrapper>
56
+ <Icon name="project" size="16" />
57
+ </S.IconWrapper>
58
+ <S.Name>{trimNames ? trimText(name, 15) : name}</S.Name>
59
+ <NewFolderButton />
60
+ </S.Item>
61
+ </S.ItemWrapper>
62
+ {hasChildren && isExpanded && (
63
+ <S.ListWrapper>
64
+ <MenuList
65
+ list={item.children}
66
+ hidden={hidden}
67
+ trimNames={trimNames}
68
+ createAction={createAction}
69
+ folderID={folderID}
70
+ onClick={onClick}
71
+ />
72
+ </S.ListWrapper>
73
+ )}
74
+ </li>
75
+ );
76
+ };
77
+
78
+ interface IMenuItem {
79
+ item: IFolderTree;
80
+ folderID: number | null;
81
+ trimNames?: boolean;
82
+ hidden?: number[];
83
+ onClick(folderID: number): void;
84
+ createAction?(): void;
85
+ }
86
+
87
+ export default MenuItem;
@@ -0,0 +1,76 @@
1
+ import styled from "styled-components";
2
+
3
+ const ItemWrapper = styled.div``;
4
+
5
+ const NewIconWrapper = styled.div`
6
+ width: 16px;
7
+ height: 16px;
8
+ margin-left: auto;
9
+ `;
10
+
11
+ const Item = styled.div<{ selected: boolean }>`
12
+ display: flex;
13
+ width: 100%;
14
+ margin-bottom: ${(p) => p.theme.spacing.xxs};
15
+ align-items: center;
16
+ cursor: pointer;
17
+ padding: ${(p) => `${p.theme.spacing.xxs} ${p.theme.spacing.xs}`};
18
+ border-radius: ${(p) => p.theme.radii.s};
19
+ background-color: ${(p) => (p.selected ? p.theme.color.overlayPressedPrimary : "transparent")};
20
+ height: 32px;
21
+ overflow: hidden;
22
+ flex-shrink: 0;
23
+ &:hover {
24
+ background-color: ${(p) => (p.selected ? p.theme.color.overlayPressedPrimary : p.theme.color.overlayHoverPrimary)};
25
+ }
26
+ ${NewIconWrapper} {
27
+ opacity: ${(p) => (p.selected ? "1" : "0")};
28
+ }
29
+ `;
30
+
31
+ const Name = styled.div`
32
+ ${(p) => p.theme.textStyle.uiS};
33
+ color: ${(p) => p.theme.color.textMediumEmphasis};
34
+ margin-left: ${(p) => p.theme.spacing.xs};
35
+ flex: 1;
36
+ white-space: nowrap;
37
+ overflow: hidden;
38
+ text-overflow: ellipsis;
39
+ `;
40
+
41
+ const RootName = styled.div`
42
+ ${(p) => p.theme.textStyle.uiM};
43
+ color: ${(p) => p.theme.color.textHighEmphasis};
44
+ white-space: nowrap;
45
+ `;
46
+
47
+ const IconWrapper = styled.div`
48
+ width: 16px;
49
+ height: 16px;
50
+ svg {
51
+ path {
52
+ fill: ${(p) => p.theme.color.iconMediumEmphasis};
53
+ }
54
+ }
55
+ `;
56
+
57
+ const ArrowWrapper = styled.div`
58
+ width: 16px;
59
+ height: 16px;
60
+ margin-right: ${(p) => p.theme.spacing.xxs};
61
+ white-space: nowrap;
62
+ flex-shrink: 0;
63
+ `;
64
+
65
+ const Title = styled.div`
66
+ ${(p) => p.theme.textStyle.uiM};
67
+ color: ${(p) => p.theme.color.textMediumEmphasis};
68
+ margin-top: ${(p) => p.theme.spacing.xs};
69
+ margin-bottom: ${(p) => p.theme.spacing.xs};
70
+ `;
71
+
72
+ const ListWrapper = styled.div`
73
+ padding-left: ${(p) => `calc(${p.theme.spacing.s} * 2)`};
74
+ `;
75
+
76
+ export { ItemWrapper, Item, Name, RootName, IconWrapper, ArrowWrapper, Title, NewIconWrapper, ListWrapper };
@@ -0,0 +1,34 @@
1
+ import React from "react";
2
+ import { IFolderTree } from "@ax/types";
3
+ import MenuItem from "../MenuItem";
4
+
5
+ const MenuList = (props: IMenuListProps) => {
6
+ const { list, folderID, hidden, trimNames, createAction, onClick } = props;
7
+
8
+ return (
9
+ <ul>
10
+ {list.map((listItem) => (
11
+ <MenuItem
12
+ key={listItem.id}
13
+ item={listItem}
14
+ onClick={onClick}
15
+ folderID={folderID}
16
+ createAction={createAction}
17
+ hidden={hidden}
18
+ trimNames={trimNames}
19
+ />
20
+ ))}
21
+ </ul>
22
+ );
23
+ };
24
+
25
+ interface IMenuListProps {
26
+ list: IFolderTree[];
27
+ folderID: number | null;
28
+ hidden?: number[];
29
+ trimNames?: boolean;
30
+ createAction?(): void;
31
+ onClick(folderID: number): void;
32
+ }
33
+
34
+ export default MenuList;
@@ -0,0 +1,62 @@
1
+ import React from "react";
2
+ import { connect } from "react-redux";
3
+
4
+ import { IFolderTree, IRootState } from "@ax/types";
5
+ import { Icon } from "@ax/components";
6
+
7
+ import MenuList from "./MenuList";
8
+ import * as S from "./style";
9
+
10
+ const FolderTree = (props: IProps) => {
11
+ const { folders, folderID, title, hidden, hideRoot, trimNames, createAction, onClick } = props;
12
+
13
+ const NewFolderButton = () =>
14
+ createAction ? (
15
+ <S.NewIconWrapper onClick={createAction}>
16
+ <Icon name="newFolder" size="16" />
17
+ </S.NewIconWrapper>
18
+ ) : (
19
+ <></>
20
+ );
21
+
22
+ const handleRootClick = () => onClick(null);
23
+
24
+ return (
25
+ <>
26
+ {!hideRoot && (
27
+ <S.Item selected={!folderID} onClick={handleRootClick}>
28
+ <S.RootName>All Documents</S.RootName>
29
+ <NewFolderButton />
30
+ </S.Item>
31
+ )}
32
+ {title && <S.Title>{title}</S.Title>}
33
+ <S.TreeWrapper>
34
+ <MenuList
35
+ list={folders}
36
+ hidden={hidden}
37
+ trimNames={trimNames}
38
+ createAction={createAction}
39
+ folderID={folderID}
40
+ onClick={onClick}
41
+ />
42
+ </S.TreeWrapper>
43
+ </>
44
+ );
45
+ };
46
+
47
+ interface IProps {
48
+ folders: IFolderTree[];
49
+ folderID: number | null;
50
+ title?: string;
51
+ hidden?: number[];
52
+ hideRoot?: boolean;
53
+ trimNames?: boolean;
54
+ createAction?(): void;
55
+ onClick(folderID: number | null): void;
56
+ }
57
+
58
+ const mapStateToProps = (state: IRootState) => ({
59
+ folders: state.gallery.foldersTree,
60
+ });
61
+
62
+ export default connect(mapStateToProps)(FolderTree);
@@ -0,0 +1,49 @@
1
+ import styled from "styled-components";
2
+
3
+ const TreeWrapper = styled.div`
4
+ ul:not(:first-child) {
5
+ padding-left: ${(p) => p.theme.spacing.s};
6
+ }
7
+ `;
8
+
9
+ const NewIconWrapper = styled.div`
10
+ width: 16px;
11
+ height: 16px;
12
+ margin-left: auto;
13
+ `;
14
+
15
+ const Item = styled.div<{ selected: boolean }>`
16
+ display: flex;
17
+ width: 100%;
18
+ margin-bottom: ${(p) => p.theme.spacing.xxs};
19
+ align-items: center;
20
+ cursor: pointer;
21
+ padding: ${(p) => `${p.theme.spacing.xxs} ${p.theme.spacing.xs}`};
22
+ border-radius: ${(p) => p.theme.radii.s};
23
+ background-color: ${(p) => (p.selected ? p.theme.color.overlayPressedPrimary : "transparent")};
24
+ height: 32px;
25
+ overflow: hidden;
26
+ flex-shrink: 0;
27
+ &:hover {
28
+ background-color: ${(p) => (p.selected ? p.theme.color.overlayPressedPrimary : p.theme.color.overlayHoverPrimary)};
29
+ }
30
+ ${NewIconWrapper} {
31
+ opacity: ${(p) => (p.selected ? "1" : "0")};
32
+ }
33
+ `;
34
+
35
+ const RootName = styled.div`
36
+ ${(p) => p.theme.textStyle.uiM};
37
+ color: ${(p) => p.theme.color.textHighEmphasis};
38
+ white-space: nowrap;
39
+ `;
40
+
41
+ const Title = styled.div`
42
+ ${(p) => p.theme.textStyle.uiM};
43
+ color: ${(p) => p.theme.color.textMediumEmphasis};
44
+ margin-top: ${(p) => p.theme.spacing.xs};
45
+ margin-bottom: ${(p) => p.theme.spacing.xs};
46
+ word-break: normal;
47
+ `;
48
+
49
+ export { TreeWrapper, Item, RootName, Title, NewIconWrapper };