@conduction/nextcloud-vue 2.96.0 → 2.97.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.
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +33 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +383 -359
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +17 -3
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +61 -43
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +159 -18
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +9 -7
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +48 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +46 -12
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +144 -0
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +488 -399
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +8 -2
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +301 -18
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +29 -7
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +2 -2
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +2 -2
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useNamedSource.js +1 -1
- package/dist/esm/components/CnIndexPage/useNamedSource.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +13 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +5 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +182 -3
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/l10n/en.json.js +7 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +7 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +301 -177
- package/dist/esm/utils/queryPresets.js +13 -2
- package/dist/esm/utils/queryPresets.js.map +1 -1
- package/dist/esm/utils/scopeListLayout.js +37 -1
- package/dist/esm/utils/scopeListLayout.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +3009 -1907
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +301 -177
- package/l10n/en.json +7 -1
- package/l10n/nl.json +7 -1
- package/package.json +1 -1
- package/src/components/CnCellRenderer/CnCellRenderer.vue +57 -1
- package/src/components/CnConversationThread/CnConversationThread.md +12 -0
- package/src/components/CnConversationThread/CnConversationThread.vue +30 -4
- package/src/components/CnConversationThread/CnConversationWidget.vue +167 -24
- package/src/components/CnFactsWidget/CnFactsWidget.vue +114 -3
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +508 -236
- package/src/components/CnFilesBrowser/filesBrowserColumns.js +8 -2
- package/src/components/CnIndexPage/CnIndexPage.vue +324 -24
- package/src/components/CnIndexPage/CnIndexPageWidgets.vue +13 -4
- package/src/components/CnIndexPage/useNamedSource.js +1 -1
- package/src/components/CnObjectSidebar/CnFilesTab.vue +17 -0
- package/src/composables/indexSources.js +182 -3
- package/src/schemas/app-manifest-v2.schema.json +11 -4
- package/src/utils/queryPresets.js +13 -2
- package/src/utils/scopeListLayout.js +37 -1
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -183,8 +183,8 @@
|
|
|
183
183
|
role="toolbar"
|
|
184
184
|
:aria-label="t('nextcloud-vue', 'Actions for the selected files')"
|
|
185
185
|
data-testid="cn-files-browser-bulk-bar">
|
|
186
|
-
<span class="cn-files-browser__bulk-count" aria-live="polite">
|
|
187
|
-
{{
|
|
186
|
+
<span class="cn-files-browser__bulk-count" aria-live="polite" data-testid="cn-files-browser-bulk-count">
|
|
187
|
+
{{ selectionCountText }}
|
|
188
188
|
</span>
|
|
189
189
|
<NcButton v-for="action in bulkActions"
|
|
190
190
|
:key="action.id"
|
|
@@ -195,7 +195,8 @@
|
|
|
195
195
|
</template>
|
|
196
196
|
{{ hostLabel(action) }}
|
|
197
197
|
</NcButton>
|
|
198
|
-
<NcButton
|
|
198
|
+
<NcButton v-if="showClearSelection"
|
|
199
|
+
variant="tertiary"
|
|
199
200
|
data-testid="cn-files-browser-bulk-clear"
|
|
200
201
|
@click="clearSelection">
|
|
201
202
|
{{ t('nextcloud-vue', 'Clear selection') }}
|
|
@@ -233,269 +234,313 @@
|
|
|
233
234
|
this page, offered under the same names and icons the Files app
|
|
234
235
|
uses. What cannot run away from the Files page (the details
|
|
235
236
|
sidebar) is left out, and Show in Files covers it. -->
|
|
236
|
-
<
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
<tbody>
|
|
275
|
-
<!-- A heading row per group when the host groups on a column; the
|
|
276
|
-
destructured entry is either a group or a node. -->
|
|
277
|
-
<template v-for="{ key, group, node } in displayRows" :key="key">
|
|
278
|
-
<tr v-if="group"
|
|
279
|
-
class="cn-files-browser__group"
|
|
280
|
-
data-testid="cn-files-browser-group">
|
|
281
|
-
<th :colspan="columnCount" scope="rowgroup" class="cn-files-browser__group-heading">
|
|
282
|
-
{{ group.label }}
|
|
283
|
-
<span class="cn-files-browser__group-count">{{ group.count }}</span>
|
|
237
|
+
<div v-else
|
|
238
|
+
class="cn-files-browser__body"
|
|
239
|
+
:class="{ 'cn-files-browser__body--with-side': sideNode !== null }">
|
|
240
|
+
<table class="cn-files-browser__table" data-testid="cn-files-browser-table">
|
|
241
|
+
<thead>
|
|
242
|
+
<tr>
|
|
243
|
+
<th v-if="bulkEnabled" class="cn-files-browser__col-select" scope="col">
|
|
244
|
+
<input type="checkbox"
|
|
245
|
+
class="cn-files-browser__select"
|
|
246
|
+
:checked="allSelected"
|
|
247
|
+
:indeterminate.prop="someSelected && !allSelected"
|
|
248
|
+
:disabled="selectableIds.length === 0"
|
|
249
|
+
:aria-label="t('nextcloud-vue', 'Select all files')"
|
|
250
|
+
data-testid="cn-files-browser-select-all"
|
|
251
|
+
@change="toggleAll($event.target.checked)">
|
|
252
|
+
</th>
|
|
253
|
+
<th class="cn-files-browser__col-icon" scope="col">
|
|
254
|
+
<span class="hidden-visually">{{ t('nextcloud-vue', 'Type') }}</span>
|
|
255
|
+
</th>
|
|
256
|
+
<th v-for="column in renderedColumns"
|
|
257
|
+
:key="column.key"
|
|
258
|
+
scope="col"
|
|
259
|
+
:class="`cn-files-browser__col-${column.key}`"
|
|
260
|
+
:aria-sort="ariaSort(sortTokenOf(column))"
|
|
261
|
+
:data-testid="`cn-files-browser-header-${column.key}`">
|
|
262
|
+
<button v-if="column.sortable !== false"
|
|
263
|
+
type="button"
|
|
264
|
+
class="cn-files-browser__sort"
|
|
265
|
+
@click="sortBy(sortTokenOf(column))">
|
|
266
|
+
{{ columnLabel(column) }}
|
|
267
|
+
<component :is="sortIcon(sortTokenOf(column))" v-if="sortKey === sortTokenOf(column)" :size="16" />
|
|
268
|
+
</button>
|
|
269
|
+
<template v-else>
|
|
270
|
+
{{ columnLabel(column) }}
|
|
271
|
+
</template>
|
|
272
|
+
</th>
|
|
273
|
+
<th class="cn-files-browser__col-actions" scope="col">
|
|
274
|
+
<span class="hidden-visually">{{ t('nextcloud-vue', 'Actions') }}</span>
|
|
284
275
|
</th>
|
|
285
276
|
</tr>
|
|
277
|
+
</thead>
|
|
278
|
+
<tbody>
|
|
279
|
+
<!-- A heading row per group when the host groups on a column; the
|
|
280
|
+
destructured entry is either a group or a node. -->
|
|
281
|
+
<template v-for="{ key, group, node } in displayRows" :key="key">
|
|
282
|
+
<tr v-if="group"
|
|
283
|
+
class="cn-files-browser__group"
|
|
284
|
+
data-testid="cn-files-browser-group">
|
|
285
|
+
<th :colspan="columnCount" scope="rowgroup" class="cn-files-browser__group-heading">
|
|
286
|
+
{{ group.label }}
|
|
287
|
+
<span class="cn-files-browser__group-count">{{ group.count }}</span>
|
|
288
|
+
</th>
|
|
289
|
+
</tr>
|
|
290
|
+
<tr
|
|
291
|
+
v-else
|
|
292
|
+
:key="key"
|
|
293
|
+
class="cn-files-browser__row"
|
|
294
|
+
:class="{ 'cn-files-browser__row--folder': isFolder(node) }"
|
|
295
|
+
data-testid="cn-files-browser-row"
|
|
296
|
+
:data-name="node.basename"
|
|
297
|
+
@click="onRowClick(node, $event)"
|
|
298
|
+
@mousedown="preventMiddleClickAutoscroll"
|
|
299
|
+
@auxclick="onRowAuxClick(node, $event)">
|
|
300
|
+
<td v-if="bulkEnabled"
|
|
301
|
+
class="cn-files-browser__col-select"
|
|
302
|
+
@click.stop
|
|
303
|
+
@auxclick.stop>
|
|
304
|
+
<input v-if="!isFolder(node)"
|
|
305
|
+
type="checkbox"
|
|
306
|
+
class="cn-files-browser__select"
|
|
307
|
+
:checked="isSelected(node)"
|
|
308
|
+
:aria-label="t('nextcloud-vue', 'Select {name}', { name: node.basename })"
|
|
309
|
+
data-testid="cn-files-browser-select"
|
|
310
|
+
@change="toggleSelected(node, $event.target.checked)">
|
|
311
|
+
</td>
|
|
312
|
+
<td class="cn-files-browser__col-icon">
|
|
313
|
+
<img
|
|
314
|
+
v-if="previewUrlFor(node)"
|
|
315
|
+
class="cn-files-browser__thumb"
|
|
316
|
+
:src="previewUrlFor(node)"
|
|
317
|
+
alt=""
|
|
318
|
+
loading="lazy"
|
|
319
|
+
@error="onPreviewError(node)">
|
|
320
|
+
<img
|
|
321
|
+
v-else-if="mimeIconFor(node)"
|
|
322
|
+
class="cn-files-browser__mime"
|
|
323
|
+
:src="mimeIconFor(node)"
|
|
324
|
+
alt="">
|
|
325
|
+
<FolderOutline v-else-if="isFolder(node)" :size="32" />
|
|
326
|
+
<FileOutline v-else :size="32" />
|
|
327
|
+
</td>
|
|
328
|
+
<td v-for="column in renderedColumns"
|
|
329
|
+
:key="column.key"
|
|
330
|
+
:class="`cn-files-browser__col-${column.key}`"
|
|
331
|
+
:data-testid="`cn-files-browser-cell-${column.key}`">
|
|
332
|
+
<span v-if="column.key === 'name'" class="cn-files-browser__name">{{ node.basename }}</span>
|
|
333
|
+
<template v-else-if="column.key === 'size'">
|
|
334
|
+
{{ isFolder(node) ? '' : formatSize(node.size) }}
|
|
335
|
+
</template>
|
|
336
|
+
<NcDateTime v-else-if="column.key === 'modified'" :timestamp="node.mtime" :ignoreSeconds="true" />
|
|
337
|
+
<!-- Everything the host declared renders through the same
|
|
338
|
+
cell renderer the tables use, so a `formatter` means
|
|
339
|
+
here what it means there. -->
|
|
340
|
+
<CnCellRenderer v-else
|
|
341
|
+
:class="column.widget !== 'badge' && toneOf(column, node) ? `cn-files-browser__tone cn-files-browser__tone--${toneOf(column, node)}` : null"
|
|
342
|
+
:value="cellValue(column, node)"
|
|
343
|
+
:formatter="column.formatter || null"
|
|
344
|
+
:formatterOptions="column.formatterOptions || null"
|
|
345
|
+
:widget="column.widget || null"
|
|
346
|
+
:widgetProps="cellWidgetProps(column, node)"
|
|
347
|
+
:row="node" />
|
|
348
|
+
</td>
|
|
349
|
+
<td class="cn-files-browser__col-actions" @click.stop @auxclick.stop>
|
|
350
|
+
<NcActions :forceMenu="true" :ariaLabel="t('nextcloud-vue', 'Actions for {name}', { name: node.basename })">
|
|
351
|
+
<NcActionButton
|
|
352
|
+
v-for="action in actionsFor(node)"
|
|
353
|
+
:key="action.id"
|
|
354
|
+
:closeAfterClick="true"
|
|
355
|
+
:data-testid="`cn-files-browser-action-${action.id}`"
|
|
356
|
+
@click="run(action, node)">
|
|
357
|
+
<template #icon>
|
|
358
|
+
<NcIconSvgWrapper :svg="iconOf(action, node)" />
|
|
359
|
+
</template>
|
|
360
|
+
{{ labelOf(action, node) }}
|
|
361
|
+
</NcActionButton>
|
|
362
|
+
<!-- The host's own actions on a file (never on a folder): declared
|
|
363
|
+
in its manifest, dispatched through the page's action runner
|
|
364
|
+
with the node's file id, name and path merged in. -->
|
|
365
|
+
<template v-if="!isFolder(node)">
|
|
366
|
+
<NcActionButton
|
|
367
|
+
v-for="action in hostActionsFor(node)"
|
|
368
|
+
:key="`host-${action.id}`"
|
|
369
|
+
:closeAfterClick="true"
|
|
370
|
+
:data-testid="`cn-files-browser-host-action-${action.id}`"
|
|
371
|
+
@click="runHostAction(action, node)">
|
|
372
|
+
<template #icon>
|
|
373
|
+
<CnIcon :name="action.icon || 'FileDocumentEditOutline'" :size="20" />
|
|
374
|
+
</template>
|
|
375
|
+
{{ hostLabel(action) }}
|
|
376
|
+
</NcActionButton>
|
|
377
|
+
</template>
|
|
378
|
+
<NcActionSeparator v-if="actionsFor(node).length > 0 || (!isFolder(node) && hostActionsFor(node).length > 0)" />
|
|
379
|
+
<!-- The Files app's own rename is its list's inline input,
|
|
380
|
+
which is not here; this one is a dialog over a DAV move. -->
|
|
381
|
+
<!-- With a `source`, the Files app's actions (which act over
|
|
382
|
+
WebDAV) are not offered; download and delete go through
|
|
383
|
+
the source instead. -->
|
|
384
|
+
<NcActionLink
|
|
385
|
+
v-if="source && sourceDownloadUrl(node)"
|
|
386
|
+
:href="sourceDownloadUrl(node)"
|
|
387
|
+
:download="node.basename"
|
|
388
|
+
:closeAfterClick="true"
|
|
389
|
+
data-testid="cn-files-browser-action-download">
|
|
390
|
+
<template #icon>
|
|
391
|
+
<Download :size="20" />
|
|
392
|
+
</template>
|
|
393
|
+
{{ downloadLabel }}
|
|
394
|
+
</NcActionLink>
|
|
395
|
+
<NcActionButton v-if="source && canChange"
|
|
396
|
+
:closeAfterClick="true"
|
|
397
|
+
data-testid="cn-files-browser-action-delete"
|
|
398
|
+
@click="askRemove(node)">
|
|
399
|
+
<template #icon>
|
|
400
|
+
<TrashCanOutline :size="20" />
|
|
401
|
+
</template>
|
|
402
|
+
{{ deleteLabel }}
|
|
403
|
+
</NcActionButton>
|
|
404
|
+
<NcActionButton v-if="canChange"
|
|
405
|
+
:closeAfterClick="true"
|
|
406
|
+
data-testid="cn-files-browser-action-rename"
|
|
407
|
+
@click="askRename(node)">
|
|
408
|
+
<template #icon>
|
|
409
|
+
<Pencil :size="20" />
|
|
410
|
+
</template>
|
|
411
|
+
{{ renameLabel }}
|
|
412
|
+
</NcActionButton>
|
|
413
|
+
<NcActionLink
|
|
414
|
+
v-if="node.fileid && !source"
|
|
415
|
+
:href="permalink(node)"
|
|
416
|
+
target="_blank"
|
|
417
|
+
:closeAfterClick="true">
|
|
418
|
+
<template #icon>
|
|
419
|
+
<OpenInNew :size="20" />
|
|
420
|
+
</template>
|
|
421
|
+
{{ showInFilesLabel }}
|
|
422
|
+
</NcActionLink>
|
|
423
|
+
</NcActions>
|
|
424
|
+
</td>
|
|
425
|
+
</tr>
|
|
426
|
+
</template>
|
|
427
|
+
<tr v-if="facetActive && filteredFiles.length === 0" class="cn-files-browser__no-match-row">
|
|
428
|
+
<td :colspan="columnCount" class="cn-files-browser__no-match" data-testid="cn-files-browser-no-match">
|
|
429
|
+
{{ t('nextcloud-vue', 'No files match the filter.') }}
|
|
430
|
+
</td>
|
|
431
|
+
</tr>
|
|
432
|
+
<!-- Rows that are not nodes of this folder: documents the host
|
|
433
|
+
joined from elsewhere (another object's folder). Open and
|
|
434
|
+
download only; nothing here can change the file. -->
|
|
286
435
|
<tr
|
|
287
|
-
v-
|
|
288
|
-
:key="
|
|
289
|
-
class="cn-files-browser__row"
|
|
290
|
-
|
|
291
|
-
data-
|
|
292
|
-
|
|
293
|
-
@click="onRowClick(node, $event)"
|
|
436
|
+
v-for="item in linkedItems"
|
|
437
|
+
:key="`linked-${item.id}`"
|
|
438
|
+
class="cn-files-browser__row cn-files-browser__row--linked"
|
|
439
|
+
data-testid="cn-files-browser-linked-row"
|
|
440
|
+
:data-name="item.name"
|
|
441
|
+
@click="openLinked(item)"
|
|
294
442
|
@mousedown="preventMiddleClickAutoscroll"
|
|
295
|
-
@auxclick="
|
|
296
|
-
<td v-if="bulkEnabled"
|
|
297
|
-
class="cn-files-browser__col-select"
|
|
298
|
-
@click.stop
|
|
299
|
-
@auxclick.stop>
|
|
300
|
-
<input v-if="!isFolder(node)"
|
|
301
|
-
type="checkbox"
|
|
302
|
-
class="cn-files-browser__select"
|
|
303
|
-
:checked="isSelected(node)"
|
|
304
|
-
:aria-label="t('nextcloud-vue', 'Select {name}', { name: node.basename })"
|
|
305
|
-
data-testid="cn-files-browser-select"
|
|
306
|
-
@change="toggleSelected(node, $event.target.checked)">
|
|
307
|
-
</td>
|
|
443
|
+
@auxclick="onLinkedAuxClick(item, $event)">
|
|
444
|
+
<td v-if="bulkEnabled" class="cn-files-browser__col-select" />
|
|
308
445
|
<td class="cn-files-browser__col-icon">
|
|
309
446
|
<img
|
|
310
|
-
v-if="
|
|
311
|
-
class="cn-files-browser__thumb"
|
|
312
|
-
:src="previewUrlFor(node)"
|
|
313
|
-
alt=""
|
|
314
|
-
loading="lazy"
|
|
315
|
-
@error="onPreviewError(node)">
|
|
316
|
-
<img
|
|
317
|
-
v-else-if="mimeIconFor(node)"
|
|
447
|
+
v-if="mimeIconFor({ mime: item.mime })"
|
|
318
448
|
class="cn-files-browser__mime"
|
|
319
|
-
:src="mimeIconFor(
|
|
449
|
+
:src="mimeIconFor({ mime: item.mime })"
|
|
320
450
|
alt="">
|
|
321
|
-
<FolderOutline v-else-if="isFolder(node)" :size="32" />
|
|
322
451
|
<FileOutline v-else :size="32" />
|
|
323
452
|
</td>
|
|
453
|
+
<!-- A linked item is not a node of this folder, so it can only
|
|
454
|
+
answer for name, size and modified. It still walks the same
|
|
455
|
+
column list, or a declared column set would shift every
|
|
456
|
+
linked row one cell out of line with its header. -->
|
|
324
457
|
<td v-for="column in renderedColumns"
|
|
325
458
|
:key="column.key"
|
|
326
|
-
:class="`cn-files-browser__col-${column.key}`"
|
|
327
|
-
|
|
328
|
-
|
|
459
|
+
:class="`cn-files-browser__col-${column.key}`">
|
|
460
|
+
<template v-if="column.key === 'name'">
|
|
461
|
+
<span class="cn-files-browser__name">{{ item.name }}</span>
|
|
462
|
+
<span v-if="item.note" class="cn-files-browser__note">
|
|
463
|
+
<a
|
|
464
|
+
v-if="item.noteHref"
|
|
465
|
+
:href="item.noteHref"
|
|
466
|
+
class="cn-files-browser__note-link"
|
|
467
|
+
@click.stop>{{ item.note }}</a>
|
|
468
|
+
<template v-else>{{ item.note }}</template>
|
|
469
|
+
</span>
|
|
470
|
+
</template>
|
|
329
471
|
<template v-else-if="column.key === 'size'">
|
|
330
|
-
{{
|
|
472
|
+
{{ item.size ? formatSize(item.size) : '' }}
|
|
331
473
|
</template>
|
|
332
|
-
<NcDateTime v-else-if="column.key === 'modified'" :timestamp="
|
|
333
|
-
<!-- Everything the host declared renders through the same
|
|
334
|
-
cell renderer the tables use, so a `formatter` means
|
|
335
|
-
here what it means there. -->
|
|
336
|
-
<CnCellRenderer v-else
|
|
337
|
-
:value="cellValue(column, node)"
|
|
338
|
-
:formatter="column.formatter || null"
|
|
339
|
-
:formatterOptions="column.formatterOptions || null"
|
|
340
|
-
:widget="column.widget || null"
|
|
341
|
-
:row="node" />
|
|
474
|
+
<NcDateTime v-else-if="column.key === 'modified' && item.mtime" :timestamp="item.mtime" :ignoreSeconds="true" />
|
|
342
475
|
</td>
|
|
343
476
|
<td class="cn-files-browser__col-actions" @click.stop @auxclick.stop>
|
|
344
|
-
<NcActions :forceMenu="true" :ariaLabel="t('nextcloud-vue', 'Actions for {name}', { name:
|
|
345
|
-
<
|
|
346
|
-
v-
|
|
347
|
-
:
|
|
477
|
+
<NcActions :forceMenu="true" :ariaLabel="t('nextcloud-vue', 'Actions for {name}', { name: item.name })">
|
|
478
|
+
<NcActionLink
|
|
479
|
+
v-if="item.href"
|
|
480
|
+
:href="item.href"
|
|
481
|
+
target="_blank"
|
|
348
482
|
:closeAfterClick="true"
|
|
349
|
-
|
|
350
|
-
@click="run(action, node)">
|
|
483
|
+
data-testid="cn-files-browser-linked-open">
|
|
351
484
|
<template #icon>
|
|
352
|
-
<
|
|
485
|
+
<OpenInNew :size="20" />
|
|
353
486
|
</template>
|
|
354
|
-
{{
|
|
355
|
-
</
|
|
356
|
-
<!-- The host's own actions on a file (never on a folder): declared
|
|
357
|
-
in its manifest, dispatched through the page's action runner
|
|
358
|
-
with the node's file id, name and path merged in. -->
|
|
359
|
-
<template v-if="!isFolder(node)">
|
|
360
|
-
<NcActionButton
|
|
361
|
-
v-for="action in hostActionsFor(node)"
|
|
362
|
-
:key="`host-${action.id}`"
|
|
363
|
-
:closeAfterClick="true"
|
|
364
|
-
:data-testid="`cn-files-browser-host-action-${action.id}`"
|
|
365
|
-
@click="runHostAction(action, node)">
|
|
366
|
-
<template #icon>
|
|
367
|
-
<CnIcon :name="action.icon || 'FileDocumentEditOutline'" :size="20" />
|
|
368
|
-
</template>
|
|
369
|
-
{{ hostLabel(action) }}
|
|
370
|
-
</NcActionButton>
|
|
371
|
-
</template>
|
|
372
|
-
<NcActionSeparator v-if="actionsFor(node).length > 0 || (!isFolder(node) && hostActionsFor(node).length > 0)" />
|
|
373
|
-
<!-- The Files app's own rename is its list's inline input,
|
|
374
|
-
which is not here; this one is a dialog over a DAV move. -->
|
|
375
|
-
<!-- With a `source`, the Files app's actions (which act over
|
|
376
|
-
WebDAV) are not offered; download and delete go through
|
|
377
|
-
the source instead. -->
|
|
487
|
+
{{ openLinkedLabel }}
|
|
488
|
+
</NcActionLink>
|
|
378
489
|
<NcActionLink
|
|
379
|
-
v-if="
|
|
380
|
-
:href="
|
|
381
|
-
:download="
|
|
490
|
+
v-if="item.downloadHref"
|
|
491
|
+
:href="item.downloadHref"
|
|
492
|
+
:download="item.name"
|
|
382
493
|
:closeAfterClick="true"
|
|
383
|
-
data-testid="cn-files-browser-
|
|
494
|
+
data-testid="cn-files-browser-linked-download">
|
|
384
495
|
<template #icon>
|
|
385
496
|
<Download :size="20" />
|
|
386
497
|
</template>
|
|
387
498
|
{{ downloadLabel }}
|
|
388
499
|
</NcActionLink>
|
|
389
|
-
<NcActionButton v-if="source && canChange"
|
|
390
|
-
:closeAfterClick="true"
|
|
391
|
-
data-testid="cn-files-browser-action-delete"
|
|
392
|
-
@click="askRemove(node)">
|
|
393
|
-
<template #icon>
|
|
394
|
-
<TrashCanOutline :size="20" />
|
|
395
|
-
</template>
|
|
396
|
-
{{ deleteLabel }}
|
|
397
|
-
</NcActionButton>
|
|
398
|
-
<NcActionButton v-if="canChange"
|
|
399
|
-
:closeAfterClick="true"
|
|
400
|
-
data-testid="cn-files-browser-action-rename"
|
|
401
|
-
@click="askRename(node)">
|
|
402
|
-
<template #icon>
|
|
403
|
-
<Pencil :size="20" />
|
|
404
|
-
</template>
|
|
405
|
-
{{ renameLabel }}
|
|
406
|
-
</NcActionButton>
|
|
407
|
-
<NcActionLink
|
|
408
|
-
v-if="node.fileid && !source"
|
|
409
|
-
:href="permalink(node)"
|
|
410
|
-
target="_blank"
|
|
411
|
-
:closeAfterClick="true">
|
|
412
|
-
<template #icon>
|
|
413
|
-
<OpenInNew :size="20" />
|
|
414
|
-
</template>
|
|
415
|
-
{{ showInFilesLabel }}
|
|
416
|
-
</NcActionLink>
|
|
417
500
|
</NcActions>
|
|
418
501
|
</td>
|
|
419
502
|
</tr>
|
|
420
|
-
</
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
:
|
|
432
|
-
class="cn-files-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
<FileOutline v-else :size="32" />
|
|
446
|
-
</td>
|
|
447
|
-
<!-- A linked item is not a node of this folder, so it can only
|
|
448
|
-
answer for name, size and modified. It still walks the same
|
|
449
|
-
column list, or a declared column set would shift every
|
|
450
|
-
linked row one cell out of line with its header. -->
|
|
451
|
-
<td v-for="column in renderedColumns"
|
|
452
|
-
:key="column.key"
|
|
453
|
-
:class="`cn-files-browser__col-${column.key}`">
|
|
454
|
-
<template v-if="column.key === 'name'">
|
|
455
|
-
<span class="cn-files-browser__name">{{ item.name }}</span>
|
|
456
|
-
<span v-if="item.note" class="cn-files-browser__note">
|
|
457
|
-
<a
|
|
458
|
-
v-if="item.noteHref"
|
|
459
|
-
:href="item.noteHref"
|
|
460
|
-
class="cn-files-browser__note-link"
|
|
461
|
-
@click.stop>{{ item.note }}</a>
|
|
462
|
-
<template v-else>{{ item.note }}</template>
|
|
463
|
-
</span>
|
|
464
|
-
</template>
|
|
465
|
-
<template v-else-if="column.key === 'size'">
|
|
466
|
-
{{ item.size ? formatSize(item.size) : '' }}
|
|
503
|
+
</tbody>
|
|
504
|
+
</table>
|
|
505
|
+
|
|
506
|
+
<!-- `sideCards`: cards about the last selected file, beside the list. -->
|
|
507
|
+
<aside v-if="sideNode !== null"
|
|
508
|
+
class="cn-files-browser__side"
|
|
509
|
+
:aria-label="t('nextcloud-vue', 'About {name}', { name: sideNode.basename })"
|
|
510
|
+
data-testid="cn-files-browser-side">
|
|
511
|
+
<section v-for="card in sideCardsFor(sideNode)"
|
|
512
|
+
:key="card.id"
|
|
513
|
+
class="cn-files-browser__side-card"
|
|
514
|
+
:data-testid="`cn-files-browser-side-card-${card.id}`">
|
|
515
|
+
<h3 class="cn-files-browser__side-title">
|
|
516
|
+
{{ card.title }}
|
|
517
|
+
</h3>
|
|
518
|
+
<dl v-if="card.fields.length > 0" class="cn-files-browser__side-facts">
|
|
519
|
+
<template v-for="field in card.fields" :key="field.key">
|
|
520
|
+
<dt>{{ field.label }}</dt>
|
|
521
|
+
<dd :class="field.tone ? `cn-files-browser__tone cn-files-browser__tone--${field.tone}` : ''">
|
|
522
|
+
<CnCellRenderer
|
|
523
|
+
:value="field.value"
|
|
524
|
+
:formatter="field.formatter || null"
|
|
525
|
+
:formatterOptions="field.formatterOptions || null"
|
|
526
|
+
:row="sideNode" />
|
|
527
|
+
</dd>
|
|
467
528
|
</template>
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
<NcActionLink
|
|
484
|
-
v-if="item.downloadHref"
|
|
485
|
-
:href="item.downloadHref"
|
|
486
|
-
:download="item.name"
|
|
487
|
-
:closeAfterClick="true"
|
|
488
|
-
data-testid="cn-files-browser-linked-download">
|
|
489
|
-
<template #icon>
|
|
490
|
-
<Download :size="20" />
|
|
491
|
-
</template>
|
|
492
|
-
{{ downloadLabel }}
|
|
493
|
-
</NcActionLink>
|
|
494
|
-
</NcActions>
|
|
495
|
-
</td>
|
|
496
|
-
</tr>
|
|
497
|
-
</tbody>
|
|
498
|
-
</table>
|
|
529
|
+
</dl>
|
|
530
|
+
<div v-if="card.actions.length > 0" class="cn-files-browser__side-actions">
|
|
531
|
+
<NcButton v-for="action in card.actions"
|
|
532
|
+
:key="action.id"
|
|
533
|
+
:data-testid="`cn-files-browser-side-action-${action.id}`"
|
|
534
|
+
@click="runHostAction(action, sideNode)">
|
|
535
|
+
<template v-if="action.icon" #icon>
|
|
536
|
+
<CnIcon :name="action.icon" :size="20" />
|
|
537
|
+
</template>
|
|
538
|
+
{{ hostLabel(action) }}
|
|
539
|
+
</NcButton>
|
|
540
|
+
</div>
|
|
541
|
+
</section>
|
|
542
|
+
</aside>
|
|
543
|
+
</div>
|
|
499
544
|
|
|
500
545
|
<p v-if="dropHint && canChange && !loading && error === ''"
|
|
501
546
|
class="cn-files-browser__drop-hint"
|
|
@@ -980,6 +1025,46 @@ export default {
|
|
|
980
1025
|
default: () => [],
|
|
981
1026
|
},
|
|
982
1027
|
|
|
1028
|
+
/**
|
|
1029
|
+
* The bulk bar's count, as a translatable template with `{count}`
|
|
1030
|
+
* ("{count} documents selected"); `selectionLabelOne` is used for one.
|
|
1031
|
+
* Empty reads "{count} selected".
|
|
1032
|
+
*
|
|
1033
|
+
* @spec openspec/changes/files-browser-side-cards/specs/files-browser/spec.md#requirement-the-bulk-bar-names-what-is-selected
|
|
1034
|
+
*/
|
|
1035
|
+
selectionLabel: {
|
|
1036
|
+
type: String,
|
|
1037
|
+
default: '',
|
|
1038
|
+
},
|
|
1039
|
+
|
|
1040
|
+
/** The bulk bar's count for one selected file, e.g. "{count} document selected". */
|
|
1041
|
+
selectionLabelOne: {
|
|
1042
|
+
type: String,
|
|
1043
|
+
default: '',
|
|
1044
|
+
},
|
|
1045
|
+
|
|
1046
|
+
/** Whether the bulk bar ends in a "Clear selection" button. */
|
|
1047
|
+
showClearSelection: {
|
|
1048
|
+
type: Boolean,
|
|
1049
|
+
default: true,
|
|
1050
|
+
},
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* Cards beside the list about the last selected file:
|
|
1054
|
+
* `[{ id, title, fields: [{ key, label, source?, formatter?, formatterOptions?, colorMap?, colorKey? }], actions? }]`.
|
|
1055
|
+
* `title` may hold `{name}`, the file's name. A field reads `rowData`
|
|
1056
|
+
* (`source: 'row'`, the default) or the node (`source: 'node'`); a field
|
|
1057
|
+
* with no value is left out. `actions` are declared like `rowActions`
|
|
1058
|
+
* and run on that file. No side column while nothing is selected.
|
|
1059
|
+
*
|
|
1060
|
+
* @type {Array<{id: string, title: string, fields?: Array<object>, actions?: Array<object>}>}
|
|
1061
|
+
* @spec openspec/changes/files-browser-side-cards/specs/files-browser/spec.md#requirement-cards-beside-the-list-describe-the-selected-file
|
|
1062
|
+
*/
|
|
1063
|
+
sideCards: {
|
|
1064
|
+
type: Array,
|
|
1065
|
+
default: () => [],
|
|
1066
|
+
},
|
|
1067
|
+
|
|
983
1068
|
/**
|
|
984
1069
|
* The key of a declared column to group the files on: a heading row
|
|
985
1070
|
* per value, in the order each is first met, with its count. Files
|
|
@@ -1212,6 +1297,36 @@ export default {
|
|
|
1212
1297
|
*
|
|
1213
1298
|
* @return {Array<object>} The file nodes.
|
|
1214
1299
|
*/
|
|
1300
|
+
/**
|
|
1301
|
+
* The bulk bar's count text.
|
|
1302
|
+
*
|
|
1303
|
+
* @return {string}
|
|
1304
|
+
* @spec openspec/changes/files-browser-side-cards/specs/files-browser/spec.md#requirement-the-bulk-bar-names-what-is-selected
|
|
1305
|
+
*/
|
|
1306
|
+
selectionCountText() {
|
|
1307
|
+
const count = this.selectedIds.length
|
|
1308
|
+
const template = count === 1 && this.selectionLabelOne ? this.selectionLabelOne : this.selectionLabel
|
|
1309
|
+
if (template) {
|
|
1310
|
+
return this.cnTranslate(template).replace(/\{count\}/g, String(count))
|
|
1311
|
+
}
|
|
1312
|
+
return t('nextcloud-vue', '{count} selected', { count })
|
|
1313
|
+
},
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* The file the side cards describe: the last one selected, or null
|
|
1317
|
+
* without side cards or a selection.
|
|
1318
|
+
*
|
|
1319
|
+
* @return {object|null}
|
|
1320
|
+
* @spec openspec/changes/files-browser-side-cards/specs/files-browser/spec.md#requirement-cards-beside-the-list-describe-the-selected-file
|
|
1321
|
+
*/
|
|
1322
|
+
sideNode() {
|
|
1323
|
+
if (!Array.isArray(this.sideCards) || this.sideCards.length === 0 || this.selectedIds.length === 0) {
|
|
1324
|
+
return null
|
|
1325
|
+
}
|
|
1326
|
+
const id = this.selectedIds[this.selectedIds.length - 1]
|
|
1327
|
+
return this.fileNodes.find((node) => String(node.fileid) === id) || null
|
|
1328
|
+
},
|
|
1329
|
+
|
|
1215
1330
|
fileNodes() {
|
|
1216
1331
|
return this.sorted.filter((node) => !this.isFolder(node))
|
|
1217
1332
|
},
|
|
@@ -2098,6 +2213,80 @@ export default {
|
|
|
2098
2213
|
return fileColumnValue(column, node, this.resolvedRowData)
|
|
2099
2214
|
},
|
|
2100
2215
|
|
|
2216
|
+
/**
|
|
2217
|
+
* The tone a column or card field draws a value in: its `colorMap`
|
|
2218
|
+
* entry for the value (case-insensitive), read from the `colorKey` field
|
|
2219
|
+
* of the row when given, else from the value itself. '' without one.
|
|
2220
|
+
*
|
|
2221
|
+
* @param {object} column A resolved column or a side card field.
|
|
2222
|
+
* @param {object} node The node.
|
|
2223
|
+
* @return {string} A badge variant (`success`, `warning`, `error`, ...) or ''.
|
|
2224
|
+
* @spec openspec/changes/files-browser-side-cards/specs/files-browser/spec.md#requirement-a-row-column-can-draw-its-values-in-tones
|
|
2225
|
+
*/
|
|
2226
|
+
toneOf(column, node) {
|
|
2227
|
+
const map = column && column.colorMap
|
|
2228
|
+
if (!map || typeof map !== 'object') {
|
|
2229
|
+
return ''
|
|
2230
|
+
}
|
|
2231
|
+
const raw = column.colorKey
|
|
2232
|
+
? fileColumnValue({ key: column.colorKey, source: 'row' }, node, this.resolvedRowData)
|
|
2233
|
+
: this.cellValue(column, node)
|
|
2234
|
+
if (raw === null || raw === undefined || typeof raw === 'object') {
|
|
2235
|
+
return ''
|
|
2236
|
+
}
|
|
2237
|
+
const wanted = String(raw).toLowerCase()
|
|
2238
|
+
const hit = Object.keys(map).find((key) => key.toLowerCase() === wanted)
|
|
2239
|
+
return hit ? String(map[hit]) : ''
|
|
2240
|
+
},
|
|
2241
|
+
|
|
2242
|
+
/**
|
|
2243
|
+
* The widget props a cell gets: the column's own, and for a `badge`
|
|
2244
|
+
* its tone as the variant.
|
|
2245
|
+
*
|
|
2246
|
+
* @param {object} column A resolved column.
|
|
2247
|
+
* @param {object} node The node.
|
|
2248
|
+
* @return {object|null}
|
|
2249
|
+
*/
|
|
2250
|
+
cellWidgetProps(column, node) {
|
|
2251
|
+
if (column.widget !== 'badge') {
|
|
2252
|
+
return column.widgetProps || null
|
|
2253
|
+
}
|
|
2254
|
+
const tone = this.toneOf(column, node)
|
|
2255
|
+
return { ...(column.widgetProps || {}), ...(tone ? { variant: tone } : {}) }
|
|
2256
|
+
},
|
|
2257
|
+
|
|
2258
|
+
/**
|
|
2259
|
+
* The side cards for a file, resolved: the title with `{name}` filled
|
|
2260
|
+
* in, the fields that have a value with their tone, and the actions.
|
|
2261
|
+
*
|
|
2262
|
+
* @param {object} node The node.
|
|
2263
|
+
* @return {Array<{id: string, title: string, fields: Array<object>, actions: Array<object>}>}
|
|
2264
|
+
* @spec openspec/changes/files-browser-side-cards/specs/files-browser/spec.md#requirement-cards-beside-the-list-describe-the-selected-file
|
|
2265
|
+
*/
|
|
2266
|
+
sideCardsFor(node) {
|
|
2267
|
+
return this.sideCards
|
|
2268
|
+
.filter((card) => card && card.id)
|
|
2269
|
+
.map((card) => ({
|
|
2270
|
+
id: String(card.id),
|
|
2271
|
+
title: this.cnTranslate(String(card.title || '')).replace(/\{name\}/g, node.basename),
|
|
2272
|
+
fields: (Array.isArray(card.fields) ? card.fields : [])
|
|
2273
|
+
.filter((field) => field && field.key)
|
|
2274
|
+
.map((field) => {
|
|
2275
|
+
const column = { ...field, source: field.source || 'row' }
|
|
2276
|
+
return {
|
|
2277
|
+
key: String(field.key),
|
|
2278
|
+
label: this.cnTranslate(String(field.label || field.key)),
|
|
2279
|
+
value: this.cellValue(column, node),
|
|
2280
|
+
formatter: field.formatter,
|
|
2281
|
+
formatterOptions: field.formatterOptions,
|
|
2282
|
+
tone: this.toneOf(column, node),
|
|
2283
|
+
}
|
|
2284
|
+
})
|
|
2285
|
+
.filter((field) => field.value !== null && field.value !== undefined && field.value !== ''),
|
|
2286
|
+
actions: (Array.isArray(card.actions) ? card.actions : []).filter((action) => action && action.id),
|
|
2287
|
+
}))
|
|
2288
|
+
},
|
|
2289
|
+
|
|
2101
2290
|
/**
|
|
2102
2291
|
* Whether a user currently sees a column, for the chooser's ticks.
|
|
2103
2292
|
*
|
|
@@ -2577,6 +2766,89 @@ export default {
|
|
|
2577
2766
|
padding: 24px 0;
|
|
2578
2767
|
}
|
|
2579
2768
|
|
|
2769
|
+
/* `sideCards`: the list and, while a file is selected, a column of cards. */
|
|
2770
|
+
.cn-files-browser__body--with-side {
|
|
2771
|
+
display: grid;
|
|
2772
|
+
grid-template-columns: minmax(0, 1fr) minmax(240px, 300px);
|
|
2773
|
+
align-items: start;
|
|
2774
|
+
gap: 16px;
|
|
2775
|
+
}
|
|
2776
|
+
|
|
2777
|
+
@media (max-width: 900px) {
|
|
2778
|
+
.cn-files-browser__body--with-side {
|
|
2779
|
+
grid-template-columns: minmax(0, 1fr);
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
.cn-files-browser__side {
|
|
2784
|
+
display: flex;
|
|
2785
|
+
flex-direction: column;
|
|
2786
|
+
gap: 12px;
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
.cn-files-browser__side-card {
|
|
2790
|
+
display: flex;
|
|
2791
|
+
flex-direction: column;
|
|
2792
|
+
gap: 10px;
|
|
2793
|
+
padding: 16px 18px;
|
|
2794
|
+
border: 1px solid var(--color-border);
|
|
2795
|
+
border-radius: var(--border-radius-large);
|
|
2796
|
+
background: var(--color-main-background);
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2799
|
+
.cn-files-browser__side-title {
|
|
2800
|
+
margin: 0;
|
|
2801
|
+
font-size: 15px;
|
|
2802
|
+
font-weight: 700;
|
|
2803
|
+
overflow-wrap: anywhere;
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
.cn-files-browser__side-facts {
|
|
2807
|
+
display: grid;
|
|
2808
|
+
grid-template-columns: max-content minmax(0, 1fr);
|
|
2809
|
+
gap: 6px 12px;
|
|
2810
|
+
margin: 0;
|
|
2811
|
+
font-size: 14px;
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
.cn-files-browser__side-facts dt {
|
|
2815
|
+
color: var(--color-text-maxcontrast);
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
.cn-files-browser__side-facts dd {
|
|
2819
|
+
margin: 0;
|
|
2820
|
+
overflow-wrap: anywhere;
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
.cn-files-browser__side-actions {
|
|
2824
|
+
display: flex;
|
|
2825
|
+
flex-wrap: wrap;
|
|
2826
|
+
gap: 8px;
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
/* A value drawn in a tone (`colorMap` on a column that is not a badge): the
|
|
2830
|
+
text in the tone's colour, as the boards write a restricted level. */
|
|
2831
|
+
.cn-files-browser__tone {
|
|
2832
|
+
font-weight: 600;
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
.cn-files-browser__tone--success {
|
|
2836
|
+
color: var(--color-success-text, var(--color-success));
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
.cn-files-browser__tone--warning {
|
|
2840
|
+
color: var(--color-warning-text, var(--color-warning));
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
.cn-files-browser__tone--error {
|
|
2844
|
+
color: var(--color-error-text, var(--color-error));
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
.cn-files-browser__tone--primary,
|
|
2848
|
+
.cn-files-browser__tone--info {
|
|
2849
|
+
color: var(--color-primary-element-light-text, var(--color-primary-element));
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2580
2852
|
.cn-files-browser__table {
|
|
2581
2853
|
width: 100%;
|
|
2582
2854
|
border-collapse: collapse;
|