@securancy/file-explorer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +7 -0
  2. package/default-styling.pcss +39 -0
  3. package/dist/components/FileExplorer.svelte +443 -0
  4. package/dist/components/FileExplorer.svelte.d.ts +63 -0
  5. package/dist/components/FileExplorerBreadcrumb.svelte +263 -0
  6. package/dist/components/FileExplorerBreadcrumb.svelte.d.ts +18 -0
  7. package/dist/components/FileExplorerCreateDirectory.svelte +77 -0
  8. package/dist/components/FileExplorerCreateDirectory.svelte.d.ts +24 -0
  9. package/dist/components/FileExplorerDirectoryColumn.svelte +456 -0
  10. package/dist/components/FileExplorerDirectoryColumn.svelte.d.ts +39 -0
  11. package/dist/components/FileExplorerDirectoryIndex.svelte +367 -0
  12. package/dist/components/FileExplorerDirectoryIndex.svelte.d.ts +33 -0
  13. package/dist/components/FileExplorerDisplayModeSwitcher.svelte +300 -0
  14. package/dist/components/FileExplorerDisplayModeSwitcher.svelte.d.ts +19 -0
  15. package/dist/components/FileExplorerFileDetailColumn.svelte +340 -0
  16. package/dist/components/FileExplorerFileDetailColumn.svelte.d.ts +24 -0
  17. package/dist/components/FileIcon.svelte +310 -0
  18. package/dist/components/FileIcon.svelte.d.ts +19 -0
  19. package/dist/file-explorer.pcss +304 -0
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.js +2 -0
  22. package/dist/models/file-explorer-display-mode.d.ts +4 -0
  23. package/dist/models/file-explorer-display-mode.js +5 -0
  24. package/dist/models/file-item.d.ts +23 -0
  25. package/dist/models/file-item.js +1 -0
  26. package/dist/models/index.d.ts +3 -0
  27. package/dist/models/index.js +3 -0
  28. package/dist/models/translations.d.ts +19 -0
  29. package/dist/models/translations.js +17 -0
  30. package/dist/utilities/file-utilities.d.ts +8 -0
  31. package/dist/utilities/file-utilities.js +49 -0
  32. package/dist/utilities/index.d.ts +1 -0
  33. package/dist/utilities/index.js +1 -0
  34. package/dist/validation/file-upload-schema.d.ts +2 -0
  35. package/dist/validation/file-upload-schema.js +2 -0
  36. package/package.json +72 -0
@@ -0,0 +1,367 @@
1
+ <script>import FileIcon from "./FileIcon.svelte";
2
+ import FileExplorerFileDetailColumn from "./FileExplorerFileDetailColumn.svelte";
3
+ import { createEventDispatcher } from "svelte";
4
+ import { resize, ResizeDirections } from "@securancy/svelte-utilities";
5
+ import { Icon, Popover, PopoverItem } from "@securancy/svelte-components";
6
+ import { getExtension, openItem } from "../utilities/index.js";
7
+ const dispatch = createEventDispatcher();
8
+ export let directoryName;
9
+ export let filePath;
10
+ export let fileItems;
11
+ export let currentPath;
12
+ export let routePrefix;
13
+ export let translations;
14
+ export let canEdit;
15
+ export let documents;
16
+ export let getFilePreview;
17
+ let currentFileItem;
18
+ let activeFileItem;
19
+ let filePathSplit;
20
+ let innerWidth = 0;
21
+ $: filePathSplit = filePath.split("/");
22
+ $: currentFileItem = filePathSplit.shift();
23
+ $: activeFileItem = fileItems.find((fi) => fi.name === currentFileItem);
24
+ function addItem() {
25
+ dispatch("upload-file", { path: currentPath });
26
+ }
27
+ function createDirectory() {
28
+ dispatch("create-directory", { path: currentPath });
29
+ }
30
+ </script>
31
+
32
+ <svelte:window bind:innerWidth />
33
+
34
+ {#if !activeFileItem || (activeFileItem && activeFileItem.type !== 'directory')}
35
+ <div
36
+ class="file-explorer__index"
37
+ use:resize={{
38
+ disabled: innerWidth < 1024,
39
+ directions: [ResizeDirections.East],
40
+ parentPadding: true,
41
+ }}
42
+ >
43
+ <div class="file-explorer__index-scroll-container">
44
+ <div class="file-explorer__grid">
45
+ <div class="file-explorer__grid-header">
46
+ <span>
47
+ {directoryName} ({fileItems?.length ?? 0})
48
+ </span>
49
+ {#if canEdit}
50
+ <div class="inline-block">
51
+ <Popover placement="bottom-end" trigger="click">
52
+ <button slot="trigger" type="button">
53
+ <Icon class="fa-solid fa-add" />
54
+ </button>
55
+ <PopoverItem closeOnClick on:click={createDirectory}>{translations.createDirectory}</PopoverItem>
56
+ <PopoverItem closeOnClick on:click={addItem}>{translations.uploadFile}</PopoverItem>
57
+ </Popover>
58
+ </div>
59
+ {/if}
60
+ </div>
61
+ {#each fileItems as item}
62
+ <button
63
+ class="file-explorer__grid-item"
64
+ class:file-explorer__grid-item--active={activeFileItem === item}
65
+ title={translations.itemTitle(item)}
66
+ type="button"
67
+ on:click={() => openItem(item, routePrefix)}
68
+ >
69
+ {#if item.type === 'directory'}
70
+ <Icon
71
+ class="fa-light fa-2xl fa-folder{activeFileItem?.name === item.name ? '-open' : ''}"
72
+ size="custom"
73
+ />
74
+ {:else}
75
+ <FileIcon extension={getExtension(item.name)} size="grid" />
76
+ {/if}
77
+ <span>{item.name}</span>
78
+ </button>
79
+ {:else}
80
+ <p class="file-explorer__message">
81
+ {translations.emptyDirectory}
82
+ </p>
83
+ {/each}
84
+ </div>
85
+ </div>
86
+ </div>
87
+ {/if}
88
+
89
+ <!-- The component repeats itself until the end of the filePath is reached or shows a FileDetail -->
90
+ {#if activeFileItem}
91
+ {#if activeFileItem.type === 'directory'}
92
+ <svelte:self
93
+ {canEdit}
94
+ currentPath={[activeFileItem.path, activeFileItem.name].join('/')}
95
+ directoryName={currentFileItem || ''}
96
+ {documents}
97
+ fileItems={activeFileItem.children || []}
98
+ filePath={filePathSplit.join('/')}
99
+ {getFilePreview}
100
+ {routePrefix}
101
+ {translations}
102
+ />
103
+ {:else}
104
+ <FileExplorerFileDetailColumn
105
+ fileItem={activeFileItem}
106
+ {getFilePreview}
107
+ {translations}
108
+ on:delete-file
109
+ />
110
+ {/if}
111
+ {/if}
112
+
113
+ <style>/* eslint-disable */
114
+ /**
115
+ * Media queries and devices
116
+ */
117
+ /**
118
+ * Some mixins that can be used dynamically inside @each loops
119
+ */
120
+ .file-explorer {
121
+ position: relative;
122
+ display: flex;
123
+ flex-direction: column;
124
+ height: 100%;
125
+ width: 100%;
126
+ background: var(--file-explorer-background);
127
+ overflow: hidden;
128
+ }
129
+ .file-explorer__controls {
130
+ flex-shrink: 0;
131
+ display: flex;
132
+ border-bottom: var(--file-explorer-border-style);
133
+ padding: var(--file-explorer-default-spacing);
134
+ background: var(--file-explorer-background-shade);
135
+ }
136
+ .file-explorer__content {
137
+ flex-grow: 1;
138
+ display: flex;
139
+ overflow-x: auto;
140
+ scroll-behavior: smooth;
141
+ }
142
+ /* Keep the index within screen */
143
+ @media (width >= 769px) {
144
+ /* @formatter:off */
145
+ .file-explorer--display-mode-index .file-explorer__content {
146
+ /* @formatter:on */
147
+ overflow-x: inherit;
148
+ }
149
+ }
150
+ .file-explorer__column, .file-explorer__index {
151
+ flex-shrink: 0;
152
+ border-right: var(--file-explorer-border-style);
153
+ background: var(--file-explorer-background);
154
+ }
155
+ .file-explorer__column {
156
+ display: flex;
157
+ flex-direction: column;
158
+ width: var(--file-explorer-column-default-width);
159
+ min-width: var(--file-explorer-column-min-width);
160
+ overflow: hidden;
161
+ }
162
+ .file-explorer__column--file-detail {
163
+ flex-grow: 1;
164
+ width: var(--file-explorer-preview-default-width);
165
+ display: flex;
166
+ flex-direction: column;
167
+ }
168
+ .file-explorer__column--sticky {
169
+ position: sticky;
170
+ left: 0;
171
+ z-index: 1;
172
+ }
173
+ .file-explorer__column::after {
174
+ content: '';
175
+ position: absolute;
176
+ inset: 0;
177
+ pointer-events: none;
178
+ transition: background-color 0.2s ease-in-out;
179
+ }
180
+ .file-explorer__column--dragover {
181
+ cursor: copy;
182
+ }
183
+ .file-explorer__column--dragover::after {
184
+ pointer-events: all;
185
+ background-color: var(--file-explorer-background-dragover);
186
+ }
187
+ .file-explorer__index {
188
+ display: flex;
189
+ flex-direction: column;
190
+ width: var(--file-explorer-index-default-width);
191
+ overflow: hidden;
192
+ }
193
+ @media (width >= 769px) {
194
+ .file-explorer__index {
195
+ flex-shrink: 1
196
+ }
197
+ }
198
+ .file-explorer__index--hidden {
199
+ display: none;
200
+ }
201
+ .file-explorer__column-scroll-container, .file-explorer__index-scroll-container {
202
+ flex-grow: 1;
203
+ overflow-y: auto;
204
+ padding: calc(var(--file-explorer-default-spacing) * 1.5) var(--file-explorer-default-spacing) 0 var(--file-explorer-default-spacing);
205
+ }
206
+ .file-explorer__grid {
207
+ display: flex;
208
+ align-items: flex-start;
209
+ flex-wrap: wrap;
210
+ gap: var(--file-explorer-default-spacing);
211
+ }
212
+ .file-explorer__breadcrumb {
213
+ /* @todo */
214
+ }
215
+ .file-explorer__display-mode-switcher {
216
+ display: flex;
217
+ gap: calc(0.5 * var(--file-explorer-default-spacing));
218
+ margin-left: auto;
219
+ }
220
+ .file-explorer__search {
221
+ margin-bottom: var(--file-explorer-default-spacing);
222
+ padding: calc(var(--file-explorer-default-spacing) * 1.5) var(--file-explorer-default-spacing) 0 var(--file-explorer-default-spacing);
223
+ }
224
+ .file-explorer__list {
225
+ margin-bottom: var(--file-explorer-default-spacing);
226
+ }
227
+ .file-explorer__list-header {
228
+ display: flex;
229
+ justify-content: space-between;
230
+ gap: calc(0.5 * var(--file-explorer-default-spacing));
231
+ width: 100%;
232
+ margin-bottom: calc(0.5 * var(--file-explorer-default-spacing));
233
+ color: var(--file-explorer-list-header-color);
234
+ }
235
+ .file-explorer__list-header span {
236
+ overflow: hidden;
237
+ white-space: nowrap;
238
+ text-overflow: ellipsis;
239
+ }
240
+ .file-explorer__list-header button {
241
+ flex-shrink: 0;
242
+ color: var(--file-explorer-action-primary-color);
243
+ cursor: pointer;
244
+ }
245
+ .file-explorer__grid-header {
246
+ width: 100%;
247
+ }
248
+ .file-explorer__grid-header button {
249
+ color: var(--file-explorer-action-primary-color);
250
+ cursor: pointer;
251
+ }
252
+ .file-explorer__list-item, .file-explorer__grid-item {
253
+ border-radius: var(--file-explorer-list-item-border-radius);
254
+ background: none;
255
+ color: var(--file-explorer-list-item-color);
256
+ }
257
+ .file-explorer__list-item > :global(i), .file-explorer__grid-item > :global(i) {
258
+ flex-shrink: 0;
259
+ }
260
+ .file-explorer__list-item:not(.file-explorer__list-item--active):hover, .file-explorer__grid-item:not(.file-explorer__grid-item--active):hover {
261
+ background: var(--file-explorer-list-item-background-hover);
262
+ }
263
+ .file-explorer__list-item--active, .file-explorer__grid-item--active {
264
+ color: var(--file-explorer-list-item-color-active);
265
+ background: var(--file-explorer-list-item-background-active);
266
+ }
267
+ .file-explorer__grid-item {
268
+ display: flex;
269
+ flex-direction: column;
270
+ align-items: center;
271
+
272
+ /* 3 items in a grid, spaced out with default spacing means the width of 2 gaps must be subtracted from width */
273
+ width: calc(33.33% - (0.6666 * var(--file-explorer-default-spacing)));
274
+ padding: 5px 2px;
275
+ }
276
+ @media (width >= 769px) {
277
+ .file-explorer__grid-item {
278
+ width: 100px
279
+ }
280
+ }
281
+ .file-explorer__grid-item--active {
282
+ /* @todo */
283
+ }
284
+ .file-explorer__grid-item > span {
285
+ word-break: break-word;
286
+ margin-top: calc(0.25 * var(--file-explorer-default-spacing));
287
+ }
288
+ .file-explorer__list-item {
289
+ display: flex;
290
+ align-items: baseline;
291
+ width: 100%;
292
+ text-align: left;
293
+ padding: var(--file-explorer-list-item-spacing);
294
+ white-space: nowrap;
295
+ overflow: hidden;
296
+ text-overflow: ellipsis;
297
+ }
298
+ .file-explorer__list-item > span {
299
+ flex-grow: 1;
300
+ min-width: 0;
301
+ overflow: hidden;
302
+ text-overflow: ellipsis;
303
+ }
304
+ .file-explorer__list-item > :global(i:first-child) {
305
+ margin-right: var(--file-explorer-list-item-spacing);
306
+ }
307
+ .file-explorer__list-item > :global(i:last-child) {
308
+ margin-left: var(--file-explorer-list-item-spacing);
309
+ }
310
+ .file-explorer__message {
311
+ display: block;
312
+ padding: var(--file-explorer-list-item-spacing) 0;
313
+ color: var(--file-explorer-message-color);
314
+ }
315
+ .file-explorer__image-preview {
316
+ max-width: 100%;
317
+ margin: 0 auto;
318
+ }
319
+ .file-explorer-preview__title {
320
+ font-size: var(--font-size--h1);
321
+ font-weight: var(--font-weight--semi-bold);
322
+ overflow: hidden;
323
+ text-overflow: ellipsis;
324
+ white-space: nowrap;
325
+ }
326
+ .file-explorer-preview__download {
327
+ color: var(--file-explorer-action-primary-color);
328
+ font-weight: var(--font-weight--semi-bold);
329
+ }
330
+ .file-explorer-preview__download:hover {
331
+ text-decoration-line: underline;
332
+ }
333
+ .file-explorer-preview__info {
334
+ margin-top: 14px;
335
+ }
336
+ .file-explorer-preview__info span {
337
+ color: var(--file-explorer-message-color);
338
+ }
339
+ .file-explorer-preview__info button {
340
+ cursor: pointer;
341
+ }
342
+ .file-explorer__scroll-back-button {
343
+ position: fixed;
344
+ bottom: var(--file-explorer-default-spacing);
345
+ right: var(--file-explorer-default-spacing);
346
+ z-index: 2;
347
+ background: var(--file-explorer-action-primary-color);
348
+ color: var(--file-explorer-action-primary-color-contrast);
349
+ padding: var(--file-explorer-list-item-spacing);
350
+ border-radius: var(--file-explorer-list-item-border-radius);
351
+ }
352
+ .file-explorer__file-icon--large {
353
+ width: 100%;
354
+ text-align: center;
355
+ padding: calc(2 * var(--file-explorer-default-spacing));
356
+ }
357
+ .file-explorer__file-icon--large :global(i) {
358
+ font-size: var(--file-explorer-preview-icon-size);
359
+ }
360
+ .file-explorer__text--semi-bold {
361
+ font-weight: var(--file-explorer-text-semi-bold);
362
+ }
363
+ .file-explorer__loader {
364
+ display: flex;
365
+ justify-content: center;
366
+ }
367
+ </style>
@@ -0,0 +1,33 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { DocumentTranslations, FileItem, FilePreview, FileSystemItem } from '../index.js';
3
+ import type { Refreshable } from '@securancy/svelte-utilities';
4
+ import type { CreateDirectoryEvent, UploadFileEvent } from './FileExplorer.svelte';
5
+ declare const __propDef: {
6
+ props: {
7
+ directoryName: string;
8
+ filePath: string;
9
+ fileItems: FileSystemItem[];
10
+ currentPath: string;
11
+ routePrefix: string;
12
+ translations: DocumentTranslations;
13
+ canEdit: boolean;
14
+ documents: Refreshable<FileSystemItem[]>;
15
+ getFilePreview: (fileItem: FileItem) => Promise<FilePreview>;
16
+ };
17
+ events: {
18
+ 'delete-file': CustomEvent<import("./FileExplorer.svelte").DeleteFileEvent>;
19
+ 'upload-file': CustomEvent<UploadFileEvent>;
20
+ 'create-directory': CustomEvent<CreateDirectoryEvent>;
21
+ } & {
22
+ [evt: string]: CustomEvent<any>;
23
+ };
24
+ slots: {};
25
+ exports?: {} | undefined;
26
+ bindings?: string | undefined;
27
+ };
28
+ export type FileExplorerDirectoryIndexProps = typeof __propDef.props;
29
+ export type FileExplorerDirectoryIndexEvents = typeof __propDef.events;
30
+ export type FileExplorerDirectoryIndexSlots = typeof __propDef.slots;
31
+ export default class FileExplorerDirectoryIndex extends SvelteComponent<FileExplorerDirectoryIndexProps, FileExplorerDirectoryIndexEvents, FileExplorerDirectoryIndexSlots> {
32
+ }
33
+ export {};
@@ -0,0 +1,300 @@
1
+ <script>import { FileExplorerDisplayMode } from "../index.js";
2
+ import { Icon } from "@securancy/svelte-components";
3
+ export let displayMode;
4
+ let modes = Object.values(FileExplorerDisplayMode);
5
+ const modeLabels = {
6
+ columns: "Columns",
7
+ index: "Full directory"
8
+ };
9
+ const modeIcons = {
10
+ columns: "fa-columns-3",
11
+ index: "fa-grid"
12
+ };
13
+ </script>
14
+
15
+ <div class="file-explorer__display-mode-switcher">
16
+ {#each modes as mode}
17
+ <label
18
+ aria-label={modeLabels[mode]}
19
+ title="Switch display mode to '{modeLabels[mode].toLowerCase()}'"
20
+ >
21
+ <input
22
+ name="displayMode"
23
+ type="radio"
24
+ value={mode}
25
+ bind:group={displayMode}>
26
+ <Icon class="fa-light {modeIcons[mode]}" />
27
+ </label>
28
+ {/each}
29
+ </div>
30
+
31
+ <style>/* eslint-disable */
32
+ /**
33
+ * Media queries and devices
34
+ */
35
+ /**
36
+ * Some mixins that can be used dynamically inside @each loops
37
+ */
38
+ .file-explorer {
39
+ position: relative;
40
+ display: flex;
41
+ flex-direction: column;
42
+ height: 100%;
43
+ width: 100%;
44
+ background: var(--file-explorer-background);
45
+ overflow: hidden;
46
+ }
47
+ .file-explorer__controls {
48
+ flex-shrink: 0;
49
+ display: flex;
50
+ border-bottom: var(--file-explorer-border-style);
51
+ padding: var(--file-explorer-default-spacing);
52
+ background: var(--file-explorer-background-shade);
53
+ }
54
+ .file-explorer__content {
55
+ flex-grow: 1;
56
+ display: flex;
57
+ overflow-x: auto;
58
+ scroll-behavior: smooth;
59
+ }
60
+ /* Keep the index within screen */
61
+ @media (width >= 769px) {
62
+ /* @formatter:off */
63
+ .file-explorer--display-mode-index .file-explorer__content {
64
+ /* @formatter:on */
65
+ overflow-x: inherit;
66
+ }
67
+ }
68
+ .file-explorer__column, .file-explorer__index {
69
+ flex-shrink: 0;
70
+ border-right: var(--file-explorer-border-style);
71
+ background: var(--file-explorer-background);
72
+ }
73
+ .file-explorer__column {
74
+ display: flex;
75
+ flex-direction: column;
76
+ width: var(--file-explorer-column-default-width);
77
+ min-width: var(--file-explorer-column-min-width);
78
+ overflow: hidden;
79
+ }
80
+ .file-explorer__column--file-detail {
81
+ flex-grow: 1;
82
+ width: var(--file-explorer-preview-default-width);
83
+ display: flex;
84
+ flex-direction: column;
85
+ }
86
+ .file-explorer__column--sticky {
87
+ position: sticky;
88
+ left: 0;
89
+ z-index: 1;
90
+ }
91
+ .file-explorer__column::after {
92
+ content: '';
93
+ position: absolute;
94
+ inset: 0;
95
+ pointer-events: none;
96
+ transition: background-color 0.2s ease-in-out;
97
+ }
98
+ .file-explorer__column--dragover {
99
+ cursor: copy;
100
+ }
101
+ .file-explorer__column--dragover::after {
102
+ pointer-events: all;
103
+ background-color: var(--file-explorer-background-dragover);
104
+ }
105
+ .file-explorer__index {
106
+ display: flex;
107
+ flex-direction: column;
108
+ width: var(--file-explorer-index-default-width);
109
+ overflow: hidden;
110
+ }
111
+ @media (width >= 769px) {
112
+ .file-explorer__index {
113
+ flex-shrink: 1
114
+ }
115
+ }
116
+ .file-explorer__index--hidden {
117
+ display: none;
118
+ }
119
+ .file-explorer__column-scroll-container, .file-explorer__index-scroll-container {
120
+ flex-grow: 1;
121
+ overflow-y: auto;
122
+ padding: calc(var(--file-explorer-default-spacing) * 1.5) var(--file-explorer-default-spacing) 0 var(--file-explorer-default-spacing);
123
+ }
124
+ .file-explorer__grid {
125
+ display: flex;
126
+ align-items: flex-start;
127
+ flex-wrap: wrap;
128
+ gap: var(--file-explorer-default-spacing);
129
+ }
130
+ .file-explorer__breadcrumb {
131
+ /* @todo */
132
+ }
133
+ .file-explorer__display-mode-switcher {
134
+ display: flex;
135
+ gap: calc(0.5 * var(--file-explorer-default-spacing));
136
+ margin-left: auto;
137
+ }
138
+ .file-explorer__search {
139
+ margin-bottom: var(--file-explorer-default-spacing);
140
+ padding: calc(var(--file-explorer-default-spacing) * 1.5) var(--file-explorer-default-spacing) 0 var(--file-explorer-default-spacing);
141
+ }
142
+ .file-explorer__list {
143
+ margin-bottom: var(--file-explorer-default-spacing);
144
+ }
145
+ .file-explorer__list-header {
146
+ display: flex;
147
+ justify-content: space-between;
148
+ gap: calc(0.5 * var(--file-explorer-default-spacing));
149
+ width: 100%;
150
+ margin-bottom: calc(0.5 * var(--file-explorer-default-spacing));
151
+ color: var(--file-explorer-list-header-color);
152
+ }
153
+ .file-explorer__list-header span {
154
+ overflow: hidden;
155
+ white-space: nowrap;
156
+ text-overflow: ellipsis;
157
+ }
158
+ .file-explorer__list-header button {
159
+ flex-shrink: 0;
160
+ color: var(--file-explorer-action-primary-color);
161
+ cursor: pointer;
162
+ }
163
+ .file-explorer__grid-header {
164
+ width: 100%;
165
+ }
166
+ .file-explorer__grid-header button {
167
+ color: var(--file-explorer-action-primary-color);
168
+ cursor: pointer;
169
+ }
170
+ .file-explorer__list-item, .file-explorer__grid-item {
171
+ border-radius: var(--file-explorer-list-item-border-radius);
172
+ background: none;
173
+ color: var(--file-explorer-list-item-color);
174
+ }
175
+ .file-explorer__list-item > :global(i), .file-explorer__grid-item > :global(i) {
176
+ flex-shrink: 0;
177
+ }
178
+ .file-explorer__list-item:not(.file-explorer__list-item--active):hover, .file-explorer__grid-item:not(.file-explorer__grid-item--active):hover {
179
+ background: var(--file-explorer-list-item-background-hover);
180
+ }
181
+ .file-explorer__list-item--active, .file-explorer__grid-item--active {
182
+ color: var(--file-explorer-list-item-color-active);
183
+ background: var(--file-explorer-list-item-background-active);
184
+ }
185
+ .file-explorer__grid-item {
186
+ display: flex;
187
+ flex-direction: column;
188
+ align-items: center;
189
+
190
+ /* 3 items in a grid, spaced out with default spacing means the width of 2 gaps must be subtracted from width */
191
+ width: calc(33.33% - (0.6666 * var(--file-explorer-default-spacing)));
192
+ padding: 5px 2px;
193
+ }
194
+ @media (width >= 769px) {
195
+ .file-explorer__grid-item {
196
+ width: 100px
197
+ }
198
+ }
199
+ .file-explorer__grid-item--active {
200
+ /* @todo */
201
+ }
202
+ .file-explorer__grid-item > span {
203
+ word-break: break-word;
204
+ margin-top: calc(0.25 * var(--file-explorer-default-spacing));
205
+ }
206
+ .file-explorer__list-item {
207
+ display: flex;
208
+ align-items: baseline;
209
+ width: 100%;
210
+ text-align: left;
211
+ padding: var(--file-explorer-list-item-spacing);
212
+ white-space: nowrap;
213
+ overflow: hidden;
214
+ text-overflow: ellipsis;
215
+ }
216
+ .file-explorer__list-item > span {
217
+ flex-grow: 1;
218
+ min-width: 0;
219
+ overflow: hidden;
220
+ text-overflow: ellipsis;
221
+ }
222
+ .file-explorer__list-item > :global(i:first-child) {
223
+ margin-right: var(--file-explorer-list-item-spacing);
224
+ }
225
+ .file-explorer__list-item > :global(i:last-child) {
226
+ margin-left: var(--file-explorer-list-item-spacing);
227
+ }
228
+ .file-explorer__message {
229
+ display: block;
230
+ padding: var(--file-explorer-list-item-spacing) 0;
231
+ color: var(--file-explorer-message-color);
232
+ }
233
+ .file-explorer__image-preview {
234
+ max-width: 100%;
235
+ margin: 0 auto;
236
+ }
237
+ .file-explorer-preview__title {
238
+ font-size: var(--font-size--h1);
239
+ font-weight: var(--font-weight--semi-bold);
240
+ overflow: hidden;
241
+ text-overflow: ellipsis;
242
+ white-space: nowrap;
243
+ }
244
+ .file-explorer-preview__download {
245
+ color: var(--file-explorer-action-primary-color);
246
+ font-weight: var(--font-weight--semi-bold);
247
+ }
248
+ .file-explorer-preview__download:hover {
249
+ text-decoration-line: underline;
250
+ }
251
+ .file-explorer-preview__info {
252
+ margin-top: 14px;
253
+ }
254
+ .file-explorer-preview__info span {
255
+ color: var(--file-explorer-message-color);
256
+ }
257
+ .file-explorer-preview__info button {
258
+ cursor: pointer;
259
+ }
260
+ .file-explorer__scroll-back-button {
261
+ position: fixed;
262
+ bottom: var(--file-explorer-default-spacing);
263
+ right: var(--file-explorer-default-spacing);
264
+ z-index: 2;
265
+ background: var(--file-explorer-action-primary-color);
266
+ color: var(--file-explorer-action-primary-color-contrast);
267
+ padding: var(--file-explorer-list-item-spacing);
268
+ border-radius: var(--file-explorer-list-item-border-radius);
269
+ }
270
+ .file-explorer__file-icon--large {
271
+ width: 100%;
272
+ text-align: center;
273
+ padding: calc(2 * var(--file-explorer-default-spacing));
274
+ }
275
+ .file-explorer__file-icon--large :global(i) {
276
+ font-size: var(--file-explorer-preview-icon-size);
277
+ }
278
+ .file-explorer__text--semi-bold {
279
+ font-weight: var(--file-explorer-text-semi-bold);
280
+ }
281
+ .file-explorer__loader {
282
+ display: flex;
283
+ justify-content: center;
284
+ }
285
+ label {
286
+ position: relative;
287
+ cursor: pointer;
288
+ }
289
+ input[type="radio"] {
290
+ position: absolute;
291
+ opacity: 0;
292
+ width: 1em;
293
+ height: 1em;
294
+ top: 0;
295
+ left: 0;
296
+ }
297
+ input[type="radio"]:checked + :global(i) {
298
+ color: var(--file-explorer-action-primary-color);
299
+ }
300
+ </style>