sanity-plugin-media 4.3.6 → 5.0.1

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 (162) hide show
  1. package/package.json +8 -17
  2. package/dist/index.cjs +0 -4721
  3. package/dist/index.cjs.map +0 -1
  4. package/dist/index.d.cts +0 -239
  5. package/dist/index.d.cts.map +0 -1
  6. package/sanity.json +0 -8
  7. package/src/__tests__/fixtures/createEpicTestStore.ts +0 -28
  8. package/src/__tests__/fixtures/listenMock.ts +0 -9
  9. package/src/__tests__/fixtures/mockSanityClient.ts +0 -84
  10. package/src/__tests__/fixtures/renderWithProviders.tsx +0 -55
  11. package/src/__tests__/fixtures/rootState.ts +0 -27
  12. package/src/__tests__/fixtures/withinDialog.ts +0 -28
  13. package/src/components/AssetGridVirtualized/index.tsx +0 -94
  14. package/src/components/AssetMetadata/index.tsx +0 -122
  15. package/src/components/AssetTableVirtualized/index.tsx +0 -73
  16. package/src/components/AutoTagInputWrapper/index.tsx +0 -85
  17. package/src/components/Browser/Browser.test.tsx +0 -45
  18. package/src/components/Browser/index.tsx +0 -90
  19. package/src/components/Browser/useBrowserInit.ts +0 -126
  20. package/src/components/ButtonAssetCopy/index.tsx +0 -65
  21. package/src/components/ButtonViewGroup/index.tsx +0 -39
  22. package/src/components/CardAsset/CardAsset.test.tsx +0 -323
  23. package/src/components/CardAsset/index.tsx +0 -290
  24. package/src/components/CardUpload/index.tsx +0 -161
  25. package/src/components/Controls/index.tsx +0 -136
  26. package/src/components/DebugControls/index.tsx +0 -80
  27. package/src/components/Dialog/index.tsx +0 -11
  28. package/src/components/DialogAssetEdit/Details.tsx +0 -181
  29. package/src/components/DialogAssetEdit/DialogAssetEdit.test.tsx +0 -216
  30. package/src/components/DialogAssetEdit/index.tsx +0 -493
  31. package/src/components/DialogConfirm/index.tsx +0 -90
  32. package/src/components/DialogSearchFacets/index.tsx +0 -42
  33. package/src/components/DialogTagCreate/DialogTagCreate.test.tsx +0 -121
  34. package/src/components/DialogTagCreate/index.tsx +0 -111
  35. package/src/components/DialogTagEdit/DialogTagEdit.test.tsx +0 -165
  36. package/src/components/DialogTagEdit/index.tsx +0 -201
  37. package/src/components/DialogTags/index.tsx +0 -45
  38. package/src/components/Dialogs/index.tsx +0 -76
  39. package/src/components/DocumentList/index.tsx +0 -62
  40. package/src/components/FileAssetPreview/index.tsx +0 -37
  41. package/src/components/FileIcon/index.tsx +0 -43
  42. package/src/components/FormBuilderTool/FormBuilderTool.test.tsx +0 -63
  43. package/src/components/FormBuilderTool/index.tsx +0 -69
  44. package/src/components/FormFieldInputLabel/index.tsx +0 -66
  45. package/src/components/FormFieldInputTags/index.tsx +0 -98
  46. package/src/components/FormFieldInputText/index.tsx +0 -41
  47. package/src/components/FormFieldInputTextarea/index.tsx +0 -43
  48. package/src/components/FormSubmitButton/index.tsx +0 -59
  49. package/src/components/Header/index.tsx +0 -80
  50. package/src/components/Image/index.tsx +0 -41
  51. package/src/components/Items/index.tsx +0 -68
  52. package/src/components/Notifications/index.tsx +0 -24
  53. package/src/components/OrderSelect/index.tsx +0 -66
  54. package/src/components/PickedBar/index.tsx +0 -77
  55. package/src/components/Progress/index.tsx +0 -38
  56. package/src/components/ReduxProvider/index.tsx +0 -96
  57. package/src/components/SearchFacet/index.tsx +0 -66
  58. package/src/components/SearchFacetNumber/index.tsx +0 -133
  59. package/src/components/SearchFacetSelect/index.tsx +0 -110
  60. package/src/components/SearchFacetString/index.tsx +0 -88
  61. package/src/components/SearchFacetTags/index.tsx +0 -121
  62. package/src/components/SearchFacets/index.tsx +0 -72
  63. package/src/components/SearchFacetsControl/index.tsx +0 -140
  64. package/src/components/TableHeader/index.tsx +0 -110
  65. package/src/components/TableHeaderItem/index.tsx +0 -61
  66. package/src/components/TableRowAsset/index.tsx +0 -419
  67. package/src/components/TableRowUpload/index.tsx +0 -164
  68. package/src/components/Tag/index.tsx +0 -200
  69. package/src/components/TagIcon/index.tsx +0 -22
  70. package/src/components/TagView/index.tsx +0 -39
  71. package/src/components/TagViewHeader/index.tsx +0 -70
  72. package/src/components/TagsPanel/index.tsx +0 -40
  73. package/src/components/TagsVirtualized/index.tsx +0 -160
  74. package/src/components/TextInputNumber/index.tsx +0 -32
  75. package/src/components/TextInputSearch/index.tsx +0 -60
  76. package/src/components/Tool/index.tsx +0 -13
  77. package/src/components/UploadDropzone/UploadDropzone.test.tsx +0 -40
  78. package/src/components/UploadDropzone/index.tsx +0 -173
  79. package/src/config/orders.ts +0 -28
  80. package/src/config/searchFacets.ts +0 -312
  81. package/src/constants.ts +0 -87
  82. package/src/contexts/AssetSourceDispatchContext.tsx +0 -38
  83. package/src/contexts/DropzoneDispatchContext.tsx +0 -32
  84. package/src/contexts/ToolOptionsContext.tsx +0 -66
  85. package/src/formSchema/index.test.ts +0 -56
  86. package/src/formSchema/index.ts +0 -39
  87. package/src/hooks/useBreakpointIndex.ts +0 -50
  88. package/src/hooks/useKeyPress.ts +0 -39
  89. package/src/hooks/usePortalPopoverProps.ts +0 -13
  90. package/src/hooks/useTypedSelector.ts +0 -7
  91. package/src/hooks/useVersionedClient.ts +0 -6
  92. package/src/index.ts +0 -5
  93. package/src/modules/assets/actions.ts +0 -42
  94. package/src/modules/assets/deleteAndUpdateEpics.test.ts +0 -87
  95. package/src/modules/assets/fetchEpic.test.ts +0 -73
  96. package/src/modules/assets/index.ts +0 -782
  97. package/src/modules/assets/reducer.test.ts +0 -91
  98. package/src/modules/assets/tagsAndListenerEpics.test.ts +0 -206
  99. package/src/modules/debug/index.ts +0 -28
  100. package/src/modules/dialog/actions.ts +0 -10
  101. package/src/modules/dialog/epics.test.ts +0 -168
  102. package/src/modules/dialog/index.ts +0 -238
  103. package/src/modules/dialog/reducer.test.ts +0 -185
  104. package/src/modules/index.ts +0 -117
  105. package/src/modules/notifications/epics.test.ts +0 -374
  106. package/src/modules/notifications/index.ts +0 -199
  107. package/src/modules/notifications/reducer.test.ts +0 -54
  108. package/src/modules/search/index.test.ts +0 -36
  109. package/src/modules/search/index.ts +0 -167
  110. package/src/modules/selected/index.ts +0 -22
  111. package/src/modules/selectors.test.ts +0 -21
  112. package/src/modules/selectors.ts +0 -17
  113. package/src/modules/tags/epics.test.ts +0 -96
  114. package/src/modules/tags/index.test.ts +0 -42
  115. package/src/modules/tags/index.ts +0 -540
  116. package/src/modules/types.ts +0 -3
  117. package/src/modules/uploads/actions.ts +0 -13
  118. package/src/modules/uploads/epics.test.ts +0 -109
  119. package/src/modules/uploads/index.test.ts +0 -59
  120. package/src/modules/uploads/index.ts +0 -272
  121. package/src/operators/checkTagName.test.ts +0 -29
  122. package/src/operators/checkTagName.ts +0 -33
  123. package/src/operators/debugThrottle.ts +0 -25
  124. package/src/plugin.tsx +0 -54
  125. package/src/schemas/tag.ts +0 -28
  126. package/src/styled/GlobalStyles/index.tsx +0 -40
  127. package/src/styled/react-select/creatable.tsx +0 -184
  128. package/src/styled/react-select/single.tsx +0 -184
  129. package/src/types/index.ts +0 -346
  130. package/src/types/sanity-ui.d.ts +0 -5
  131. package/src/utils/applyMediaTags.ts +0 -87
  132. package/src/utils/blocksToText.test.ts +0 -43
  133. package/src/utils/blocksToText.ts +0 -27
  134. package/src/utils/constructFilter.test.ts +0 -120
  135. package/src/utils/constructFilter.ts +0 -98
  136. package/src/utils/generatePreviewBlobUrl.test.ts +0 -68
  137. package/src/utils/generatePreviewBlobUrl.ts +0 -53
  138. package/src/utils/getAssetResolution.test.ts +0 -13
  139. package/src/utils/getAssetResolution.ts +0 -7
  140. package/src/utils/getDocumentAssetIds.test.ts +0 -50
  141. package/src/utils/getDocumentAssetIds.ts +0 -35
  142. package/src/utils/getSchemeColor.test.ts +0 -12
  143. package/src/utils/getSchemeColor.ts +0 -43
  144. package/src/utils/getTagSelectOptions.test.ts +0 -44
  145. package/src/utils/getTagSelectOptions.ts +0 -16
  146. package/src/utils/getUniqueDocuments.test.ts +0 -26
  147. package/src/utils/getUniqueDocuments.ts +0 -15
  148. package/src/utils/imageDprUrl.test.ts +0 -46
  149. package/src/utils/imageDprUrl.ts +0 -27
  150. package/src/utils/isSupportedAssetType.test.ts +0 -16
  151. package/src/utils/isSupportedAssetType.ts +0 -15
  152. package/src/utils/mediaField.ts +0 -73
  153. package/src/utils/sanitizeFormData.test.ts +0 -59
  154. package/src/utils/sanitizeFormData.ts +0 -26
  155. package/src/utils/typeGuards.test.ts +0 -18
  156. package/src/utils/typeGuards.ts +0 -9
  157. package/src/utils/uploadSanityAsset.test.ts +0 -29
  158. package/src/utils/uploadSanityAsset.ts +0 -97
  159. package/src/utils/withMaxConcurrency.test.ts +0 -43
  160. package/src/utils/withMaxConcurrency.ts +0 -55
  161. package/src/utils/zodFormResolver.ts +0 -17
  162. package/v2-incompatible.js +0 -11
package/dist/index.cjs DELETED
@@ -1,4721 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var jsxRuntime = require("react/jsx-runtime"), icons = require("@sanity/icons"), sanity = require("sanity"), ui = require("@sanity/ui"), react = require("react"), isHotkeyEsm = require("is-hotkey-esm"), styledComponents = require("styled-components"), reactRedux = require("react-redux"), toolkit = require("@reduxjs/toolkit"), pluralize = require("pluralize"), reduxObservable = require("redux-observable"), rxjs = require("rxjs"), operators$1 = require("rxjs/operators"), groq = require("groq"), nanoid = require("nanoid"), uuid = require("@sanity/uuid"), reactNprogress = require("@tanem/react-nprogress"), color = require("@sanity/color"), Select = require("react-select"), reactVirtuoso = require("react-virtuoso"), reactHookForm = require("react-hook-form"), z = require("zod"), zod = require("@hookform/resolvers/zod"), dateFns = require("date-fns"), filesize = require("filesize"), copy = require("copy-to-clipboard"), router = require("sanity/router"), reactFileIcon = require("react-file-icon"), CreatableSelect = require("react-select/creatable"), reactDropzone = require("react-dropzone");
4
- function _interopDefaultCompat(e) {
5
- return e && typeof e == "object" && "default" in e ? e : { default: e };
6
- }
7
- function _interopNamespaceCompat(e) {
8
- if (e && typeof e == "object" && "default" in e) return e;
9
- var n = /* @__PURE__ */ Object.create(null);
10
- return e && Object.keys(e).forEach(function(k) {
11
- if (k !== "default") {
12
- var d = Object.getOwnPropertyDescriptor(e, k);
13
- Object.defineProperty(n, k, d.get ? d : {
14
- enumerable: !0,
15
- get: function() {
16
- return e[k];
17
- }
18
- });
19
- }
20
- }), n.default = e, Object.freeze(n);
21
- }
22
- var pluralize__default = /* @__PURE__ */ _interopDefaultCompat(pluralize), groq__default = /* @__PURE__ */ _interopDefaultCompat(groq), Select__default = /* @__PURE__ */ _interopDefaultCompat(Select), z__namespace = /* @__PURE__ */ _interopNamespaceCompat(z), filesize__default = /* @__PURE__ */ _interopDefaultCompat(filesize), copy__default = /* @__PURE__ */ _interopDefaultCompat(copy), CreatableSelect__default = /* @__PURE__ */ _interopDefaultCompat(CreatableSelect);
23
- const useKeyPress = (hotkey, onPress) => {
24
- const keyPressed = react.useRef(!1), downHandler = react.useCallback((e) => {
25
- isHotkeyEsm.isHotkey(hotkey, e) && (keyPressed.current = !0, onPress && onPress());
26
- }, [hotkey, onPress]), upHandler = react.useCallback(() => {
27
- keyPressed.current = !1;
28
- }, []);
29
- return react.useEffect(() => (window.addEventListener("keydown", downHandler), window.addEventListener("keyup", upHandler), () => {
30
- window.removeEventListener("keydown", downHandler), window.removeEventListener("keyup", upHandler);
31
- }), [downHandler, upHandler]), keyPressed;
32
- }, AssetSourceDispatchContext = react.createContext(void 0), AssetBrowserDispatchProvider = (props) => {
33
- const {
34
- children,
35
- onSelect
36
- } = props, contextValue = react.useMemo(() => ({
37
- onSelect
38
- }), [onSelect]);
39
- return /* @__PURE__ */ jsxRuntime.jsx(AssetSourceDispatchContext.Provider, { value: contextValue, children });
40
- }, useAssetSourceActions = () => {
41
- const context = react.useContext(AssetSourceDispatchContext);
42
- if (context === void 0)
43
- throw new Error("useAssetSourceActions must be used within an AssetSourceDispatchProvider");
44
- return context;
45
- }, useVersionedClient = () => sanity.useClient({
46
- apiVersion: "2025-10-02"
47
- }), customScrollbar = styledComponents.css`::-webkit-scrollbar{width:14px;}::-webkit-scrollbar-thumb{border-radius:10px;border:4px solid rgba(0,0,0,0);background:var(--card-border-color);background-clip:padding-box;&:hover{background:var(--card-muted-fg-color);background-clip:padding-box;}}`, GlobalStyle = styledComponents.createGlobalStyle`.media__custom-scrollbar{${customScrollbar}}div[data-ui="Box"]{${customScrollbar}}div[data-ui="Dialog"]{background-color:rgba(15,17,18,0.9);}`, useTypedSelector = reactRedux.useSelector, ORDER_DICTIONARY = {
48
- _createdAt: {
49
- asc: "Last created: Oldest first",
50
- desc: "Last created: Newest first"
51
- },
52
- _updatedAt: {
53
- asc: "Last updated: Oldest first",
54
- desc: "Last updated: Newest first"
55
- },
56
- mimeType: {
57
- asc: "MIME type: A to Z",
58
- desc: "MIME type: Z to A"
59
- },
60
- originalFilename: {
61
- asc: "File name: A to Z",
62
- desc: "File name: Z to A"
63
- },
64
- size: {
65
- asc: "File size: Smallest first",
66
- desc: "File size: Largest first"
67
- }
68
- }, getOrderTitle = (field, direction) => ORDER_DICTIONARY[field][direction], divider = {
69
- type: "divider"
70
- }, inputs = {
71
- altText: {
72
- assetTypes: ["file", "image"],
73
- field: "altText",
74
- name: "altText",
75
- operatorType: "empty",
76
- operatorTypes: ["empty", "notEmpty", null, "includes", "doesNotInclude"],
77
- title: "Alt text",
78
- type: "string",
79
- value: ""
80
- },
81
- creditLine: {
82
- assetTypes: ["file", "image"],
83
- field: "creditLine",
84
- name: "creditLine",
85
- operatorType: "empty",
86
- operatorTypes: ["empty", "notEmpty", null, "includes", "doesNotInclude"],
87
- title: "Credit",
88
- type: "string",
89
- value: ""
90
- },
91
- description: {
92
- assetTypes: ["file", "image"],
93
- field: "description",
94
- name: "description",
95
- operatorType: "empty",
96
- operatorTypes: ["empty", "notEmpty", null, "includes", "doesNotInclude"],
97
- title: "Description",
98
- type: "string",
99
- value: ""
100
- },
101
- fileName: {
102
- assetTypes: ["file", "image"],
103
- field: "originalFilename",
104
- name: "filename",
105
- operatorType: "includes",
106
- operatorTypes: ["includes", "doesNotInclude"],
107
- title: "File name",
108
- type: "string",
109
- value: ""
110
- },
111
- height: {
112
- assetTypes: ["image"],
113
- field: "metadata.dimensions.height",
114
- name: "height",
115
- operatorType: "greaterThan",
116
- operatorTypes: ["greaterThan", "greaterThanOrEqualTo", "lessThan", "lessThanOrEqualTo", null, "equalTo"],
117
- title: "Height",
118
- type: "number",
119
- value: 400
120
- },
121
- inCurrentDocument: {
122
- assetTypes: ["file", "image"],
123
- name: "inCurrentDocument",
124
- operatorType: "is",
125
- options: [{
126
- name: "true",
127
- title: "True",
128
- value: groq__default.default`_id in $documentAssetIds`
129
- }, {
130
- name: "false",
131
- title: "False",
132
- value: groq__default.default`!(_id in $documentAssetIds)`
133
- }],
134
- selectOnly: !0,
135
- title: "In use in current document",
136
- type: "select",
137
- value: "true"
138
- },
139
- inUse: {
140
- assetTypes: ["file", "image"],
141
- name: "inUse",
142
- operatorType: "is",
143
- options: [{
144
- name: "true",
145
- title: "True",
146
- value: groq__default.default`count(*[references(^._id)]) > 0`
147
- }, {
148
- name: "false",
149
- title: "False",
150
- value: groq__default.default`count(*[references(^._id)]) == 0`
151
- }],
152
- title: "In use",
153
- type: "select",
154
- value: "true"
155
- },
156
- isOpaque: {
157
- assetTypes: ["image"],
158
- field: "metadata.isOpaque",
159
- name: "isOpaque",
160
- operatorType: "equalTo",
161
- options: [{
162
- name: "true",
163
- title: "True",
164
- value: "false"
165
- }, {
166
- name: "false",
167
- title: "False",
168
- value: "true"
169
- }],
170
- title: "Has transparency",
171
- type: "select",
172
- value: "true"
173
- },
174
- orientation: {
175
- assetTypes: ["image"],
176
- name: "orientation",
177
- operatorType: "is",
178
- operatorTypes: ["is", "isNot"],
179
- options: [{
180
- name: "portrait",
181
- title: "Portrait",
182
- value: "metadata.dimensions.aspectRatio < 1"
183
- }, {
184
- name: "landscape",
185
- title: "Landscape",
186
- value: "metadata.dimensions.aspectRatio > 1"
187
- }, {
188
- name: "square",
189
- title: "Square",
190
- value: "metadata.dimensions.aspectRatio == 1"
191
- }],
192
- title: "Orientation",
193
- type: "select",
194
- value: "portrait"
195
- },
196
- size: {
197
- assetTypes: ["file", "image"],
198
- field: "size",
199
- modifier: "kb",
200
- modifiers: [{
201
- name: "kb",
202
- title: "KB",
203
- fieldModifier: (fieldName) => `round(${fieldName} / 1000)`
204
- }, {
205
- name: "mb",
206
- title: "MB",
207
- fieldModifier: (fieldName) => `round(${fieldName} / 1000000)`
208
- }],
209
- name: "size",
210
- operatorType: "greaterThan",
211
- operatorTypes: ["greaterThan", "greaterThanOrEqualTo", "lessThan", "lessThanOrEqualTo", null, "equalTo"],
212
- title: "File size",
213
- type: "number",
214
- value: 0
215
- },
216
- tag: {
217
- assetTypes: ["file", "image"],
218
- field: "opt.media.tags",
219
- name: "tag",
220
- operatorType: "references",
221
- operatorTypes: ["references", "doesNotReference", null, "empty", "notEmpty"],
222
- title: "Tags",
223
- type: "searchable"
224
- },
225
- title: {
226
- assetTypes: ["file", "image"],
227
- field: "title",
228
- name: "title",
229
- operatorType: "empty",
230
- operatorTypes: ["empty", "notEmpty", null, "includes", "doesNotInclude"],
231
- title: "Title",
232
- type: "string",
233
- value: ""
234
- },
235
- type: {
236
- assetTypes: ["file", "image"],
237
- name: "type",
238
- operatorType: "is",
239
- operatorTypes: ["is", "isNot"],
240
- options: [{
241
- name: "image",
242
- title: "Image",
243
- value: 'mimeType match "image*"'
244
- }, {
245
- name: "video",
246
- title: "Video",
247
- value: 'mimeType match "video*"'
248
- }, {
249
- name: "audio",
250
- title: "Audio",
251
- value: 'mimeType match "audio*"'
252
- }, {
253
- name: "pdf",
254
- title: "PDF",
255
- value: 'mimeType == "application/pdf"'
256
- }],
257
- title: "File type",
258
- type: "select",
259
- value: "image"
260
- },
261
- width: {
262
- assetTypes: ["image"],
263
- field: "metadata.dimensions.width",
264
- name: "width",
265
- operatorType: "greaterThan",
266
- operatorTypes: ["greaterThan", "greaterThanOrEqualTo", "lessThan", "lessThanOrEqualTo", null, "equalTo"],
267
- title: "Width",
268
- type: "number",
269
- value: 400
270
- }
271
- }, operators = {
272
- doesNotInclude: {
273
- fn: (value, field) => value ? `!(${field} match '*${value}*')` : void 0,
274
- label: "does not include"
275
- },
276
- doesNotReference: {
277
- fn: (value, _field) => value ? `!references('${value}')` : void 0,
278
- label: "does not include"
279
- },
280
- empty: {
281
- fn: (_value, field) => `!defined(${field})`,
282
- hideInput: !0,
283
- label: "is empty"
284
- },
285
- equalTo: {
286
- fn: (value, field) => value ? `${field} == ${value}` : void 0,
287
- label: "is equal to"
288
- },
289
- greaterThan: {
290
- fn: (value, field) => value ? `${field} > ${value}` : void 0,
291
- label: "is greater than"
292
- },
293
- greaterThanOrEqualTo: {
294
- fn: (value, field) => value ? `${field} >= ${value}` : void 0,
295
- label: "is greater than or equal to"
296
- },
297
- includes: {
298
- fn: (value, field) => value ? `${field} match '*${value}*'` : void 0,
299
- label: "includes"
300
- },
301
- is: {
302
- fn: (value, _field) => `${value}`,
303
- label: "is"
304
- },
305
- isNot: {
306
- fn: (value, _field) => `!(${value})`,
307
- label: "is not"
308
- },
309
- lessThan: {
310
- fn: (value, field) => value ? `${field} < ${value}` : void 0,
311
- label: "is less than"
312
- },
313
- lessThanOrEqualTo: {
314
- fn: (value, field) => value ? `${field} <= ${value}` : void 0,
315
- label: "is less than or equal to"
316
- },
317
- notEmpty: {
318
- fn: (_value, field) => `defined(${field})`,
319
- hideInput: !0,
320
- label: "is not empty"
321
- },
322
- references: {
323
- fn: (value, _field) => value ? `references('${value}')` : void 0,
324
- label: "includes"
325
- }
326
- }, SUPPORTED_ASSET_TYPES = ["file", "image"], ORDER_OPTIONS = [
327
- {
328
- direction: "desc",
329
- field: "_createdAt"
330
- },
331
- {
332
- direction: "asc",
333
- field: "_createdAt"
334
- },
335
- // Divider
336
- null,
337
- {
338
- direction: "desc",
339
- field: "_updatedAt"
340
- },
341
- {
342
- direction: "asc",
343
- field: "_updatedAt"
344
- },
345
- // Divider
346
- null,
347
- {
348
- direction: "asc",
349
- field: "originalFilename"
350
- },
351
- {
352
- direction: "desc",
353
- field: "originalFilename"
354
- },
355
- // Divider
356
- null,
357
- {
358
- direction: "desc",
359
- field: "size"
360
- },
361
- {
362
- direction: "asc",
363
- field: "size"
364
- }
365
- ], FACETS = [inputs.tag, divider, inputs.inUse, inputs.inCurrentDocument, divider, inputs.title, inputs.altText, inputs.creditLine, inputs.description, divider, inputs.isOpaque, divider, inputs.fileName, inputs.size, inputs.type, divider, inputs.orientation, inputs.width, inputs.height], GRID_TEMPLATE_COLUMNS = {
366
- SMALL: "3rem 100px auto 1.5rem",
367
- LARGE: "3rem 100px auto 5.5rem 5.5rem 3.5rem 8.5rem 4.75rem 2rem"
368
- }, PANEL_HEIGHT = 32, TAG_DOCUMENT_NAME = "media.tag", TAGS_PANEL_WIDTH = 250, debugThrottle = (throttled) => function(source) {
369
- return rxjs.iif(() => !!throttled, source.pipe(operators$1.delay(3e3), operators$1.mergeMap((v) => Math.random() > 0.5 ? rxjs.throwError({
370
- message: "Test error",
371
- statusCode: 500
372
- }) : rxjs.of(v))), source);
373
- }, constructFilter = ({
374
- assetTypes,
375
- searchFacets,
376
- searchQuery
377
- }) => {
378
- const documentAssetTypes = assetTypes.map((type) => `sanity.${type}Asset`), baseFilter = groq__default.default`
379
- _type in ${JSON.stringify(documentAssetTypes)} && !(_id in path("drafts.**"))
380
- `, searchFacetFragments = searchFacets.reduce((acc, facet) => {
381
- if (facet.type === "number") {
382
- const {
383
- field,
384
- modifier,
385
- modifiers,
386
- operatorType,
387
- value
388
- } = facet, operator = operators[operatorType], currentModifier = modifiers?.find((m) => m.name === modifier), facetField = currentModifier?.fieldModifier ? currentModifier.fieldModifier(field) : field, fragment = operator.fn(value, facetField);
389
- fragment && acc.push(fragment);
390
- }
391
- if (facet.type === "searchable") {
392
- const {
393
- field,
394
- operatorType,
395
- value
396
- } = facet, fragment = operators[operatorType].fn(value?.value, field);
397
- fragment && acc.push(fragment);
398
- }
399
- if (facet.type === "select") {
400
- const {
401
- field,
402
- operatorType,
403
- options,
404
- value
405
- } = facet, operator = operators[operatorType], currentOptionValue = options?.find((l) => l.name === value)?.value, fragment = operator.fn(currentOptionValue, field);
406
- fragment && acc.push(fragment);
407
- }
408
- if (facet.type === "string") {
409
- const {
410
- field,
411
- operatorType,
412
- value
413
- } = facet, fragment = operators[operatorType].fn(value, field);
414
- fragment && acc.push(fragment);
415
- }
416
- return acc;
417
- }, []);
418
- return [
419
- // Base filter
420
- baseFilter,
421
- // Search query (if present)
422
- // NOTE: Currently this only searches direct fields on sanity.fileAsset/sanity.imageAsset and NOT referenced tags
423
- // It's possible to add this by adding the following line to the searchQuery, but it's quite slow
424
- // references(*[_type == "media.tag" && name.current == "${searchQuery.trim()}"]._id)
425
- ...searchQuery ? [groq__default.default`[_id, altText, assetId, creditLine, description, originalFilename, title, url] match '*${searchQuery.trim()}*'`] : [],
426
- // Search facets
427
- ...searchFacetFragments
428
- ].join(" && ");
429
- }, checkTagName = (client, name) => function(source) {
430
- return source.pipe(operators$1.mergeMap(() => rxjs.from(client.fetch(groq__default.default`count(*[_type == "${TAG_DOCUMENT_NAME}" && name.current == $name])`, {
431
- name
432
- }))), operators$1.mergeMap((existingTagCount) => existingTagCount > 0 ? rxjs.throwError({
433
- message: "Tag already exists",
434
- statusCode: 409
435
- }) : rxjs.of(!0)));
436
- }, getTagSelectOptions = (tags) => tags.reduce((acc, val) => {
437
- const tag = val?.tag;
438
- return tag && acc.push({
439
- label: tag?.name?.current,
440
- value: tag?._id
441
- }), acc;
442
- }, []), ASSETS_ACTIONS = {
443
- tagsAddComplete: toolkit.createAction("actions/tagsAddComplete", function({
444
- assets,
445
- tag
446
- }) {
447
- return {
448
- payload: {
449
- assets,
450
- tag
451
- }
452
- };
453
- }),
454
- tagsAddError: toolkit.createAction("actions/tagsAddError", function({
455
- assets,
456
- error,
457
- tag
458
- }) {
459
- return {
460
- payload: {
461
- assets,
462
- error,
463
- tag
464
- }
465
- };
466
- }),
467
- tagsAddRequest: toolkit.createAction("actions/tagsAddRequest", function({
468
- assets,
469
- tag
470
- }) {
471
- return {
472
- payload: {
473
- assets,
474
- tag
475
- }
476
- };
477
- }),
478
- tagsRemoveComplete: toolkit.createAction("actions/tagsRemoveComplete", function({
479
- assets,
480
- tag
481
- }) {
482
- return {
483
- payload: {
484
- assets,
485
- tag
486
- }
487
- };
488
- }),
489
- tagsRemoveError: toolkit.createAction("actions/tagsRemoveError", function({
490
- assets,
491
- error,
492
- tag
493
- }) {
494
- return {
495
- payload: {
496
- assets,
497
- error,
498
- tag
499
- }
500
- };
501
- }),
502
- tagsRemoveRequest: toolkit.createAction("actions/tagsRemoveRequest", function({
503
- assets,
504
- tag
505
- }) {
506
- return {
507
- payload: {
508
- assets,
509
- tag
510
- }
511
- };
512
- })
513
- }, DIALOG_ACTIONS = {
514
- showTagCreate: toolkit.createAction("dialog/showTagCreate"),
515
- showTagEdit: toolkit.createAction("dialog/showTagEdit", function({
516
- tagId
517
- }) {
518
- return {
519
- payload: {
520
- tagId
521
- }
522
- };
523
- })
524
- }, initialState$7 = {
525
- allIds: [],
526
- byIds: {},
527
- creating: !1,
528
- creatingError: void 0,
529
- fetchCount: -1,
530
- fetching: !1,
531
- fetchingError: void 0,
532
- panelVisible: !0
533
- }, tagsSlice = toolkit.createSlice({
534
- name: "tags",
535
- initialState: initialState$7,
536
- extraReducers: (builder) => {
537
- builder.addCase(DIALOG_ACTIONS.showTagCreate, (state) => {
538
- delete state.creatingError;
539
- }).addCase(DIALOG_ACTIONS.showTagEdit, (state, action) => {
540
- const {
541
- tagId
542
- } = action.payload;
543
- delete state.byIds[tagId].error;
544
- }).addMatcher(toolkit.isAnyOf(ASSETS_ACTIONS.tagsAddComplete, ASSETS_ACTIONS.tagsAddError, ASSETS_ACTIONS.tagsRemoveComplete, ASSETS_ACTIONS.tagsRemoveError), (state, action) => {
545
- const {
546
- tag
547
- } = action.payload;
548
- state.byIds[tag._id].updating = !1;
549
- }).addMatcher(toolkit.isAnyOf(ASSETS_ACTIONS.tagsAddRequest, ASSETS_ACTIONS.tagsRemoveRequest), (state, action) => {
550
- const {
551
- tag
552
- } = action.payload;
553
- state.byIds[tag._id].updating = !0;
554
- });
555
- },
556
- reducers: {
557
- createComplete(state, action) {
558
- const {
559
- tag
560
- } = action.payload;
561
- state.creating = !1, state.allIds.includes(tag._id) || state.allIds.push(tag._id), state.byIds[tag._id] = {
562
- _type: "tag",
563
- picked: !1,
564
- tag,
565
- updating: !1
566
- };
567
- },
568
- createError(state, action) {
569
- state.creating = !1, state.creatingError = action.payload.error;
570
- },
571
- createRequest(state, _action) {
572
- state.creating = !0, delete state.creatingError;
573
- },
574
- deleteComplete(state, action) {
575
- const {
576
- tagId
577
- } = action.payload, deleteIndex = state.allIds.indexOf(tagId);
578
- deleteIndex >= 0 && state.allIds.splice(deleteIndex, 1), delete state.byIds[tagId];
579
- },
580
- deleteError(state, action) {
581
- const {
582
- error,
583
- tag
584
- } = action.payload, tagId = tag?._id;
585
- state.byIds[tagId].error = error, state.byIds[tagId].updating = !1;
586
- },
587
- deleteRequest(state, action) {
588
- const tagId = action.payload?.tag?._id;
589
- state.byIds[tagId].picked = !1, state.byIds[tagId].updating = !0, Object.keys(state.byIds).forEach((key) => {
590
- delete state.byIds[key].error;
591
- });
592
- },
593
- fetchComplete(state, action) {
594
- const {
595
- tags
596
- } = action.payload;
597
- tags?.forEach((tag) => {
598
- state.allIds.push(tag._id), state.byIds[tag._id] = {
599
- _type: "tag",
600
- picked: !1,
601
- tag,
602
- updating: !1
603
- };
604
- }), state.fetching = !1, state.fetchCount = tags.length || 0, delete state.fetchingError;
605
- },
606
- fetchError(state, action) {
607
- const {
608
- error
609
- } = action.payload;
610
- state.fetching = !1, state.fetchingError = error;
611
- },
612
- fetchRequest: {
613
- reducer: (state, _action) => {
614
- state.fetching = !0, delete state.fetchingError;
615
- },
616
- prepare: () => ({
617
- payload: {
618
- query: groq__default.default`
619
- {
620
- "items": *[
621
- _type == "${TAG_DOCUMENT_NAME}"
622
- && !(_id in path("drafts.**"))
623
- ] {
624
- _createdAt,
625
- _updatedAt,
626
- _id,
627
- _rev,
628
- _type,
629
- name
630
- } | order(name.current asc),
631
- }
632
- `
633
- }
634
- })
635
- },
636
- // Queue batch tag creation
637
- listenerCreateQueue(_state, _action) {
638
- },
639
- // Apply created tags (via sanity real-time events)
640
- listenerCreateQueueComplete(state, action) {
641
- const {
642
- tags
643
- } = action.payload;
644
- tags?.forEach((tag) => {
645
- state.byIds[tag._id] = {
646
- _type: "tag",
647
- picked: !1,
648
- tag,
649
- updating: !1
650
- }, state.allIds.includes(tag._id) || state.allIds.push(tag._id);
651
- });
652
- },
653
- // Queue batch tag deletion
654
- listenerDeleteQueue(_state, _action) {
655
- },
656
- // Apply deleted tags (via sanity real-time events)
657
- listenerDeleteQueueComplete(state, action) {
658
- const {
659
- tagIds
660
- } = action.payload;
661
- tagIds?.forEach((tagId) => {
662
- const deleteIndex = state.allIds.indexOf(tagId);
663
- deleteIndex >= 0 && state.allIds.splice(deleteIndex, 1), delete state.byIds[tagId];
664
- });
665
- },
666
- // Queue batch tag updates
667
- listenerUpdateQueue(_state, _action) {
668
- },
669
- // Apply updated tags (via sanity real-time events)
670
- listenerUpdateQueueComplete(state, action) {
671
- const {
672
- tags
673
- } = action.payload;
674
- tags?.forEach((tag) => {
675
- state.byIds[tag._id] && (state.byIds[tag._id].tag = tag);
676
- });
677
- },
678
- // Set tag panel visibility
679
- panelVisibleSet(state, action) {
680
- const {
681
- panelVisible
682
- } = action.payload;
683
- state.panelVisible = panelVisible;
684
- },
685
- // Sort all tags by name
686
- sort(state) {
687
- state.allIds.sort((a, b) => {
688
- const tagA = state.byIds[a].tag.name.current, tagB = state.byIds[b].tag.name.current;
689
- return tagA < tagB ? -1 : tagA > tagB ? 1 : 0;
690
- });
691
- },
692
- updateComplete(state, action) {
693
- const {
694
- tag
695
- } = action.payload;
696
- state.byIds[tag._id].tag = tag, state.byIds[tag._id].updating = !1;
697
- },
698
- updateError(state, action) {
699
- const {
700
- error,
701
- tag
702
- } = action.payload, tagId = tag?._id;
703
- state.byIds[tagId].error = error, state.byIds[tagId].updating = !1;
704
- },
705
- updateRequest(state, action) {
706
- const {
707
- tag
708
- } = action.payload;
709
- state.byIds[tag?._id].updating = !0;
710
- }
711
- }
712
- }), tagsCreateEpic = (action$, state$, {
713
- client
714
- }) => action$.pipe(operators$1.filter(tagsSlice.actions.createRequest.match), operators$1.withLatestFrom(state$), operators$1.mergeMap(([action, state]) => {
715
- const {
716
- assetId,
717
- name
718
- } = action.payload;
719
- return rxjs.of(action).pipe(debugThrottle(state.debug.badConnection), checkTagName(client, name), operators$1.mergeMap(() => client.observable.create({
720
- _type: TAG_DOCUMENT_NAME,
721
- name: {
722
- _type: "slug",
723
- current: name
724
- }
725
- })), operators$1.mergeMap((result) => rxjs.of(tagsSlice.actions.createComplete({
726
- assetId,
727
- tag: result
728
- }))), operators$1.catchError((error) => rxjs.of(tagsSlice.actions.createError({
729
- error: {
730
- message: error?.message || "Internal error",
731
- statusCode: error?.statusCode || 500
732
- },
733
- name
734
- }))));
735
- })), tagsDeleteEpic = (action$, state$, {
736
- client
737
- }) => action$.pipe(operators$1.filter(tagsSlice.actions.deleteRequest.match), operators$1.withLatestFrom(state$), operators$1.mergeMap(([action, state]) => {
738
- const {
739
- tag
740
- } = action.payload;
741
- return rxjs.of(action).pipe(
742
- // Optionally throttle
743
- debugThrottle(state.debug.badConnection),
744
- // Fetch assets which reference this tag
745
- operators$1.mergeMap(() => client.observable.fetch(groq__default.default`*[
746
- _type in ["sanity.fileAsset", "sanity.imageAsset"]
747
- && references(*[_type == "media.tag" && name.current == $tagName]._id)
748
- ] {
749
- _id,
750
- _rev,
751
- opt
752
- }`, {
753
- tagName: tag.name.current
754
- })),
755
- // Create transaction which remove tag references from all matched assets and delete tag
756
- operators$1.mergeMap((assets) => {
757
- const transaction = assets.map((asset) => ({
758
- id: asset._id,
759
- patch: {
760
- // this will cause the transaction to fail if the document has been modified since it was fetched.
761
- ifRevisionID: asset._rev,
762
- unset: [`opt.media.tags[_ref == "${tag._id}"]`]
763
- }
764
- })).reduce((tx, patch) => tx.patch(patch.id, patch.patch), client.transaction());
765
- return transaction.delete(tag._id), rxjs.from(transaction.commit());
766
- }),
767
- // Dispatch complete action
768
- operators$1.mergeMap(() => rxjs.of(tagsSlice.actions.deleteComplete({
769
- tagId: tag._id
770
- }))),
771
- operators$1.catchError((error) => rxjs.of(tagsSlice.actions.deleteError({
772
- error: {
773
- message: error?.message || "Internal error",
774
- statusCode: error?.statusCode || 500
775
- },
776
- tag
777
- })))
778
- );
779
- })), tagsFetchEpic = (action$, state$, {
780
- client
781
- }) => action$.pipe(operators$1.filter(tagsSlice.actions.fetchRequest.match), operators$1.withLatestFrom(state$), operators$1.switchMap(([action, state]) => {
782
- const {
783
- query
784
- } = action.payload;
785
- return rxjs.of(action).pipe(
786
- // Optionally throttle
787
- debugThrottle(state.debug.badConnection),
788
- // Fetch tags
789
- operators$1.mergeMap(() => client.observable.fetch(query)),
790
- // Dispatch complete action
791
- operators$1.mergeMap((result) => {
792
- const {
793
- items
794
- } = result;
795
- return rxjs.of(tagsSlice.actions.fetchComplete({
796
- tags: items
797
- }));
798
- }),
799
- operators$1.catchError((error) => rxjs.of(tagsSlice.actions.fetchError({
800
- error: {
801
- message: error?.message || "Internal error",
802
- statusCode: error?.statusCode || 500
803
- }
804
- })))
805
- );
806
- })), tagsListenerCreateQueueEpic = (action$) => action$.pipe(operators$1.filter(tagsSlice.actions.listenerCreateQueue.match), operators$1.bufferTime(2e3), operators$1.filter((actions) => actions.length > 0), operators$1.mergeMap((actions) => {
807
- const tags = actions?.map((action) => action.payload.tag);
808
- return rxjs.of(tagsSlice.actions.listenerCreateQueueComplete({
809
- tags
810
- }));
811
- })), tagsListenerDeleteQueueEpic = (action$) => action$.pipe(operators$1.filter(tagsSlice.actions.listenerDeleteQueue.match), operators$1.bufferTime(2e3), operators$1.filter((actions) => actions.length > 0), operators$1.mergeMap((actions) => {
812
- const tagIds = actions?.map((action) => action.payload.tagId);
813
- return rxjs.of(tagsSlice.actions.listenerDeleteQueueComplete({
814
- tagIds
815
- }));
816
- })), tagsListenerUpdateQueueEpic = (action$) => action$.pipe(operators$1.filter(tagsSlice.actions.listenerUpdateQueue.match), operators$1.bufferTime(2e3), operators$1.filter((actions) => actions.length > 0), operators$1.mergeMap((actions) => {
817
- const tags = actions?.map((action) => action.payload.tag);
818
- return rxjs.of(tagsSlice.actions.listenerUpdateQueueComplete({
819
- tags
820
- }));
821
- })), tagsSortEpic = (action$) => action$.pipe(reduxObservable.ofType(tagsSlice.actions.listenerCreateQueueComplete.type, tagsSlice.actions.listenerUpdateQueueComplete.type), operators$1.bufferTime(1e3), operators$1.filter((actions) => actions.length > 0), operators$1.mergeMap(() => rxjs.of(tagsSlice.actions.sort()))), tagsUpdateEpic = (action$, state$, {
822
- client
823
- }) => action$.pipe(operators$1.filter(tagsSlice.actions.updateRequest.match), operators$1.withLatestFrom(state$), operators$1.mergeMap(([action, state]) => {
824
- const {
825
- closeDialogId,
826
- formData,
827
- tag
828
- } = action.payload;
829
- return rxjs.of(action).pipe(
830
- // Optionally throttle
831
- debugThrottle(state.debug.badConnection),
832
- // Check if tag name is available, throw early if not
833
- checkTagName(client, formData?.name?.current),
834
- // Patch document (Update tag)
835
- operators$1.mergeMap(() => rxjs.from(client.patch(tag._id).set({
836
- name: {
837
- _type: "slug",
838
- current: formData?.name.current
839
- }
840
- }).commit())),
841
- // Dispatch complete action
842
- operators$1.mergeMap((updatedTag) => rxjs.of(tagsSlice.actions.updateComplete({
843
- closeDialogId,
844
- tag: updatedTag
845
- }))),
846
- operators$1.catchError((error) => rxjs.of(tagsSlice.actions.updateError({
847
- error: {
848
- message: error?.message || "Internal error",
849
- statusCode: error?.statusCode || 500
850
- },
851
- tag
852
- })))
853
- );
854
- })), selectTagsByIds = (state) => state.tags.byIds, selectTagsAllIds = (state) => state.tags.allIds, selectTags = toolkit.createSelector([selectTagsByIds, selectTagsAllIds], (byIds, allIds) => allIds.map((id) => byIds[id])), selectTagById = toolkit.createSelector([selectTagsByIds, (_state, tagId) => tagId], (byIds, tagId) => byIds[tagId]), selectTagSelectOptions = (asset) => (state) => {
855
- const tags = asset?.opt?.media?.tags?.reduce((acc, v) => {
856
- const tagItem = state.tags.byIds[v._ref];
857
- return tagItem?.tag && acc.push(tagItem), acc;
858
- }, []);
859
- return tags && tags?.length > 0 ? getTagSelectOptions(tags) : null;
860
- }, tagsActions = {
861
- ...tagsSlice.actions
862
- };
863
- var tagsReducer = tagsSlice.reducer;
864
- const initialState$6 = {
865
- facets: [],
866
- query: ""
867
- }, searchSlice = toolkit.createSlice({
868
- name: "search",
869
- initialState: initialState$6,
870
- reducers: {
871
- // Add search facet
872
- facetsAdd(state, action) {
873
- state.facets.push({
874
- ...action.payload.facet,
875
- id: uuid.uuid()
876
- });
877
- },
878
- // Clear all search facets
879
- facetsClear(state) {
880
- state.facets = [];
881
- },
882
- // Remove search facet by name
883
- facetsRemoveByName(state, action) {
884
- state.facets = state.facets.filter((facet) => facet.name !== action.payload.facetName);
885
- },
886
- // Remove search facet by name
887
- facetsRemoveByTag(state, action) {
888
- state.facets = state.facets.filter((facet) => !(facet.name === "tag" && facet.type === "searchable" && (facet.operatorType === "references" || facet.operatorType === "doesNotReference") && facet.value?.value === action.payload.tagId));
889
- },
890
- // Remove search facet by name
891
- facetsRemoveById(state, action) {
892
- state.facets = state.facets.filter((facet) => facet.id !== action.payload.facetId);
893
- },
894
- // Update an existing search facet
895
- facetsUpdate(state, action) {
896
- const {
897
- modifier,
898
- name,
899
- operatorType,
900
- value
901
- } = action.payload, facet = state.facets.find((f) => f.name === name);
902
- facet && (facet.type === "number" && modifier && (facet.modifier = modifier), operatorType && (facet.operatorType = operatorType), typeof value < "u" && (facet.value = value), state.facets = state.facets.filter((f) => f.name !== facet.name || f.id === facet.id));
903
- },
904
- // Update an existing search facet
905
- facetsUpdateById(state, action) {
906
- const {
907
- modifier,
908
- id,
909
- operatorType,
910
- value
911
- } = action.payload;
912
- state.facets.forEach((facet, index) => {
913
- facet.id === id && (facet.type === "number" && modifier && (facet.modifier = modifier), operatorType && (facet.operatorType = operatorType), typeof value < "u" && (state.facets[index].value = value));
914
- });
915
- },
916
- // Update existing search query
917
- querySet(state, action) {
918
- state.query = action.payload?.searchQuery;
919
- }
920
- }
921
- }), searchFacetTagUpdateEpic = (action$, state$) => action$.pipe(operators$1.filter(tagsActions.updateComplete.match), operators$1.withLatestFrom(state$), operators$1.mergeMap(([action, state]) => {
922
- const {
923
- tag
924
- } = action.payload, currentSearchFacetTag = state.search.facets?.find((facet) => facet.name === "tag"), tagItem = state.tags.byIds[tag._id];
925
- return currentSearchFacetTag?.type === "searchable" && currentSearchFacetTag.value?.value === tag._id ? rxjs.of(searchSlice.actions.facetsUpdate({
926
- name: "tag",
927
- value: {
928
- label: tagItem?.tag?.name?.current,
929
- value: tagItem?.tag?._id
930
- }
931
- })) : rxjs.EMPTY;
932
- })), selectIsSearchFacetTag = toolkit.createSelector([(state) => state.search.facets, (_state, tagId) => tagId], (searchFacets, tagId) => searchFacets.some((facet) => facet.name === "tag" && facet.type === "searchable" && (facet.operatorType === "references" || facet.operatorType === "doesNotReference") && facet.value?.value === tagId)), searchActions = {
933
- ...searchSlice.actions
934
- };
935
- var searchReducer = searchSlice.reducer;
936
- const UPLOADS_ACTIONS = {
937
- uploadComplete: toolkit.createAction("uploads/uploadComplete", function({
938
- asset
939
- }) {
940
- return {
941
- payload: {
942
- asset
943
- }
944
- };
945
- })
946
- }, defaultOrder = ORDER_OPTIONS[0], initialState$5 = {
947
- allIds: [],
948
- assetTypes: [],
949
- byIds: {},
950
- fetchCount: -1,
951
- fetching: !1,
952
- fetchingError: void 0,
953
- lastPicked: void 0,
954
- order: {
955
- direction: defaultOrder.direction,
956
- field: defaultOrder.field,
957
- title: getOrderTitle(defaultOrder.field, defaultOrder.direction)
958
- },
959
- pageIndex: 0,
960
- pageSize: 100,
961
- // totalCount: -1,
962
- view: "grid"
963
- }, assetsSlice = toolkit.createSlice({
964
- name: "assets",
965
- initialState: initialState$5,
966
- extraReducers: (builder) => {
967
- builder.addCase(UPLOADS_ACTIONS.uploadComplete, (state, action) => {
968
- const {
969
- asset
970
- } = action.payload;
971
- state.byIds[asset._id] = {
972
- _type: "asset",
973
- asset,
974
- picked: !1,
975
- updating: !1
976
- };
977
- }).addCase(ASSETS_ACTIONS.tagsAddComplete, (state, action) => {
978
- const {
979
- assets
980
- } = action.payload;
981
- assets.forEach((asset) => {
982
- state.byIds[asset.asset._id].updating = !1;
983
- });
984
- }).addCase(ASSETS_ACTIONS.tagsAddError, (state, action) => {
985
- const {
986
- assets
987
- } = action.payload;
988
- assets.forEach((asset) => {
989
- state.byIds[asset.asset._id].updating = !1;
990
- });
991
- }).addCase(ASSETS_ACTIONS.tagsAddRequest, (state, action) => {
992
- const {
993
- assets
994
- } = action.payload;
995
- assets.forEach((asset) => {
996
- state.byIds[asset.asset._id].updating = !0;
997
- });
998
- }).addCase(ASSETS_ACTIONS.tagsRemoveComplete, (state, action) => {
999
- const {
1000
- assets
1001
- } = action.payload;
1002
- assets.forEach((asset) => {
1003
- state.byIds[asset.asset._id].updating = !1;
1004
- });
1005
- }).addCase(ASSETS_ACTIONS.tagsRemoveError, (state, action) => {
1006
- const {
1007
- assets
1008
- } = action.payload;
1009
- assets.forEach((asset) => {
1010
- state.byIds[asset.asset._id].updating = !1;
1011
- });
1012
- }).addCase(ASSETS_ACTIONS.tagsRemoveRequest, (state, action) => {
1013
- const {
1014
- assets
1015
- } = action.payload;
1016
- assets.forEach((asset) => {
1017
- state.byIds[asset.asset._id].updating = !0;
1018
- });
1019
- });
1020
- },
1021
- reducers: {
1022
- // Clear asset order
1023
- clear(state) {
1024
- state.allIds = [];
1025
- },
1026
- // Remove assets and update page index
1027
- deleteComplete(state, action) {
1028
- const {
1029
- assetIds
1030
- } = action.payload;
1031
- assetIds?.forEach((id) => {
1032
- const deleteIndex = state.allIds.indexOf(id);
1033
- deleteIndex >= 0 && state.allIds.splice(deleteIndex, 1), delete state.byIds[id];
1034
- }), state.pageIndex = Math.floor(state.allIds.length / state.pageSize) - 1;
1035
- },
1036
- deleteError(state, action) {
1037
- const {
1038
- assetIds,
1039
- error
1040
- } = action.payload, itemErrors = error?.response?.body?.error?.items?.map((item) => item.error);
1041
- assetIds?.forEach((id) => {
1042
- state.byIds[id].updating = !1;
1043
- }), itemErrors?.forEach((item) => {
1044
- state.byIds[item.id].error = item.description;
1045
- });
1046
- },
1047
- deleteRequest(state, action) {
1048
- const {
1049
- assets
1050
- } = action.payload;
1051
- assets.forEach((asset) => {
1052
- state.byIds[asset?._id].updating = !0;
1053
- }), Object.keys(state.byIds).forEach((key) => {
1054
- delete state.byIds[key].error;
1055
- });
1056
- },
1057
- fetchComplete(state, action) {
1058
- const assets = action.payload?.assets || [];
1059
- assets && assets.forEach((asset) => {
1060
- state.allIds.includes(asset._id) || state.allIds.push(asset._id), state.byIds[asset._id] = {
1061
- _type: "asset",
1062
- asset,
1063
- picked: !1,
1064
- updating: !1
1065
- };
1066
- }), state.fetching = !1, state.fetchCount = assets.length || 0, delete state.fetchingError;
1067
- },
1068
- fetchError(state, action) {
1069
- const error = action.payload;
1070
- state.fetching = !1, state.fetchingError = error;
1071
- },
1072
- fetchRequest: {
1073
- reducer: (state, _action) => {
1074
- state.fetching = !0, delete state.fetchingError;
1075
- },
1076
- prepare: ({
1077
- params = {},
1078
- queryFilter,
1079
- selector = "",
1080
- sort = groq__default.default`order(_updatedAt desc)`
1081
- }) => {
1082
- const query = groq__default.default`
1083
- {
1084
- "items": *[${queryFilter}] {
1085
- _id,
1086
- _type,
1087
- _createdAt,
1088
- _updatedAt,
1089
- altText,
1090
- creditLine,
1091
- description,
1092
- extension,
1093
- metadata {
1094
- dimensions,
1095
- exif,
1096
- isOpaque,
1097
- },
1098
- mimeType,
1099
- opt {
1100
- media
1101
- },
1102
- originalFilename,
1103
- size,
1104
- source {
1105
- name,
1106
- id,
1107
- url,
1108
- },
1109
- title,
1110
- url
1111
- } ${sort || selector ? "|" : ""} ${sort} ${selector},
1112
- }
1113
- `;
1114
- return {
1115
- payload: {
1116
- params,
1117
- query
1118
- }
1119
- };
1120
- }
1121
- },
1122
- insertUploads(state, action) {
1123
- const {
1124
- results
1125
- } = action.payload;
1126
- Object.entries(results).forEach(([hash, assetId]) => {
1127
- assetId && !state.allIds.includes(hash) && state.allIds.push(assetId);
1128
- });
1129
- },
1130
- listenerCreateQueue(_state, _action) {
1131
- },
1132
- listenerCreateQueueComplete(state, action) {
1133
- const {
1134
- assets
1135
- } = action.payload;
1136
- assets?.forEach((asset) => {
1137
- state.byIds[asset?._id]?.asset && (state.byIds[asset._id].asset = asset);
1138
- });
1139
- },
1140
- listenerDeleteQueue(_state, _action) {
1141
- },
1142
- listenerDeleteQueueComplete(state, action) {
1143
- const {
1144
- assetIds
1145
- } = action.payload;
1146
- assetIds?.forEach((assetId) => {
1147
- const deleteIndex = state.allIds.indexOf(assetId);
1148
- deleteIndex >= 0 && state.allIds.splice(deleteIndex, 1), delete state.byIds[assetId];
1149
- });
1150
- },
1151
- listenerUpdateQueue(_state, _action) {
1152
- },
1153
- listenerUpdateQueueComplete(state, action) {
1154
- const {
1155
- assets
1156
- } = action.payload;
1157
- assets?.forEach((asset) => {
1158
- state.byIds[asset?._id]?.asset && (state.byIds[asset._id].asset = asset);
1159
- });
1160
- },
1161
- loadNextPage() {
1162
- },
1163
- loadPageIndex(state, action) {
1164
- state.pageIndex = action.payload.pageIndex;
1165
- },
1166
- orderSet(state, action) {
1167
- state.order = action.payload?.order, state.pageIndex = 0;
1168
- },
1169
- pick(state, action) {
1170
- const {
1171
- assetId,
1172
- picked
1173
- } = action.payload;
1174
- state.byIds[assetId].picked = picked, state.lastPicked = picked ? assetId : void 0;
1175
- },
1176
- pickAll(state) {
1177
- state.allIds.forEach((id) => {
1178
- state.byIds[id].picked = !0;
1179
- });
1180
- },
1181
- pickClear(state) {
1182
- state.lastPicked = void 0, Object.values(state.byIds).forEach((asset) => {
1183
- state.byIds[asset.asset._id].picked = !1;
1184
- });
1185
- },
1186
- pickRange(state, action) {
1187
- const startIndex = state.allIds.findIndex((id) => id === action.payload.startId), endIndex = state.allIds.findIndex((id) => id === action.payload.endId), indices = [startIndex, endIndex].sort((a, b) => a - b);
1188
- state.allIds.slice(indices[0], indices[1] + 1).forEach((key) => {
1189
- state.byIds[key].picked = !0;
1190
- }), state.lastPicked = state.allIds[endIndex];
1191
- },
1192
- sort(state) {
1193
- state.allIds.sort((a, b) => {
1194
- const tagA = state.byIds[a].asset[state.order.field], tagB = state.byIds[b].asset[state.order.field];
1195
- return tagA < tagB ? state.order.direction === "asc" ? -1 : 1 : tagA > tagB ? state.order.direction === "asc" ? 1 : -1 : 0;
1196
- });
1197
- },
1198
- updateComplete(state, action) {
1199
- const {
1200
- asset
1201
- } = action.payload;
1202
- state.byIds[asset._id].updating = !1, state.byIds[asset._id].asset = asset;
1203
- },
1204
- updateError(state, action) {
1205
- const {
1206
- asset,
1207
- error
1208
- } = action.payload, assetId = asset?._id;
1209
- state.byIds[assetId].error = error.message, state.byIds[assetId].updating = !1;
1210
- },
1211
- updateRequest(state, action) {
1212
- const assetId = action.payload?.asset?._id;
1213
- state.byIds[assetId].updating = !0;
1214
- },
1215
- viewSet(state, action) {
1216
- state.view = action.payload?.view;
1217
- }
1218
- }
1219
- }), assetsDeleteEpic = (action$, _state$, {
1220
- client
1221
- }) => action$.pipe(operators$1.filter(assetsActions.deleteRequest.match), operators$1.mergeMap((action) => {
1222
- const {
1223
- assets
1224
- } = action.payload, assetIds = assets.map((asset) => asset._id);
1225
- return rxjs.of(assets).pipe(operators$1.mergeMap(() => client.observable.delete({
1226
- query: groq__default.default`*[_id in ${JSON.stringify(assetIds)}]`
1227
- })), operators$1.mergeMap(() => rxjs.of(assetsActions.deleteComplete({
1228
- assetIds
1229
- }))), operators$1.catchError((error) => rxjs.of(assetsActions.deleteError({
1230
- assetIds,
1231
- error
1232
- }))));
1233
- })), assetsFetchEpic = (action$, state$, {
1234
- client
1235
- }) => action$.pipe(operators$1.filter(assetsActions.fetchRequest.match), operators$1.withLatestFrom(state$), operators$1.switchMap(([action, state]) => {
1236
- const params = action.payload?.params, query = action.payload?.query;
1237
- return rxjs.of(action).pipe(debugThrottle(state.debug.badConnection), operators$1.mergeMap(() => client.observable.fetch(query, params)), operators$1.mergeMap((result) => {
1238
- const {
1239
- items
1240
- // totalCount
1241
- } = result;
1242
- return rxjs.of(assetsActions.fetchComplete({
1243
- assets: items
1244
- }));
1245
- }), operators$1.catchError((error) => rxjs.of(assetsActions.fetchError({
1246
- message: error?.message || "Internal error",
1247
- statusCode: error?.statusCode || 500
1248
- }))));
1249
- })), assetsFetchPageIndexEpic = (action$, state$) => action$.pipe(operators$1.filter(assetsActions.loadPageIndex.match), operators$1.withLatestFrom(state$), operators$1.switchMap(([action, state]) => {
1250
- const pageSize = state.assets.pageSize, start = action.payload.pageIndex * pageSize, end = start + pageSize, documentId = state?.selected.document?._id, documentAssetIds = state?.selected?.documentAssetIds, constructedFilter = constructFilter({
1251
- assetTypes: state.assets.assetTypes,
1252
- searchFacets: state.search.facets,
1253
- searchQuery: state.search.query
1254
- }), params = {
1255
- ...documentId ? {
1256
- documentId
1257
- } : {},
1258
- documentAssetIds
1259
- };
1260
- return rxjs.of(assetsActions.fetchRequest({
1261
- params,
1262
- queryFilter: constructedFilter,
1263
- selector: groq__default.default`[${start}...${end}]`,
1264
- sort: groq__default.default`order(${state.assets?.order?.field} ${state.assets?.order?.direction})`
1265
- }));
1266
- })), assetsFetchNextPageEpic = (action$, state$) => action$.pipe(operators$1.filter(assetsActions.loadNextPage.match), operators$1.withLatestFrom(state$), operators$1.switchMap(([_action, state]) => rxjs.of(assetsActions.loadPageIndex({
1267
- pageIndex: state.assets.pageIndex + 1
1268
- })))), assetsFetchAfterDeleteAllEpic = (action$, state$) => action$.pipe(operators$1.filter(assetsActions.deleteComplete.match), operators$1.withLatestFrom(state$), operators$1.switchMap(([_action, state]) => {
1269
- if (state.assets.allIds.length === 0) {
1270
- const nextPageIndex = Math.floor(state.assets.allIds.length / state.assets.pageSize);
1271
- return rxjs.of(assetsActions.loadPageIndex({
1272
- pageIndex: nextPageIndex
1273
- }));
1274
- }
1275
- return rxjs.EMPTY;
1276
- })), filterAssetWithoutTag = (tag) => (asset) => (asset?.asset?.opt?.media?.tags?.findIndex((t) => t._ref === tag?._id) ?? -1) < 0, patchOperationTagAppend = ({
1277
- tag
1278
- }) => (patch) => patch.setIfMissing({
1279
- opt: {}
1280
- }).setIfMissing({
1281
- "opt.media": {}
1282
- }).setIfMissing({
1283
- "opt.media.tags": []
1284
- }).append("opt.media.tags", [{
1285
- _key: nanoid.nanoid(),
1286
- _ref: tag?._id,
1287
- _type: "reference",
1288
- _weak: !0
1289
- }]), patchOperationTagUnset = ({
1290
- asset,
1291
- tag
1292
- }) => (patch) => patch.ifRevisionId(asset?.asset?._rev).unset([`opt.media.tags[_ref == "${tag._id}"]`]), assetsOrderSetEpic = (action$) => action$.pipe(operators$1.filter(assetsActions.orderSet.match), operators$1.mergeMap(() => rxjs.of(
1293
- assetsActions.clear(),
1294
- //
1295
- assetsActions.loadPageIndex({
1296
- pageIndex: 0
1297
- })
1298
- ))), assetsSearchEpic = (action$) => action$.pipe(reduxObservable.ofType(searchActions.facetsAdd.type, searchActions.facetsClear.type, searchActions.facetsRemoveById.type, searchActions.facetsRemoveByName.type, searchActions.facetsRemoveByTag.type, searchActions.facetsUpdate.type, searchActions.facetsUpdateById.type, searchActions.querySet.type), operators$1.debounceTime(400), operators$1.mergeMap(() => rxjs.of(
1299
- assetsActions.clear(),
1300
- //
1301
- assetsActions.loadPageIndex({
1302
- pageIndex: 0
1303
- })
1304
- ))), assetsListenerCreateQueueEpic = (action$) => action$.pipe(operators$1.filter(assetsActions.listenerCreateQueue.match), operators$1.bufferTime(2e3), operators$1.filter((actions) => actions.length > 0), operators$1.mergeMap((actions) => {
1305
- const assets = actions?.map((action) => action.payload.asset);
1306
- return rxjs.of(assetsActions.listenerCreateQueueComplete({
1307
- assets
1308
- }));
1309
- })), assetsListenerDeleteQueueEpic = (action$) => action$.pipe(operators$1.filter(assetsActions.listenerDeleteQueue.match), operators$1.bufferTime(2e3), operators$1.filter((actions) => actions.length > 0), operators$1.mergeMap((actions) => {
1310
- const assetIds = actions?.map((action) => action.payload.assetId);
1311
- return rxjs.of(assetsActions.listenerDeleteQueueComplete({
1312
- assetIds
1313
- }));
1314
- })), assetsListenerUpdateQueueEpic = (action$) => action$.pipe(operators$1.filter(assetsActions.listenerUpdateQueue.match), operators$1.bufferTime(2e3), operators$1.filter((actions) => actions.length > 0), operators$1.mergeMap((actions) => {
1315
- const assets = actions?.map((action) => action.payload.asset);
1316
- return rxjs.of(assetsActions.listenerUpdateQueueComplete({
1317
- assets
1318
- }));
1319
- })), assetsSortEpic = (action$) => action$.pipe(reduxObservable.ofType(assetsActions.insertUploads.type, assetsActions.listenerUpdateQueueComplete.type, assetsActions.updateComplete.type), operators$1.mergeMap(() => rxjs.of(assetsActions.sort()))), assetsTagsAddEpic = (action$, state$, {
1320
- client
1321
- }) => action$.pipe(operators$1.filter(ASSETS_ACTIONS.tagsAddRequest.match), operators$1.withLatestFrom(state$), operators$1.mergeMap(([action, state]) => {
1322
- const {
1323
- assets,
1324
- tag
1325
- } = action.payload;
1326
- return rxjs.of(action).pipe(
1327
- // Optionally throttle
1328
- debugThrottle(state.debug.badConnection),
1329
- // Add tag references to all picked assets
1330
- operators$1.mergeMap(() => {
1331
- const transaction = (selectAssetsPicked(state)?.filter(filterAssetWithoutTag(tag))).reduce((tx, pickedAsset) => tx.patch(pickedAsset?.asset?._id, patchOperationTagAppend({
1332
- tag
1333
- })), client.transaction());
1334
- return rxjs.from(transaction.commit());
1335
- }),
1336
- // Dispatch complete action
1337
- operators$1.mergeMap(() => rxjs.of(ASSETS_ACTIONS.tagsAddComplete({
1338
- assets,
1339
- tag
1340
- }))),
1341
- operators$1.catchError((error) => rxjs.of(ASSETS_ACTIONS.tagsAddError({
1342
- assets,
1343
- error: {
1344
- message: error?.message || "Internal error",
1345
- statusCode: error?.statusCode || 500
1346
- },
1347
- tag
1348
- })))
1349
- );
1350
- })), assetsTagsRemoveEpic = (action$, state$, {
1351
- client
1352
- }) => action$.pipe(operators$1.filter(ASSETS_ACTIONS.tagsRemoveRequest.match), operators$1.withLatestFrom(state$), operators$1.mergeMap(([action, state]) => {
1353
- const {
1354
- assets,
1355
- tag
1356
- } = action.payload;
1357
- return rxjs.of(action).pipe(
1358
- // Optionally throttle
1359
- debugThrottle(state.debug.badConnection),
1360
- // Remove tag references from all picked assets
1361
- operators$1.mergeMap(() => {
1362
- const transaction = selectAssetsPicked(state).reduce((tx, pickedAsset) => tx.patch(pickedAsset?.asset?._id, patchOperationTagUnset({
1363
- asset: pickedAsset,
1364
- tag
1365
- })), client.transaction());
1366
- return rxjs.from(transaction.commit());
1367
- }),
1368
- // Dispatch complete action
1369
- operators$1.mergeMap(() => rxjs.of(ASSETS_ACTIONS.tagsRemoveComplete({
1370
- assets,
1371
- tag
1372
- }))),
1373
- operators$1.catchError((error) => rxjs.of(ASSETS_ACTIONS.tagsRemoveError({
1374
- assets,
1375
- error: {
1376
- message: error?.message || "Internal error",
1377
- statusCode: error?.statusCode || 500
1378
- },
1379
- tag
1380
- })))
1381
- );
1382
- })), assetsUnpickEpic = (action$) => action$.pipe(reduxObservable.ofType(assetsActions.orderSet.type, assetsActions.viewSet.type, searchActions.facetsAdd.type, searchActions.facetsClear.type, searchActions.facetsRemoveById.type, searchActions.facetsRemoveByName.type, searchActions.facetsRemoveByTag.type, searchActions.facetsUpdate.type, searchActions.facetsUpdateById.type, searchActions.querySet.type), operators$1.mergeMap(() => rxjs.of(assetsActions.pickClear()))), assetsUpdateEpic = (action$, state$, {
1383
- client
1384
- }) => action$.pipe(operators$1.filter(assetsActions.updateRequest.match), operators$1.withLatestFrom(state$), operators$1.mergeMap(([action, state]) => {
1385
- const {
1386
- asset,
1387
- closeDialogId,
1388
- formData
1389
- } = action.payload;
1390
- return rxjs.of(action).pipe(debugThrottle(state.debug.badConnection), operators$1.mergeMap(() => rxjs.from(client.patch(asset._id).setIfMissing({
1391
- opt: {}
1392
- }).setIfMissing({
1393
- "opt.media": {}
1394
- }).set(formData).commit())), operators$1.mergeMap((updatedAsset) => rxjs.of(assetsActions.updateComplete({
1395
- asset: updatedAsset,
1396
- closeDialogId
1397
- }))), operators$1.catchError((error) => rxjs.of(assetsActions.updateError({
1398
- asset,
1399
- error: {
1400
- message: error?.message || "Internal error",
1401
- statusCode: error?.statusCode || 500
1402
- }
1403
- }))));
1404
- })), selectAssetsByIds = (state) => state.assets.byIds, selectAssetsAllIds = (state) => state.assets.allIds, selectAssetById = toolkit.createSelector([(state) => state.assets.byIds, (_state, assetId) => assetId], (byIds, assetId) => byIds[assetId] || void 0), selectAssets = toolkit.createSelector([selectAssetsByIds, selectAssetsAllIds], (byIds, allIds) => allIds.map((id) => byIds[id])), selectAssetsLength = toolkit.createSelector([selectAssets], (assets) => assets.length), selectAssetsPicked = toolkit.createSelector([selectAssets], (assets) => assets.filter((item) => item?.picked)), selectAssetsPickedLength = toolkit.createSelector([selectAssetsPicked], (assetsPicked) => assetsPicked.length), assetsActions = {
1405
- ...assetsSlice.actions
1406
- };
1407
- var assetsReducer = assetsSlice.reducer;
1408
- const initialState$4 = {
1409
- items: []
1410
- }, dialogSlice = toolkit.createSlice({
1411
- name: "dialog",
1412
- initialState: initialState$4,
1413
- extraReducers: (builder) => {
1414
- builder.addCase(DIALOG_ACTIONS.showTagCreate, (state) => {
1415
- state.items.push({
1416
- id: "tagCreate",
1417
- type: "tagCreate"
1418
- });
1419
- }), builder.addCase(DIALOG_ACTIONS.showTagEdit, (state, action) => {
1420
- const {
1421
- tagId
1422
- } = action.payload;
1423
- state.items.push({
1424
- id: tagId,
1425
- tagId,
1426
- type: "tagEdit"
1427
- });
1428
- });
1429
- },
1430
- reducers: {
1431
- // Clear all dialogs
1432
- clear(state) {
1433
- state.items = [];
1434
- },
1435
- // Add newly created inline tag to assetEdit dialog
1436
- inlineTagCreate(state, action) {
1437
- const {
1438
- assetId,
1439
- tag
1440
- } = action.payload;
1441
- state.items.forEach((item) => {
1442
- item.type === "assetEdit" && item.assetId === assetId && (item.lastCreatedTag = {
1443
- label: tag.name.current,
1444
- value: tag._id
1445
- });
1446
- });
1447
- },
1448
- // Remove inline tags from assetEdit dialog
1449
- inlineTagRemove(state, action) {
1450
- const {
1451
- tagIds
1452
- } = action.payload;
1453
- state.items.forEach((item) => {
1454
- item.type === "assetEdit" && (item.lastRemovedTagIds = tagIds);
1455
- });
1456
- },
1457
- // Remove dialog by id
1458
- remove(state, action) {
1459
- const id = action.payload?.id;
1460
- state.items = state.items.filter((item) => item.id !== id);
1461
- },
1462
- showConfirmAssetsTagAdd(state, action) {
1463
- const {
1464
- assetsPicked,
1465
- closeDialogId,
1466
- tag
1467
- } = action.payload, suffix = `${assetsPicked.length} ${pluralize__default.default("asset", assetsPicked.length)}`;
1468
- state.items.push({
1469
- closeDialogId,
1470
- confirmCallbackAction: ASSETS_ACTIONS.tagsAddRequest({
1471
- assets: assetsPicked,
1472
- tag
1473
- }),
1474
- confirmText: `Yes, add tag to ${suffix}`,
1475
- title: `Add tag ${tag.name.current} to ${suffix}?`,
1476
- id: "confirm",
1477
- headerTitle: "Confirm tag addition",
1478
- tone: "primary",
1479
- type: "confirm"
1480
- });
1481
- },
1482
- showConfirmAssetsTagRemove(state, action) {
1483
- const {
1484
- assetsPicked,
1485
- closeDialogId,
1486
- tag
1487
- } = action.payload, suffix = `${assetsPicked.length} ${pluralize__default.default("asset", assetsPicked.length)}`;
1488
- state.items.push({
1489
- closeDialogId,
1490
- confirmCallbackAction: ASSETS_ACTIONS.tagsRemoveRequest({
1491
- assets: assetsPicked,
1492
- tag
1493
- }),
1494
- confirmText: `Yes, remove tag from ${suffix}`,
1495
- headerTitle: "Confirm tag removal",
1496
- id: "confirm",
1497
- title: `Remove tag ${tag.name.current} from ${suffix}?`,
1498
- tone: "critical",
1499
- type: "confirm"
1500
- });
1501
- },
1502
- showConfirmDeleteAssets(state, action) {
1503
- const {
1504
- assets,
1505
- closeDialogId
1506
- } = action.payload, suffix = `${assets.length} ${pluralize__default.default("asset", assets.length)}`;
1507
- state.items.push({
1508
- closeDialogId,
1509
- confirmCallbackAction: assetsActions.deleteRequest({
1510
- assets: assets.map((assetItem) => assetItem.asset)
1511
- }),
1512
- confirmText: `Yes, delete ${suffix}`,
1513
- description: "This operation cannot be reversed. Are you sure you want to continue?",
1514
- title: `Permanently delete ${suffix}?`,
1515
- id: "confirm",
1516
- headerTitle: "Confirm deletion",
1517
- tone: "critical",
1518
- type: "confirm"
1519
- });
1520
- },
1521
- showConfirmDeleteTag(state, action) {
1522
- const {
1523
- closeDialogId,
1524
- tag
1525
- } = action.payload, suffix = "tag";
1526
- state.items.push({
1527
- closeDialogId,
1528
- confirmCallbackAction: tagsActions.deleteRequest({
1529
- tag
1530
- }),
1531
- confirmText: `Yes, delete ${suffix}`,
1532
- description: "This operation cannot be reversed. Are you sure you want to continue?",
1533
- title: `Permanently delete ${suffix}?`,
1534
- id: "confirm",
1535
- headerTitle: "Confirm deletion",
1536
- tone: "critical",
1537
- type: "confirm"
1538
- });
1539
- },
1540
- showAssetEdit(state, action) {
1541
- const {
1542
- assetId
1543
- } = action.payload;
1544
- state.items.push({
1545
- assetId,
1546
- id: assetId,
1547
- type: "assetEdit"
1548
- });
1549
- },
1550
- showSearchFacets(state) {
1551
- state.items.push({
1552
- id: "searchFacets",
1553
- type: "searchFacets"
1554
- });
1555
- },
1556
- showTags(state) {
1557
- state.items.push({
1558
- id: "tags",
1559
- type: "tags"
1560
- });
1561
- }
1562
- }
1563
- }), dialogClearOnAssetUpdateEpic = (action$) => action$.pipe(reduxObservable.ofType(assetsActions.deleteComplete.type, assetsActions.updateComplete.type, tagsActions.deleteComplete.type, tagsActions.updateComplete.type), operators$1.filter((action) => !!action?.payload?.closeDialogId), operators$1.mergeMap((action) => {
1564
- const dialogId = action?.payload?.closeDialogId;
1565
- return dialogId ? rxjs.of(dialogSlice.actions.remove({
1566
- id: dialogId
1567
- })) : rxjs.EMPTY;
1568
- })), dialogTagCreateEpic = (action$) => action$.pipe(operators$1.filter(tagsActions.createComplete.match), operators$1.mergeMap((action) => {
1569
- const {
1570
- assetId,
1571
- tag
1572
- } = action?.payload || {};
1573
- return assetId ? rxjs.of(dialogSlice.actions.inlineTagCreate({
1574
- tag,
1575
- assetId
1576
- })) : tag._id ? rxjs.of(dialogSlice.actions.remove({
1577
- id: "tagCreate"
1578
- })) : rxjs.EMPTY;
1579
- })), dialogTagDeleteEpic = (action$) => action$.pipe(operators$1.filter(tagsActions.listenerDeleteQueueComplete.match), operators$1.mergeMap((action) => {
1580
- const {
1581
- tagIds
1582
- } = action?.payload || {};
1583
- return rxjs.of(dialogSlice.actions.inlineTagRemove({
1584
- tagIds
1585
- }));
1586
- })), dialogActions = {
1587
- ...dialogSlice.actions
1588
- };
1589
- var dialogReducer = dialogSlice.reducer;
1590
- const ButtonViewGroup = () => {
1591
- const dispatch = reactRedux.useDispatch(), view = useTypedSelector((state) => state.assets.view);
1592
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Inline, { space: 0, style: {
1593
- whiteSpace: "nowrap"
1594
- }, children: [
1595
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, icon: icons.ThLargeIcon, mode: view === "grid" ? "default" : "ghost", onClick: () => dispatch(assetsActions.viewSet({
1596
- view: "grid"
1597
- })), style: {
1598
- borderBottomRightRadius: 0,
1599
- borderTopRightRadius: 0
1600
- } }),
1601
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, icon: icons.ThListIcon, mode: view === "table" ? "default" : "ghost", onClick: () => dispatch(assetsActions.viewSet({
1602
- view: "table"
1603
- })), style: {
1604
- borderBottomLeftRadius: 0,
1605
- borderTopLeftRadius: 0
1606
- } })
1607
- ] });
1608
- };
1609
- function usePortalPopoverProps() {
1610
- const portal = ui.usePortal();
1611
- return {
1612
- animate: !0,
1613
- constrainSize: !0,
1614
- floatingBoundary: portal.element,
1615
- portal: !0,
1616
- referenceBoundary: portal.element
1617
- };
1618
- }
1619
- const OrderSelect = () => {
1620
- const dispatch = reactRedux.useDispatch(), order = useTypedSelector((state) => state.assets.order), popoverProps = usePortalPopoverProps();
1621
- return /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, { button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, icon: icons.SortIcon, mode: "bleed", padding: 3, text: getOrderTitle(order.field, order.direction) }), id: "order", menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, { children: ORDER_OPTIONS?.map((item, index) => {
1622
- if (item) {
1623
- const selected = order.field === item.field && order.direction === item.direction;
1624
- return /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, { disabled: selected, fontSize: 1, iconRight: selected, onClick: () => dispatch(assetsActions.orderSet({
1625
- order: {
1626
- direction: item.direction,
1627
- field: item.field
1628
- }
1629
- })), padding: 2, selected, space: 4, style: {
1630
- minWidth: "200px"
1631
- }, text: getOrderTitle(item.field, item.direction) }, index);
1632
- }
1633
- return /* @__PURE__ */ jsxRuntime.jsx(ui.MenuDivider, {}, index);
1634
- }) }), popover: popoverProps });
1635
- }, Progress = (props) => {
1636
- const {
1637
- loading
1638
- } = props, {
1639
- animationDuration,
1640
- isFinished,
1641
- progress
1642
- } = reactNprogress.useNProgress({
1643
- animationDuration: 300,
1644
- isAnimating: loading
1645
- });
1646
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
1647
- opacity: isFinished ? 0 : 1,
1648
- transition: `opacity ${animationDuration}ms linear`
1649
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
1650
- height: "1px",
1651
- background: "rgba(255, 255, 255, 0.5)",
1652
- position: "absolute",
1653
- left: 0,
1654
- top: 0,
1655
- transition: `width ${animationDuration}ms linear`,
1656
- width: `${progress * 100}%`
1657
- } }) });
1658
- }, SCHEME_COLORS = {
1659
- bg: {
1660
- dark: color.hues.gray[950].hex,
1661
- light: color.hues.gray[50].hex
1662
- },
1663
- bg2: {
1664
- dark: color.hues.gray[900].hex,
1665
- light: color.hues.gray[100].hex
1666
- },
1667
- inputEnabledBorder: {
1668
- dark: ui.studioTheme.color.dark.default.input.default.enabled.border,
1669
- light: ui.studioTheme.color.light.default.input.default.enabled.border
1670
- },
1671
- inputHoveredBorder: {
1672
- dark: ui.studioTheme.color.dark.default.input.default.hovered.border,
1673
- light: ui.studioTheme.color.light.default.input.default.hovered.border
1674
- },
1675
- mutedHoveredBg: {
1676
- dark: ui.studioTheme.color.dark.primary.muted.primary.hovered.bg,
1677
- light: ui.studioTheme.color.light.primary.muted.primary.hovered.bg
1678
- },
1679
- mutedHoveredFg: {
1680
- dark: ui.studioTheme.color.dark.primary.muted.primary.hovered.fg,
1681
- light: ui.studioTheme.color.light.primary.muted.primary.hovered.fg
1682
- },
1683
- mutedSelectedBg: {
1684
- dark: ui.studioTheme.color.dark.primary.muted.primary.selected.bg,
1685
- light: ui.studioTheme.color.light.primary.muted.primary.selected.bg
1686
- },
1687
- spotBlue: {
1688
- dark: ui.studioTheme.color.dark.primary.spot.blue,
1689
- light: ui.studioTheme.color.light.primary.spot.blue
1690
- }
1691
- };
1692
- function getSchemeColor(scheme, colorKey) {
1693
- return SCHEME_COLORS[colorKey]?.[scheme];
1694
- }
1695
- const Container$1 = /* @__PURE__ */ styledComponents.styled(ui.Box).withConfig({
1696
- displayName: "Container",
1697
- componentId: "sc-1g47yaa-0"
1698
- })(({
1699
- $scheme,
1700
- theme
1701
- }) => styledComponents.css`background:${getSchemeColor($scheme, "bg")};border-radius:${ui.rem(theme.sanity.radius[2])};`), SearchFacet = (props) => {
1702
- const {
1703
- children,
1704
- facet
1705
- } = props, scheme = sanity.useColorSchemeValue(), dispatch = reactRedux.useDispatch(), handleClose = () => {
1706
- dispatch(searchActions.facetsRemoveById({
1707
- facetId: facet.id
1708
- }));
1709
- };
1710
- return /* @__PURE__ */ jsxRuntime.jsx(Container$1, { padding: [2, 2, 1], $scheme: scheme, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: ["flex-start", "flex-start", "center"], direction: ["column", "column", "row"], children: [
1711
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingBottom: [3, 3, 0], paddingLeft: 1, paddingRight: 2, paddingTop: [1, 1, 0], children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: 0, style: {
1712
- whiteSpace: "nowrap"
1713
- }, children: facet.title }) }),
1714
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", children: [
1715
- children,
1716
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginLeft: 1, paddingX: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 0, children: /* @__PURE__ */ jsxRuntime.jsx(icons.CloseIcon, { onClick: handleClose }) }) })
1717
- ] })
1718
- ] }) });
1719
- }, TextInputNumber = (props) => {
1720
- const {
1721
- onValueChange,
1722
- value,
1723
- ...remainingProps
1724
- } = props;
1725
- return /* @__PURE__ */ jsxRuntime.jsx(
1726
- ui.TextInput,
1727
- {
1728
- ...remainingProps,
1729
- onChange: (e) => {
1730
- const val = e.target.value;
1731
- (val === "" || /^[0-9\b]+$/.test(val)) && onValueChange(parseInt(val, 10) || "");
1732
- },
1733
- value: value ?? ""
1734
- }
1735
- );
1736
- }, SearchFacetNumber = ({
1737
- facet
1738
- }) => {
1739
- const dispatch = reactRedux.useDispatch(), popoverProps = usePortalPopoverProps(), modifiers = facet?.modifiers, selectedModifier = facet?.modifier ? modifiers?.find((modifier) => modifier.name === facet?.modifier) : modifiers?.[0], handleOperatorItemClick = (operatorType) => {
1740
- dispatch(searchActions.facetsUpdateById({
1741
- id: facet.id,
1742
- operatorType
1743
- }));
1744
- }, handleModifierClick = (modifier) => {
1745
- dispatch(searchActions.facetsUpdateById({
1746
- id: facet.id,
1747
- modifier: modifier.name
1748
- }));
1749
- }, handleValueChange = (value) => {
1750
- dispatch(searchActions.facetsUpdateById({
1751
- id: facet.id,
1752
- value
1753
- }));
1754
- }, selectedOperatorType = facet.operatorType ?? "greaterThan";
1755
- return /* @__PURE__ */ jsxRuntime.jsxs(SearchFacet, { facet, children: [
1756
- facet?.operatorTypes && /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, { button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, iconRight: icons.SelectIcon, padding: 2, text: operators[selectedOperatorType].label }), id: "operators", menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, { children: facet.operatorTypes.map((operatorType, index) => operatorType ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, { disabled: operatorType === selectedOperatorType, fontSize: 1, onClick: () => handleOperatorItemClick(operatorType), padding: 2, text: operators[operatorType].label }, operatorType) : /* @__PURE__ */ jsxRuntime.jsx(ui.MenuDivider, {}, index)) }), popover: popoverProps }),
1757
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginX: 1, style: {
1758
- maxWidth: "50px"
1759
- }, children: /* @__PURE__ */ jsxRuntime.jsx(TextInputNumber, { fontSize: 1, onValueChange: handleValueChange, padding: 2, radius: 2, width: 2, value: facet?.value }) }),
1760
- modifiers && /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, { button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, iconRight: icons.SelectIcon, padding: 2, text: selectedModifier?.title }), id: "modifier", menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, { children: modifiers.map((modifier) => {
1761
- const selected = modifier.name === facet.modifier;
1762
- return /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, { disabled: selected, fontSize: 1, onClick: () => handleModifierClick(modifier), padding: 2, text: modifier.title }, modifier.name);
1763
- }) }), popover: popoverProps })
1764
- ] });
1765
- }, SearchFacetSelect = ({
1766
- facet
1767
- }) => {
1768
- const dispatch = reactRedux.useDispatch(), popoverProps = usePortalPopoverProps(), options = facet?.options, selectedItem = options?.find((v) => v.name === facet?.value), handleListItemClick = (option) => {
1769
- dispatch(searchActions.facetsUpdate({
1770
- name: facet.name,
1771
- value: option.name
1772
- }));
1773
- }, handleOperatorItemClick = (operatorType) => {
1774
- dispatch(searchActions.facetsUpdate({
1775
- name: facet.name,
1776
- operatorType
1777
- }));
1778
- }, selectedOperatorType = facet?.operatorType ?? "is";
1779
- return /* @__PURE__ */ jsxRuntime.jsxs(SearchFacet, { facet, children: [
1780
- facet?.operatorTypes && /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, { button: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginRight: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, iconRight: icons.SelectIcon, padding: 2, text: operators[selectedOperatorType].label }) }), id: "operators", menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, { children: facet.operatorTypes.map((operatorType, index) => operatorType ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, { disabled: operatorType === selectedOperatorType, fontSize: 1, onClick: () => handleOperatorItemClick(operatorType), padding: 2, text: operators[operatorType].label }, operatorType) : /* @__PURE__ */ jsxRuntime.jsx(ui.MenuDivider, {}, index)) }), popover: popoverProps }),
1781
- /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, { button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, iconRight: icons.SelectIcon, padding: 2, text: selectedItem?.title }), id: "list", menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, { children: options?.map((item) => {
1782
- const selected = item.name === selectedItem?.name;
1783
- return /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, { disabled: selected, fontSize: 1, onClick: () => handleListItemClick(item), padding: 2, text: item.title }, item.name);
1784
- }) }), popover: popoverProps })
1785
- ] });
1786
- }, SearchFacetString = ({
1787
- facet
1788
- }) => {
1789
- const dispatch = reactRedux.useDispatch(), popoverProps = usePortalPopoverProps(), handleOperatorItemClick = (operatorType) => {
1790
- dispatch(searchActions.facetsUpdateById({
1791
- id: facet.id,
1792
- operatorType
1793
- }));
1794
- }, handleChange = (e) => {
1795
- dispatch(searchActions.facetsUpdateById({
1796
- id: facet.id,
1797
- value: e.target.value
1798
- }));
1799
- }, selectedOperatorType = facet.operatorType;
1800
- return /* @__PURE__ */ jsxRuntime.jsxs(SearchFacet, { facet, children: [
1801
- facet?.operatorTypes && /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, { button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, iconRight: icons.SelectIcon, padding: 2, text: operators[selectedOperatorType].label }), id: "operators", menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, { children: facet.operatorTypes.map((operatorType, index) => operatorType ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, { disabled: operatorType === selectedOperatorType, fontSize: 1, onClick: () => handleOperatorItemClick(operatorType), padding: 2, text: operators[operatorType].label }, operatorType) : /* @__PURE__ */ jsxRuntime.jsx(ui.MenuDivider, {}, index)) }), popover: popoverProps }),
1802
- !operators[selectedOperatorType].hideInput && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginLeft: 1, style: {
1803
- maxWidth: "125px"
1804
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, { fontSize: 1, onChange: handleChange, padding: 2, radius: 2, width: 2, value: facet?.value }) })
1805
- ] });
1806
- }, {
1807
- fonts: {
1808
- text: {
1809
- sizes: themeTextSizes
1810
- }
1811
- },
1812
- radius: themeRadius$1,
1813
- space: themeSpace$1
1814
- } = ui.studioTheme, reactSelectStyles$1 = (scheme) => ({
1815
- control: (styles, {
1816
- isDisabled,
1817
- isFocused
1818
- }) => {
1819
- let boxShadow = "inset 0 0 0 1px var(--card-border-color)";
1820
- return isFocused && (boxShadow = `inset 0 0 0 1px ${getSchemeColor(scheme, "inputEnabledBorder")},
1821
- 0 0 0 1px ${getSchemeColor(scheme, "bg2")},
1822
- 0 0 0 3px var(--card-focus-ring-color) !important`), {
1823
- ...styles,
1824
- backgroundColor: "var(--card-bg-color)",
1825
- color: "inherit",
1826
- border: "none",
1827
- borderRadius: themeRadius$1[2],
1828
- boxShadow,
1829
- fontSize: themeTextSizes[1].fontSize,
1830
- minHeight: "25px",
1831
- opacity: isDisabled ? 0.5 : "inherit",
1832
- outline: "none",
1833
- transition: "none",
1834
- "&:hover": {
1835
- boxShadow: `inset 0 0 0 1px ${getSchemeColor(scheme, "inputHoveredBorder")}`
1836
- }
1837
- };
1838
- },
1839
- input: (styles) => ({
1840
- ...styles,
1841
- color: "var(--card-fg-color)",
1842
- fontFamily: ui.studioTheme.fonts.text.family,
1843
- fontSize: themeTextSizes[1].fontSize,
1844
- marginLeft: ui.rem(themeSpace$1[2])
1845
- }),
1846
- menuList: (styles) => ({
1847
- ...styles,
1848
- padding: 0
1849
- }),
1850
- noOptionsMessage: (styles) => ({
1851
- ...styles,
1852
- fontFamily: ui.studioTheme.fonts.text.family,
1853
- fontSize: themeTextSizes[1].fontSize,
1854
- lineHeight: "1em"
1855
- }),
1856
- option: (styles, {
1857
- isFocused
1858
- }) => ({
1859
- ...styles,
1860
- backgroundColor: isFocused ? getSchemeColor(scheme, "spotBlue") : "transparent",
1861
- borderRadius: themeRadius$1[2],
1862
- color: isFocused ? getSchemeColor(scheme, "bg") : "inherit",
1863
- fontSize: themeTextSizes[1].fontSize,
1864
- lineHeight: "1em",
1865
- margin: 0,
1866
- padding: ui.rem(themeSpace$1[1]),
1867
- "&:hover": {
1868
- backgroundColor: getSchemeColor(scheme, "spotBlue"),
1869
- color: getSchemeColor(scheme, "bg")
1870
- }
1871
- }),
1872
- placeholder: (styles) => ({
1873
- ...styles,
1874
- fontSize: themeTextSizes[1].fontSize,
1875
- marginLeft: ui.rem(themeSpace$1[2]),
1876
- paddingLeft: 0
1877
- }),
1878
- singleValue: (styles) => ({
1879
- ...styles,
1880
- alignItems: "center",
1881
- display: "inline-flex",
1882
- height: "100%",
1883
- marginLeft: ui.rem(themeSpace$1[2])
1884
- }),
1885
- valueContainer: (styles) => ({
1886
- ...styles,
1887
- margin: 0,
1888
- padding: 0
1889
- })
1890
- }), ClearIndicator = (props) => /* @__PURE__ */ jsxRuntime.jsx(Select.components.ClearIndicator, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingRight: 1, style: {
1891
- transform: "scale(0.85)"
1892
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 0, children: /* @__PURE__ */ jsxRuntime.jsx(icons.CloseIcon, {}) }) }) }), Menu$1 = (props) => /* @__PURE__ */ jsxRuntime.jsx(Select.components.Menu, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { radius: 1, shadow: 2, children: props.children }) }), MenuList$1 = (props) => {
1893
- const {
1894
- children
1895
- } = props, MAX_ROWS = 5, OPTION_HEIGHT = 33;
1896
- if (Array.isArray(children)) {
1897
- const height = children.length > MAX_ROWS ? OPTION_HEIGHT * MAX_ROWS : children.length * OPTION_HEIGHT;
1898
- return /* @__PURE__ */ jsxRuntime.jsx(reactVirtuoso.Virtuoso, { className: "media__custom-scrollbar", itemContent: (index) => {
1899
- const item = children[index];
1900
- return /* @__PURE__ */ jsxRuntime.jsx(Option$1, { ...item.props });
1901
- }, style: {
1902
- height
1903
- }, totalCount: children.length });
1904
- }
1905
- return /* @__PURE__ */ jsxRuntime.jsx(Select.components.MenuList, { ...props, children });
1906
- }, NoOptionsMessage = (props) => /* @__PURE__ */ jsxRuntime.jsx(Select.components.NoOptionsMessage, { ...props, children: props.children }), Option$1 = (props) => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 1, children: /* @__PURE__ */ jsxRuntime.jsx(Select.components.Option, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingY: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: {
1907
- color: "inherit"
1908
- }, textOverflow: "ellipsis", children: props.children }) }) }) }), SingleValue = (props) => /* @__PURE__ */ jsxRuntime.jsx(Select.components.SingleValue, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, textOverflow: "ellipsis", children: props.children }) }), reactSelectComponents$1 = {
1909
- ClearIndicator,
1910
- DropdownIndicator: null,
1911
- IndicatorSeparator: null,
1912
- Menu: Menu$1,
1913
- MenuList: MenuList$1,
1914
- NoOptionsMessage,
1915
- Option: Option$1,
1916
- SingleValue
1917
- }, SearchFacetTags = ({
1918
- facet
1919
- }) => {
1920
- const scheme = sanity.useColorSchemeValue(), dispatch = reactRedux.useDispatch(), tags = useTypedSelector((state) => selectTags(state)), tagsFetching = useTypedSelector((state) => state.tags.fetching), allTagOptions = getTagSelectOptions(tags), popoverProps = usePortalPopoverProps(), handleChange = (option) => {
1921
- dispatch(searchActions.facetsUpdateById({
1922
- id: facet.id,
1923
- value: option
1924
- }));
1925
- }, handleOperatorItemClick = (operatorType) => {
1926
- dispatch(searchActions.facetsUpdateById({
1927
- id: facet.id,
1928
- operatorType
1929
- }));
1930
- }, selectedOperatorType = facet.operatorType;
1931
- return /* @__PURE__ */ jsxRuntime.jsxs(SearchFacet, { facet, children: [
1932
- facet?.operatorTypes && /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, { button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, iconRight: icons.SelectIcon, padding: 2, text: operators[selectedOperatorType].label }), id: "operators", menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, { children: facet.operatorTypes.map((operatorType, index) => operatorType ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, { disabled: operatorType === selectedOperatorType, fontSize: 1, onClick: () => handleOperatorItemClick(operatorType), padding: 2, space: 4, style: {
1933
- minWidth: "150px"
1934
- }, text: operators[operatorType].label }, operatorType) : /* @__PURE__ */ jsxRuntime.jsx(ui.MenuDivider, {}, index)) }), popover: popoverProps }),
1935
- !operators[selectedOperatorType].hideInput && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginX: 1, style: {
1936
- width: "160px"
1937
- }, children: /* @__PURE__ */ jsxRuntime.jsx(Select__default.default, { components: reactSelectComponents$1, instanceId: "facet-searchable", isClearable: !0, isDisabled: tagsFetching, isSearchable: !0, name: "tags", noOptionsMessage: () => "No tags", onChange: (value) => handleChange(value), options: allTagOptions, placeholder: tagsFetching ? "Loading..." : "Select...", styles: reactSelectStyles$1(scheme), value: facet?.value }) })
1938
- ] });
1939
- }, StackContainer = /* @__PURE__ */ styledComponents.styled(ui.Flex).withConfig({
1940
- displayName: "StackContainer",
1941
- componentId: "sc-cuu8kf-0"
1942
- })(({
1943
- theme
1944
- }) => styledComponents.css`> *{margin-bottom:${ui.rem(theme.sanity.space[2])};}`), SearchFacets = (props) => {
1945
- const {
1946
- layout = "inline"
1947
- } = props, searchFacets = useTypedSelector((state) => state.search.facets), Items2 = searchFacets.map((facet) => {
1948
- const key = facet.id;
1949
- return facet.type === "number" ? /* @__PURE__ */ jsxRuntime.jsx(SearchFacetNumber, { facet }, key) : facet.type === "searchable" ? /* @__PURE__ */ jsxRuntime.jsx(SearchFacetTags, { facet }, key) : facet.type === "select" ? /* @__PURE__ */ jsxRuntime.jsx(SearchFacetSelect, { facet }, key) : facet.type === "string" ? /* @__PURE__ */ jsxRuntime.jsx(SearchFacetString, { facet }, key) : null;
1950
- });
1951
- if (layout === "inline")
1952
- return searchFacets.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Inline, { space: 2, children: Items2 }) });
1953
- if (layout === "stack")
1954
- return /* @__PURE__ */ jsxRuntime.jsx(StackContainer, { align: "flex-start", direction: "column", children: Items2 });
1955
- throw Error("Invalid layout");
1956
- }, ToolOptionsContext = react.createContext(null), ToolOptionsProvider = ({
1957
- options,
1958
- children
1959
- }) => {
1960
- const value = react.useMemo(() => {
1961
- let creditLineExcludeSources;
1962
- return options?.creditLine?.excludeSources && (creditLineExcludeSources = Array.isArray(options?.creditLine?.excludeSources) ? options.creditLine.excludeSources : [options?.creditLine?.excludeSources]), {
1963
- dropzone: {
1964
- maxSize: options?.maximumUploadSize
1965
- },
1966
- components: {
1967
- details: options?.components?.details
1968
- },
1969
- createTagsOnUpload: options?.createTagsOnUpload ?? !0,
1970
- creditLine: {
1971
- enabled: options?.creditLine?.enabled || !1,
1972
- excludeSources: creditLineExcludeSources
1973
- },
1974
- directUploads: options?.directUploads ?? !0,
1975
- locales: options?.locales
1976
- };
1977
- }, [options?.creditLine?.enabled, options?.components, options?.createTagsOnUpload, options?.creditLine?.excludeSources, options?.maximumUploadSize, options?.directUploads, options?.locales]);
1978
- return /* @__PURE__ */ jsxRuntime.jsx(ToolOptionsContext.Provider, { value, children });
1979
- }, useToolOptions = () => {
1980
- const context = react.useContext(ToolOptionsContext);
1981
- if (!context)
1982
- throw new Error("useToolOptions must be used within an ToolOptionsProvider");
1983
- return context;
1984
- }, SearchFacetsControl = () => {
1985
- const dispatch = reactRedux.useDispatch(), assetTypes = useTypedSelector((state) => state.assets.assetTypes), searchFacets = useTypedSelector((state) => state.search.facets), selectedDocument = useTypedSelector((state) => state.selected.document), popoverProps = usePortalPopoverProps(), {
1986
- creditLine
1987
- } = useToolOptions(), isTool = !selectedDocument, filteredFacets = FACETS.filter((facet) => !creditLine?.enabled && facet?.type === "string" && facet?.name === "creditLine" ? !1 : facet.type === "group" || facet.type === "divider" ? !0 : isTool ? !facet?.selectOnly : facet.assetTypes.filter((assetType) => assetTypes.includes(assetType)).length > 0).filter((facet, index, facets) => {
1988
- const previousFacet = facets[index - 1];
1989
- return !(facet.type === "divider" && (index === 0 || index === facets.length - 1) || facet.type === "divider" && previousFacet?.type === "divider");
1990
- }), hasSearchFacets = filteredFacets.length > 0, renderMenuFacets = (facets, level = 0) => /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: facets?.map((facet, index) => {
1991
- if (facet.type === "divider")
1992
- return /* @__PURE__ */ jsxRuntime.jsx(ui.MenuDivider, {}, index);
1993
- if (facet.type === "group")
1994
- return /* @__PURE__ */ jsxRuntime.jsx(ui.MenuGroup, { text: facet.title, title: facet.title, children: renderMenuFacets(facet.facets, level + 1) }, `group-${level}-${index}`);
1995
- if (facet) {
1996
- const disabled = !facet.operatorTypes && !!searchFacets.find((v) => v.name === facet.name);
1997
- return /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, { disabled, fontSize: 1, onClick: () => dispatch(searchActions.facetsAdd({
1998
- facet
1999
- })), padding: 2, text: facet.title }, facet.name);
2000
- }
2001
- return null;
2002
- }) });
2003
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { children: [
2004
- /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, { button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled: !hasSearchFacets, fontSize: 1, icon: icons.AddIcon, mode: "bleed", space: 2, text: "Add filter", tone: "primary" }), id: "facets", menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, { children: renderMenuFacets(filteredFacets) }), popover: {
2005
- ...popoverProps,
2006
- placement: "right-start"
2007
- } }),
2008
- searchFacets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, mode: "bleed", onClick: () => dispatch(searchActions.facetsClear()), text: "Clear" })
2009
- ] });
2010
- }, TagIcon = () => /* @__PURE__ */ jsxRuntime.jsxs(
2011
- "svg",
2012
- {
2013
- "data-sanity-icon": "media__tag",
2014
- fill: "currentColor",
2015
- height: "1em",
2016
- stroke: "currentColor",
2017
- strokeWidth: "0",
2018
- viewBox: "0 0 512 512",
2019
- width: "1em",
2020
- children: [
2021
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M435.25 48h-122.9a14.46 14.46 0 00-10.2 4.2L56.45 297.9a28.85 28.85 0 000 40.7l117 117a28.85 28.85 0 0040.7 0L459.75 210a14.46 14.46 0 004.2-10.2v-123a28.66 28.66 0 00-28.7-28.8z", fill: "none", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "32" }),
2022
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M384 160a32 32 0 1132-32 32 32 0 01-32 32z" })
2023
- ]
2024
- }
2025
- ), TextInputSearch = () => {
2026
- const searchQuery = useTypedSelector((state) => state.search.query), dispatch = reactRedux.useDispatch(), handleChange = (e) => {
2027
- dispatch(searchActions.querySet({
2028
- searchQuery: e.currentTarget.value
2029
- }));
2030
- }, handleClear = () => {
2031
- dispatch(searchActions.querySet({
2032
- searchQuery: ""
2033
- }));
2034
- };
2035
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { style: {
2036
- position: "relative"
2037
- }, children: [
2038
- /* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, { fontSize: 1, icon: icons.SearchIcon, onChange: handleChange, placeholder: "Search", radius: 2, value: searchQuery }),
2039
- searchQuery.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "center", onClick: handleClear, style: {
2040
- cursor: "pointer",
2041
- height: "100%",
2042
- opacity: 0.75,
2043
- position: "absolute",
2044
- right: 0,
2045
- top: 0,
2046
- width: "2em",
2047
- zIndex: 1
2048
- // force stacking context
2049
- }, children: /* @__PURE__ */ jsxRuntime.jsx(icons.CloseIcon, {}) })
2050
- ] });
2051
- }, Controls = () => {
2052
- const dispatch = reactRedux.useDispatch(), fetching = useTypedSelector((state) => state.assets.fetching), pageIndex = useTypedSelector((state) => state.assets.pageIndex), searchFacets = useTypedSelector((state) => state.search.facets), tagsPanelVisible = useTypedSelector((state) => state.tags.panelVisible), mediaIndex = ui.useMediaIndex(), handleShowSearchFacetDialog = () => {
2053
- dispatch(dialogActions.showSearchFacets());
2054
- }, handleShowTagsDialog = () => {
2055
- dispatch(dialogActions.showTags());
2056
- }, toggleTagsPanelToggle = () => {
2057
- dispatch(tagsActions.panelVisibleSet({
2058
- panelVisible: !tagsPanelVisible
2059
- }));
2060
- };
2061
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { paddingY: 2, style: {
2062
- borderBottom: "1px solid var(--card-border-color)",
2063
- zIndex: 2
2064
- }, children: [
2065
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "flex-start", direction: ["column", "column", "column", "column", "row"], justify: "space-between", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { flex: 1, style: {
2066
- alignItems: "flex-start",
2067
- flex: 1,
2068
- height: "100%",
2069
- justifyContent: mediaIndex < 2 ? "space-between" : "flex-start",
2070
- position: "relative",
2071
- width: "100%"
2072
- }, children: [
2073
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginX: 2, style: {
2074
- minWidth: "200px"
2075
- }, children: /* @__PURE__ */ jsxRuntime.jsx(TextInputSearch, {}) }),
2076
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { display: ["none", "none", "block"], children: [
2077
- /* @__PURE__ */ jsxRuntime.jsx(SearchFacets, {}),
2078
- /* @__PURE__ */ jsxRuntime.jsx(SearchFacetsControl, {})
2079
- ] }),
2080
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { display: ["block", "block", "none"], marginX: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Inline, { space: 2, style: {
2081
- whiteSpace: "nowrap"
2082
- }, children: [
2083
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, mode: "ghost", onClick: handleShowSearchFacetDialog, text: `Filters${searchFacets.length > 0 ? ` (${searchFacets.length})` : ""}`, tone: "primary" }),
2084
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, mode: "ghost", onClick: handleShowTagsDialog, text: "Tags", tone: "primary" })
2085
- ] }) })
2086
- ] }) }) }),
2087
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", justify: ["space-between"], children: [
2088
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginX: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ButtonViewGroup, {}) }),
2089
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { marginX: 2, children: [
2090
- /* @__PURE__ */ jsxRuntime.jsx(OrderSelect, {}),
2091
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { display: ["none", "none", "block"], marginLeft: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, icon: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
2092
- transform: "scale(0.75)"
2093
- }, children: /* @__PURE__ */ jsxRuntime.jsx(TagIcon, {}) }), onClick: toggleTagsPanelToggle, mode: tagsPanelVisible ? "default" : "ghost", text: tagsPanelVisible ? "Tags" : "" }) })
2094
- ] })
2095
- ] }) }),
2096
- /* @__PURE__ */ jsxRuntime.jsx(Progress, { loading: fetching }, pageIndex)
2097
- ] });
2098
- }, initialState$3 = {
2099
- badConnection: !1,
2100
- enabled: !1
2101
- }, debugSlice = toolkit.createSlice({
2102
- name: "debug",
2103
- initialState: initialState$3,
2104
- reducers: {
2105
- setBadConnection(state, action) {
2106
- state.badConnection = action.payload;
2107
- },
2108
- toggleEnabled(state) {
2109
- state.enabled = !state.enabled;
2110
- }
2111
- }
2112
- }), debugActions = {
2113
- ...debugSlice.actions
2114
- };
2115
- var debugReducer = debugSlice.reducer;
2116
- const DebugControls = () => {
2117
- const dispatch = reactRedux.useDispatch(), badConnection = useTypedSelector((state) => state.debug.badConnection), debugEnabled = useTypedSelector((state) => state.debug.enabled), handleChange = (e) => {
2118
- const checked = e.target.checked;
2119
- dispatch(debugActions.setBadConnection(checked));
2120
- };
2121
- return useKeyPress("alt+ctrl+shift+/", () => {
2122
- dispatch(debugActions.toggleEnabled());
2123
- }), debugEnabled ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 4, style: {
2124
- bottom: 0,
2125
- left: 0,
2126
- pointerEvents: "none",
2127
- position: "fixed",
2128
- width: "100%"
2129
- }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", children: [
2130
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginRight: 3, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: /* @__PURE__ */ jsxRuntime.jsx(icons.PlugIcon, {}) }) }),
2131
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { animate: !0, content: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: badConnection ? "Bad connection: +3000ms & 50% chance to fail" : "No connection throttling" }) }), fallbackPlacements: ["right", "left"], placement: "bottom", portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Switch, { checked: badConnection, onChange: handleChange, style: {
2132
- pointerEvents: "auto"
2133
- } }) })
2134
- ] }) }) : null;
2135
- };
2136
- function localizedStringSchema(locales) {
2137
- if (!locales || locales.length === 0)
2138
- return z__namespace.string().trim().optional();
2139
- const shape = {};
2140
- for (const locale of locales)
2141
- shape[locale.id] = z__namespace.string().trim().optional();
2142
- return z__namespace.object(shape).passthrough();
2143
- }
2144
- const tagOptionSchema = z__namespace.object({
2145
- label: z__namespace.string().trim().min(1, {
2146
- message: "Label cannot be empty"
2147
- }),
2148
- value: z__namespace.string().trim().min(1, {
2149
- message: "Value cannot be empty"
2150
- })
2151
- });
2152
- function getAssetFormSchema(locales) {
2153
- return z__namespace.object({
2154
- altText: localizedStringSchema(locales),
2155
- creditLine: localizedStringSchema(locales),
2156
- description: localizedStringSchema(locales),
2157
- opt: z__namespace.object({
2158
- media: z__namespace.object({
2159
- tags: z__namespace.array(tagOptionSchema).nullable()
2160
- })
2161
- }),
2162
- originalFilename: z__namespace.string().trim().min(1, {
2163
- message: "Filename cannot be empty"
2164
- }),
2165
- title: localizedStringSchema(locales)
2166
- });
2167
- }
2168
- getAssetFormSchema();
2169
- const tagFormSchema = z__namespace.object({
2170
- name: z__namespace.string().min(1, {
2171
- message: "Name cannot be empty"
2172
- })
2173
- });
2174
- function getUniqueDocuments(documents) {
2175
- const draftIds = documents.reduce((acc, doc) => doc._id.startsWith("drafts.") ? acc.concat(doc._id.slice(7)) : acc, []);
2176
- return documents.filter((doc) => !draftIds.includes(doc._id));
2177
- }
2178
- const imageDprUrl = (asset, options) => {
2179
- const dpi = typeof window > "u" || !window.devicePixelRatio ? 1 : Math.round(window.devicePixelRatio), imgH = options?.height ? options?.height * Math.max(1, dpi) : void 0, imgW = options.width * Math.max(1, dpi), urlParams = new URLSearchParams();
2180
- return urlParams.append("fit", "max"), urlParams.append("w", imgW.toString()), imgH && urlParams.append("h", imgH.toString()), `${asset.url}?${urlParams.toString()}`;
2181
- }, sanitizeFormData = (formData) => Object.keys(formData).reduce((acc, key) => {
2182
- const val = formData[key];
2183
- return typeof val == "object" && val !== null && val.constructor !== Array ? acc[key] = sanitizeFormData(val) : val === "" || typeof val > "u" || val?.length === 0 ? acc[key] = null : typeof val == "string" && val ? acc[key] = formData[key].trim() : acc[key] = formData[key], acc;
2184
- }, {}), isFileAsset = (asset) => asset._type === "sanity.fileAsset", isImageAsset = (asset) => asset._type === "sanity.imageAsset";
2185
- function zodFormResolver(schema) {
2186
- return zod.zodResolver(schema);
2187
- }
2188
- const getAssetResolution = (asset) => `${asset.metadata.dimensions.width}x${asset.metadata.dimensions.height}px`, ButtonAssetCopy = ({
2189
- disabled,
2190
- url
2191
- }) => {
2192
- const popoverProps = usePortalPopoverProps(), refPopoverTimeout = react.useRef(null), [popoverVisible, setPopoverVisible] = react.useState(!1), handleClick = () => {
2193
- refPopoverTimeout.current && clearTimeout(refPopoverTimeout.current), setPopoverVisible(!0), copy__default.default(url), refPopoverTimeout.current = setTimeout(() => {
2194
- setPopoverVisible(!1);
2195
- }, 1250);
2196
- };
2197
- return react.useEffect(() => () => {
2198
- refPopoverTimeout.current && clearTimeout(refPopoverTimeout.current);
2199
- }, []), /* @__PURE__ */ jsxRuntime.jsx(ui.Popover, { content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: "Copied!" }), open: popoverVisible, padding: 2, placement: "top", radius: 1, ...popoverProps, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled, fontSize: 1, icon: icons.ClipboardIcon, mode: "ghost", onClick: handleClick, text: "Copy URL" }) });
2200
- }, Row = ({
2201
- label,
2202
- value
2203
- }) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "space-between", children: [
2204
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: {
2205
- opacity: 0.8,
2206
- width: "40%"
2207
- }, textOverflow: "ellipsis", children: label }),
2208
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: {
2209
- opacity: 0.4,
2210
- textAlign: "right",
2211
- width: "60%"
2212
- }, textOverflow: "ellipsis", children: value })
2213
- ] }), AssetMetadata = (props) => {
2214
- const {
2215
- asset,
2216
- item
2217
- } = props, exif = asset?.metadata?.exif, handleDownload = () => {
2218
- window.location.href = `${asset.url}?dl=${asset.originalFilename}`;
2219
- };
2220
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { marginTop: 3, children: [
2221
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
2222
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Size", value: filesize__default.default(asset?.size, {
2223
- base: 10,
2224
- round: 0
2225
- }) }),
2226
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "MIME type", value: asset?.mimeType }),
2227
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Extension", value: asset?.extension?.toUpperCase() }),
2228
- isImageAsset(asset) && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Dimensions", value: getAssetResolution(asset) })
2229
- ] }) }),
2230
- exif && (exif.DateTimeOriginal || exif.FNumber || exif.FocalLength || exif.ExposureTime || exif.ISO) && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2231
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginY: 4, style: {
2232
- background: "var(--card-border-color)",
2233
- height: "1px",
2234
- width: "100%"
2235
- } }),
2236
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
2237
- exif.ISO && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "ISO", value: exif.ISO }),
2238
- exif.FNumber && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Aperture", value: `\u0192/${exif.FNumber}` }),
2239
- exif.FocalLength && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Focal length", value: `${exif.FocalLength}mm` }),
2240
- exif.ExposureTime && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Exposure time", value: `1/${1 / exif.ExposureTime}` }),
2241
- exif.DateTimeOriginal && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Original date", value: dateFns.format(new Date(exif.DateTimeOriginal), "PPp") })
2242
- ] }) })
2243
- ] }),
2244
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Inline, { space: 2, children: [
2245
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled: !item || item?.updating, fontSize: 1, icon: icons.DownloadIcon, mode: "ghost", onClick: handleDownload, text: "Download" }),
2246
- /* @__PURE__ */ jsxRuntime.jsx(ButtonAssetCopy, { disabled: !item || item?.updating, url: asset.url })
2247
- ] }) })
2248
- ] });
2249
- }, Dialog = (props) => /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { ...props, style: {
2250
- position: "fixed"
2251
- } }), DocumentList = ({
2252
- documents,
2253
- isLoading
2254
- }) => {
2255
- const schema = sanity.useSchema();
2256
- return isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: "Loading..." }) : documents.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: "No documents are referencing this asset" }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { flex: 1, marginBottom: 2, padding: 2, radius: 2, shadow: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 2, children: documents?.map((doc) => /* @__PURE__ */ jsxRuntime.jsx(ReferringDocument, { doc, schemaType: schema.get(doc._type) }, doc._id)) }) });
2257
- }, ReferringDocument = (props) => {
2258
- const {
2259
- doc,
2260
- schemaType
2261
- } = props, {
2262
- onClick
2263
- } = router.useIntentLink({
2264
- intent: "edit",
2265
- params: {
2266
- id: doc._id
2267
- }
2268
- });
2269
- return schemaType ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { mode: "bleed", onClick, padding: 2, style: {
2270
- width: "100%"
2271
- }, children: /* @__PURE__ */ jsxRuntime.jsx(sanity.Preview, { layout: "default", schemaType, value: doc }) }, doc._id) : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: 1, children: [
2272
- "A document of the unknown type ",
2273
- /* @__PURE__ */ jsxRuntime.jsx("em", { children: doc._type })
2274
- ] }) });
2275
- }, Container = /* @__PURE__ */ styledComponents.styled(ui.Box).withConfig({
2276
- displayName: "Container",
2277
- componentId: "sc-19eu02y-0"
2278
- })(({
2279
- theme
2280
- }) => styledComponents.css`text{font-family:${theme.sanity.fonts.text.family} !important;font-size:8px !important;font-weight:500 !important;}`), FileIcon = (props) => {
2281
- const {
2282
- extension,
2283
- onClick,
2284
- width
2285
- } = props;
2286
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "center", onClick, style: {
2287
- height: "100%"
2288
- }, children: /* @__PURE__ */ jsxRuntime.jsx(Container, { style: {
2289
- width
2290
- }, children: extension ? /* @__PURE__ */ jsxRuntime.jsx(reactFileIcon.FileIcon, { extension, ...reactFileIcon.defaultStyles[extension] }) : /* @__PURE__ */ jsxRuntime.jsx(reactFileIcon.FileIcon, {}) }) });
2291
- }, FileAssetPreview = (props) => {
2292
- const {
2293
- asset
2294
- } = props;
2295
- return asset.mimeType.search("audio") === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "center", style: {
2296
- height: "100%"
2297
- }, children: /* @__PURE__ */ jsxRuntime.jsx("audio", { controls: !0, src: asset.url, style: {
2298
- width: "100%"
2299
- } }) }) : asset.mimeType.search("video") === 0 ? /* @__PURE__ */ jsxRuntime.jsx("video", { controls: !0, src: asset.url, style: {
2300
- height: "100%",
2301
- width: "100%"
2302
- } }) : /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { extension: asset.extension, width: "50%" });
2303
- }, FormSubmitButton = (props) => {
2304
- const {
2305
- disabled,
2306
- isValid,
2307
- lastUpdated,
2308
- onClick
2309
- } = props;
2310
- let content;
2311
- return isValid ? lastUpdated ? content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2312
- "Last updated",
2313
- /* @__PURE__ */ jsxRuntime.jsx("br", {}),
2314
- " ",
2315
- dateFns.format(new Date(lastUpdated), "PPp")
2316
- ] }) : content = "No unpublished changes" : content = "There are validation errors that need to be fixed before this document can be published", /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { animate: !0, content: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 3, style: {
2317
- maxWidth: "185px"
2318
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: content }) }), disabled: "ontouchstart" in window, placement: "top", portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled, fontSize: 1, onClick, text: "Save and close", tone: "primary" }) }) });
2319
- }, Image$1 = styledComponents.styled.img.withConfig({
2320
- displayName: "Image",
2321
- componentId: "sc-hf3ld2-0"
2322
- })`--checkerboard-color:${(props) => props.$scheme ? getSchemeColor(props.$scheme, "bg2") : "inherit"};display:block;width:100%;height:100%;object-fit:contain;${(props) => props.$showCheckerboard && styledComponents.css`background-image:linear-gradient(45deg,var(--checkerboard-color) 25%,transparent 25%),linear-gradient(-45deg,var(--checkerboard-color) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--checkerboard-color) 75%),linear-gradient(-45deg,transparent 75%,var(--checkerboard-color) 75%);background-size:20px 20px;background-position:0 0,0 10px,10px -10px,-10px 0;`}`, {
2323
- radius: themeRadius,
2324
- space: themeSpace
2325
- } = ui.studioTheme, reactSelectStyles = (scheme) => ({
2326
- control: (styles, {
2327
- isFocused
2328
- }) => {
2329
- let boxShadow = "inset 0 0 0 1px var(--card-border-color)";
2330
- return isFocused && (boxShadow = `inset 0 0 0 1px ${getSchemeColor(scheme, "inputEnabledBorder")},
2331
- 0 0 0 1px var(--card-bg-color),
2332
- 0 0 0 3px var(--card-focus-ring-color) !important`), {
2333
- ...styles,
2334
- backgroundColor: "var(--card-bg-color)",
2335
- color: "inherit",
2336
- border: "none",
2337
- borderRadius: themeRadius[1],
2338
- boxShadow,
2339
- margin: 0,
2340
- minHeight: "35px",
2341
- outline: "none",
2342
- padding: ui.rem(themeSpace[1]),
2343
- transition: "none",
2344
- "&:hover": {
2345
- boxShadow: `inset 0 0 0 1px ${getSchemeColor(scheme, "inputHoveredBorder")}`
2346
- }
2347
- };
2348
- },
2349
- indicatorsContainer: (styles, {
2350
- isDisabled
2351
- }) => ({
2352
- ...styles,
2353
- opacity: isDisabled ? 0.25 : 1
2354
- }),
2355
- input: (styles) => ({
2356
- ...styles,
2357
- color: "var(--card-fg-color)",
2358
- fontFamily: ui.studioTheme.fonts.text.family,
2359
- marginLeft: ui.rem(themeSpace[2])
2360
- }),
2361
- menuList: (styles) => ({
2362
- ...styles
2363
- }),
2364
- multiValue: (styles, {
2365
- isDisabled
2366
- }) => ({
2367
- ...styles,
2368
- backgroundColor: getSchemeColor(scheme, "mutedHoveredBg"),
2369
- borderRadius: themeRadius[2],
2370
- opacity: isDisabled ? 0.5 : 1
2371
- }),
2372
- multiValueLabel: () => ({
2373
- color: getSchemeColor(scheme, "mutedHoveredFg"),
2374
- fontSize: "inherit",
2375
- padding: 0
2376
- }),
2377
- multiValueRemove: (styles) => ({
2378
- ...styles,
2379
- borderTopLeftRadius: 0,
2380
- borderBottomLeftRadius: 0,
2381
- svg: {
2382
- color: getSchemeColor(scheme, "mutedHoveredFg")
2383
- },
2384
- "&:hover": {
2385
- backgroundColor: getSchemeColor(scheme, "mutedSelectedBg")
2386
- }
2387
- }),
2388
- noOptionsMessage: (styles) => ({
2389
- ...styles,
2390
- fontFamily: ui.studioTheme.fonts.text.family,
2391
- lineHeight: "1em"
2392
- }),
2393
- option: (styles, {
2394
- isFocused
2395
- }) => ({
2396
- ...styles,
2397
- backgroundColor: isFocused ? getSchemeColor(scheme, "spotBlue") : "transparent",
2398
- borderRadius: themeRadius[2],
2399
- color: isFocused ? getSchemeColor(scheme, "bg") : "inherit",
2400
- padding: `${ui.rem(themeSpace[1])} ${ui.rem(themeSpace[2])}`,
2401
- "&:hover": {
2402
- backgroundColor: getSchemeColor(scheme, "spotBlue"),
2403
- color: getSchemeColor(scheme, "bg")
2404
- }
2405
- }),
2406
- placeholder: (styles) => ({
2407
- ...styles,
2408
- marginLeft: ui.rem(themeSpace[2])
2409
- }),
2410
- valueContainer: (styles) => ({
2411
- ...styles,
2412
- margin: 0,
2413
- padding: 0
2414
- })
2415
- }), DropdownIndicator = (props) => /* @__PURE__ */ jsxRuntime.jsx(Select.components.DropdownIndicator, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingX: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: /* @__PURE__ */ jsxRuntime.jsx(icons.ChevronDownIcon, {}) }) }) }), Menu = (props) => /* @__PURE__ */ jsxRuntime.jsx(Select.components.Menu, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { radius: 1, shadow: 2, children: props.children }) }), MenuList = (props) => {
2416
- const {
2417
- children
2418
- } = props, MAX_ROWS = 5, OPTION_HEIGHT = 37;
2419
- if (Array.isArray(children)) {
2420
- const height = children.length > MAX_ROWS ? OPTION_HEIGHT * MAX_ROWS : children.length * OPTION_HEIGHT;
2421
- return /* @__PURE__ */ jsxRuntime.jsx(reactVirtuoso.Virtuoso, { className: "media__custom-scrollbar", itemContent: (index) => {
2422
- const item = children[index];
2423
- return /* @__PURE__ */ jsxRuntime.jsx(Option, { ...item.props });
2424
- }, style: {
2425
- height
2426
- }, totalCount: children.length });
2427
- }
2428
- return /* @__PURE__ */ jsxRuntime.jsx(Select.components.MenuList, { ...props, children });
2429
- }, MultiValueLabel = (props) => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 2, paddingRight: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "medium", children: /* @__PURE__ */ jsxRuntime.jsx(Select.components.MultiValueLabel, { ...props }) }) }), MultiValueRemove = (props) => /* @__PURE__ */ jsxRuntime.jsx(Select.components.MultiValueRemove, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx(icons.CloseIcon, { color: "#1f2123" }) }), Option = (props) => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingX: 1, paddingY: 1, children: /* @__PURE__ */ jsxRuntime.jsx(Select.components.Option, { ...props, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", children: [
2430
- props.data.__isNew__ && /* @__PURE__ */ jsxRuntime.jsx(icons.AddIcon, { style: {
2431
- marginRight: "3px"
2432
- } }),
2433
- props.children
2434
- ] }) }) }), reactSelectComponents = {
2435
- DropdownIndicator,
2436
- IndicatorSeparator: null,
2437
- Menu,
2438
- MenuList,
2439
- MultiValueLabel,
2440
- MultiValueRemove,
2441
- Option
2442
- }, StyledErrorOutlineIcon = /* @__PURE__ */ styledComponents.styled(icons.ErrorOutlineIcon).withConfig({
2443
- displayName: "StyledErrorOutlineIcon",
2444
- componentId: "sc-xxpdbt-0"
2445
- })(({
2446
- theme
2447
- }) => ({
2448
- color: theme.sanity.color.spot.red
2449
- })), FormFieldInputLabel = (props) => {
2450
- const {
2451
- description,
2452
- error,
2453
- label,
2454
- name
2455
- } = props;
2456
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2457
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginY: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Inline, { space: 2, children: [
2458
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "label", htmlFor: name, size: 1, weight: "semibold", children: label }),
2459
- error && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { animate: !0, content: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { muted: !0, size: 1, children: [
2460
- /* @__PURE__ */ jsxRuntime.jsx(StyledErrorOutlineIcon, { style: {
2461
- marginRight: "0.1em"
2462
- } }),
2463
- error
2464
- ] }) }), fallbackPlacements: ["top", "left"], placement: "right", portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx(StyledErrorOutlineIcon, {}) }) })
2465
- ] }) }),
2466
- description && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginY: 3, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { htmlFor: name, muted: !0, size: 1, children: description }) })
2467
- ] });
2468
- }, FormFieldInputTags = (props) => {
2469
- const {
2470
- control,
2471
- description,
2472
- disabled,
2473
- error,
2474
- label,
2475
- name,
2476
- onCreateTag,
2477
- options,
2478
- placeholder,
2479
- value
2480
- } = props, scheme = sanity.useColorSchemeValue(), creating = useTypedSelector((state) => state.tags.creating), tagsFetching = useTypedSelector((state) => state.tags.fetching);
2481
- return /* @__PURE__ */ jsxRuntime.jsxs(
2482
- ui.Box,
2483
- {
2484
- style: {
2485
- zIndex: 2
2486
- },
2487
- children: [
2488
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputLabel, { description, error, label, name }),
2489
- /* @__PURE__ */ jsxRuntime.jsx(reactHookForm.Controller, { control, defaultValue: value, name, render: ({
2490
- field
2491
- }) => {
2492
- const {
2493
- onBlur,
2494
- onChange,
2495
- value: controllerValue
2496
- } = field;
2497
- return /* @__PURE__ */ jsxRuntime.jsx(
2498
- CreatableSelect__default.default,
2499
- {
2500
- components: reactSelectComponents,
2501
- instanceId: "tags",
2502
- isClearable: !1,
2503
- isDisabled: creating || disabled || tagsFetching,
2504
- isLoading: creating,
2505
- isMulti: !0,
2506
- name,
2507
- noOptionsMessage: () => "No tags",
2508
- onBlur,
2509
- onChange,
2510
- onCreateOption: onCreateTag,
2511
- options,
2512
- placeholder: tagsFetching ? "Loading..." : placeholder,
2513
- styles: reactSelectStyles(scheme),
2514
- value: controllerValue
2515
- }
2516
- );
2517
- } })
2518
- ]
2519
- }
2520
- );
2521
- }, FormFieldInputText = react.forwardRef((props, ref) => {
2522
- const {
2523
- description,
2524
- disabled,
2525
- error,
2526
- label,
2527
- name,
2528
- placeholder,
2529
- value,
2530
- ...rest
2531
- } = props;
2532
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { children: [
2533
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputLabel, { description, error, label, name }),
2534
- /* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, { ...rest, autoComplete: "off", autoFocus: !0, defaultValue: value, disabled, id: name, name, placeholder, ref })
2535
- ] });
2536
- }), FormFieldInputTextarea = react.forwardRef((props, ref) => {
2537
- const {
2538
- description,
2539
- disabled,
2540
- error,
2541
- label,
2542
- name,
2543
- placeholder,
2544
- rows,
2545
- value,
2546
- ...rest
2547
- } = props;
2548
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { children: [
2549
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputLabel, { description, error, label, name }),
2550
- /* @__PURE__ */ jsxRuntime.jsx(ui.TextArea, { ...rest, autoComplete: "off", defaultValue: value, disabled, id: name, name, placeholder, ref, rows })
2551
- ] });
2552
- });
2553
- function toStringField(value) {
2554
- if (typeof value == "string") return value;
2555
- if (typeof value == "object" && value !== null)
2556
- return Object.values(value).find((v) => v) || void 0;
2557
- }
2558
- function Details({
2559
- formUpdating,
2560
- handleCreateTag,
2561
- control,
2562
- errors,
2563
- register,
2564
- allTagOptions,
2565
- assetTagOptions,
2566
- currentAsset,
2567
- creditLine,
2568
- locales
2569
- }) {
2570
- const hasLocales = locales && locales.length > 0, [activeLocaleTab, setActiveLocaleTab] = react.useState(0);
2571
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
2572
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputTags, { control, disabled: formUpdating, error: errors?.opt?.media?.tags?.message, label: "Tags", name: "opt.media.tags", onCreateTag: handleCreateTag, options: allTagOptions, placeholder: "Select or create...", value: assetTagOptions }),
2573
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputText, { ...register("originalFilename"), disabled: formUpdating, error: errors?.originalFilename?.message, label: "Filename", name: "originalFilename", value: currentAsset?.originalFilename }),
2574
- hasLocales ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { marginTop: 2, shadow: 1, padding: 3, radius: 1, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
2575
- /* @__PURE__ */ jsxRuntime.jsx(ui.TabList, { space: 2, children: locales.map((locale, idx) => /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, { id: `locale-tab-${locale.id}`, "aria-controls": `locale-panel-${locale.id}`, selected: activeLocaleTab === idx, onClick: () => setActiveLocaleTab(idx), label: locale.title }, locale.id)) }),
2576
- locales.map((locale, idx) => /* @__PURE__ */ jsxRuntime.jsx(ui.TabPanel, { id: `locale-panel-${locale.id}`, "aria-labelledby": `locale-tab-${locale.id}`, hidden: activeLocaleTab !== idx, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
2577
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputText, { ...register(`title.${locale.id}`), disabled: formUpdating, error: errors?.title?.[locale.id]?.message, label: "Title", name: `title.${locale.id}` }),
2578
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputText, { ...register(`altText.${locale.id}`), disabled: formUpdating, error: errors?.altText?.[locale.id]?.message, label: "Alt Text", name: `altText.${locale.id}` }),
2579
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputTextarea, { ...register(`description.${locale.id}`), disabled: formUpdating, error: errors?.description?.[locale.id]?.message, label: "Description", name: `description.${locale.id}`, rows: 5 }),
2580
- creditLine?.enabled && /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputText, { ...register(`creditLine.${locale.id}`), error: errors?.creditLine?.[locale.id]?.message, label: "Credit", name: `creditLine.${locale.id}`, disabled: formUpdating || creditLine?.excludeSources?.includes(currentAsset?.source?.name) })
2581
- ] }) }, locale.id))
2582
- ] }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2583
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputText, { ...register("title"), disabled: formUpdating, error: errors?.title?.message, label: "Title", name: "title", value: toStringField(currentAsset?.title) }),
2584
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputText, { ...register("altText"), disabled: formUpdating, error: errors?.altText?.message, label: "Alt Text", name: "altText", value: toStringField(currentAsset?.altText) }),
2585
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputTextarea, { ...register("description"), disabled: formUpdating, error: errors?.description?.message, label: "Description", name: "description", rows: 5, value: toStringField(currentAsset?.description) }),
2586
- creditLine?.enabled && /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputText, { ...register("creditLine"), error: errors?.creditLine?.message, label: "Credit", name: "creditLine", value: toStringField(currentAsset?.creditLine), disabled: formUpdating || creditLine?.excludeSources?.includes(currentAsset?.source?.name) })
2587
- ] })
2588
- ] });
2589
- }
2590
- function renderDefaultDetails(props) {
2591
- return /* @__PURE__ */ jsxRuntime.jsx(Details, { ...props });
2592
- }
2593
- const DialogAssetEdit = (props) => {
2594
- const {
2595
- children,
2596
- dialog: {
2597
- assetId,
2598
- id,
2599
- lastCreatedTag,
2600
- lastRemovedTagIds
2601
- }
2602
- } = props, client = useVersionedClient(), scheme = sanity.useColorSchemeValue(), documentStore = sanity.useDocumentStore(), dispatch = reactRedux.useDispatch(), assetItem = useTypedSelector((state) => selectAssetById(state, String(assetId))), tags = useTypedSelector(selectTags), assetUpdatedPrev = react.useRef(void 0), [assetSnapshot, setAssetSnapshot] = react.useState(assetItem?.asset), [tabSection, setTabSection] = react.useState("details"), currentAsset = assetItem ? assetItem?.asset : assetSnapshot, allTagOptions = getTagSelectOptions(tags), assetTagOptions = useTypedSelector(selectTagSelectOptions(currentAsset)), {
2603
- creditLine,
2604
- components: {
2605
- details: CustomDetails
2606
- } = {},
2607
- locales
2608
- } = useToolOptions(), generateDefaultValues = react.useCallback((asset) => {
2609
- if (locales && locales.length > 0) {
2610
- const makeLocaleObj = (field) => {
2611
- const obj = {};
2612
- for (let i = 0; i < locales.length; i++) {
2613
- const locale = locales[i];
2614
- typeof field == "object" && field && field[locale.id] ? obj[locale.id] = field[locale.id] : typeof field == "string" ? obj[locale.id] = i === 0 ? field : "" : obj[locale.id] = "";
2615
- }
2616
- return obj;
2617
- };
2618
- return {
2619
- altText: makeLocaleObj(asset?.altText),
2620
- creditLine: makeLocaleObj(asset?.creditLine),
2621
- description: makeLocaleObj(asset?.description),
2622
- originalFilename: asset?.originalFilename || "",
2623
- opt: {
2624
- media: {
2625
- tags: assetTagOptions
2626
- }
2627
- },
2628
- title: makeLocaleObj(asset?.title)
2629
- };
2630
- }
2631
- const flattenField = (field) => typeof field == "string" ? field : typeof field == "object" && field !== null && Object.values(field).find((v) => v) || "";
2632
- return {
2633
- altText: flattenField(asset?.altText),
2634
- creditLine: flattenField(asset?.creditLine),
2635
- description: flattenField(asset?.description),
2636
- originalFilename: asset?.originalFilename || "",
2637
- opt: {
2638
- media: {
2639
- tags: assetTagOptions
2640
- }
2641
- },
2642
- title: flattenField(asset?.title)
2643
- };
2644
- }, [assetTagOptions, locales]), {
2645
- control,
2646
- // Read the formState before render to subscribe the form state through Proxy
2647
- formState: {
2648
- errors,
2649
- isDirty,
2650
- isValid
2651
- },
2652
- getValues,
2653
- handleSubmit,
2654
- register,
2655
- reset,
2656
- setValue
2657
- } = reactHookForm.useForm({
2658
- defaultValues: generateDefaultValues(assetItem?.asset),
2659
- mode: "onChange",
2660
- resolver: zodFormResolver(getAssetFormSchema(locales))
2661
- }), formUpdating = !assetItem || assetItem?.updating, handleClose = react.useCallback(() => {
2662
- dispatch(dialogActions.remove({
2663
- id
2664
- }));
2665
- }, [dispatch, id]), handleDelete = react.useCallback(() => {
2666
- assetItem?.asset && dispatch(dialogActions.showConfirmDeleteAssets({
2667
- assets: [assetItem],
2668
- closeDialogId: assetItem?.asset._id
2669
- }));
2670
- }, [assetItem, dispatch]), handleAssetUpdate = react.useCallback((update) => {
2671
- const {
2672
- result,
2673
- transition
2674
- } = update;
2675
- result && transition === "update" && setAssetSnapshot(result);
2676
- }, []), handleCreateTag = react.useCallback((tagName) => {
2677
- dispatch(tagsActions.createRequest({
2678
- assetId: currentAsset?._id,
2679
- name: tagName
2680
- }));
2681
- }, [currentAsset?._id, dispatch]), hasOrphanedLocales = react.useMemo(() => {
2682
- if (!currentAsset) return !1;
2683
- const isLocaleObj = (v) => typeof v == "object" && v !== null && !Array.isArray(v), fields = [currentAsset.title, currentAsset.altText, currentAsset.description, ...currentAsset._type === "sanity.imageAsset" ? [currentAsset.creditLine] : []];
2684
- if (!fields.some((f) => isLocaleObj(f))) return !1;
2685
- if (!locales || locales.length === 0) return !0;
2686
- const configuredIds = new Set(locales.map((l) => l.id));
2687
- return fields.some((f) => isLocaleObj(f) ? Object.keys(f).some((k) => !configuredIds.has(k)) : !1);
2688
- }, [currentAsset, locales]), handleCleanupLocales = react.useCallback(async () => {
2689
- if (!currentAsset) return;
2690
- const cleanField = (field) => {
2691
- if (typeof field != "object" || field === null || Array.isArray(field)) return field;
2692
- const obj = field;
2693
- if (!locales || locales.length === 0)
2694
- return Object.keys(obj).sort().map((k) => obj[k]).find((v) => v) || "";
2695
- const configuredIds = new Set(locales.map((l) => l.id)), cleaned = {};
2696
- for (const [key, val] of Object.entries(obj))
2697
- configuredIds.has(key) && (cleaned[key] = val);
2698
- return cleaned;
2699
- };
2700
- await client.patch(currentAsset._id).set({
2701
- title: cleanField(currentAsset.title),
2702
- altText: cleanField(currentAsset.altText),
2703
- description: cleanField(currentAsset.description),
2704
- ...currentAsset._type === "sanity.imageAsset" && {
2705
- creditLine: cleanField(currentAsset.creditLine)
2706
- }
2707
- }).commit();
2708
- }, [client, currentAsset, locales]), onSubmit = react.useCallback((formData) => {
2709
- if (!assetItem?.asset)
2710
- return;
2711
- const sanitizedFormData = sanitizeFormData(formData);
2712
- dispatch(assetsActions.updateRequest({
2713
- asset: assetItem?.asset,
2714
- closeDialogId: assetItem?.asset._id,
2715
- formData: {
2716
- ...sanitizedFormData,
2717
- // Map tags to sanity references
2718
- opt: {
2719
- media: {
2720
- ...sanitizedFormData.opt.media,
2721
- tags: sanitizedFormData.opt.media.tags?.map((tag) => ({
2722
- _ref: tag.value,
2723
- _type: "reference",
2724
- _weak: !0
2725
- })) || null
2726
- }
2727
- }
2728
- }
2729
- }));
2730
- }, [assetItem?.asset, dispatch]);
2731
- react.useEffect(() => {
2732
- if (!assetItem?.asset)
2733
- return;
2734
- const subscriptionAsset = client.listen(groq__default.default`*[_id == $id]`, {
2735
- id: assetItem?.asset._id
2736
- }).subscribe(handleAssetUpdate);
2737
- return () => {
2738
- subscriptionAsset?.unsubscribe();
2739
- };
2740
- }, [assetItem?.asset, client, handleAssetUpdate]), react.useEffect(() => {
2741
- if (lastCreatedTag) {
2742
- const updatedTags = (getValues("opt.media.tags") || []).concat([lastCreatedTag]);
2743
- setValue("opt.media.tags", updatedTags, {
2744
- shouldDirty: !0
2745
- });
2746
- }
2747
- }, [getValues, lastCreatedTag, setValue]), react.useEffect(() => {
2748
- if (lastRemovedTagIds) {
2749
- const updatedTags = (getValues("opt.media.tags") || []).filter((tag) => !lastRemovedTagIds.includes(tag.value));
2750
- setValue("opt.media.tags", updatedTags, {
2751
- shouldDirty: !0
2752
- });
2753
- }
2754
- }, [getValues, lastRemovedTagIds, setValue]), react.useEffect(() => {
2755
- assetUpdatedPrev.current !== assetItem?.asset._updatedAt && reset(generateDefaultValues(assetItem?.asset)), assetUpdatedPrev.current = assetItem?.asset._updatedAt;
2756
- }, [assetItem?.asset, generateDefaultValues, reset]);
2757
- const Footer = () => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
2758
- hasOrphanedLocales && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 3, radius: 2, shadow: 1, tone: "caution", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", justify: "space-between", gap: 3, children: [
2759
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: "This asset has localized fields that are no longer configured. Clean them up to avoid validation errors." }),
2760
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, mode: "ghost", onClick: handleCleanupLocales, text: "Cleanup localized fields", tone: "caution" })
2761
- ] }) }),
2762
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "space-between", children: [
2763
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled: formUpdating, fontSize: 1, mode: "bleed", onClick: handleDelete, text: "Delete", tone: "critical" }),
2764
- /* @__PURE__ */ jsxRuntime.jsx(FormSubmitButton, { disabled: formUpdating || !isDirty || !isValid || hasOrphanedLocales, isValid, lastUpdated: currentAsset?._updatedAt, onClick: handleSubmit(onSubmit) })
2765
- ] })
2766
- ] }) });
2767
- if (!currentAsset)
2768
- return null;
2769
- const detailsProps = {
2770
- control,
2771
- errors,
2772
- formUpdating,
2773
- register,
2774
- setValue,
2775
- assetTagOptions,
2776
- allTagOptions,
2777
- handleCreateTag,
2778
- currentAsset,
2779
- creditLine,
2780
- locales
2781
- };
2782
- return /* @__PURE__ */ jsxRuntime.jsxs(
2783
- Dialog,
2784
- {
2785
- animate: !0,
2786
- footer: /* @__PURE__ */ jsxRuntime.jsx(Footer, {}),
2787
- header: "Asset details",
2788
- id,
2789
- onClose: handleClose,
2790
- width: 3,
2791
- children: [
2792
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: ["column-reverse", "column-reverse", "row-reverse"], children: [
2793
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, marginTop: [5, 5, 0], padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(sanity.WithReferringDocuments, { documentStore, id: currentAsset._id, children: ({
2794
- isLoading,
2795
- referringDocuments
2796
- }) => {
2797
- const uniqueReferringDocuments = getUniqueDocuments(referringDocuments);
2798
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2799
- /* @__PURE__ */ jsxRuntime.jsxs(ui.TabList, { space: 2, children: [
2800
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, { "aria-controls": "details-panel", disabled: formUpdating, id: "details-tab", label: "Details", onClick: () => setTabSection("details"), selected: tabSection === "details", size: 2 }),
2801
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, { "aria-controls": "references-panel", disabled: formUpdating, id: "references-tab", label: `References${!isLoading && Array.isArray(uniqueReferringDocuments) ? ` (${uniqueReferringDocuments.length})` : ""}`, onClick: () => setTabSection("references"), selected: tabSection === "references", size: 2 })
2802
- ] }),
2803
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { as: "form", marginTop: 4, onSubmit: handleSubmit(onSubmit), children: [
2804
- !assetItem && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { marginBottom: 3, padding: 3, radius: 2, shadow: 1, tone: "critical", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: "This file cannot be found \u2013 it may have been deleted." }) }),
2805
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: {
2806
- display: "none"
2807
- }, tabIndex: -1, type: "submit" }),
2808
- /* @__PURE__ */ jsxRuntime.jsx(ui.TabPanel, { "aria-labelledby": "details", hidden: tabSection !== "details", id: "details-panel", children: CustomDetails ? /* @__PURE__ */ jsxRuntime.jsx(CustomDetails, { ...detailsProps, renderDefaultDetails }) : /* @__PURE__ */ jsxRuntime.jsx(Details, { ...detailsProps }) }),
2809
- /* @__PURE__ */ jsxRuntime.jsx(ui.TabPanel, { "aria-labelledby": "references", hidden: tabSection !== "references", id: "references-panel", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 5, children: assetItem?.asset && /* @__PURE__ */ jsxRuntime.jsx(DocumentList, { documents: uniqueReferringDocuments, isLoading }) }) })
2810
- ] })
2811
- ] });
2812
- } }) }),
2813
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { flex: 1, padding: 4, children: [
2814
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { style: {
2815
- aspectRatio: "1"
2816
- }, children: [
2817
- isFileAsset(currentAsset) && /* @__PURE__ */ jsxRuntime.jsx(FileAssetPreview, { asset: currentAsset }),
2818
- isImageAsset(currentAsset) && /* @__PURE__ */ jsxRuntime.jsx(Image$1, { draggable: !1, $scheme: scheme, $showCheckerboard: !currentAsset?.metadata?.isOpaque, src: imageDprUrl(currentAsset, {
2819
- height: 600,
2820
- width: 600
2821
- }) })
2822
- ] }),
2823
- currentAsset && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 4, children: /* @__PURE__ */ jsxRuntime.jsx(AssetMetadata, { asset: currentAsset, item: assetItem }) })
2824
- ] })
2825
- ] }),
2826
- children
2827
- ]
2828
- }
2829
- );
2830
- }, DialogConfirm = (props) => {
2831
- const {
2832
- children,
2833
- dialog
2834
- } = props, dispatch = reactRedux.useDispatch(), handleClose = () => {
2835
- dispatch(dialogActions.remove({
2836
- id: dialog?.id
2837
- }));
2838
- }, handleConfirm = () => {
2839
- dialog?.closeDialogId && dispatch(dialogActions.remove({
2840
- id: dialog?.closeDialogId
2841
- })), dialog?.confirmCallbackAction && dispatch(dialog.confirmCallbackAction), handleClose();
2842
- };
2843
- return /* @__PURE__ */ jsxRuntime.jsxs(
2844
- Dialog,
2845
- {
2846
- animate: !0,
2847
- footer: /* @__PURE__ */ jsxRuntime.jsx(() => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "space-between", children: [
2848
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, mode: "bleed", onClick: handleClose, text: "Cancel" }),
2849
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, onClick: handleConfirm, text: dialog?.confirmText, tone: dialog?.tone })
2850
- ] }) }), {}),
2851
- header: /* @__PURE__ */ jsxRuntime.jsx(() => /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", children: [
2852
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingX: 1, children: /* @__PURE__ */ jsxRuntime.jsx(icons.WarningOutlineIcon, {}) }),
2853
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginLeft: 2, children: dialog?.headerTitle })
2854
- ] }), {}),
2855
- id: "confirm",
2856
- onClose: handleClose,
2857
- width: 1,
2858
- children: [
2859
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingX: 4, paddingY: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
2860
- dialog?.title && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: dialog.title }),
2861
- dialog?.description && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: /* @__PURE__ */ jsxRuntime.jsx("em", { children: dialog.description }) })
2862
- ] }) }),
2863
- children
2864
- ]
2865
- }
2866
- );
2867
- }, DialogSearchFacets = (props) => {
2868
- const {
2869
- children,
2870
- dialog: {
2871
- id
2872
- }
2873
- } = props, dispatch = reactRedux.useDispatch(), handleClose = react.useCallback(() => {
2874
- dispatch(dialogActions.clear());
2875
- }, [dispatch]);
2876
- return /* @__PURE__ */ jsxRuntime.jsxs(Dialog, { animate: !0, header: "Filters", id, onClose: handleClose, width: 1, children: [
2877
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { padding: 3, children: [
2878
- /* @__PURE__ */ jsxRuntime.jsx(SearchFacets, { layout: "stack" }),
2879
- /* @__PURE__ */ jsxRuntime.jsx(SearchFacetsControl, {})
2880
- ] }),
2881
- children
2882
- ] });
2883
- }, DialogTagCreate = (props) => {
2884
- const {
2885
- children,
2886
- dialog: {
2887
- id
2888
- }
2889
- } = props, dispatch = reactRedux.useDispatch(), creating = useTypedSelector((state) => state.tags.creating), creatingError = useTypedSelector((state) => state.tags.creatingError), {
2890
- // Read the formState before render to subscribe the form state through Proxy
2891
- formState: {
2892
- errors,
2893
- isDirty,
2894
- isValid
2895
- },
2896
- handleSubmit,
2897
- register,
2898
- setError
2899
- } = reactHookForm.useForm({
2900
- defaultValues: {
2901
- name: ""
2902
- },
2903
- mode: "onChange",
2904
- resolver: zodFormResolver(tagFormSchema)
2905
- }), formUpdating = creating, handleClose = () => {
2906
- dispatch(dialogActions.clear());
2907
- }, onSubmit = (formData) => {
2908
- const sanitizedFormData = sanitizeFormData(formData);
2909
- dispatch(tagsActions.createRequest({
2910
- name: sanitizedFormData.name
2911
- }));
2912
- };
2913
- return react.useEffect(() => {
2914
- creatingError && setError("name", {
2915
- message: creatingError?.message
2916
- });
2917
- }, [creatingError, setError]), /* @__PURE__ */ jsxRuntime.jsxs(
2918
- Dialog,
2919
- {
2920
- animate: !0,
2921
- footer: /* @__PURE__ */ jsxRuntime.jsx(() => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { justify: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsx(FormSubmitButton, { disabled: formUpdating || !isDirty || !isValid, isValid, onClick: handleSubmit(onSubmit) }) }) }), {}),
2922
- header: "Create Tag",
2923
- id,
2924
- onClose: handleClose,
2925
- width: 1,
2926
- children: [
2927
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { as: "form", padding: 4, onSubmit: handleSubmit(onSubmit), children: [
2928
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: {
2929
- display: "none"
2930
- }, tabIndex: -1, type: "submit" }),
2931
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputText, { ...register("name"), disabled: formUpdating, error: errors?.name?.message, label: "Name", name: "name" })
2932
- ] }),
2933
- children
2934
- ]
2935
- }
2936
- );
2937
- }, DialogTagEdit = (props) => {
2938
- const {
2939
- children,
2940
- dialog: {
2941
- id,
2942
- tagId
2943
- }
2944
- } = props, client = useVersionedClient(), dispatch = reactRedux.useDispatch(), tagItem = useTypedSelector((state) => selectTagById(state, String(tagId))), [tagSnapshot, setTagSnapshot] = react.useState(tagItem?.tag), currentTag = tagItem ? tagItem?.tag : tagSnapshot, generateDefaultValues = react.useCallback((tag) => ({
2945
- name: tag?.name?.current || ""
2946
- }), []), {
2947
- // Read the formState before render to subscribe the form state through Proxy
2948
- formState: {
2949
- errors,
2950
- isDirty,
2951
- isValid
2952
- },
2953
- handleSubmit,
2954
- register,
2955
- reset,
2956
- setError
2957
- } = reactHookForm.useForm({
2958
- defaultValues: generateDefaultValues(tagItem?.tag),
2959
- mode: "onChange",
2960
- resolver: zodFormResolver(tagFormSchema)
2961
- }), formUpdating = !tagItem || tagItem?.updating, handleClose = () => {
2962
- dispatch(dialogActions.remove({
2963
- id
2964
- }));
2965
- }, onSubmit = (formData) => {
2966
- if (!tagItem?.tag)
2967
- return;
2968
- const sanitizedFormData = sanitizeFormData(formData);
2969
- dispatch(tagsActions.updateRequest({
2970
- closeDialogId: tagItem?.tag?._id,
2971
- formData: {
2972
- name: {
2973
- _type: "slug",
2974
- current: sanitizedFormData.name
2975
- }
2976
- },
2977
- tag: tagItem?.tag
2978
- }));
2979
- }, handleDelete = () => {
2980
- tagItem?.tag && dispatch(dialogActions.showConfirmDeleteTag({
2981
- closeDialogId: tagItem?.tag?._id,
2982
- tag: tagItem?.tag
2983
- }));
2984
- }, handleTagUpdate = react.useCallback((update) => {
2985
- const {
2986
- result,
2987
- transition
2988
- } = update;
2989
- result && transition === "update" && (setTagSnapshot(result), reset(generateDefaultValues(result)));
2990
- }, [reset, generateDefaultValues]);
2991
- react.useEffect(() => {
2992
- tagItem?.error && setError("name", {
2993
- message: tagItem.error?.message
2994
- });
2995
- }, [setError, tagItem?.error]), react.useEffect(() => {
2996
- if (!tagItem?.tag)
2997
- return;
2998
- const subscriptionAsset = client.listen(groq__default.default`*[_id == $id]`, {
2999
- id: tagItem?.tag._id
3000
- }).subscribe(handleTagUpdate);
3001
- return () => {
3002
- subscriptionAsset?.unsubscribe();
3003
- };
3004
- }, [client, handleTagUpdate, tagItem?.tag]);
3005
- const Footer = () => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "space-between", children: [
3006
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled: formUpdating, fontSize: 1, mode: "bleed", onClick: handleDelete, text: "Delete", tone: "critical" }),
3007
- /* @__PURE__ */ jsxRuntime.jsx(FormSubmitButton, { disabled: formUpdating || !isDirty || !isValid, isValid, lastUpdated: tagItem?.tag?._updatedAt, onClick: handleSubmit(onSubmit) })
3008
- ] }) });
3009
- return currentTag ? /* @__PURE__ */ jsxRuntime.jsxs(
3010
- Dialog,
3011
- {
3012
- animate: !0,
3013
- footer: /* @__PURE__ */ jsxRuntime.jsx(Footer, {}),
3014
- header: "Edit Tag",
3015
- id,
3016
- onClose: handleClose,
3017
- width: 1,
3018
- children: [
3019
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { as: "form", padding: 4, onSubmit: handleSubmit(onSubmit), children: [
3020
- !tagItem && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { marginBottom: 3, padding: 3, radius: 2, shadow: 1, tone: "critical", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: "This tag cannot be found \u2013 it may have been deleted." }) }),
3021
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: {
3022
- display: "none"
3023
- }, tabIndex: -1, type: "submit" }),
3024
- /* @__PURE__ */ jsxRuntime.jsx(FormFieldInputText, { ...register("name"), disabled: formUpdating, error: errors?.name?.message, label: "Name", name: "name" })
3025
- ] }),
3026
- children
3027
- ]
3028
- }
3029
- ) : null;
3030
- }, TagContainer = styledComponents.styled(ui.Flex).withConfig({
3031
- displayName: "TagContainer",
3032
- componentId: "sc-sujhn-0"
3033
- })`height:${PANEL_HEIGHT}px;`, ButtonContainer = styledComponents.styled(ui.Flex).withConfig({
3034
- displayName: "ButtonContainer",
3035
- componentId: "sc-sujhn-1"
3036
- })`@media (pointer:fine){visibility:hidden;}@media (hover:hover) and (pointer:fine){${TagContainer}:hover &{visibility:visible;}}`, TagButton = (props) => {
3037
- const {
3038
- disabled,
3039
- icon,
3040
- onClick,
3041
- tone,
3042
- tooltip
3043
- } = props;
3044
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { animate: !0, content: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { padding: 2, width: 0, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: tooltip }) }), disabled: "ontouchstart" in window, placement: "top", portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled, fontSize: 1, icon, mode: "bleed", onClick, padding: 2, tone }) });
3045
- }, Tag = (props) => {
3046
- const {
3047
- actions,
3048
- tag
3049
- } = props, dispatch = reactRedux.useDispatch(), assetsPicked = useTypedSelector(selectAssetsPicked), isSearchFacetTag = useTypedSelector((state) => selectIsSearchFacetTag(state, tag?.tag?._id)), handleSearchFacetTagRemove = () => {
3050
- dispatch(searchActions.facetsRemoveByTag({
3051
- tagId: tag.tag._id
3052
- }));
3053
- }, handleShowAddTagToAssetsDialog = () => {
3054
- dispatch(dialogActions.showConfirmAssetsTagAdd({
3055
- assetsPicked,
3056
- tag: tag.tag
3057
- }));
3058
- }, handleShowRemoveTagFromAssetsDialog = () => {
3059
- dispatch(dialogActions.showConfirmAssetsTagRemove({
3060
- assetsPicked,
3061
- tag: tag.tag
3062
- }));
3063
- }, handleShowTagDeleteDialog = () => {
3064
- dispatch(dialogActions.showConfirmDeleteTag({
3065
- tag: tag.tag
3066
- }));
3067
- }, handleShowTagEditDialog = () => {
3068
- dispatch(DIALOG_ACTIONS.showTagEdit({
3069
- tagId: tag?.tag?._id
3070
- }));
3071
- }, handleSearchFacetTagAddOrUpdate = () => {
3072
- const searchFacet = {
3073
- ...inputs.tag,
3074
- value: {
3075
- label: tag?.tag?.name?.current,
3076
- value: tag?.tag?._id
3077
- }
3078
- };
3079
- dispatch(isSearchFacetTag ? searchActions.facetsUpdate({
3080
- name: "tag",
3081
- operatorType: "references",
3082
- value: searchFacet.value
3083
- }) : searchActions.facetsAdd({
3084
- facet: searchFacet
3085
- }));
3086
- };
3087
- return /* @__PURE__ */ jsxRuntime.jsxs(TagContainer, { align: "center", flex: 1, justify: "space-between", paddingLeft: 3, children: [
3088
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, style: {
3089
- opacity: tag?.updating ? 0.5 : 1,
3090
- userSelect: "none"
3091
- }, textOverflow: "ellipsis", children: tag?.tag?.name?.current }) }),
3092
- /* @__PURE__ */ jsxRuntime.jsxs(ButtonContainer, { align: "center", style: {
3093
- flexShrink: 0
3094
- }, children: [
3095
- actions?.includes("search") && /* @__PURE__ */ jsxRuntime.jsx(TagButton, { disabled: tag?.updating, icon: isSearchFacetTag ? /* @__PURE__ */ jsxRuntime.jsx(icons.CloseIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.SearchIcon, {}), onClick: isSearchFacetTag ? handleSearchFacetTagRemove : handleSearchFacetTagAddOrUpdate, tooltip: isSearchFacetTag ? "Remove filter" : "Filter by tag" }),
3096
- actions?.includes("edit") && /* @__PURE__ */ jsxRuntime.jsx(TagButton, { disabled: tag?.updating, icon: /* @__PURE__ */ jsxRuntime.jsx(icons.EditIcon, {}), onClick: handleShowTagEditDialog, tone: "primary", tooltip: "Edit tag" }),
3097
- actions?.includes("applyAll") && /* @__PURE__ */ jsxRuntime.jsx(TagButton, { disabled: tag?.updating, icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpIcon, {}), onClick: handleShowAddTagToAssetsDialog, tone: "primary", tooltip: "Add tag to selected assets" }),
3098
- actions?.includes("removeAll") && /* @__PURE__ */ jsxRuntime.jsx(TagButton, { disabled: tag?.updating, icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownIcon, {}), onClick: handleShowRemoveTagFromAssetsDialog, tone: "critical", tooltip: "Remove tag from selected assets" }),
3099
- actions?.includes("delete") && /* @__PURE__ */ jsxRuntime.jsx(TagButton, { disabled: tag?.updating, icon: /* @__PURE__ */ jsxRuntime.jsx(icons.TrashIcon, {}), onClick: handleShowTagDeleteDialog, tone: "critical", tooltip: "Delete tag" })
3100
- ] })
3101
- ] });
3102
- }, VirtualRow$1 = react.memo(({
3103
- isScrolling,
3104
- item
3105
- }) => typeof item == "string" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "space-between", paddingX: 3, style: {
3106
- height: `${PANEL_HEIGHT}px`
3107
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: 0, children: item }) }, item) : /* @__PURE__ */ jsxRuntime.jsx(Tag, { actions: isScrolling ? void 0 : item.actions, tag: item }, item.tag?._id)), TagsVirtualized = () => {
3108
- const assetsPicked = useTypedSelector(selectAssetsPicked), tags = useTypedSelector(selectTags), [isScrolling, setIsScrolling] = react.useState(!1), pickedTagIds = assetsPicked?.reduce((acc, val) => {
3109
- const assetTagIds = val?.asset?.opt?.media?.tags?.map((tag) => tag._ref) || [];
3110
- return acc = acc.concat(assetTagIds), acc;
3111
- }, []), pickedTagIdsUnique = [...new Set(pickedTagIds)], tagIdsSegmented = pickedTagIdsUnique.reduce((acc, tagId) => (assetsPicked.every((assetItem) => (assetItem.asset.opt?.media?.tags?.findIndex((tag) => tag._ref === tagId) ?? -1) >= 0) ? acc.appliedToAll.push(tagId) : acc.appliedToSome.push(tagId), acc), {
3112
- appliedToAll: [],
3113
- appliedToSome: []
3114
- }), tagsAppliedToAll = tags.filter((tag) => tagIdsSegmented.appliedToAll.includes(tag.tag._id)).map((tagItem) => ({
3115
- ...tagItem,
3116
- actions: ["delete", "edit", "removeAll", "search"]
3117
- })), tagsAppliedToSome = tags.filter((tag) => tagIdsSegmented.appliedToSome.includes(tag.tag._id)).map((tagItem) => ({
3118
- ...tagItem,
3119
- actions: ["applyAll", "delete", "edit", "removeAll", "search"]
3120
- })), tagsUnused = tags.filter((tag) => !pickedTagIdsUnique.includes(tag.tag._id)).map((tagItem) => ({
3121
- ...tagItem,
3122
- actions: ["applyAll", "delete", "edit", "search"]
3123
- }));
3124
- let items = [];
3125
- return assetsPicked.length === 0 ? items = tags.map((tagItem) => ({
3126
- ...tagItem,
3127
- actions: ["delete", "edit", "search"]
3128
- })) : (tagsAppliedToAll?.length > 0 && (items = [
3129
- ...items,
3130
- //
3131
- assetsPicked.length === 1 ? "Used" : "Used by all",
3132
- ...tagsAppliedToAll
3133
- ]), tagsAppliedToSome?.length > 0 && (items = [
3134
- ...items,
3135
- //
3136
- "Used by some",
3137
- ...tagsAppliedToSome
3138
- ]), tagsUnused?.length > 0 && (items = [
3139
- ...items,
3140
- //
3141
- "Unused",
3142
- ...tagsUnused
3143
- ])), /* @__PURE__ */ jsxRuntime.jsx(reactVirtuoso.Virtuoso, { className: "media__custom-scrollbar", computeItemKey: (index) => {
3144
- const item = items[index];
3145
- return typeof item == "string" ? item : item.tag._id;
3146
- }, isScrolling: setIsScrolling, itemContent: (index) => /* @__PURE__ */ jsxRuntime.jsx(VirtualRow$1, { isScrolling, item: items[index] }), style: {
3147
- flex: 1,
3148
- overflowX: "hidden"
3149
- }, totalCount: items.length });
3150
- }, TagViewHeader = ({
3151
- allowCreate,
3152
- light,
3153
- title
3154
- }) => {
3155
- const scheme = sanity.useColorSchemeValue(), dispatch = reactRedux.useDispatch(), tagsCreating = useTypedSelector((state) => state.tags.creating), tagsFetching = useTypedSelector((state) => state.tags.fetching), handleTagCreate = () => {
3156
- dispatch(DIALOG_ACTIONS.showTagCreate());
3157
- };
3158
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", justify: "space-between", paddingLeft: 3, style: {
3159
- background: light ? getSchemeColor(scheme, "bg") : "inherit",
3160
- borderBottom: "1px solid var(--card-border-color)",
3161
- flexShrink: 0,
3162
- height: `${PANEL_HEIGHT}px`
3163
- }, children: [
3164
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Inline, { space: 2, children: [
3165
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: 0, children: title }),
3166
- tagsFetching && /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: 0, style: {
3167
- opacity: 0.3
3168
- }, children: "Loading..." })
3169
- ] }),
3170
- allowCreate && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginRight: 1, children: /* @__PURE__ */ jsxRuntime.jsx(
3171
- ui.Button,
3172
- {
3173
- disabled: tagsCreating,
3174
- fontSize: 1,
3175
- icon: icons.ComposeIcon,
3176
- mode: "bleed",
3177
- onClick: handleTagCreate,
3178
- style: {
3179
- background: "transparent",
3180
- boxShadow: "none"
3181
- }
3182
- }
3183
- ) })
3184
- ] }) });
3185
- }, TagView = () => {
3186
- const numPickedAssets = useTypedSelector(selectAssetsPickedLength), tags = useTypedSelector(selectTags), fetching = useTypedSelector((state) => state.tags.fetching), fetchComplete = useTypedSelector((state) => state.tags.fetchCount) !== -1, hasTags = !fetching && tags?.length > 0, hasPicked = numPickedAssets > 0;
3187
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", flex: 1, height: "fill", children: [
3188
- /* @__PURE__ */ jsxRuntime.jsx(TagViewHeader, { allowCreate: !0, light: hasPicked, title: hasPicked ? "Tags (in selection)" : "Tags" }),
3189
- fetchComplete && !hasTags && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: /* @__PURE__ */ jsxRuntime.jsx("em", { children: "No tags" }) }) }),
3190
- hasTags && /* @__PURE__ */ jsxRuntime.jsx(TagsVirtualized, {})
3191
- ] });
3192
- }, DialogTags = (props) => {
3193
- const {
3194
- children,
3195
- dialog: {
3196
- id
3197
- }
3198
- } = props, dispatch = reactRedux.useDispatch(), handleClose = react.useCallback(() => {
3199
- dispatch(dialogActions.clear());
3200
- }, [dispatch]);
3201
- return /* @__PURE__ */ jsxRuntime.jsxs(Dialog, { animate: !0, header: "All Tags", id, onClose: handleClose, width: 1, children: [
3202
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
3203
- height: "100%",
3204
- minHeight: "420px"
3205
- // explicit height required as <TagView> is virtualized
3206
- }, children: /* @__PURE__ */ jsxRuntime.jsx(TagView, {}) }),
3207
- children
3208
- ] });
3209
- }, Dialogs = () => {
3210
- const currentDialogs = useTypedSelector((state) => state.dialog.items), renderDialogs = (dialogs, index) => {
3211
- if (dialogs.length === 0 || index >= dialogs.length)
3212
- return null;
3213
- const dialog = dialogs[index], childDialogs = renderDialogs(dialogs, index + 1);
3214
- return dialog.type === "assetEdit" ? /* @__PURE__ */ jsxRuntime.jsx(DialogAssetEdit, { dialog, children: childDialogs }, index) : dialog.type === "confirm" ? /* @__PURE__ */ jsxRuntime.jsx(DialogConfirm, { dialog, children: childDialogs }, index) : dialog.type === "searchFacets" ? /* @__PURE__ */ jsxRuntime.jsx(DialogSearchFacets, { dialog, children: childDialogs }, index) : dialog.type === "tagCreate" ? /* @__PURE__ */ jsxRuntime.jsx(DialogTagCreate, { dialog, children: childDialogs }, index) : dialog.type === "tagEdit" ? /* @__PURE__ */ jsxRuntime.jsx(DialogTagEdit, { dialog, children: childDialogs }, index) : dialog.type === "tags" ? /* @__PURE__ */ jsxRuntime.jsx(DialogTags, { dialog, children: childDialogs }, index) : null;
3215
- };
3216
- return renderDialogs(currentDialogs, 0);
3217
- }, DropzoneDispatchContext = react.createContext(void 0), DropzoneDispatchProvider = (props) => {
3218
- const {
3219
- children,
3220
- open
3221
- } = props, contextValue = react.useMemo(() => ({
3222
- open
3223
- }), [open]);
3224
- return /* @__PURE__ */ jsxRuntime.jsx(DropzoneDispatchContext.Provider, { value: contextValue, children });
3225
- }, useDropzoneActions = () => {
3226
- const context = react.useContext(DropzoneDispatchContext);
3227
- if (context === void 0)
3228
- throw new Error("useDropzoneActions must be used within an DropzoneDispatchProvider");
3229
- return context;
3230
- }, Header = (props) => {
3231
- const {
3232
- onClose
3233
- } = props, {
3234
- open
3235
- } = useDropzoneActions(), {
3236
- onSelect
3237
- } = useAssetSourceActions(), assetTypes = useTypedSelector((state) => state.assets.assetTypes), selectedDocument = useTypedSelector((state) => state.selected.document), {
3238
- directUploads
3239
- } = useToolOptions();
3240
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingY: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", justify: "space-between", children: [
3241
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, marginX: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Inline, { style: {
3242
- whiteSpace: "nowrap"
3243
- }, children: [
3244
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { textOverflow: "ellipsis", weight: "semibold", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: onSelect ? `Insert ${assetTypes.join(" or ")}` : "Browse Assets" }) }),
3245
- selectedDocument && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { display: ["none", "none", "block"], children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { children: [
3246
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
3247
- margin: "0 0.5em"
3248
- }, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Icon, { symbol: "arrow-right" }) }),
3249
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
3250
- textTransform: "capitalize"
3251
- }, children: selectedDocument._type })
3252
- ] }) })
3253
- ] }) }),
3254
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { marginX: 2, children: [
3255
- directUploads && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 1, icon: icons.UploadIcon, mode: "bleed", onClick: open, text: `Upload ${assetTypes.length === 1 ? pluralize__default.default(assetTypes[0]) : "assets"}` }),
3256
- onClose && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
3257
- flexShrink: 0
3258
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled: !onClose, icon: icons.CloseIcon, mode: "bleed", onClick: onClose, radius: 2 }) })
3259
- ] })
3260
- ] }) });
3261
- }, useBreakpointIndex = () => {
3262
- const mediaQueryLists = ui.studioTheme?.container?.map((width) => window.matchMedia(`(max-width: ${width}px)`)), getBreakpointIndex = () => mediaQueryLists.findIndex((mql) => mql.matches), [value, setValue] = react.useState(getBreakpointIndex());
3263
- return react.useEffect(() => {
3264
- const handleBreakpoint = () => {
3265
- setValue(getBreakpointIndex);
3266
- };
3267
- return mediaQueryLists.forEach((mql) => {
3268
- try {
3269
- mql.addEventListener("change", handleBreakpoint);
3270
- } catch {
3271
- try {
3272
- mql.addListener(handleBreakpoint);
3273
- } catch {
3274
- }
3275
- }
3276
- }), () => {
3277
- try {
3278
- mediaQueryLists.forEach((mql) => mql.removeEventListener("change", handleBreakpoint));
3279
- } catch {
3280
- try {
3281
- mediaQueryLists.forEach((mql) => mql.removeListener(handleBreakpoint));
3282
- } catch {
3283
- }
3284
- }
3285
- };
3286
- }, []), value;
3287
- }, selectCombinedItems = toolkit.createSelector([(state) => state.assets.allIds, (state) => state.uploads.allIds], (assetIds, uploadIds) => {
3288
- const assetItems = assetIds.map((id) => ({
3289
- id,
3290
- type: "asset"
3291
- }));
3292
- return [...uploadIds.map((id) => ({
3293
- id,
3294
- type: "upload"
3295
- })), ...assetItems];
3296
- }), CardWrapper$1 = styledComponents.styled(ui.Flex).withConfig({
3297
- displayName: "CardWrapper",
3298
- componentId: "sc-88amzd-0"
3299
- })`box-sizing:border-box;height:100%;overflow:hidden;position:relative;width:100%;`, CardContainer = /* @__PURE__ */ styledComponents.styled(ui.Flex).withConfig({
3300
- displayName: "CardContainer",
3301
- componentId: "sc-88amzd-1"
3302
- })(({
3303
- $picked,
3304
- theme,
3305
- $updating
3306
- }) => styledComponents.css`border:1px solid transparent;height:100%;pointer-events:${$updating ? "none" : "auto"};position:relative;transition:all 300ms;user-select:none;width:100%;border:${$picked ? `1px solid ${theme.sanity.color.spot.orange} !important` : "1px solid inherit"};${!$updating && styledComponents.css`@media (hover:hover) and (pointer:fine){&:hover{border:1px solid var(--card-border-color);}}`}`), ContextActionContainer$2 = /* @__PURE__ */ styledComponents.styled(ui.Flex).withConfig({
3307
- displayName: "ContextActionContainer",
3308
- componentId: "sc-88amzd-2"
3309
- })(({
3310
- $scheme
3311
- }) => styledComponents.css`cursor:pointer;height:${PANEL_HEIGHT}px;transition:all 300ms;@media (hover:hover) and (pointer:fine){&:hover{background:${getSchemeColor($scheme, "bg")};}}`), StyledWarningOutlineIcon = /* @__PURE__ */ styledComponents.styled(icons.WarningFilledIcon).withConfig({
3312
- displayName: "StyledWarningOutlineIcon",
3313
- componentId: "sc-88amzd-3"
3314
- })(({
3315
- theme
3316
- }) => ({
3317
- color: theme.sanity.color.spot.red
3318
- })), CardAsset$1 = (props) => {
3319
- const {
3320
- id,
3321
- selected
3322
- } = props, scheme = sanity.useColorSchemeValue(), shiftPressed = useKeyPress("shift"), dispatch = reactRedux.useDispatch(), lastPicked = useTypedSelector((state) => state.assets.lastPicked), item = useTypedSelector((state) => selectAssetById(state, id)), asset = item?.asset, error = item?.error, isOpaque = item?.asset?.metadata?.isOpaque, picked = item?.picked, updating = item?.updating, {
3323
- onSelect
3324
- } = useAssetSourceActions();
3325
- if (!asset)
3326
- return null;
3327
- const handleAssetClick = (e) => {
3328
- e.stopPropagation(), onSelect ? onSelect([{
3329
- kind: "assetDocumentId",
3330
- value: asset._id
3331
- }]) : shiftPressed.current ? dispatch(picked ? assetsActions.pick({
3332
- assetId: asset._id,
3333
- picked: !picked
3334
- }) : assetsActions.pickRange({
3335
- startId: lastPicked || asset._id,
3336
- endId: asset._id
3337
- })) : dispatch(dialogActions.showAssetEdit({
3338
- assetId: asset._id
3339
- }));
3340
- }, handleContextActionClick = (e) => {
3341
- e.stopPropagation(), onSelect ? dispatch(dialogActions.showAssetEdit({
3342
- assetId: asset._id
3343
- })) : shiftPressed.current && !picked ? dispatch(assetsActions.pickRange({
3344
- startId: lastPicked || asset._id,
3345
- endId: asset._id
3346
- })) : dispatch(assetsActions.pick({
3347
- assetId: asset._id,
3348
- picked: !picked
3349
- }));
3350
- }, opacityContainer = updating ? 0.5 : 1, opacityPreview = selected || updating ? 0.25 : 1;
3351
- return /* @__PURE__ */ jsxRuntime.jsx(CardWrapper$1, { padding: 1, children: /* @__PURE__ */ jsxRuntime.jsxs(CardContainer, { direction: "column", $picked: picked, $updating: item.updating, children: [
3352
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { flex: 1, style: {
3353
- cursor: selected ? "default" : "pointer",
3354
- position: "relative"
3355
- }, children: [
3356
- /* @__PURE__ */ jsxRuntime.jsxs("div", { onClick: handleAssetClick, style: {
3357
- height: "100%",
3358
- opacity: opacityPreview
3359
- }, children: [
3360
- isFileAsset(asset) && /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { extension: asset.extension, width: "80px" }),
3361
- isImageAsset(asset) && /* @__PURE__ */ jsxRuntime.jsx(Image$1, { draggable: !1, $scheme: scheme, $showCheckerboard: !isOpaque, src: imageDprUrl(asset, {
3362
- height: 250,
3363
- width: 250
3364
- }), style: {
3365
- draggable: !1,
3366
- transition: "opacity 1000ms"
3367
- } })
3368
- ] }),
3369
- selected && !updating && /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "center", style: {
3370
- height: "100%",
3371
- left: 0,
3372
- opacity: opacityContainer,
3373
- position: "absolute",
3374
- top: 0,
3375
- width: "100%"
3376
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 2, children: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckmarkCircleIcon, {}) }) }),
3377
- updating && /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "center", style: {
3378
- height: "100%",
3379
- left: 0,
3380
- position: "absolute",
3381
- top: 0,
3382
- width: "100%"
3383
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, {}) })
3384
- ] }),
3385
- /* @__PURE__ */ jsxRuntime.jsxs(ContextActionContainer$2, { align: "center", onClick: handleContextActionClick, paddingX: 1, $scheme: scheme, style: {
3386
- opacity: opacityContainer
3387
- }, children: [
3388
- onSelect ? /* @__PURE__ */ jsxRuntime.jsx(icons.EditIcon, { style: {
3389
- flexShrink: 0,
3390
- opacity: 0.5
3391
- } }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { checked: picked, readOnly: !0, style: {
3392
- flexShrink: 0,
3393
- pointerEvents: "none",
3394
- transform: "scale(0.8)"
3395
- } }),
3396
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginLeft: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 0, textOverflow: "ellipsis", children: asset.originalFilename }) })
3397
- ] }),
3398
- error && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 3, style: {
3399
- position: "absolute",
3400
- right: 0,
3401
- top: 0
3402
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { animate: !0, content: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { padding: 2, width: 0, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: error }) }), placement: "left", portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: /* @__PURE__ */ jsxRuntime.jsx(StyledWarningOutlineIcon, { color: "critical" }) }) }) })
3403
- ] }) });
3404
- };
3405
- var CardAsset = react.memo(CardAsset$1);
3406
- const PREVIEW_WIDTH = 180, createBlob = (img) => new Promise((resolve) => {
3407
- const imageAspect = img.width / img.height, canvas = document.createElement("canvas");
3408
- canvas.width = PREVIEW_WIDTH, canvas.height = Math.max(PREVIEW_WIDTH / imageAspect, 1);
3409
- try {
3410
- canvas.getContext("2d")?.drawImage(img, 0, 0, PREVIEW_WIDTH, PREVIEW_WIDTH / imageAspect), canvas.toBlob(resolve, "image/jpeg");
3411
- } catch (err) {
3412
- console.warn("Unable to generate preview image:", err);
3413
- }
3414
- }), createImageEl = (file) => new Promise((resolve) => {
3415
- const blobUrlLarge = window.URL.createObjectURL(file), img = new Image();
3416
- img.onload = () => {
3417
- window.URL.revokeObjectURL(blobUrlLarge), resolve(img);
3418
- }, img.src = blobUrlLarge;
3419
- }), generatePreviewBlobUrl = async (file) => {
3420
- const imageEl = await createImageEl(file), blob = await createBlob(imageEl);
3421
- if (!blob)
3422
- throw Error("Unable to generate file Blob");
3423
- return window.URL.createObjectURL(blob);
3424
- }, generatePreviewBlobUrl$ = (file) => rxjs.of(null).pipe(operators$1.mergeMap(() => rxjs.from(generatePreviewBlobUrl(file)))), DEFAULT_CONCURRENCY = 4;
3425
- function remove(array, item) {
3426
- const index = array.indexOf(item);
3427
- return index > -1 && array.splice(index, 1), array;
3428
- }
3429
- const createThrottler = (concurrency = DEFAULT_CONCURRENCY) => {
3430
- const currentSubscriptions = [], pendingObservables = [], ready$ = new rxjs.Subject();
3431
- function request(observable) {
3432
- return new rxjs.Observable((observer) => {
3433
- if (currentSubscriptions.length >= concurrency)
3434
- return scheduleAndWait$(observable).pipe(operators$1.mergeMap(request)).subscribe(observer);
3435
- const subscription = observable.subscribe(observer);
3436
- return currentSubscriptions.push(subscription), () => {
3437
- for (remove(currentSubscriptions, subscription), remove(pendingObservables, observable), subscription.unsubscribe(); pendingObservables.length > 0 && currentSubscriptions.length < concurrency; )
3438
- ready$.next(pendingObservables.shift());
3439
- };
3440
- });
3441
- }
3442
- function scheduleAndWait$(observable) {
3443
- return pendingObservables.push(observable), ready$.asObservable().pipe(operators$1.first((obs) => obs === observable));
3444
- }
3445
- return request;
3446
- }, withMaxConcurrency = (func, concurrency = DEFAULT_CONCURRENCY) => {
3447
- const throttler = createThrottler(concurrency);
3448
- return (...args) => rxjs.from(throttler(func(...args)));
3449
- }, fetchExisting$ = (client, type, hash) => client.observable.fetch("*[_type == $documentType && sha1hash == $hash][0]", {
3450
- documentType: type,
3451
- hash
3452
- }), readFile$ = (file) => new rxjs.Observable((subscriber) => {
3453
- const reader = new FileReader();
3454
- return reader.onload = () => {
3455
- subscriber.next(reader.result), subscriber.complete();
3456
- }, reader.onerror = (err) => {
3457
- subscriber.error(err);
3458
- }, reader.readAsArrayBuffer(file), () => {
3459
- reader.abort();
3460
- };
3461
- }), hexFromBuffer = (buffer) => Array.prototype.map.call(new Uint8Array(buffer), (x) => `00${x.toString(16)}`.slice(-2)).join(""), hashFile$ = (file) => !window.crypto || !window.crypto.subtle || !window.FileReader ? rxjs.throwError({
3462
- message: "Unable to generate hash: uploads are only allowed in secure contexts",
3463
- statusCode: 500
3464
- }) : readFile$(file).pipe(operators$1.mergeMap((arrayBuffer) => window.crypto.subtle.digest("SHA-1", arrayBuffer)), operators$1.map(hexFromBuffer)), uploadSanityAsset$ = (client, assetType, file, hash) => rxjs.of(null).pipe(
3465
- // NOTE: the sanity api will still dedupe unique files, but this saves us from uploading the asset file entirely
3466
- operators$1.mergeMap(() => fetchExisting$(client, `sanity.${assetType}Asset`, hash)),
3467
- // Cancel if the asset already exists
3468
- operators$1.mergeMap((existingAsset) => existingAsset ? rxjs.throwError({
3469
- message: "Asset already exists",
3470
- statusCode: 409
3471
- }) : rxjs.of(null)),
3472
- operators$1.mergeMap(() => client.observable.assets.upload(assetType, file, {
3473
- extract: ["blurhash", "exif", "location", "lqip", "palette"],
3474
- preserveFilename: !0
3475
- }).pipe(operators$1.map((event) => event.type === "response" ? {
3476
- // rewrite to a 'complete' event
3477
- asset: event.body.document,
3478
- id: event.body.document._id,
3479
- type: "complete"
3480
- } : event)))
3481
- ), uploadAsset$ = withMaxConcurrency(uploadSanityAsset$), initialState$2 = {
3482
- allIds: [],
3483
- byIds: {}
3484
- }, uploadsSlice = toolkit.createSlice({
3485
- name: "uploads",
3486
- initialState: initialState$2,
3487
- extraReducers: (builder) => {
3488
- builder.addCase(UPLOADS_ACTIONS.uploadComplete, (state, action) => {
3489
- const {
3490
- asset
3491
- } = action.payload;
3492
- state.byIds[asset.sha1hash] && (state.byIds[asset.sha1hash].status = "complete");
3493
- });
3494
- },
3495
- reducers: {
3496
- checkRequest(_state, _action) {
3497
- },
3498
- checkComplete(state, action) {
3499
- const {
3500
- results
3501
- } = action.payload;
3502
- Object.keys(results).forEach((hash) => {
3503
- const deleteIndex = state.allIds.indexOf(hash);
3504
- if (deleteIndex >= 0 && state.allIds.splice(deleteIndex, 1), state.byIds[hash]) {
3505
- const blobUrl = state.byIds[hash].objectUrl;
3506
- blobUrl && window.URL.revokeObjectURL(blobUrl), delete state.byIds[hash];
3507
- }
3508
- });
3509
- },
3510
- previewReady(state, action) {
3511
- const {
3512
- blobUrl,
3513
- hash
3514
- } = action.payload;
3515
- state.byIds[hash] && (state.byIds[hash].objectUrl = blobUrl);
3516
- },
3517
- uploadCancel(state, action) {
3518
- const {
3519
- hash
3520
- } = action.payload, deleteIndex = state.allIds.indexOf(hash);
3521
- deleteIndex >= 0 && state.allIds.splice(deleteIndex, 1), state.byIds[hash] && delete state.byIds[hash];
3522
- },
3523
- uploadError(state, action) {
3524
- const {
3525
- hash
3526
- } = action.payload, deleteIndex = state.allIds.indexOf(hash);
3527
- deleteIndex >= 0 && state.allIds.splice(deleteIndex, 1), delete state.byIds[hash];
3528
- },
3529
- uploadRequest(_state, _action) {
3530
- },
3531
- uploadProgress(state, action) {
3532
- const {
3533
- event,
3534
- uploadHash
3535
- } = action.payload;
3536
- state.byIds[uploadHash].percent = event.percent, state.byIds[uploadHash].status = "uploading";
3537
- },
3538
- uploadStart(state, action) {
3539
- const {
3540
- uploadItem
3541
- } = action.payload;
3542
- state.allIds.includes(uploadItem.hash) || state.allIds.push(uploadItem.hash), state.byIds[uploadItem.hash] = uploadItem;
3543
- }
3544
- }
3545
- }), uploadsAssetStartEpic = (action$, _state$, {
3546
- client
3547
- }) => action$.pipe(operators$1.filter(uploadsActions.uploadStart.match), operators$1.mergeMap((action) => {
3548
- const {
3549
- file,
3550
- uploadItem
3551
- } = action.payload;
3552
- return rxjs.merge(
3553
- // Generate low res preview
3554
- rxjs.of(null).pipe(operators$1.mergeMap(() => generatePreviewBlobUrl$(file)), operators$1.mergeMap((url) => rxjs.of(uploadsActions.previewReady({
3555
- blobUrl: url,
3556
- hash: uploadItem.hash
3557
- })))),
3558
- // Upload asset and receive progress / complete events
3559
- rxjs.of(null).pipe(
3560
- // delay(500000), // debug uploads
3561
- operators$1.mergeMap(() => uploadAsset$(client, uploadItem.assetType, file, uploadItem.hash)),
3562
- operators$1.takeUntil(action$.pipe(operators$1.filter(uploadsActions.uploadCancel.match), operators$1.filter((v) => v.payload.hash === uploadItem.hash))),
3563
- operators$1.mergeMap((event) => event?.type === "complete" ? rxjs.of(UPLOADS_ACTIONS.uploadComplete({
3564
- asset: event.asset
3565
- })) : event?.type === "progress" && event?.stage === "upload" ? rxjs.of(uploadsActions.uploadProgress({
3566
- event,
3567
- uploadHash: uploadItem.hash
3568
- })) : rxjs.empty()),
3569
- operators$1.catchError((error) => rxjs.of(uploadsActions.uploadError({
3570
- error: {
3571
- message: error?.message || "Internal error",
3572
- statusCode: error?.statusCode || 500
3573
- },
3574
- hash: uploadItem.hash
3575
- })))
3576
- )
3577
- );
3578
- })), uploadsAssetUploadEpic = (action$, state$) => action$.pipe(operators$1.filter(uploadsActions.uploadRequest.match), operators$1.withLatestFrom(state$), operators$1.mergeMap(([action, state]) => {
3579
- const {
3580
- file,
3581
- forceAsAssetType
3582
- } = action.payload;
3583
- return rxjs.of(action).pipe(
3584
- // Generate SHA1 hash from local file
3585
- // This will throw in insecure contexts (non-localhost / https)
3586
- operators$1.mergeMap(() => hashFile$(file)),
3587
- // Ignore if the file exists and is currently being uploaded
3588
- operators$1.filter((hash) => !state.uploads.byIds[hash]),
3589
- // Dispatch start action and begin upload process
3590
- operators$1.mergeMap((hash) => {
3591
- const uploadItem = {
3592
- _type: "upload",
3593
- assetType: forceAsAssetType || (file.type.indexOf("image") >= 0 ? "image" : "file"),
3594
- hash,
3595
- name: file.name,
3596
- size: file.size,
3597
- status: "queued"
3598
- };
3599
- return rxjs.of(uploadsActions.uploadStart({
3600
- file,
3601
- uploadItem
3602
- }));
3603
- })
3604
- );
3605
- })), uploadsCompleteQueueEpic = (action$) => action$.pipe(operators$1.filter(UPLOADS_ACTIONS.uploadComplete.match), operators$1.mergeMap((action) => rxjs.of(uploadsActions.checkRequest({
3606
- assets: [action.payload.asset]
3607
- })))), uploadsCheckRequestEpic = (action$, state$, {
3608
- client
3609
- }) => action$.pipe(operators$1.filter(uploadsActions.checkRequest.match), operators$1.withLatestFrom(state$), operators$1.mergeMap(([action, state]) => {
3610
- const {
3611
- assets
3612
- } = action.payload, documentIds = assets.map((asset) => asset._id), constructedFilter = constructFilter({
3613
- assetTypes: state.assets.assetTypes,
3614
- searchFacets: state.search.facets,
3615
- searchQuery: state.search.query
3616
- }), query = groq__default.default`
3617
- *[${constructedFilter} && _id in $documentIds].sha1hash
3618
- `;
3619
- return rxjs.of(action).pipe(
3620
- operators$1.delay(1e3),
3621
- // give Sanity some time to register the recently uploaded asset
3622
- operators$1.mergeMap(() => client.observable.fetch(query, {
3623
- documentIds
3624
- })),
3625
- operators$1.mergeMap((resultHashes) => {
3626
- const checkedResults = assets.reduce((acc, asset) => (acc[asset.sha1hash] = resultHashes.includes(asset.sha1hash) ? asset._id : null, acc), {});
3627
- return rxjs.of(
3628
- uploadsActions.checkComplete({
3629
- results: checkedResults
3630
- }),
3631
- //
3632
- assetsActions.insertUploads({
3633
- results: checkedResults
3634
- })
3635
- );
3636
- })
3637
- );
3638
- })), selectUploadById = toolkit.createSelector([(state) => state.uploads.byIds, (_state, uploadId) => uploadId], (byIds, uploadId) => byIds[uploadId]), uploadsActions = {
3639
- ...uploadsSlice.actions
3640
- };
3641
- var uploadsReducer = uploadsSlice.reducer;
3642
- const CardWrapper = styledComponents.styled(ui.Flex).withConfig({
3643
- displayName: "CardWrapper",
3644
- componentId: "sc-11n35er-0"
3645
- })`box-sizing:border-box;height:100%;overflow:hidden;position:relative;width:100%;`, CardUpload = (props) => {
3646
- const {
3647
- id
3648
- } = props, scheme = sanity.useColorSchemeValue(), dispatch = reactRedux.useDispatch(), item = useTypedSelector((state) => selectUploadById(state, id));
3649
- if (!item)
3650
- return null;
3651
- const fileSize = filesize__default.default(item.size, {
3652
- base: 10,
3653
- round: 0
3654
- }), percentLoaded = Math.round(item.percent || 0), isComplete = item.status === "complete", isUploading = item.status === "uploading", isQueued = item.status === "queued";
3655
- let status;
3656
- isComplete && (status = "Verifying"), isUploading && (status = `${percentLoaded}%`), isQueued && (status = "Queued");
3657
- const handleCancelUpload = () => {
3658
- dispatch(uploadsActions.uploadCancel({
3659
- hash: item.hash
3660
- }));
3661
- };
3662
- return /* @__PURE__ */ jsxRuntime.jsx(CardWrapper, { padding: 1, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", flex: 1, style: {
3663
- background: getSchemeColor(scheme, "bg"),
3664
- border: "1px solid transparent",
3665
- height: "100%",
3666
- position: "relative"
3667
- }, children: [
3668
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
3669
- background: "var(--card-fg-color)",
3670
- bottom: 0,
3671
- height: "1px",
3672
- left: 0,
3673
- position: "absolute",
3674
- width: "100%",
3675
- transform: `scaleX(${percentLoaded * 0.01})`,
3676
- transformOrigin: "bottom left",
3677
- transition: "all 1000ms ease-out"
3678
- } }),
3679
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { flex: 1, style: {
3680
- position: "relative"
3681
- }, children: [
3682
- item.assetType === "image" && item?.objectUrl && /* @__PURE__ */ jsxRuntime.jsx(Image$1, { draggable: !1, $scheme: scheme, src: item.objectUrl, style: {
3683
- opacity: 0.4
3684
- } }),
3685
- item.assetType === "file" && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
3686
- height: "100%",
3687
- opacity: 0.1
3688
- }, children: /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { width: "80px" }) }),
3689
- !isComplete && percentLoaded !== 100 && /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", direction: "column", justify: "center", style: {
3690
- height: "100%",
3691
- left: 0,
3692
- position: "absolute",
3693
- top: 0,
3694
- width: "100%"
3695
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 4, icon: icons.CloseIcon, mode: "bleed", onClick: handleCancelUpload, padding: 2, style: {
3696
- background: "none",
3697
- boxShadow: "none"
3698
- }, tone: "critical" }) })
3699
- ] }),
3700
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", justify: "space-between", paddingX: 2, style: {
3701
- height: `${PANEL_HEIGHT}px`
3702
- }, children: [
3703
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, marginRight: 1, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: 0, textOverflow: "ellipsis", children: [
3704
- item.name,
3705
- " (",
3706
- fileSize,
3707
- ")"
3708
- ] }) }),
3709
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, style: {
3710
- flexShrink: 0
3711
- }, weight: "semibold", children: status })
3712
- ] })
3713
- ] }) });
3714
- }, CARD_HEIGHT = 220, CARD_WIDTH = 240, VirtualCell = react.memo(({
3715
- item,
3716
- selected
3717
- }) => item?.type === "asset" ? /* @__PURE__ */ jsxRuntime.jsx(CardAsset, { id: item.id, selected }) : item?.type === "upload" ? /* @__PURE__ */ jsxRuntime.jsx(CardUpload, { id: item.id }) : null), StyledItemContainer = styledComponents.styled.div.withConfig({
3718
- displayName: "StyledItemContainer",
3719
- componentId: "sc-9owt7i-0"
3720
- })`height:${CARD_HEIGHT}px;width:${CARD_WIDTH}px;`, ItemContainer = react.forwardRef((props, ref) => {
3721
- const {
3722
- context,
3723
- ...rest
3724
- } = props;
3725
- return /* @__PURE__ */ jsxRuntime.jsx(StyledItemContainer, { ref, ...rest });
3726
- }), StyledListContainer = styledComponents.styled.div.withConfig({
3727
- displayName: "StyledListContainer",
3728
- componentId: "sc-9owt7i-1"
3729
- })`display:grid;grid-template-columns:repeat(auto-fill,${CARD_WIDTH}px);grid-template-rows:repeat(auto-fill,${CARD_HEIGHT}px);justify-content:center;margin:0 auto;`, ListContainer = react.forwardRef((props, ref) => {
3730
- const {
3731
- context,
3732
- ...rest
3733
- } = props;
3734
- return /* @__PURE__ */ jsxRuntime.jsx(StyledListContainer, { ref, ...rest });
3735
- }), AssetGridVirtualized = (props) => {
3736
- const {
3737
- items,
3738
- onLoadMore
3739
- } = props, selectedAssets = useTypedSelector((state) => state.selected.assets), selectedIds = selectedAssets && selectedAssets.map((asset) => asset._id) || [], totalCount = items?.length;
3740
- return totalCount === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(reactVirtuoso.VirtuosoGrid, { className: "media__custom-scrollbar", computeItemKey: (index) => items[index]?.id ?? index, components: {
3741
- Item: ItemContainer,
3742
- List: ListContainer
3743
- }, endReached: onLoadMore, itemContent: (index) => {
3744
- const item = items[index], selected = selectedIds.includes(item.id);
3745
- return /* @__PURE__ */ jsxRuntime.jsx(VirtualCell, { item, selected });
3746
- }, overscan: 48, style: {
3747
- overflowX: "hidden",
3748
- overflowY: "scroll"
3749
- }, totalCount });
3750
- }, TableHeaderItem = (props) => {
3751
- const {
3752
- field,
3753
- title
3754
- } = props, dispatch = reactRedux.useDispatch(), order = useTypedSelector((state) => state.assets.order), isActive = order.field === field;
3755
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { muted: !field, size: 0, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { onClick: field ? () => {
3756
- if (!(!field || !title))
3757
- if (isActive) {
3758
- const direction = order.direction === "asc" ? "desc" : "asc";
3759
- dispatch(assetsActions.orderSet({
3760
- order: {
3761
- field,
3762
- direction
3763
- }
3764
- }));
3765
- } else
3766
- dispatch(assetsActions.orderSet({
3767
- order: {
3768
- field,
3769
- direction: "asc"
3770
- }
3771
- }));
3772
- } : void 0, style: {
3773
- cursor: field ? "pointer" : "default",
3774
- display: "inline",
3775
- whiteSpace: "nowrap"
3776
- }, children: [
3777
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
3778
- marginRight: "0.4em"
3779
- }, children: title }),
3780
- isActive && order?.direction === "asc" && /* @__PURE__ */ jsxRuntime.jsx(icons.ChevronUpIcon, {}),
3781
- isActive && order?.direction === "desc" && /* @__PURE__ */ jsxRuntime.jsx(icons.ChevronDownIcon, {})
3782
- ] }) });
3783
- }, ContextActionContainer$1 = /* @__PURE__ */ styledComponents.styled(ui.Flex).withConfig({
3784
- displayName: "ContextActionContainer",
3785
- componentId: "sc-i9fhtm-0"
3786
- })(({
3787
- $scheme
3788
- }) => styledComponents.css`cursor:pointer;@media (hover:hover) and (pointer:fine){&:hover{background:${getSchemeColor($scheme, "bg")};}}`), TableHeader = () => {
3789
- const scheme = sanity.useColorSchemeValue(), dispatch = reactRedux.useDispatch(), fetching = useTypedSelector((state) => state.assets.fetching), itemsLength = useTypedSelector(selectAssetsLength), numPickedAssets = useTypedSelector(selectAssetsPickedLength), mediaIndex = ui.useMediaIndex(), {
3790
- onSelect
3791
- } = useAssetSourceActions(), allSelected = numPickedAssets === itemsLength, handleContextActionClick = (e) => {
3792
- e.stopPropagation(), dispatch(allSelected ? assetsActions.pickClear() : assetsActions.pickAll());
3793
- };
3794
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Grid, { style: {
3795
- alignItems: "center",
3796
- background: "var(--card-bg-color)",
3797
- borderBottom: "1px solid var(--card-border-color)",
3798
- gridColumnGap: mediaIndex < 3 ? 0 : "16px",
3799
- gridTemplateColumns: GRID_TEMPLATE_COLUMNS.LARGE,
3800
- height: mediaIndex < 3 ? 0 : `${PANEL_HEIGHT}px`,
3801
- letterSpacing: "0.025em",
3802
- position: "sticky",
3803
- textTransform: "uppercase",
3804
- top: 0,
3805
- visibility: mediaIndex < 3 ? "hidden" : "visible",
3806
- width: "100%",
3807
- zIndex: 1
3808
- // force stacking context
3809
- }, children: [
3810
- onSelect ? /* @__PURE__ */ jsxRuntime.jsx(TableHeaderItem, {}) : /* @__PURE__ */ jsxRuntime.jsx(ContextActionContainer$1, { align: "center", justify: "center", onClick: handleContextActionClick, $scheme: scheme, style: {
3811
- height: "100%",
3812
- position: "relative"
3813
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { checked: !fetching && allSelected, readOnly: !0, style: {
3814
- pointerEvents: "none",
3815
- // TODO: consider alternative for usability
3816
- transform: "scale(0.8)"
3817
- } }) }),
3818
- /* @__PURE__ */ jsxRuntime.jsx(TableHeaderItem, {}),
3819
- /* @__PURE__ */ jsxRuntime.jsx(TableHeaderItem, { field: "originalFilename", title: "Filename" }),
3820
- /* @__PURE__ */ jsxRuntime.jsx(TableHeaderItem, { title: "Resolution" }),
3821
- /* @__PURE__ */ jsxRuntime.jsx(TableHeaderItem, { field: "mimeType", title: "MIME type" }),
3822
- /* @__PURE__ */ jsxRuntime.jsx(TableHeaderItem, { field: "size", title: "Size" }),
3823
- /* @__PURE__ */ jsxRuntime.jsx(TableHeaderItem, { field: "_updatedAt", title: "Last updated" }),
3824
- /* @__PURE__ */ jsxRuntime.jsx(TableHeaderItem, { title: "References" }),
3825
- /* @__PURE__ */ jsxRuntime.jsx(TableHeaderItem, {})
3826
- ] });
3827
- }, REFERENCE_COUNT_VISIBILITY_DELAY = 750, ContainerGrid = /* @__PURE__ */ styledComponents.styled(ui.Grid).withConfig({
3828
- displayName: "ContainerGrid",
3829
- componentId: "sc-1nb1qw9-0"
3830
- })(({
3831
- $scheme,
3832
- $selected,
3833
- $updating
3834
- }) => styledComponents.css`align-items:center;cursor:${$selected ? "default" : "pointer"};height:100%;pointer-events:${$updating ? "none" : "auto"};user-select:none;white-space:nowrap;${!$updating && styledComponents.css`@media (hover:hover) and (pointer:fine){&:hover{background:${getSchemeColor($scheme, "bg")};}}`}`), ContextActionContainer = /* @__PURE__ */ styledComponents.styled(ui.Flex).withConfig({
3835
- displayName: "ContextActionContainer",
3836
- componentId: "sc-1nb1qw9-1"
3837
- })(({
3838
- $scheme
3839
- }) => styledComponents.css`cursor:pointer;@media (hover:hover) and (pointer:fine){&:hover{background:${getSchemeColor($scheme, "bg2")};}}`), StyledWarningIcon = /* @__PURE__ */ styledComponents.styled(icons.WarningFilledIcon).withConfig({
3840
- displayName: "StyledWarningIcon",
3841
- componentId: "sc-1nb1qw9-2"
3842
- })(({
3843
- theme
3844
- }) => ({
3845
- color: theme.sanity.color.spot.red
3846
- })), TableRowAsset$1 = (props) => {
3847
- const {
3848
- id,
3849
- selected
3850
- } = props, scheme = sanity.useColorSchemeValue(), shiftPressed = useKeyPress("shift"), [referenceCountVisible, setReferenceCountVisible] = react.useState(!1), refCountVisibleTimeout = react.useRef(null), dispatch = reactRedux.useDispatch(), lastPicked = useTypedSelector((state) => state.assets.lastPicked), item = useTypedSelector((state) => selectAssetById(state, id)), mediaIndex = ui.useMediaIndex(), asset = item?.asset, error = item?.error, isOpaque = item?.asset?.metadata?.isOpaque, picked = item?.picked, updating = item?.updating, {
3851
- onSelect
3852
- } = useAssetSourceActions(), handleContextActionClick = react.useCallback((e) => {
3853
- e.stopPropagation(), asset && (onSelect ? dispatch(dialogActions.showAssetEdit({
3854
- assetId: asset._id
3855
- })) : shiftPressed.current && !picked ? dispatch(assetsActions.pickRange({
3856
- startId: lastPicked || asset._id,
3857
- endId: asset._id
3858
- })) : dispatch(assetsActions.pick({
3859
- assetId: asset._id,
3860
- picked: !picked
3861
- })));
3862
- }, [asset, dispatch, lastPicked, onSelect, picked, shiftPressed]), handleClick = react.useCallback((e) => {
3863
- e.stopPropagation(), asset && (onSelect ? onSelect([{
3864
- kind: "assetDocumentId",
3865
- value: asset._id
3866
- }]) : shiftPressed.current ? dispatch(picked ? assetsActions.pick({
3867
- assetId: asset._id,
3868
- picked: !picked
3869
- }) : assetsActions.pickRange({
3870
- startId: lastPicked || asset._id,
3871
- endId: asset._id
3872
- })) : dispatch(dialogActions.showAssetEdit({
3873
- assetId: asset._id
3874
- })));
3875
- }, [asset, dispatch, lastPicked, onSelect, picked, shiftPressed]), opacityCell = updating ? 0.5 : 1, opacityPreview = selected || updating ? 0.1 : 1;
3876
- return react.useEffect(() => (refCountVisibleTimeout.current = setTimeout(() => setReferenceCountVisible(!0), REFERENCE_COUNT_VISIBILITY_DELAY), () => {
3877
- refCountVisibleTimeout.current && clearTimeout(refCountVisibleTimeout.current);
3878
- }), []), asset ? /* @__PURE__ */ jsxRuntime.jsxs(ContainerGrid, { onClick: selected ? void 0 : handleClick, $scheme: scheme, $selected: selected, style: {
3879
- gridColumnGap: mediaIndex < 3 ? 0 : "16px",
3880
- gridRowGap: 0,
3881
- gridTemplateColumns: mediaIndex < 3 ? GRID_TEMPLATE_COLUMNS.SMALL : GRID_TEMPLATE_COLUMNS.LARGE,
3882
- gridTemplateRows: mediaIndex < 3 ? "auto" : "1fr"
3883
- }, $updating: item.updating, children: [
3884
- /* @__PURE__ */ jsxRuntime.jsx(ContextActionContainer, { onClick: handleContextActionClick, $scheme: scheme, style: {
3885
- alignItems: "center",
3886
- gridColumn: 1,
3887
- gridRowStart: 1,
3888
- gridRowEnd: "span 5",
3889
- height: "100%",
3890
- justifyContent: "center",
3891
- opacity: opacityCell,
3892
- position: "relative"
3893
- }, children: onSelect ? /* @__PURE__ */ jsxRuntime.jsx(icons.EditIcon, { style: {
3894
- flexShrink: 0,
3895
- opacity: 0.5
3896
- } }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { checked: picked, readOnly: !0, style: {
3897
- pointerEvents: "none",
3898
- // TODO: consider alternative for usability
3899
- transform: "scale(0.8)"
3900
- } }) }),
3901
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
3902
- gridColumn: 2,
3903
- gridRowStart: 1,
3904
- gridRowEnd: "span 5",
3905
- height: "90px",
3906
- width: "100px"
3907
- }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", justify: "center", style: {
3908
- height: "100%",
3909
- position: "relative"
3910
- }, children: [
3911
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { style: {
3912
- height: "100%",
3913
- opacity: opacityPreview,
3914
- position: "relative"
3915
- }, children: [
3916
- isFileAsset(asset) && /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { extension: asset.extension, width: "40px" }),
3917
- isImageAsset(asset) && /* @__PURE__ */ jsxRuntime.jsx(Image$1, { draggable: !1, $scheme: scheme, $showCheckerboard: !isOpaque, src: imageDprUrl(asset, {
3918
- height: 100,
3919
- width: 100
3920
- }) })
3921
- ] }),
3922
- updating && /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "center", style: {
3923
- height: "100%",
3924
- left: 0,
3925
- position: "absolute",
3926
- top: 0,
3927
- width: "100%"
3928
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, {}) }),
3929
- selected && !updating && /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "center", style: {
3930
- height: "100%",
3931
- left: 0,
3932
- position: "absolute",
3933
- top: 0,
3934
- width: "100%"
3935
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 2, children: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckmarkCircleIcon, {}) }) })
3936
- ] }) }),
3937
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginLeft: mediaIndex < 3 ? 3 : 0, style: {
3938
- gridColumn: 3,
3939
- gridRow: mediaIndex < 3 ? 2 : "auto",
3940
- opacity: opacityCell
3941
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, style: {
3942
- lineHeight: "2em"
3943
- }, textOverflow: "ellipsis", children: asset.originalFilename }) }),
3944
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginLeft: mediaIndex < 3 ? 3 : 0, style: {
3945
- gridColumn: mediaIndex < 3 ? 3 : 4,
3946
- gridRow: mediaIndex < 3 ? 3 : "auto",
3947
- opacity: opacityCell
3948
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, style: {
3949
- lineHeight: "2em"
3950
- }, textOverflow: "ellipsis", children: isImageAsset(asset) && getAssetResolution(asset) }) }),
3951
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
3952
- display: mediaIndex < 3 ? "none" : "block",
3953
- gridColumn: 5,
3954
- gridRow: "auto",
3955
- opacity: opacityCell
3956
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, style: {
3957
- lineHeight: "2em"
3958
- }, textOverflow: "ellipsis", children: asset.mimeType }) }),
3959
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
3960
- display: mediaIndex < 3 ? "none" : "block",
3961
- gridColumn: 6,
3962
- gridRow: "auto",
3963
- opacity: opacityCell
3964
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, style: {
3965
- lineHeight: "2em"
3966
- }, textOverflow: "ellipsis", children: filesize__default.default(asset.size, {
3967
- base: 10,
3968
- round: 0
3969
- }) }) }),
3970
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginLeft: mediaIndex < 3 ? 3 : 0, style: {
3971
- gridColumn: mediaIndex < 3 ? 3 : 7,
3972
- gridRow: mediaIndex < 3 ? 4 : "auto",
3973
- opacity: opacityCell
3974
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, style: {
3975
- lineHeight: "2em"
3976
- }, textOverflow: "ellipsis", children: dateFns.formatRelative(new Date(asset._updatedAt), /* @__PURE__ */ new Date()) }) }),
3977
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
3978
- display: mediaIndex < 3 ? "none" : "block",
3979
- gridColumn: 8,
3980
- gridRow: "auto",
3981
- opacity: opacityCell
3982
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, style: {
3983
- lineHeight: "2em"
3984
- }, textOverflow: "ellipsis", children: referenceCountVisible ? /* @__PURE__ */ jsxRuntime.jsx(sanity.WithReferringDocuments, { id, children: ({
3985
- isLoading,
3986
- referringDocuments
3987
- }) => {
3988
- const uniqueDocuments = getUniqueDocuments(referringDocuments);
3989
- return isLoading ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: "-" }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.isArray(uniqueDocuments) ? uniqueDocuments.length : 0 });
3990
- } }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: "-" }) }) }),
3991
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "center", style: {
3992
- gridColumn: mediaIndex < 3 ? 4 : 9,
3993
- gridRowStart: "1",
3994
- gridRowEnd: mediaIndex < 3 ? "span 5" : "auto",
3995
- opacity: opacityCell
3996
- }, children: error && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { animate: !0, content: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { padding: 2, width: 0, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: error }) }), placement: "left", portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: /* @__PURE__ */ jsxRuntime.jsx(StyledWarningIcon, { color: "critical" }) }) }) }) })
3997
- ] }) : null;
3998
- };
3999
- var TableRowAsset = react.memo(TableRowAsset$1);
4000
- const TableRowUpload = (props) => {
4001
- const {
4002
- id
4003
- } = props, scheme = sanity.useColorSchemeValue(), dispatch = reactRedux.useDispatch(), item = useTypedSelector((state) => selectUploadById(state, id)), mediaIndex = ui.useMediaIndex();
4004
- if (!item)
4005
- return null;
4006
- const fileSize = filesize__default.default(item.size, {
4007
- base: 10,
4008
- round: 0
4009
- }), percentLoaded = Math.round(item.percent || 0), isComplete = item.status === "complete", isUploading = item.status === "uploading", isQueued = item.status === "queued";
4010
- let status;
4011
- isComplete && (status = "Verifying"), isUploading && (status = `${percentLoaded}%`), isQueued && (status = "Queued");
4012
- const handleCancelUpload = () => {
4013
- dispatch(uploadsActions.uploadCancel({
4014
- hash: item.hash
4015
- }));
4016
- };
4017
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Grid, { style: {
4018
- alignItems: "center",
4019
- background: getSchemeColor(scheme, "bg"),
4020
- gridColumnGap: mediaIndex < 3 ? 0 : "16px",
4021
- gridRowGap: 0,
4022
- gridTemplateColumns: mediaIndex < 3 ? GRID_TEMPLATE_COLUMNS.SMALL : GRID_TEMPLATE_COLUMNS.LARGE,
4023
- gridTemplateRows: mediaIndex < 3 ? "auto" : "1fr",
4024
- height: "100%",
4025
- position: "relative"
4026
- }, children: [
4027
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
4028
- background: "var(--card-fg-color)",
4029
- bottom: 0,
4030
- height: "1px",
4031
- left: 0,
4032
- position: "absolute",
4033
- width: "100%",
4034
- transform: `scaleX(${percentLoaded * 0.01})`,
4035
- transformOrigin: "bottom left",
4036
- transition: "all 1000ms ease-out"
4037
- } }),
4038
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
4039
- gridColumn: 2,
4040
- gridRowStart: mediaIndex < 3 ? 1 : "auto",
4041
- gridRowEnd: mediaIndex < 3 ? "span 4" : "auto",
4042
- height: "90px",
4043
- width: "100px"
4044
- }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { style: {
4045
- height: "100%",
4046
- position: "relative"
4047
- }, children: [
4048
- item.assetType === "image" && item?.objectUrl && /* @__PURE__ */ jsxRuntime.jsx(Image$1, { draggable: !1, $scheme: scheme, src: item.objectUrl, style: {
4049
- opacity: 0.25
4050
- } }),
4051
- item.assetType === "file" && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
4052
- height: "100%",
4053
- opacity: 0.1
4054
- }, children: /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { width: "40px" }) }),
4055
- !isComplete && percentLoaded !== 100 && /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "center", style: {
4056
- position: "absolute",
4057
- height: "100%",
4058
- left: 0,
4059
- top: 0,
4060
- width: "100%"
4061
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { fontSize: 3, icon: icons.CloseIcon, mode: "bleed", onClick: handleCancelUpload, padding: 2, style: {
4062
- background: "none",
4063
- boxShadow: "none"
4064
- }, tone: "critical" }) })
4065
- ] }) }),
4066
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
4067
- gridColumn: mediaIndex < 3 ? 3 : "3/8",
4068
- gridRow: mediaIndex < 3 ? "2/4" : "auto",
4069
- marginLeft: mediaIndex < 3 ? 3 : 0
4070
- }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
4071
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { muted: !0, size: 1, textOverflow: "ellipsis", children: [
4072
- item.name,
4073
- " (",
4074
- fileSize,
4075
- ")"
4076
- ] }),
4077
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, textOverflow: "ellipsis", weight: "semibold", children: status })
4078
- ] }) })
4079
- ] });
4080
- }, VirtualRow = react.memo(({
4081
- item,
4082
- selected
4083
- }) => item?.type === "asset" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
4084
- height: "100px"
4085
- }, children: /* @__PURE__ */ jsxRuntime.jsx(TableRowAsset, { id: item.id, selected }) }) : item?.type === "upload" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
4086
- height: "100px"
4087
- }, children: /* @__PURE__ */ jsxRuntime.jsx(TableRowUpload, { id: item.id }) }) : null), AssetTableVirtualized = (props) => {
4088
- const {
4089
- items,
4090
- onLoadMore
4091
- } = props, selectedAssets = useTypedSelector((state) => state.selected.assets), selectedIds = selectedAssets && selectedAssets.map((asset) => asset._id) || [], totalCount = items?.length;
4092
- return totalCount === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(reactVirtuoso.GroupedVirtuoso, { className: "media__custom-scrollbar", computeItemKey: (index) => items[index]?.id || index, endReached: onLoadMore, groupCounts: Array(1).fill(totalCount), groupContent: () => /* @__PURE__ */ jsxRuntime.jsx(TableHeader, {}), itemContent: (index) => {
4093
- const item = items[index], selected = selectedIds.includes(item?.id || "");
4094
- return /* @__PURE__ */ jsxRuntime.jsx(VirtualRow, { item, selected });
4095
- }, style: {
4096
- overflowX: "hidden"
4097
- } });
4098
- }, Items = () => {
4099
- const dispatch = reactRedux.useDispatch(), fetchCount = useTypedSelector((state) => state.assets.fetchCount), fetching = useTypedSelector((state) => state.assets.fetching), tagsPanelVisible = useTypedSelector((state) => state.tags.panelVisible), view = useTypedSelector((state) => state.assets.view), combinedItems = useTypedSelector(selectCombinedItems), breakpointIndex = useBreakpointIndex(), hasFetchedOnce = fetchCount >= 0, hasItems = combinedItems.length > 0, handleLoadMoreItems = () => {
4100
- fetching || dispatch(assetsActions.loadNextPage());
4101
- };
4102
- return react.useEffect(() => {
4103
- breakpointIndex <= 1 && tagsPanelVisible && dispatch(tagsActions.panelVisibleSet({
4104
- panelVisible: !1
4105
- }));
4106
- }, [breakpointIndex, dispatch, tagsPanelVisible]), /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, style: {
4107
- width: "100%"
4108
- }, children: !hasItems && hasFetchedOnce && !fetching ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "semibold", children: "No results for the current query" }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4109
- view === "grid" && /* @__PURE__ */ jsxRuntime.jsx(AssetGridVirtualized, { items: combinedItems, onLoadMore: handleLoadMoreItems }),
4110
- view === "table" && /* @__PURE__ */ jsxRuntime.jsx(AssetTableVirtualized, { items: combinedItems, onLoadMore: handleLoadMoreItems })
4111
- ] }) });
4112
- }, Notifications = () => {
4113
- const items = useTypedSelector((state) => state.notifications.items), toast = ui.useToast();
4114
- return react.useEffect(() => {
4115
- if (items.length > 0) {
4116
- const lastItem = items[items.length - 1];
4117
- toast.push({
4118
- closable: !0,
4119
- status: lastItem.status,
4120
- title: lastItem.title
4121
- });
4122
- }
4123
- }, [items, toast]), null;
4124
- }, PickedBar = () => {
4125
- const scheme = sanity.useColorSchemeValue(), dispatch = reactRedux.useDispatch(), assetsPicked = useTypedSelector(selectAssetsPicked), handlePickClear = () => {
4126
- dispatch(assetsActions.pickClear());
4127
- }, handleDeletePicked = () => {
4128
- dispatch(dialogActions.showConfirmDeleteAssets({
4129
- assets: assetsPicked
4130
- }));
4131
- };
4132
- return assetsPicked.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", justify: "flex-start", style: {
4133
- background: getSchemeColor(scheme, "bg"),
4134
- borderBottom: "1px solid var(--card-border-color)",
4135
- height: `${PANEL_HEIGHT}px`,
4136
- position: "relative",
4137
- width: "100%"
4138
- }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", paddingX: 3, children: [
4139
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingRight: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Label, { size: 0, style: {
4140
- color: "inherit"
4141
- }, children: [
4142
- assetsPicked.length,
4143
- " ",
4144
- pluralize__default.default("asset", assetsPicked.length),
4145
- " selected"
4146
- ] }) }),
4147
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { mode: "bleed", onClick: handlePickClear, padding: 2, style: {
4148
- background: "none",
4149
- boxShadow: "none"
4150
- }, tone: "default", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: 0, children: "Deselect" }) }),
4151
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { mode: "bleed", onClick: handleDeletePicked, padding: 2, style: {
4152
- background: "none",
4153
- boxShadow: "none"
4154
- }, tone: "critical", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: 0, children: "Delete" }) })
4155
- ] }) });
4156
- };
4157
- function messageFromGenericErrorPayload(payload) {
4158
- return !payload || typeof payload != "object" ? "Unknown error" : "error" in payload && payload.error && typeof payload.error == "object" && payload.error !== null && "message" in payload.error ? String(payload.error.message) : "message" in payload && typeof payload.message == "string" ? String(payload.message) : "Unknown error";
4159
- }
4160
- const initialState$1 = {
4161
- items: []
4162
- }, notificationsSlice = toolkit.createSlice({
4163
- name: "notifications",
4164
- initialState: initialState$1,
4165
- reducers: {
4166
- add(state, action) {
4167
- const {
4168
- asset,
4169
- status,
4170
- title
4171
- } = action.payload;
4172
- state.items.push({
4173
- asset,
4174
- status,
4175
- title
4176
- });
4177
- }
4178
- }
4179
- }), notificationsAssetsDeleteCompleteEpic = (action$) => action$.pipe(operators$1.filter(assetsActions.deleteComplete.match), operators$1.mergeMap((action) => {
4180
- const {
4181
- assetIds
4182
- } = action.payload, deletedCount = assetIds.length;
4183
- return rxjs.of(notificationsSlice.actions.add({
4184
- status: "info",
4185
- title: `${deletedCount} ${pluralize__default.default("asset", deletedCount)} deleted`
4186
- }));
4187
- })), notificationsAssetsDeleteErrorEpic = (action$) => action$.pipe(operators$1.filter(assetsActions.deleteError.match), operators$1.mergeMap((action) => {
4188
- const {
4189
- assetIds
4190
- } = action.payload, count = assetIds.length;
4191
- return rxjs.of(notificationsSlice.actions.add({
4192
- status: "error",
4193
- title: `Unable to delete ${count} ${pluralize__default.default("asset", count)}. Please review any asset errors and try again.`
4194
- }));
4195
- })), notificationsAssetsTagsAddCompleteEpic = (action$) => action$.pipe(operators$1.filter(ASSETS_ACTIONS.tagsAddComplete.match), operators$1.mergeMap((action) => {
4196
- const count = action?.payload?.assets?.length;
4197
- return rxjs.of(notificationsSlice.actions.add({
4198
- status: "info",
4199
- title: `Tag added to ${count} ${pluralize__default.default("asset", count)}`
4200
- }));
4201
- })), notificationsAssetsTagsRemoveCompleteEpic = (action$) => action$.pipe(operators$1.filter(ASSETS_ACTIONS.tagsRemoveComplete.match), operators$1.mergeMap((action) => {
4202
- const count = action?.payload?.assets?.length;
4203
- return rxjs.of(notificationsSlice.actions.add({
4204
- status: "info",
4205
- title: `Tag removed from ${count} ${pluralize__default.default("asset", count)}`
4206
- }));
4207
- })), notificationsAssetsUpdateCompleteEpic = (action$) => action$.pipe(operators$1.filter(assetsActions.updateComplete.match), operators$1.bufferTime(2e3), operators$1.filter((actions) => actions.length > 0), operators$1.mergeMap((actions) => {
4208
- const updatedCount = actions.length;
4209
- return rxjs.of(notificationsSlice.actions.add({
4210
- status: "info",
4211
- title: `${updatedCount} ${pluralize__default.default("asset", updatedCount)} updated`
4212
- }));
4213
- })), notificationsGenericErrorEpic = (action$) => action$.pipe(reduxObservable.ofType(assetsActions.fetchError.type, assetsActions.updateError.type, tagsActions.createError.type, tagsActions.deleteError.type, tagsActions.fetchError.type, tagsActions.updateError.type, uploadsActions.uploadError.type), operators$1.mergeMap((action) => {
4214
- const title = `An error occurred: ${messageFromGenericErrorPayload(action.payload)}`;
4215
- return rxjs.of(notificationsSlice.actions.add({
4216
- status: "error",
4217
- title
4218
- }));
4219
- })), notificationsTagCreateCompleteEpic = (action$) => action$.pipe(operators$1.filter(tagsActions.createComplete.match), operators$1.mergeMap(() => rxjs.of(notificationsSlice.actions.add({
4220
- status: "info",
4221
- title: "Tag created"
4222
- })))), notificationsTagDeleteCompleteEpic = (action$) => action$.pipe(operators$1.filter(tagsActions.deleteComplete.match), operators$1.mergeMap(() => rxjs.of(notificationsSlice.actions.add({
4223
- status: "info",
4224
- title: "Tag deleted"
4225
- })))), notificationsTagUpdateCompleteEpic = (action$) => action$.pipe(operators$1.filter(tagsActions.updateComplete.match), operators$1.mergeMap(() => rxjs.of(notificationsSlice.actions.add({
4226
- status: "info",
4227
- title: "Tag updated"
4228
- })))), notificationsActions = {
4229
- ...notificationsSlice.actions
4230
- };
4231
- var notificationsReducer = notificationsSlice.reducer;
4232
- const initialState = {
4233
- assets: [],
4234
- document: void 0,
4235
- documentAssetIds: []
4236
- }, selectedSlice = toolkit.createSlice({
4237
- name: "selected",
4238
- initialState,
4239
- reducers: {}
4240
- });
4241
- var selectedReducer = selectedSlice.reducer;
4242
- const rootEpic = reduxObservable.combineEpics(assetsDeleteEpic, assetsFetchEpic, assetsFetchAfterDeleteAllEpic, assetsFetchNextPageEpic, assetsFetchPageIndexEpic, assetsListenerCreateQueueEpic, assetsListenerDeleteQueueEpic, assetsListenerUpdateQueueEpic, assetsOrderSetEpic, assetsSearchEpic, assetsSortEpic, assetsTagsAddEpic, assetsTagsRemoveEpic, assetsUnpickEpic, assetsUpdateEpic, dialogClearOnAssetUpdateEpic, dialogTagCreateEpic, dialogTagDeleteEpic, notificationsAssetsDeleteErrorEpic, notificationsAssetsDeleteCompleteEpic, notificationsAssetsTagsAddCompleteEpic, notificationsAssetsTagsRemoveCompleteEpic, notificationsAssetsUpdateCompleteEpic, notificationsGenericErrorEpic, notificationsTagCreateCompleteEpic, notificationsTagDeleteCompleteEpic, notificationsTagUpdateCompleteEpic, searchFacetTagUpdateEpic, tagsCreateEpic, tagsDeleteEpic, tagsFetchEpic, tagsListenerCreateQueueEpic, tagsListenerDeleteQueueEpic, tagsListenerUpdateQueueEpic, tagsSortEpic, tagsUpdateEpic, uploadsAssetStartEpic, uploadsAssetUploadEpic, uploadsCheckRequestEpic, uploadsCompleteQueueEpic), reducers = {
4243
- assets: assetsReducer,
4244
- debug: debugReducer,
4245
- dialog: dialogReducer,
4246
- notifications: notificationsReducer,
4247
- search: searchReducer,
4248
- selected: selectedReducer,
4249
- tags: tagsReducer,
4250
- uploads: uploadsReducer
4251
- }, rootReducer = toolkit.combineReducers(reducers), isPlainObject = (value) => value !== null && typeof value == "object" && !Array.isArray(value), getAssetIds = (node, acc = []) => (Array.isArray(node) && node.forEach((v) => {
4252
- getAssetIds(v, acc);
4253
- }), isPlainObject(node) && (node?.asset?._type === "reference" && node?.asset?._ref && acc.push(node.asset._ref), Object.values(node).forEach((val) => {
4254
- getAssetIds(val, acc);
4255
- })), acc), getDocumentAssetIds = (document2) => {
4256
- const assetIds = getAssetIds(document2);
4257
- return [...new Set(assetIds.sort())];
4258
- };
4259
- function isSupportedAssetType(assetType) {
4260
- return assetType ? SUPPORTED_ASSET_TYPES.includes(assetType) : !1;
4261
- }
4262
- class ReduxProvider extends react.Component {
4263
- constructor(props) {
4264
- super(props);
4265
- const epicMiddleware = reduxObservable.createEpicMiddleware({
4266
- dependencies: {
4267
- client: props.client
4268
- // inject sanity client as a dependency to all epics
4269
- }
4270
- });
4271
- this.store = toolkit.configureStore({
4272
- reducer: rootReducer,
4273
- middleware: (getDefaultMiddleware) => getDefaultMiddleware({
4274
- /*
4275
- serializableCheck: {
4276
- ignoredActions: [
4277
- assetsActions.deleteError.type,
4278
- uploadsActions.uploadRequest.type,
4279
- uploadsActions.uploadStart.type,
4280
- ]
4281
- },
4282
- */
4283
- // TODO: remove once we're no longer storing non-serializable data in the store
4284
- serializableCheck: !1,
4285
- thunk: !1
4286
- }).prepend(epicMiddleware),
4287
- devTools: !0,
4288
- preloadedState: {
4289
- assets: {
4290
- ...initialState$5,
4291
- assetTypes: isSupportedAssetType(props?.assetType) ? [props.assetType] : ["file", "image"]
4292
- },
4293
- debug: {
4294
- badConnection: !1,
4295
- enabled: !1
4296
- },
4297
- dialog: {
4298
- items: []
4299
- },
4300
- notifications: {
4301
- items: []
4302
- },
4303
- search: {
4304
- facets: [],
4305
- query: ""
4306
- },
4307
- selected: {
4308
- assets: props.selectedAssets || [],
4309
- document: props.document,
4310
- documentAssetIds: props.document ? getDocumentAssetIds(props.document) : []
4311
- },
4312
- tags: {
4313
- allIds: [],
4314
- byIds: {},
4315
- creating: !1,
4316
- fetchCount: -1,
4317
- fetching: !1,
4318
- panelVisible: !0
4319
- },
4320
- uploads: {
4321
- allIds: [],
4322
- byIds: {}
4323
- }
4324
- }
4325
- }), epicMiddleware.run(rootEpic);
4326
- }
4327
- render() {
4328
- return /* @__PURE__ */ jsxRuntime.jsx(reactRedux.Provider, { store: this.store, children: this.props.children });
4329
- }
4330
- }
4331
- const TagsPanel = () => useTypedSelector((state) => state.tags.panelVisible) ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: {
4332
- position: "relative",
4333
- width: TAGS_PANEL_WIDTH
4334
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { className: "media__custom-scrollbar", style: {
4335
- borderLeft: "1px solid var(--card-border-color)",
4336
- height: "100%",
4337
- overflowX: "hidden",
4338
- overflowY: "auto",
4339
- position: "absolute",
4340
- right: 0,
4341
- top: 0,
4342
- width: "100%"
4343
- }, children: /* @__PURE__ */ jsxRuntime.jsx(TagView, {}) }) }) : null, UploadContainer = styledComponents.styled.div.withConfig({
4344
- displayName: "UploadContainer",
4345
- componentId: "sc-1wiv2t5-0"
4346
- })`color:white;height:100%;min-height:100%;right:0;top:0;width:100%;&:focus{outline:none;}`, DragActiveContainer = styledComponents.styled.div.withConfig({
4347
- displayName: "DragActiveContainer",
4348
- componentId: "sc-1wiv2t5-1"
4349
- })`align-items:center;background:rgba(0,0,0,0.75);display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;width:100%;z-index:3;`;
4350
- async function filterFiles(fileList) {
4351
- const files = Array.from(fileList), filteredFiles = [];
4352
- for (const file of files)
4353
- try {
4354
- await file.slice(0, 1).arrayBuffer(), filteredFiles.push(file);
4355
- } catch {
4356
- }
4357
- return filteredFiles;
4358
- }
4359
- const UploadDropzone = (props) => {
4360
- const {
4361
- children
4362
- } = props, {
4363
- dropzone: {
4364
- maxSize
4365
- },
4366
- directUploads
4367
- } = useToolOptions(), {
4368
- onSelect
4369
- } = useAssetSourceActions(), dispatch = reactRedux.useDispatch(), assetTypes = useTypedSelector((state) => state.assets.assetTypes), isImageAssetType = assetTypes.length === 1 && assetTypes[0] === "image", handleDrop = async (acceptedFiles) => {
4370
- acceptedFiles.forEach((file) => dispatch(uploadsActions.uploadRequest({
4371
- file,
4372
- forceAsAssetType: assetTypes.length === 1 ? assetTypes[0] : void 0
4373
- })));
4374
- }, handleDropRejected = (rejections) => {
4375
- rejections.flatMap(({
4376
- errors
4377
- }) => errors.map(({
4378
- code
4379
- }) => code)).includes("file-too-large") && dispatch(notificationsActions.add({
4380
- status: "error",
4381
- title: "One or more files exceed the maximum upload size."
4382
- }));
4383
- }, handleFileGetter = async (event) => {
4384
- let fileList;
4385
- if (event.type === "drop" && "dataTransfer" in event && (fileList = event?.dataTransfer?.files), event.type === "change") {
4386
- const target = event?.target;
4387
- target?.files && (fileList = target.files);
4388
- }
4389
- if (!fileList)
4390
- return [];
4391
- const files = await filterFiles(fileList);
4392
- return fileList?.length !== files.length && dispatch(notificationsActions.add({
4393
- status: "error",
4394
- title: "Unable to upload some items (folders and packages aren't supported)"
4395
- })), files;
4396
- }, {
4397
- getRootProps,
4398
- getInputProps,
4399
- isDragActive,
4400
- open
4401
- } = reactDropzone.useDropzone({
4402
- accept: isImageAssetType ? "image/*" : "",
4403
- getFilesFromEvent: handleFileGetter,
4404
- noClick: !0,
4405
- // HACK: Disable drag and drop functionality when in a selecting context
4406
- // (This is currently due to Sanity's native image input taking precedence with drag and drop)
4407
- noDrag: !!onSelect,
4408
- onDrop: handleDrop,
4409
- maxSize,
4410
- onDropRejected: handleDropRejected,
4411
- disabled: !directUploads
4412
- });
4413
- return /* @__PURE__ */ jsxRuntime.jsx(DropzoneDispatchProvider, { open, children: /* @__PURE__ */ jsxRuntime.jsxs(UploadContainer, { ...getRootProps(), children: [
4414
- /* @__PURE__ */ jsxRuntime.jsx("input", { ...getInputProps() }),
4415
- isDragActive && /* @__PURE__ */ jsxRuntime.jsx(DragActiveContainer, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { direction: "column", justify: "center", style: {
4416
- color: color.white.hex
4417
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 3, style: {
4418
- color: "inherit"
4419
- }, children: "Drop files to upload" }) }) }),
4420
- children
4421
- ] }) });
4422
- };
4423
- function getMediaTagNames(schemaType) {
4424
- const mediaTags = schemaType?.options?.mediaTags;
4425
- if (!mediaTags?.length) return [];
4426
- const unique = new Set(mediaTags.map((t) => t?.trim()).filter((t) => !!t?.length));
4427
- return Array.from(unique);
4428
- }
4429
- function createAssetHandler(dispatch) {
4430
- return (update) => {
4431
- const {
4432
- documentId,
4433
- result,
4434
- transition
4435
- } = update;
4436
- switch (transition) {
4437
- case "appear":
4438
- dispatch(assetsActions.listenerCreateQueue({
4439
- asset: result
4440
- }));
4441
- break;
4442
- case "disappear":
4443
- dispatch(assetsActions.listenerDeleteQueue({
4444
- assetId: documentId
4445
- }));
4446
- break;
4447
- case "update":
4448
- dispatch(assetsActions.listenerUpdateQueue({
4449
- asset: result
4450
- }));
4451
- break;
4452
- }
4453
- };
4454
- }
4455
- function createTagHandler(dispatch) {
4456
- return (update) => {
4457
- const {
4458
- documentId,
4459
- result,
4460
- transition
4461
- } = update;
4462
- switch (transition) {
4463
- case "appear":
4464
- dispatch(tagsActions.listenerCreateQueue({
4465
- tag: result
4466
- }));
4467
- break;
4468
- case "disappear":
4469
- dispatch(tagsActions.listenerDeleteQueue({
4470
- tagId: documentId
4471
- }));
4472
- break;
4473
- case "update":
4474
- dispatch(tagsActions.listenerUpdateQueue({
4475
- tag: result
4476
- }));
4477
- break;
4478
- }
4479
- };
4480
- }
4481
- function useBrowserInit(client, schemaType) {
4482
- const dispatch = reactRedux.useDispatch(), tagsByIds = reactRedux.useSelector((state) => state.tags.byIds), tagsFetchCount = reactRedux.useSelector((state) => state.tags.fetchCount), tagNames = getMediaTagNames(schemaType), hasMediaTags = tagNames.length > 0;
4483
- react.useEffect(() => {
4484
- hasMediaTags || dispatch(searchActions.facetsClear()), dispatch(tagsActions.fetchRequest());
4485
- const assetSubscription = client.listen(groq__default.default`*[_type in ["sanity.fileAsset", "sanity.imageAsset"] && !(_id in path("drafts.**"))]`).subscribe(createAssetHandler(dispatch)), tagSubscription = client.listen(groq__default.default`*[_type == "${TAG_DOCUMENT_NAME}" && !(_id in path("drafts.**"))]`).subscribe(createTagHandler(dispatch));
4486
- return () => {
4487
- assetSubscription.unsubscribe(), tagSubscription.unsubscribe();
4488
- };
4489
- }, [client, dispatch, hasMediaTags]), react.useEffect(() => {
4490
- if (!hasMediaTags || tagsFetchCount < 0) return;
4491
- const tagFacetInput = inputs.tag;
4492
- if (tagFacetInput.type !== "searchable") return;
4493
- const resolvedTags = tagNames.map((name) => Object.values(tagsByIds).find((item) => item.tag.name.current === name)).filter((item) => !!item);
4494
- dispatch(searchActions.facetsClear());
4495
- for (const tagItem of resolvedTags)
4496
- dispatch(searchActions.facetsAdd({
4497
- facet: {
4498
- ...tagFacetInput,
4499
- operatorType: "references",
4500
- value: {
4501
- label: tagItem.tag.name.current,
4502
- value: tagItem.tag._id
4503
- }
4504
- }
4505
- }));
4506
- }, [tagsFetchCount, hasMediaTags]);
4507
- }
4508
- const BrowserContent = ({
4509
- onClose,
4510
- schemaType
4511
- }) => {
4512
- const client = useVersionedClient(), [portalElement, setPortalElement] = react.useState(null);
4513
- return useBrowserInit(client, schemaType), /* @__PURE__ */ jsxRuntime.jsx(ui.PortalProvider, { element: portalElement, children: /* @__PURE__ */ jsxRuntime.jsxs(UploadDropzone, { children: [
4514
- /* @__PURE__ */ jsxRuntime.jsx(Dialogs, {}),
4515
- /* @__PURE__ */ jsxRuntime.jsx(Notifications, {}),
4516
- /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { display: "flex", height: "fill", ref: setPortalElement, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", flex: 1, children: [
4517
- /* @__PURE__ */ jsxRuntime.jsx(Header, { onClose }),
4518
- /* @__PURE__ */ jsxRuntime.jsx(Controls, {}),
4519
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { flex: 1, children: [
4520
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "flex-end", direction: "column", flex: 1, style: {
4521
- position: "relative"
4522
- }, children: [
4523
- /* @__PURE__ */ jsxRuntime.jsx(PickedBar, {}),
4524
- /* @__PURE__ */ jsxRuntime.jsx(Items, {})
4525
- ] }),
4526
- /* @__PURE__ */ jsxRuntime.jsx(TagsPanel, {})
4527
- ] }),
4528
- /* @__PURE__ */ jsxRuntime.jsx(DebugControls, {})
4529
- ] }) })
4530
- ] }) });
4531
- }, Browser = (props) => {
4532
- const client = useVersionedClient();
4533
- return /* @__PURE__ */ jsxRuntime.jsx(ReduxProvider, { assetType: props?.assetType, client, document: props?.document, selectedAssets: props?.selectedAssets, children: /* @__PURE__ */ jsxRuntime.jsxs(AssetBrowserDispatchProvider, { onSelect: props?.onSelect, children: [
4534
- /* @__PURE__ */ jsxRuntime.jsx(GlobalStyle, {}),
4535
- /* @__PURE__ */ jsxRuntime.jsx(BrowserContent, { onClose: props?.onClose, schemaType: props?.schemaType })
4536
- ] }) });
4537
- }, FormBuilderTool = (props) => {
4538
- const {
4539
- onClose
4540
- } = props, portalElement = useRootPortalElement(), currentDocument = sanity.useFormValue([]);
4541
- useKeyPress("escape", onClose);
4542
- const handleStopPropagation = (event) => {
4543
- event.nativeEvent.stopImmediatePropagation(), event.stopPropagation();
4544
- }, {
4545
- zIndex
4546
- } = ui.useLayer();
4547
- return /* @__PURE__ */ jsxRuntime.jsx(ui.PortalProvider, { element: portalElement, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { onDragEnter: handleStopPropagation, onDragLeave: handleStopPropagation, onDragOver: handleStopPropagation, onDrop: handleStopPropagation, onMouseUp: handleStopPropagation, style: {
4548
- bottom: 0,
4549
- height: "auto",
4550
- left: 0,
4551
- position: "fixed",
4552
- top: 0,
4553
- width: "100%",
4554
- zIndex
4555
- }, children: /* @__PURE__ */ jsxRuntime.jsx(Browser, { document: currentDocument, schemaType: props.schemaType, ...props }) }) }) });
4556
- }, useRootPortalElement = () => {
4557
- const [container] = react.useState(() => document.createElement("div"));
4558
- return react.useEffect(() => (container.classList.add("media-portal"), document.body.appendChild(container), () => {
4559
- document.body.removeChild(container);
4560
- }), [container]), container;
4561
- }, Tool = () => /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { direction: "column", height: "fill", flex: 1, children: /* @__PURE__ */ jsxRuntime.jsx(Browser, {}) });
4562
- var mediaTag = {
4563
- title: "Media Tag",
4564
- icon: TagIcon,
4565
- name: TAG_DOCUMENT_NAME,
4566
- type: "document",
4567
- fields: [{
4568
- title: "Name",
4569
- name: "name",
4570
- type: "slug"
4571
- }],
4572
- preview: {
4573
- select: {
4574
- name: "name"
4575
- },
4576
- prepare(selection) {
4577
- const {
4578
- name
4579
- } = selection;
4580
- return {
4581
- media: TagIcon,
4582
- title: name?.current
4583
- };
4584
- }
4585
- }
4586
- };
4587
- const plugin = {
4588
- icon: icons.ImageIcon,
4589
- name: "media",
4590
- title: "Media"
4591
- }, mediaAssetSource = {
4592
- ...plugin,
4593
- component: FormBuilderTool
4594
- }, tool = {
4595
- ...plugin,
4596
- component: Tool,
4597
- __internalApplicationType: "sanity/media"
4598
- }, media = sanity.definePlugin((options) => ({
4599
- name: "media",
4600
- studio: {
4601
- components: {
4602
- layout: (props) => /* @__PURE__ */ jsxRuntime.jsx(ToolOptionsProvider, { options, children: props.renderDefault(props) })
4603
- }
4604
- },
4605
- form: {
4606
- file: {
4607
- assetSources: (prev) => [...prev, mediaAssetSource]
4608
- },
4609
- image: {
4610
- assetSources: (prev) => [...prev, mediaAssetSource]
4611
- }
4612
- },
4613
- schema: {
4614
- types: [mediaTag]
4615
- },
4616
- tools: (prev) => [...prev, tool]
4617
- })), pendingByAsset = /* @__PURE__ */ new Map();
4618
- function applyMediaTags(options) {
4619
- const {
4620
- assetId
4621
- } = options, chain = (pendingByAsset.get(assetId) ?? Promise.resolve()).then(() => doApplyMediaTags(options)), cleanup = chain.catch(() => {
4622
- }).finally(() => {
4623
- pendingByAsset.get(assetId) === cleanup && pendingByAsset.delete(assetId);
4624
- });
4625
- return pendingByAsset.set(assetId, cleanup), chain;
4626
- }
4627
- async function doApplyMediaTags({
4628
- client,
4629
- assetId,
4630
- mediaTags,
4631
- createTagsOnUpload = !0
4632
- }) {
4633
- if (!mediaTags || mediaTags.length === 0) return;
4634
- const validTags = (await Promise.all(mediaTags.map(async (tagName) => await client.fetch(groq__default.default`*[_type == "${TAG_DOCUMENT_NAME}" && name.current == $tagName][0]`, {
4635
- tagName
4636
- }) || (createTagsOnUpload ? await client.create({
4637
- _type: TAG_DOCUMENT_NAME,
4638
- name: {
4639
- _type: "slug",
4640
- current: tagName
4641
- }
4642
- }) : null)))).filter((tag) => tag !== null);
4643
- if (validTags.length === 0) return;
4644
- const existing = await client.fetch(
4645
- groq__default.default`*[_id == $assetId][0]{'tagIds': opt.media.tags[]._ref}`,
4646
- {
4647
- assetId
4648
- },
4649
- {
4650
- useCdn: !1
4651
- }
4652
- // bypass CDN cache so we see the latest committed tag refs
4653
- ), existingIds = new Set(existing?.tagIds ?? []), tagReferences = validTags.filter((tag) => !existingIds.has(tag._id)).map((tag) => ({
4654
- _key: nanoid.nanoid(),
4655
- _ref: tag._id,
4656
- _type: "reference",
4657
- _weak: !0
4658
- }));
4659
- tagReferences.length !== 0 && await client.patch(assetId).setIfMissing({
4660
- opt: {}
4661
- }).setIfMissing({
4662
- "opt.media": {}
4663
- }).setIfMissing({
4664
- "opt.media.tags": []
4665
- }).append("opt.media.tags", tagReferences).commit();
4666
- }
4667
- function AutoTagInput(props) {
4668
- const {
4669
- renderDefault,
4670
- schemaType,
4671
- value,
4672
- mediaTags: mediaTagsProp
4673
- } = props, toast = ui.useToast(), mediaTags = mediaTagsProp ?? schemaType?.options?.mediaTags, client = useVersionedClient(), {
4674
- createTagsOnUpload
4675
- } = useToolOptions(), prevAssetRef = react.useRef(void 0), isInitialMount = react.useRef(!0), currentAssetRef = value?.asset?._ref;
4676
- return react.useEffect(() => {
4677
- if (isInitialMount.current) {
4678
- isInitialMount.current = !1, prevAssetRef.current = currentAssetRef;
4679
- return;
4680
- }
4681
- const previousRef = prevAssetRef.current;
4682
- prevAssetRef.current = currentAssetRef, !(!mediaTags?.length || !currentAssetRef || currentAssetRef === previousRef) && applyMediaTags({
4683
- client,
4684
- assetId: currentAssetRef,
4685
- mediaTags,
4686
- createTagsOnUpload
4687
- }).catch((err) => {
4688
- console.error("[sanity-plugin-media] Failed to apply auto-tags:", err);
4689
- const label = mediaTags.length === 1 ? "tag" : "tags";
4690
- toast.push({
4691
- closable: !0,
4692
- status: "error",
4693
- title: `Failed to apply the media ${label} ${mediaTags.join(", ")}`
4694
- });
4695
- });
4696
- }, [currentAssetRef, mediaTags, client, createTagsOnUpload, toast]), renderDefault(props);
4697
- }
4698
- function mediaField(config) {
4699
- const {
4700
- mediaTags,
4701
- options,
4702
- components,
4703
- ...rest
4704
- } = config;
4705
- return {
4706
- ...rest,
4707
- options: {
4708
- ...options,
4709
- mediaTags
4710
- },
4711
- components: {
4712
- ...components,
4713
- input: AutoTagInput
4714
- }
4715
- };
4716
- }
4717
- exports.AutoTagInput = AutoTagInput;
4718
- exports.media = media;
4719
- exports.mediaAssetSource = mediaAssetSource;
4720
- exports.mediaField = mediaField;
4721
- //# sourceMappingURL=index.cjs.map