adminforth 2.4.0-next.300 → 2.4.0-next.301

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.
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <!-- tag form used to reset the input (method .reset() in claer() function) -->
2
+ <!-- tag form used to reset the input (method .reset() in clear() function) -->
3
3
  <form class="flex items-center justify-center w-full"
4
4
  @dragover.prevent="dragging = true"
5
5
  @dragleave.prevent="dragging = false"
@@ -20,7 +20,7 @@
20
20
  :id="id"
21
21
  type="file"
22
22
  class="hidden"
23
- :accept="props.extensions.join(',')"
23
+ :accept="normalizedExtensions.join(',')"
24
24
  @change="$event.target && doEmit(($event.target as HTMLInputElement).files!)"
25
25
  :multiple="props.multiple || false"
26
26
  />
@@ -80,7 +80,7 @@
80
80
  </p>
81
81
 
82
82
  <p class="text-xs text-lightDropzoneText dark:text-darkDropzoneText">
83
- {{ props.extensions.join(', ').toUpperCase().replace(/\./g, '') }}
83
+ {{ normalizedExtensions.join(', ').toUpperCase().replace(/\./g, '') }}
84
84
  <template v-if="props.maxSizeBytes">
85
85
  (Max size: {{ humanifySize(props.maxSizeBytes) }})
86
86
  </template>
@@ -92,7 +92,7 @@
92
92
 
93
93
  <script setup lang="ts">
94
94
  import { humanifySize } from '@/utils';
95
- import { ref, type Ref } from 'vue';
95
+ import { ref, type Ref, computed } from 'vue';
96
96
  import { IconFileSolid } from '@iconify-prerendered/vue-flowbite';
97
97
  import { watch } from 'vue';
98
98
  import adminforth from '@/adminforth';
@@ -108,6 +108,13 @@ const emit = defineEmits(['update:modelValue']);
108
108
 
109
109
  const id = `afcl-dropzone-${Math.random().toString(36).substring(7)}`;
110
110
 
111
+ const normalizedExtensions = computed(() => {
112
+ return props.extensions.map(ext => {
113
+ const trimmed = ext.trim().toLowerCase();
114
+ return trimmed.startsWith('.') ? trimmed : `.${trimmed}`;
115
+ });
116
+ });
117
+
111
118
  const selectedFiles: Ref<{
112
119
  name: string,
113
120
  size: number,
@@ -131,7 +138,7 @@ function doEmit(filesIn: FileList) {
131
138
 
132
139
  const multiple = props.multiple || false;
133
140
  const files = Array.from(filesIn);
134
- const allowedExtensions = props.extensions.map(ext => ext.toLowerCase());
141
+ const allowedExtensions = normalizedExtensions.value;
135
142
  const maxSizeBytes = props.maxSizeBytes;
136
143
 
137
144
  if (!files.length) return;
@@ -142,6 +149,18 @@ function doEmit(filesIn: FileList) {
142
149
  const extension = file.name.split('.').pop()?.toLowerCase() || '';
143
150
  const size = file.size;
144
151
 
152
+ const isDuplicate = storedFiles.value.some(
153
+ existingFile => existingFile.name === file.name && existingFile.size === file.size
154
+ );
155
+
156
+ if (isDuplicate) {
157
+ adminforth.alert({
158
+ message: `The file "${file.name}" is already selected.`,
159
+ variant: 'warning',
160
+ });
161
+ return;
162
+ }
163
+
145
164
  if (!allowedExtensions.includes(`.${extension}`)) {
146
165
  adminforth.alert({
147
166
  message: `Sorry, the file type .${extension} is not allowed. Please upload a file with one of the following extensions: ${allowedExtensions.join(', ')}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "2.4.0-next.300",
3
+ "version": "2.4.0-next.301",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",