Skip to content

Commit c2a0ae9

Browse files
authored
Merge pull request #5971 from LibreSign/feat/improve-files-list-accessibility
feat: improve files list accessibility
2 parents 3a6702d + c1e004c commit c2a0ae9

4 files changed

Lines changed: 97 additions & 28 deletions

File tree

src/assets/styles/main.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@
99

1010
.is-fullwidth{width: 100%;}
1111

12+
.hidden-visually {
13+
position: absolute;
14+
left: -10000px;
15+
top: auto;
16+
width: 1px;
17+
height: 1px;
18+
overflow: hidden;
19+
}
20+
1221
.button.is-warning{
1322
background-color: var(--color-warning, #eca700);
1423
border-color: var(--color-warning-hover, #f0b933);

src/views/FilesList/FilesList.vue

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,28 @@
3737
</template>
3838
</NcButton>
3939
</div>
40-
<NcLoadingIcon v-if="loading && !isRefreshing"
41-
class="files-list__loading-icon"
42-
:size="38"
43-
:name="t('libresign', 'Loading …')" />
44-
<NcEmptyContent v-else-if="!loading && isEmptyDir && filtersStore.activeChips.length === 0"
45-
:name="t('libresign', 'There are no documents')"
46-
:description="canRequestSign ? t('libresign', 'Choose the file to request signatures.') : ''">
47-
<template #action>
48-
<RequestPicker />
49-
</template>
50-
<template #icon>
51-
<FolderIcon />
40+
<FilesListVirtual :nodes="dirContentsSorted"
41+
:loading="loading">
42+
<template #empty>
43+
<NcLoadingIcon
44+
v-if="loading && !isRefreshing"
45+
class="files-list__loading-icon"
46+
:size="38"
47+
:name="t('libresign', 'Loading …')" />
48+
49+
<NcEmptyContent
50+
v-else-if="!loading && isEmptyDir && filtersStore.activeChips.length === 0"
51+
:name="t('libresign', 'There are no documents')"
52+
:description="canRequestSign ? t('libresign', 'Choose the file to request signatures.') : ''">
53+
<template #action>
54+
<RequestPicker />
55+
</template>
56+
<template #icon>
57+
<FolderIcon />
58+
</template>
59+
</NcEmptyContent>
5260
</template>
53-
</NcEmptyContent>
54-
<FilesListVirtual v-else
55-
:nodes="dirContentsSorted"
56-
:loading="loading" />
61+
</FilesListVirtual>
5762
</NcAppContent>
5863
</template>
5964

@@ -126,13 +131,10 @@ export default {
126131
: t('libresign', 'Switch to grid view')
127132
},
128133
dirContentsSorted() {
129-
if (!this.isEmptyDir) {
130-
return []
131-
}
132-
return this.dirContentsFiltered
134+
return this.filesStore.filesSorted()
133135
},
134136
isEmptyDir() {
135-
return Object.keys(this.filesStore.files).length === 0
137+
return this.filesStore.filesSorted().length === 0
136138
},
137139
isRefreshing() {
138140
return !this.isEmptyDir

src/views/FilesList/FilesListVirtual.vue

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,27 @@
33
- SPDX-License-Identifier: AGPL-3.0-or-later
44
-->
55
<template>
6-
<VirtualList :data-component="userConfigStore.grid_view ? FileEntryGrid : FileEntry"
7-
:loading="loading">
6+
<VirtualList ref="table"
7+
:data-component="userConfigStore.grid_view ? FileEntryGrid : FileEntry"
8+
:loading="loading"
9+
:caption="caption">
810
<template #filters>
911
<FileListFilters />
1012
</template>
1113
<template v-if="!isNoneSelected" #header-overlay>
12-
<span class="files-list__selected">{{ n('libresign', '{count} selected', '{count} selected', selectionStore.selected.length, { count: selectionStore.selected.length }) }}</span>
14+
<span class="files-list__selected">
15+
{{ n('libresign', '{count} selected', '{count} selected', selectedNodes.length, { count: selectedNodes.length }) }}
16+
</span>
1317
<FilesListTableHeaderActions />
1418
</template>
1519
<template #header>
1620
<!-- Table header and sort buttons -->
1721
<FilesListTableHeader ref="thead"
1822
:nodes="nodes" />
1923
</template>
24+
<template #empty>
25+
<slot name="empty" />
26+
</template>
2027
<template #footer>
2128
<FilesListTableFooter />
2229
</template>
@@ -76,8 +83,14 @@ export default {
7683
}
7784
},
7885
computed: {
86+
selectedNodes() {
87+
return this.selectionStore.selected
88+
},
7989
isNoneSelected() {
80-
return this.selectionStore.selected.length === 0
90+
return this.selectedNodes.length === 0
91+
},
92+
caption() {
93+
return t('libresign', 'List of files. Column headers with buttons are sortable.')
8194
},
8295
},
8396
}

src/views/FilesList/VirtualList.vue

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
- SPDX-License-Identifier: AGPL-3.0-or-later
44
-->
55
<template>
6-
<div class="files-list">
6+
<div class="files-list"
7+
:class="{ 'files-list--grid': userConfigStore.grid_view }"
8+
data-cy-files-list>
79
<div class="files-list__filters">
810
<slot name="filters" />
911
</div>
@@ -12,9 +14,26 @@
1214
<slot name="header-overlay" />
1315
</div>
1416

15-
<table class="files-list__table" :class="{ 'files-list__table--with-thead-overlay': !!$scopedSlots['header-overlay'] }">
17+
<div
18+
v-if="filesStore.filesSorted().length === 0"
19+
class="files-list__empty">
20+
<slot name="empty" />
21+
</div>
22+
23+
<table
24+
:aria-hidden="filesStore.filesSorted().length === 0"
25+
class="files-list__table"
26+
:class="{
27+
'files-list__table--with-thead-overlay': !!$scopedSlots['header-overlay'],
28+
'files-list__table--hidden': filesStore.filesSorted().length === 0,
29+
}">
30+
<!-- Accessibility table caption for screen readers -->
31+
<caption v-if="caption" class="hidden-visually">
32+
{{ caption }}
33+
</caption>
34+
1635
<!-- Header -->
17-
<thead ref="thead" class="files-list__thead">
36+
<thead ref="thead" class="files-list__thead" data-cy-files-list-thead>
1837
<slot name="header" />
1938
</thead>
2039
<!-- Body -->
@@ -55,6 +74,13 @@ export default {
5574
type: Boolean,
5675
required: true,
5776
},
77+
/**
78+
* Visually hidden caption for the table accessibility
79+
*/
80+
caption: {
81+
type: String,
82+
default: '',
83+
},
5884
},
5985
setup() {
6086
const filesStore = useFilesStore()
@@ -98,3 +124,22 @@ export default {
98124
},
99125
}
100126
</script>
127+
128+
<style scoped lang="scss">
129+
.files-list {
130+
&__empty {
131+
display: flex;
132+
flex-direction: column;
133+
align-items: center;
134+
justify-content: center;
135+
height: 100%;
136+
min-height: 300px;
137+
}
138+
139+
&__table {
140+
&--hidden {
141+
display: none;
142+
}
143+
}
144+
}
145+
</style>

0 commit comments

Comments
 (0)