1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<NcEmptyContent class="file-drop-empty-content"
data-cy-files-sharing-file-drop
:name="name">
<template #icon>
<NcIconSvgWrapper :svg="svgCloudUpload" />
</template>
<template #description>
<p>
{{ shareNote || t('files_sharing', 'Upload files to {foldername}.', { foldername }) }}
</p>
<p v-if="disclaimer">
{{ t('files_sharing', 'By uploading files, you agree to the terms of service.') }}
</p>
<NcNoteCard v-if="getSortedUploads().length"
class="file-drop-empty-content__note-card"
type="success">
<h2 id="file-drop-empty-content__heading">
{{ t('files_sharing', 'Successfully uploaded files') }}
</h2>
<ul aria-labelledby="file-drop-empty-content__heading" class="file-drop-empty-content__list">
<li v-for="file in getSortedUploads()" :key="file">
{{ file }}
</li>
</ul>
</NcNoteCard>
</template>
<template #action>
<template v-if="disclaimer">
<!-- Terms of service if enabled -->
<NcButton type="primary" @click="showDialog = true">
{{ t('files_sharing', 'View terms of service') }}
</NcButton>
<NcDialog close-on-click-outside
content-classes="terms-of-service-dialog"
:open.sync="showDialog"
:name="t('files_sharing', 'Terms of service')"
:message="disclaimer" />
</template>
<UploadPicker allow-folders
:content="() => []"
no-menu
:destination="uploadDestination"
multiple />
</template>
</NcEmptyContent>
</template>
<script lang="ts">
/* eslint-disable import/first */
// We need this on module level rather than on the instance as view will be refreshed by the files app after uploading
const uploads = new Set<string>()
</script>
<script setup lang="ts">
import { loadState } from '@nextcloud/initial-state'
import { translate as t } from '@nextcloud/l10n'
import { getUploader, UploadPicker, UploadStatus } from '@nextcloud/upload'
import { ref } from 'vue'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcDialog from '@nextcloud/vue/components/NcDialog'
import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
import svgCloudUpload from '@mdi/svg/svg/cloud-upload.svg?raw'
defineProps<{
foldername: string
}>()
const disclaimer = loadState<string>('files_sharing', 'disclaimer', '')
const shareLabel = loadState<string>('files_sharing', 'label', '')
const shareNote = loadState<string>('files_sharing', 'note', '')
const name = shareLabel || t('files_sharing', 'File drop')
const showDialog = ref(false)
const uploadDestination = getUploader().destination
getUploader()
.addNotifier((upload) => {
if (upload.status === UploadStatus.FINISHED && upload.file.name) {
// if a upload is finished and is not a meta upload (name is set)
// then we add the upload to the list of finished uploads to be shown to the user
uploads.add(upload.file.name)
}
})
/**
* Get the previous uploads as sorted list
*/
function getSortedUploads() {
return [...uploads].sort((a, b) => a.localeCompare(b))
}
</script>
<style scoped lang="scss">
.file-drop-empty-content {
margin: auto;
max-width: max(50vw, 300px);
.file-drop-empty-content__note-card {
width: fit-content;
margin-inline: auto;
}
#file-drop-empty-content__heading {
margin-block: 0 10px;
font-weight: bold;
font-size: 20px;
}
.file-drop-empty-content__list {
list-style: inside;
max-height: min(350px, 33vh);
overflow-y: scroll;
padding-inline-end: calc(2 * var(--default-grid-baseline));
}
:deep(.terms-of-service-dialog) {
min-height: min(100px, 20vh);
}
/* TODO fix in library */
:deep(.empty-content__action) {
display: flex;
gap: var(--default-grid-baseline);
}
}
</style>
|