Skip to content

Commit 199987e

Browse files
committed
feat(files): add folder icon overlay
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
1 parent e2303d0 commit 199987e

2 files changed

Lines changed: 69 additions & 6 deletions

File tree

apps/files/src/components/FileEntry.vue

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@
4444
<td class="files-list__row-name" data-cy-files-list-row-name>
4545
<!-- Icon or preview -->
4646
<span class="files-list__row-icon" @click="execDefaultAction">
47-
<FolderIcon v-if="source.type === 'folder'" />
47+
<template v-if="source.type === 'folder'">
48+
<FolderIcon />
49+
<OverlayIcon :is="folderOverlay"
50+
v-if="folderOverlay"
51+
class="files-list__row-icon-overlay" />
52+
</template>
4853

4954
<!-- Decorative image, should not be aria documented -->
5055
<span v-else-if="previewUrl && !backgroundFailed"
@@ -171,20 +176,27 @@ import { debounce } from 'debounce'
171176
import { emit } from '@nextcloud/event-bus'
172177
import { extname } from 'path'
173178
import { generateUrl } from '@nextcloud/router'
174-
import { getFileActions, DefaultType, FileType, formatFileSize, Permission, NodeStatus } from '@nextcloud/files'
179+
import { getFileActions, DefaultType, FileType, formatFileSize, Permission } from '@nextcloud/files'
175180
import { showError, showSuccess } from '@nextcloud/dialogs'
176181
import { translate } from '@nextcloud/l10n'
182+
import { Type as ShareType } from '@nextcloud/sharing'
177183
import { vOnClickOutside } from '@vueuse/components'
178184
import axios from '@nextcloud/axios'
185+
import moment from '@nextcloud/moment'
186+
import Vue from 'vue'
187+
188+
import AccountGroupIcon from 'vue-material-design-icons/AccountGroup.vue'
179189
import FileIcon from 'vue-material-design-icons/File.vue'
180190
import FolderIcon from 'vue-material-design-icons/Folder.vue'
181-
import moment from '@nextcloud/moment'
191+
import KeyIcon from 'vue-material-design-icons/Key.vue'
192+
import LinkIcon from 'vue-material-design-icons/Link.vue'
193+
import NetworkIcon from 'vue-material-design-icons/Network.vue'
194+
import ShareVariantIcon from 'vue-material-design-icons/ShareVariant.vue'
182195
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
183196
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
184197
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
185198
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
186199
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
187-
import Vue from 'vue'
188200
189201
import { ACTION_DETAILS } from '../actions/sidebarAction.ts'
190202
import { hashCode } from '../utils/hashUtils.ts'
@@ -219,6 +231,7 @@ export default Vue.extend({
219231
NcCheckboxRadioSwitch,
220232
NcLoadingIcon,
221233
NcTextField,
234+
Lock,
222235
},
223236
224237
props: {
@@ -353,6 +366,38 @@ export default Vue.extend({
353366
return ''
354367
},
355368
369+
folderOverlay() {
370+
if (this.source.type !== FileType.Folder) {
371+
return null
372+
}
373+
374+
// Link and mail shared folders
375+
const shareTypes = Object.values(this.source?.attributes?.['share-types'] || {}).flat() as number[]
376+
if (shareTypes.some(type => type === ShareType.SHARE_TYPE_LINK || type === ShareType.SHARE_TYPE_EMAIL)) {
377+
return LinkIcon
378+
}
379+
380+
// Shared folders
381+
if (shareTypes.length > 0) {
382+
return ShareVariantIcon
383+
}
384+
385+
// Encrypted folders
386+
if (this.source?.attributes?.['is-encrypted'] === 1) {
387+
return KeyIcon
388+
}
389+
390+
switch (this.source?.attributes?.['mount-type']) {
391+
case 'external':
392+
case 'external-session':
393+
return NetworkIcon
394+
case 'group':
395+
return AccountGroupIcon
396+
}
397+
398+
return null
399+
},
400+
356401
linkTo() {
357402
if (this.source.attributes.failed) {
358403
return {
@@ -869,12 +914,21 @@ export default Vue.extend({
869914
/* Hover effect on tbody lines only */
870915
tr {
871916
&:hover,
872-
&:focus,
873-
&:visible {
917+
&:focus {
874918
background-color: var(--color-background-dark);
875919
}
876920
}
877921
922+
// Folder overlay
923+
.files-list__row-icon-overlay {
924+
position: absolute;
925+
max-height: 18px;
926+
max-width: 18px;
927+
color: var(--color-main-background);
928+
// better alignment with the folder icon
929+
margin-top: 2px;
930+
}
931+
878932
/* Preview not loaded animation effect */
879933
.files-list__row-icon-preview:not([style*='background']) {
880934
background: var(--color-loading-dark);

apps/files/src/components/FilesListVirtual.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,15 @@ export default Vue.extend({
343343
width: var(--icon-preview-size);
344344
height: var(--icon-preview-size);
345345
}
346+
347+
// Slightly increase the size of the folder icon
348+
&.folder-icon {
349+
margin: -3px;
350+
svg {
351+
width: calc(var(--icon-preview-size) + 6px);
352+
height: calc(var(--icon-preview-size) + 6px);
353+
}
354+
}
346355
}
347356
348357
&-preview {

0 commit comments

Comments
 (0)