@polymarbot/nuxt-layer-shadcn-ui 0.10.0 → 0.10.1

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,13 +1,19 @@
1
1
  {
2
2
  "drag": {
3
3
  "title": "Click or drag file to this area to upload",
4
+ "titleDirectory": "Click or drag a directory to this area to upload",
4
5
  "titleMultiple": "Click or drag files to this area to upload"
5
6
  },
6
7
  "empty": "No files",
7
8
  "error": {
9
+ "accept": "{files} is not an accepted file type ({accept}).",
8
10
  "oversize": "{files} exceeds the {size} size limit."
9
11
  },
10
12
  "hint": {
13
+ "accept": "Accepted: {types}.",
14
+ "acceptAudio": "audio",
15
+ "acceptImage": "images",
16
+ "acceptVideo": "videos",
11
17
  "max": "Up to {max} files can be selected.",
12
18
  "maxSize": "Max size per file: {size}.",
13
19
  "multiple": "Multiple files can be selected.",
@@ -103,7 +103,18 @@ export const AcceptImagesOnly: Story = {
103
103
  // --- Selection behavior (all three variants side by side) ---
104
104
 
105
105
  export const Multiple: Story = {
106
- parameters: noControls,
106
+ parameters: {
107
+ ...noControls,
108
+ docs: {
109
+ source: {
110
+ code: `
111
+ <template>
112
+ <Upload v-model:fileList="fileList" variant="drag" multiple />
113
+ </template>
114
+ `.trim(),
115
+ },
116
+ },
117
+ },
107
118
  render: () => ({
108
119
  components: { Upload },
109
120
  setup: () => ({ variants }),
@@ -116,7 +127,18 @@ export const Multiple: Story = {
116
127
  }
117
128
 
118
129
  export const MaxCount: Story = {
119
- parameters: noControls,
130
+ parameters: {
131
+ ...noControls,
132
+ docs: {
133
+ source: {
134
+ code: `
135
+ <template>
136
+ <Upload v-model:fileList="fileList" variant="drag" multiple :maxCount="3" />
137
+ </template>
138
+ `.trim(),
139
+ },
140
+ },
141
+ },
120
142
  render: () => ({
121
143
  components: { Upload },
122
144
  setup: () => ({ variants }),
@@ -129,42 +151,61 @@ export const MaxCount: Story = {
129
151
  }
130
152
 
131
153
  export const MaxSize: Story = {
132
- parameters: noControls,
154
+ parameters: {
155
+ ...noControls,
156
+ docs: {
157
+ source: {
158
+ code: `
159
+ <template>
160
+ <Upload v-model:fileList="fileList" variant="drag" multiple :maxSize="50 * 1024" />
161
+ </template>
162
+ `.trim(),
163
+ },
164
+ },
165
+ },
133
166
  render: () => ({
134
167
  components: { Upload },
135
- setup () {
136
- const errorMessage = ref('')
137
- const onError = (e: unknown) => {
138
- errorMessage.value = e instanceof Error ? e.message : String(e)
139
- }
140
- return { variants, errorMessage, onError }
141
- },
168
+ setup: () => ({ variants }),
142
169
  template: `
143
170
  <div class="max-w-2xl space-y-6">
144
- <Upload
145
- v-for="v in variants"
146
- :key="v"
147
- :variant="v"
148
- multiple
149
- :maxSize="50 * 1024"
150
- @error="onError"
151
- />
152
- <p v-if="errorMessage" class="text-sm text-danger">
153
- {{ errorMessage }}
154
- </p>
171
+ <Upload v-for="v in variants" :key="v" :variant="v" multiple :maxSize="50 * 1024" />
155
172
  </div>
156
173
  `,
157
174
  }),
158
175
  }
159
176
 
160
177
  export const Directory: Story = {
161
- parameters: noControls,
178
+ parameters: {
179
+ ...noControls,
180
+ docs: {
181
+ source: {
182
+ code: `
183
+ <template>
184
+ <Upload
185
+ v-model:fileList="fileList"
186
+ variant="button"
187
+ directory
188
+ accept="image/*"
189
+ :maxCount="5"
190
+ />
191
+ </template>
192
+ `.trim(),
193
+ },
194
+ },
195
+ },
162
196
  render: () => ({
163
197
  components: { Upload },
164
198
  setup: () => ({ variants }),
165
199
  template: `
166
200
  <div class="max-w-2xl space-y-6">
167
- <Upload v-for="v in variants" :key="v" :variant="v" directory :maxCount="5" />
201
+ <Upload
202
+ v-for="v in variants"
203
+ :key="v"
204
+ :variant="v"
205
+ directory
206
+ accept="image/*"
207
+ :maxCount="5"
208
+ />
168
209
  </div>
169
210
  `,
170
211
  }),
@@ -173,7 +214,18 @@ export const Directory: Story = {
173
214
  // --- States ---
174
215
 
175
216
  export const Disabled: Story = {
176
- parameters: noControls,
217
+ parameters: {
218
+ ...noControls,
219
+ docs: {
220
+ source: {
221
+ code: `
222
+ <template>
223
+ <Upload v-model:fileList="fileList" variant="drag" disabled multiple />
224
+ </template>
225
+ `.trim(),
226
+ },
227
+ },
228
+ },
177
229
  render: () => ({
178
230
  components: { Upload },
179
231
  setup () {
@@ -196,7 +248,18 @@ export const Disabled: Story = {
196
248
  }
197
249
 
198
250
  export const Readonly: Story = {
199
- parameters: noControls,
251
+ parameters: {
252
+ ...noControls,
253
+ docs: {
254
+ source: {
255
+ code: `
256
+ <template>
257
+ <Upload v-model:fileList="fileList" variant="drag" readonly multiple />
258
+ </template>
259
+ `.trim(),
260
+ },
261
+ },
262
+ },
200
263
  render: () => ({
201
264
  components: { Upload },
202
265
  setup () {
@@ -219,7 +282,18 @@ export const Readonly: Story = {
219
282
  }
220
283
 
221
284
  export const ReadonlyEmpty: Story = {
222
- parameters: noControls,
285
+ parameters: {
286
+ ...noControls,
287
+ docs: {
288
+ source: {
289
+ code: `
290
+ <template>
291
+ <Upload variant="drag" readonly />
292
+ </template>
293
+ `.trim(),
294
+ },
295
+ },
296
+ },
223
297
  render: () => ({
224
298
  components: { Upload },
225
299
  setup: () => ({ variants }),
@@ -358,8 +432,63 @@ async function upload (files: (File | Blob)[]) {
358
432
  }),
359
433
  }
360
434
 
435
+ export const CustomHint: Story = {
436
+ parameters: {
437
+ ...noControls,
438
+ docs: {
439
+ source: {
440
+ code: `
441
+ <template>
442
+ <Upload variant="drag" multiple accept="image/*" :maxSize="50 * 1024">
443
+ <template #hint="{ lines }">
444
+ <ul class="list-disc pl-5 text-primary inline-block text-left">
445
+ <li v-for="line in lines" :key="line">{{ line }}</li>
446
+ </ul>
447
+ </template>
448
+ </Upload>
449
+ </template>
450
+ `.trim(),
451
+ },
452
+ },
453
+ },
454
+ render: () => ({
455
+ components: { Upload },
456
+ template: `
457
+ <div class="max-w-2xl">
458
+ <Upload variant="drag" multiple accept="image/*" :maxSize="50 * 1024">
459
+ <template #hint="{ lines }">
460
+ <ul class="list-disc pl-5 text-primary inline-block text-left">
461
+ <li v-for="line in lines" :key="line">{{ line }}</li>
462
+ </ul>
463
+ </template>
464
+ </Upload>
465
+ </div>
466
+ `,
467
+ }),
468
+ }
469
+
361
470
  export const EventHandling: Story = {
362
- parameters: noControls,
471
+ parameters: {
472
+ ...noControls,
473
+ docs: {
474
+ source: {
475
+ code: `
476
+ <template>
477
+ <Upload
478
+ v-model:fileList="fileList"
479
+ variant="drag"
480
+ multiple
481
+ @update:fileList="onUpdate"
482
+ @change="onChange"
483
+ @remove="onRemove"
484
+ @preview="onPreview"
485
+ @error="onError"
486
+ />
487
+ </template>
488
+ `.trim(),
489
+ },
490
+ },
491
+ },
363
492
  render: () => ({
364
493
  components: { Upload, EventLog },
365
494
  setup: () => ({ fileList: ref<UploadFile[]>([]) }),
@@ -34,6 +34,7 @@ const inputRef = ref<HTMLInputElement | null>(null)
34
34
  const isDragOver = ref(false)
35
35
  const uploadingFiles = ref<UploadFile[]>([])
36
36
  const imageLoadErrors = ref<Set<string | number>>(new Set())
37
+ const internalError = ref('')
37
38
  const internalFileList = ref<UploadFile[]>([])
38
39
 
39
40
  const previewVisible = ref(false)
@@ -93,6 +94,24 @@ function formatBytes (bytes: number) {
93
94
 
94
95
  const maxSizeLabel = computed(() => props.maxSize ? formatBytes(props.maxSize) : '')
95
96
 
97
+ const acceptLabel = computed(() => {
98
+ if (!props.accept) return ''
99
+ return props.accept
100
+ .split(',')
101
+ .map(s => s.trim())
102
+ .filter(Boolean)
103
+ .map(s => {
104
+ if (s === 'image/*') return T('hint.acceptImage')
105
+ if (s === 'video/*') return T('hint.acceptVideo')
106
+ if (s === 'audio/*') return T('hint.acceptAudio')
107
+ if (s.startsWith('.')) return s.slice(1).toUpperCase()
108
+ if (s.endsWith('/*')) return s
109
+ if (s.includes('/')) return s.split('/')[1]!.toUpperCase()
110
+ return s
111
+ })
112
+ .join(', ')
113
+ })
114
+
96
115
  const allowMany = computed(() => props.multiple || props.directory)
97
116
 
98
117
  const hintLines = computed(() => {
@@ -100,17 +119,21 @@ const hintLines = computed(() => {
100
119
  if (!allowMany.value) lines.push(T('hint.single'))
101
120
  else if (props.maxCount) lines.push(T('hint.max', { max: props.maxCount }))
102
121
  else lines.push(T('hint.multiple'))
122
+ if (acceptLabel.value) lines.push(T('hint.accept', { types: acceptLabel.value }))
103
123
  if (maxSizeLabel.value) lines.push(T('hint.maxSize', { size: maxSizeLabel.value }))
104
124
  return lines
105
125
  })
106
126
 
107
- const dragTitleText = computed(() => {
108
- if (props.text) return props.text
109
- return allowMany.value ? T('drag.titleMultiple') : T('drag.title')
110
- })
127
+ defineSlots<{
128
+ hint?: (props: { lines: string[] }) => unknown
129
+ }>()
111
130
 
112
131
  const triggerLabel = computed(() => {
113
132
  if (props.text) return props.text
133
+ if (props.variant === 'drag') {
134
+ if (props.directory) return T('drag.titleDirectory')
135
+ return allowMany.value ? T('drag.titleMultiple') : T('drag.title')
136
+ }
114
137
  return props.directory ? T('uploadDirectory') : T('upload')
115
138
  })
116
139
 
@@ -197,12 +220,43 @@ function onImageError (file: UploadFile) {
197
220
  if (file.uid != null) imageLoadErrors.value.add(file.uid)
198
221
  }
199
222
 
223
+ // Native <input accept> only filters in the file picker; drag-drop bypasses it,
224
+ // so we mirror the same patterns in JS for both paths.
225
+ function matchesAccept (file: File, accept: string) {
226
+ const patterns = accept.split(',').map(s => s.trim()).filter(Boolean)
227
+ if (!patterns.length) return true
228
+ const name = file.name.toLowerCase()
229
+ const type = file.type.toLowerCase()
230
+ return patterns.some(raw => {
231
+ const p = raw.toLowerCase()
232
+ if (p.startsWith('.')) return name.endsWith(p)
233
+ if (p.endsWith('/*')) return type.startsWith(p.slice(0, -1))
234
+ return type === p
235
+ })
236
+ }
237
+
238
+ function reportError (err: Error) {
239
+ internalError.value = err.message
240
+ emit('error', err)
241
+ }
242
+
200
243
  async function processFiles (files: File[]) {
201
244
  if (!files.length) return
245
+ internalError.value = ''
202
246
 
203
247
  let candidates = files
204
248
  if (!allowMany.value && candidates.length > 1) candidates = [ candidates[0]! ]
205
249
 
250
+ if (props.accept) {
251
+ const accept = props.accept
252
+ const rejected = candidates.filter(f => !matchesAccept(f, accept))
253
+ if (rejected.length) {
254
+ const names = rejected.map(f => f.name).join(', ')
255
+ reportError(new Error(T('error.accept', { files: names, accept: acceptLabel.value })))
256
+ candidates = candidates.filter(f => matchesAccept(f, accept))
257
+ }
258
+ }
259
+
206
260
  if (props.maxCount) {
207
261
  const remaining = props.maxCount - displayList.value.length
208
262
  if (remaining <= 0) return
@@ -214,7 +268,7 @@ async function processFiles (files: File[]) {
214
268
  const oversize = candidates.filter(f => f.size > limit)
215
269
  if (oversize.length) {
216
270
  const names = oversize.map(f => f.name).join(', ')
217
- emit('error', new Error(T('error.oversize', { files: names, size: formatBytes(limit) })))
271
+ reportError(new Error(T('error.oversize', { files: names, size: formatBytes(limit) })))
218
272
  candidates = candidates.filter(f => f.size <= limit)
219
273
  }
220
274
  }
@@ -266,7 +320,7 @@ async function processFiles (files: File[]) {
266
320
  finishUpload(entries, true)
267
321
  } catch (err) {
268
322
  finishUpload(entries, false)
269
- emit('error', err)
323
+ reportError(err instanceof Error ? err : new Error(String(err)))
270
324
  }
271
325
  }
272
326
 
@@ -326,10 +380,48 @@ function onDragLeave (e: DragEvent) {
326
380
  e.preventDefault()
327
381
  isDragOver.value = false
328
382
  }
329
- function onDrop (e: DragEvent) {
383
+
384
+ // Recursively read a FileSystemEntry into a flat File[] so dropped directories
385
+ // expand to their contents. readEntries returns at most ~100 children per call
386
+ // and must be looped until it yields an empty batch.
387
+ async function readEntry (entry: FileSystemEntry): Promise<File[]> {
388
+ if (entry.isFile) {
389
+ return new Promise(resolve => {
390
+ (entry as FileSystemFileEntry).file(f => resolve([ f ]), () => resolve([]))
391
+ })
392
+ }
393
+ if (entry.isDirectory) {
394
+ const reader = (entry as FileSystemDirectoryEntry).createReader()
395
+ const children: FileSystemEntry[] = []
396
+ while (true) {
397
+ const batch = await new Promise<FileSystemEntry[]>(resolve => {
398
+ reader.readEntries(entries => resolve(entries), () => resolve([]))
399
+ })
400
+ if (!batch.length) break
401
+ children.push(...batch)
402
+ }
403
+ const nested = await Promise.all(children.map(readEntry))
404
+ return nested.flat()
405
+ }
406
+ return []
407
+ }
408
+
409
+ async function onDrop (e: DragEvent) {
330
410
  e.preventDefault()
331
411
  isDragOver.value = false
332
412
  if (!canPickMore.value) return
413
+
414
+ const items = e.dataTransfer?.items
415
+ if (items?.length && typeof items[0]?.webkitGetAsEntry === 'function') {
416
+ const entries = Array.from(items)
417
+ .map(item => item.webkitGetAsEntry())
418
+ .filter((entry): entry is FileSystemEntry => !!entry)
419
+ const nested = await Promise.all(entries.map(readEntry))
420
+ const files = nested.flat()
421
+ if (files.length) processFiles(files)
422
+ return
423
+ }
424
+
333
425
  const files = e.dataTransfer?.files
334
426
  if (files?.length) processFiles(Array.from(files))
335
427
  }
@@ -363,12 +455,17 @@ function onDrop (e: DragEvent) {
363
455
  {{ triggerLabel }}
364
456
  </Button>
365
457
  <div class="text-xs text-muted-foreground py-1.5">
366
- <div
367
- v-for="line in hintLines"
368
- :key="line"
458
+ <slot
459
+ name="hint"
460
+ :lines="hintLines"
369
461
  >
370
- {{ line }}
371
- </div>
462
+ <div
463
+ v-for="line in hintLines"
464
+ :key="line"
465
+ >
466
+ {{ line }}
467
+ </div>
468
+ </slot>
372
469
  </div>
373
470
  </div>
374
471
 
@@ -389,15 +486,20 @@ function onDrop (e: DragEvent) {
389
486
  :class="isInvalid && 'text-danger'"
390
487
  />
391
488
  <div class="text-foreground font-medium">
392
- {{ dragTitleText }}
489
+ {{ triggerLabel }}
393
490
  </div>
394
491
  <div class="text-xs text-muted-foreground">
395
- <div
396
- v-for="line in hintLines"
397
- :key="line"
492
+ <slot
493
+ name="hint"
494
+ :lines="hintLines"
398
495
  >
399
- {{ line }}
400
- </div>
496
+ <div
497
+ v-for="line in hintLines"
498
+ :key="line"
499
+ >
500
+ {{ line }}
501
+ </div>
502
+ </slot>
401
503
  </div>
402
504
  </div>
403
505
 
@@ -557,15 +659,27 @@ function onDrop (e: DragEvent) {
557
659
  v-if="showTrigger"
558
660
  class="mt-2 text-xs text-muted-foreground"
559
661
  >
560
- <div
561
- v-for="line in hintLines"
562
- :key="line"
662
+ <slot
663
+ name="hint"
664
+ :lines="hintLines"
563
665
  >
564
- {{ line }}
565
- </div>
666
+ <div
667
+ v-for="line in hintLines"
668
+ :key="line"
669
+ >
670
+ {{ line }}
671
+ </div>
672
+ </slot>
566
673
  </div>
567
674
  </template>
568
675
 
676
+ <p
677
+ v-if="internalError"
678
+ class="mt-2 text-sm text-danger"
679
+ >
680
+ {{ internalError }}
681
+ </p>
682
+
569
683
  <!-- Image preview modal (box variant only) -->
570
684
  <Modal
571
685
  v-if="variant === 'box'"
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "انقر أو اسحب الملف إلى هذه المنطقة للتحميل",
84
+ "titleDirectory": "انقر أو اسحب مجلداً إلى هذه المنطقة للتحميل",
84
85
  "titleMultiple": "انقر أو اسحب الملفات إلى هذه المنطقة للتحميل"
85
86
  },
86
87
  "empty": "لا توجد ملفات",
87
88
  "error": {
89
+ "accept": "{files} ليس نوع ملف مقبول ({accept}).",
88
90
  "oversize": "{files} يتجاوز حد الحجم {size}."
89
91
  },
90
92
  "hint": {
93
+ "accept": "مقبول: {types}.",
94
+ "acceptAudio": "صوت",
95
+ "acceptImage": "صور",
96
+ "acceptVideo": "فيديوهات",
91
97
  "max": "يمكن تحديد {max} ملفات بحد أقصى.",
92
98
  "maxSize": "الحد الأقصى للحجم لكل ملف: {size}.",
93
99
  "multiple": "يمكن تحديد ملفات متعددة.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Klicken oder ziehen Sie eine Datei in diesen Bereich, um sie hochzuladen",
84
+ "titleDirectory": "Klicken oder ziehen Sie ein Verzeichnis in diesen Bereich, um es hochzuladen",
84
85
  "titleMultiple": "Klicken oder ziehen Sie Dateien in diesen Bereich, um sie hochzuladen"
85
86
  },
86
87
  "empty": "Keine Dateien",
87
88
  "error": {
89
+ "accept": "{files} ist kein akzeptierter Dateityp ({accept}).",
88
90
  "oversize": "{files} überschreitet das {size} Größenlimit."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Akzeptiert: {types}.",
94
+ "acceptAudio": "Audio",
95
+ "acceptImage": "Bilder",
96
+ "acceptVideo": "Videos",
91
97
  "max": "Es können bis zu {max} Dateien ausgewählt werden.",
92
98
  "maxSize": "Maximale Dateigröße: {size}.",
93
99
  "multiple": "Es können mehrere Dateien ausgewählt werden.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Click or drag file to this area to upload",
84
+ "titleDirectory": "Click or drag a directory to this area to upload",
84
85
  "titleMultiple": "Click or drag files to this area to upload"
85
86
  },
86
87
  "empty": "No files",
87
88
  "error": {
89
+ "accept": "{files} is not an accepted file type ({accept}).",
88
90
  "oversize": "{files} exceeds the {size} size limit."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Accepted: {types}.",
94
+ "acceptAudio": "audio",
95
+ "acceptImage": "images",
96
+ "acceptVideo": "videos",
91
97
  "max": "Up to {max} files can be selected.",
92
98
  "maxSize": "Max size per file: {size}.",
93
99
  "multiple": "Multiple files can be selected.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Haz clic o arrastra un archivo a esta área para subir",
84
+ "titleDirectory": "Haz clic o arrastra una carpeta a esta área para subir",
84
85
  "titleMultiple": "Haz clic o arrastra archivos a esta área para subir"
85
86
  },
86
87
  "empty": "Sin archivos",
87
88
  "error": {
89
+ "accept": "{files} no es un tipo de archivo aceptado ({accept}).",
88
90
  "oversize": "{files} excede el límite de tamaño de {size}."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Aceptado: {types}.",
94
+ "acceptAudio": "audio",
95
+ "acceptImage": "imágenes",
96
+ "acceptVideo": "vídeos",
91
97
  "max": "Se pueden seleccionar hasta {max} archivos.",
92
98
  "maxSize": "Tamaño máximo por archivo: {size}.",
93
99
  "multiple": "Se pueden seleccionar varios archivos.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Cliquez ou glissez un fichier dans cette zone pour télécharger",
84
+ "titleDirectory": "Cliquez ou glissez un répertoire dans cette zone pour télécharger",
84
85
  "titleMultiple": "Cliquez ou glissez des fichiers dans cette zone pour télécharger"
85
86
  },
86
87
  "empty": "Aucun fichier",
87
88
  "error": {
89
+ "accept": "{files} n'est pas un type de fichier accepté ({accept}).",
88
90
  "oversize": "{files} dépasse la limite de taille {size}."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Accepté : {types}.",
94
+ "acceptAudio": "audio",
95
+ "acceptImage": "images",
96
+ "acceptVideo": "vidéos",
91
97
  "max": "Jusqu'à {max} fichiers peuvent être sélectionnés.",
92
98
  "maxSize": "Taille maximale par fichier : {size}.",
93
99
  "multiple": "Plusieurs fichiers peuvent être sélectionnés.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "इस क्षेत्र में फ़ाइल को क्लिक करें या खींचें और अपलोड करें",
84
+ "titleDirectory": "इस क्षेत्र में निर्देशिका को क्लिक करें या खींचें और अपलोड करें",
84
85
  "titleMultiple": "इस क्षेत्र में फ़ाइलों को क्लिक करें या खींचें और अपलोड करें"
85
86
  },
86
87
  "empty": "कोई फ़ाइल नहीं",
87
88
  "error": {
89
+ "accept": "{files} स्वीकृत फ़ाइल प्रकार नहीं है ({accept}).",
88
90
  "oversize": "{files} {size} आकार सीमा से अधिक है।"
89
91
  },
90
92
  "hint": {
93
+ "accept": "स्वीकृत: {types}।",
94
+ "acceptAudio": "ऑडियो",
95
+ "acceptImage": "छवियाँ",
96
+ "acceptVideo": "वीडियो",
91
97
  "max": "{max} तक फ़ाइलों का चयन किया जा सकता है।",
92
98
  "maxSize": "प्रति फ़ाइल अधिकतम आकार: {size}।",
93
99
  "multiple": "एकाधिक फ़ाइलों का चयन किया जा सकता है।",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Klik atau seret file ke area ini untuk mengunggah",
84
+ "titleDirectory": "Klik atau seret direktori ke area ini untuk mengunggah",
84
85
  "titleMultiple": "Klik atau seret file ke area ini untuk mengunggah"
85
86
  },
86
87
  "empty": "Tidak ada file",
87
88
  "error": {
89
+ "accept": "{files} bukan tipe file yang didukung ({accept}).",
88
90
  "oversize": "{files} melebihi batas ukuran {size}."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Diterima: {types}.",
94
+ "acceptAudio": "audio",
95
+ "acceptImage": "gambar",
96
+ "acceptVideo": "video",
91
97
  "max": "Hingga {max} file dapat dipilih.",
92
98
  "maxSize": "Ukuran maksimal per file: {size}.",
93
99
  "multiple": "Beberapa file dapat dipilih.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Fai clic o trascina il file in quest'area per caricarlo",
84
+ "titleDirectory": "Fai clic o trascina una cartella in quest'area per caricarla",
84
85
  "titleMultiple": "Fai clic o trascina i file in quest'area per caricarli"
85
86
  },
86
87
  "empty": "Nessun file",
87
88
  "error": {
89
+ "accept": "{files} non è un tipo di file accettato ({accept}).",
88
90
  "oversize": "{files} supera il limite di dimensione {size}."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Accettato: {types}.",
94
+ "acceptAudio": "audio",
95
+ "acceptImage": "immagini",
96
+ "acceptVideo": "video",
91
97
  "max": "Possono essere selezionati fino a {max} file.",
92
98
  "maxSize": "Dimensione massima per file: {size}.",
93
99
  "multiple": "Possono essere selezionati più file.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "ファイルをクリックまたはドラッグしてこのエリアにアップロード",
84
+ "titleDirectory": "ディレクトリをクリックまたはドラッグしてこのエリアにアップロード",
84
85
  "titleMultiple": "ファイルをクリックまたはドラッグしてこのエリアにアップロード"
85
86
  },
86
87
  "empty": "ファイルなし",
87
88
  "error": {
89
+ "accept": "{files} は受け入れられていないファイル形式です ({accept})。",
88
90
  "oversize": "{files} は {size} のサイズ制限を超えています。"
89
91
  },
90
92
  "hint": {
93
+ "accept": "対応形式: {types}。",
94
+ "acceptAudio": "オーディオ",
95
+ "acceptImage": "画像",
96
+ "acceptVideo": "動画",
91
97
  "max": "最大 {max} 個のファイルを選択できます。",
92
98
  "maxSize": "ファイルあたりの最大サイズ: {size}。",
93
99
  "multiple": "複数のファイルを選択できます。",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "이 영역에 파일을 클릭하거나 드래그하여 업로드하세요",
84
+ "titleDirectory": "이 영역에 디렉토리를 클릭하거나 드래그하여 업로드하세요",
84
85
  "titleMultiple": "이 영역에 파일들을 클릭하거나 드래그하여 업로드하세요"
85
86
  },
86
87
  "empty": "파일 없음",
87
88
  "error": {
89
+ "accept": "{files}는 허용되지 않는 파일 형식입니다({accept}).",
88
90
  "oversize": "{files}는 {size} 크기 제한을 초과합니다."
89
91
  },
90
92
  "hint": {
93
+ "accept": "허용됨: {types}.",
94
+ "acceptAudio": "오디오",
95
+ "acceptImage": "이미지",
96
+ "acceptVideo": "비디오",
91
97
  "max": "최대 {max}개의 파일을 선택할 수 있습니다.",
92
98
  "maxSize": "파일당 최대 크기: {size}.",
93
99
  "multiple": "여러 파일을 선택할 수 있습니다.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Klik of sleep bestand naar dit gebied om te uploaden",
84
+ "titleDirectory": "Klik of sleep een map naar dit gebied om te uploaden",
84
85
  "titleMultiple": "Klik of sleep bestanden naar dit gebied om te uploaden"
85
86
  },
86
87
  "empty": "Geen bestanden",
87
88
  "error": {
89
+ "accept": "{files} is geen geaccepteerd bestandstype ({accept}).",
88
90
  "oversize": "{files} overschrijdt de limiet van {size}."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Geaccepteerd: {types}.",
94
+ "acceptAudio": "audio",
95
+ "acceptImage": "afbeeldingen",
96
+ "acceptVideo": "video's",
91
97
  "max": "U kunt tot {max} bestanden selecteren.",
92
98
  "maxSize": "Maximale grootte per bestand: {size}.",
93
99
  "multiple": "Meerdere bestanden kunnen worden geselecteerd.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Kliknij lub przeciągnij plik do tego obszaru, aby przesłać",
84
+ "titleDirectory": "Kliknij lub przeciągnij katalog do tego obszaru, aby przesłać",
84
85
  "titleMultiple": "Kliknij lub przeciągnij pliki do tego obszaru, aby przesłać"
85
86
  },
86
87
  "empty": "Brak plików",
87
88
  "error": {
89
+ "accept": "{files} nie jest akceptowanym typem pliku ({accept}).",
88
90
  "oversize": "{files} przekracza limit wielkości {size}."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Zaakceptowano: {types}.",
94
+ "acceptAudio": "audio",
95
+ "acceptImage": "obrazy",
96
+ "acceptVideo": "wideo",
91
97
  "max": "Można wybrać do {max} plików.",
92
98
  "maxSize": "Maksymalna wielkość pliku: {size}.",
93
99
  "multiple": "Można wybrać wiele plików.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Clique ou arraste um arquivo para esta área para fazer upload",
84
+ "titleDirectory": "Clique ou arraste um diretório para esta área para fazer upload",
84
85
  "titleMultiple": "Clique ou arraste arquivos para esta área para fazer upload"
85
86
  },
86
87
  "empty": "Sem arquivos",
87
88
  "error": {
89
+ "accept": "{files} não é um tipo de arquivo aceito ({accept}).",
88
90
  "oversize": "{files} ultrapassa o limite de tamanho de {size}."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Aceitos: {types}.",
94
+ "acceptAudio": "áudio",
95
+ "acceptImage": "imagens",
96
+ "acceptVideo": "vídeos",
91
97
  "max": "Até {max} arquivos podem ser selecionados.",
92
98
  "maxSize": "Tamanho máximo por arquivo: {size}.",
93
99
  "multiple": "Vários arquivos podem ser selecionados.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Нажмите или перетащите файл в эту область для загрузки",
84
+ "titleDirectory": "Нажмите или перетащите папку в эту область для загрузки",
84
85
  "titleMultiple": "Нажмите или перетащите файлы в эту область для загрузки"
85
86
  },
86
87
  "empty": "Нет файлов",
87
88
  "error": {
89
+ "accept": "{files} не является приемлемым типом файла ({accept}).",
88
90
  "oversize": "{files} превышает лимит размера {size}."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Принято: {types}.",
94
+ "acceptAudio": "аудио",
95
+ "acceptImage": "изображения",
96
+ "acceptVideo": "видео",
91
97
  "max": "Можно выбрать до {max} файлов.",
92
98
  "maxSize": "Максимальный размер файла: {size}.",
93
99
  "multiple": "Можно выбрать несколько файлов.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "คลิกหรือลากไฟล์ไปยังพื้นที่นี้เพื่ออัปโหลด",
84
+ "titleDirectory": "คลิกหรือลากโฟลเดอร์ไปยังพื้นที่นี้เพื่ออัปโหลด",
84
85
  "titleMultiple": "คลิกหรือลากไฟล์ไปยังพื้นที่นี้เพื่ออัปโหลด"
85
86
  },
86
87
  "empty": "ไม่มีไฟล์",
87
88
  "error": {
89
+ "accept": "{files} ไม่ใช่ประเภทไฟล์ที่ยอมรับได้ ({accept})",
88
90
  "oversize": "{files} เกินขีด จำกัด ขนาด {size}"
89
91
  },
90
92
  "hint": {
93
+ "accept": "ยอมรับ: {types}.",
94
+ "acceptAudio": "เสียง",
95
+ "acceptImage": "รูปภาพ",
96
+ "acceptVideo": "วิดีโอ",
91
97
  "max": "สามารถเลือกได้ถึง {max} ไฟล์",
92
98
  "maxSize": "ขนาดสูงสุดต่อไฟล์: {size}",
93
99
  "multiple": "สามารถเลือกไฟล์หลายไฟล์ได้",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Bu alana dosya gömmek veya sürüklemek için tıklayın",
84
+ "titleDirectory": "Bu alana bir dizin sürüklemek veya tıklamak için yükleyin",
84
85
  "titleMultiple": "Bu alana dosyaları gömmek veya sürüklemek için tıklayın"
85
86
  },
86
87
  "empty": "Dosya yok",
87
88
  "error": {
89
+ "accept": "{files} kabul edilen bir dosya türü değildir ({accept}).",
88
90
  "oversize": "{files} {size} boyutu sınırını aşıyor."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Kabul edilen: {types}.",
94
+ "acceptAudio": "ses",
95
+ "acceptImage": "görseller",
96
+ "acceptVideo": "videolar",
91
97
  "max": "{max}'a kadar dosya seçilebilir.",
92
98
  "maxSize": "Dosya başına max boyut: {size}.",
93
99
  "multiple": "Birden çok dosya seçilebilir.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "Nhấp hoặc kéo tệp vào khu vực này để tải lên",
84
+ "titleDirectory": "Nhấp hoặc kéo một thư mục vào khu vực này để tải lên",
84
85
  "titleMultiple": "Nhấp hoặc kéo các tệp vào khu vực này để tải lên"
85
86
  },
86
87
  "empty": "Không có tệp",
87
88
  "error": {
89
+ "accept": "{files} không phải là một loại tệp được chấp nhận ({accept}).",
88
90
  "oversize": "{files} vượt quá giới hạn kích thước {size}."
89
91
  },
90
92
  "hint": {
93
+ "accept": "Chấp nhận: {types}.",
94
+ "acceptAudio": "âm thanh",
95
+ "acceptImage": "hình ảnh",
96
+ "acceptVideo": "video",
91
97
  "max": "Có thể chọn tối đa {max} tệp.",
92
98
  "maxSize": "Kích thước tối đa cho mỗi tệp: {size}.",
93
99
  "multiple": "Có thể chọn nhiều tệp.",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "点击或拖动文件到此区域上传",
84
+ "titleDirectory": "点击或拖动目录到此区域上传",
84
85
  "titleMultiple": "点击或拖动文件到此区域上传"
85
86
  },
86
87
  "empty": "无文件",
87
88
  "error": {
89
+ "accept": "{files} 不是支持的文件类型 ({accept})。",
88
90
  "oversize": "{files} 超过 {size} 大小限制。"
89
91
  },
90
92
  "hint": {
93
+ "accept": "支持的格式:{types}。",
94
+ "acceptAudio": "音频",
95
+ "acceptImage": "图片",
96
+ "acceptVideo": "视频",
91
97
  "max": "最多可选择 {max} 个文件。",
92
98
  "maxSize": "单个文件最大大小:{size}。",
93
99
  "multiple": "可以选择多个文件。",
@@ -81,13 +81,19 @@
81
81
  "Upload": {
82
82
  "drag": {
83
83
  "title": "在此點擊或拖曳檔案以上傳",
84
+ "titleDirectory": "在此點擊或拖曳資料夾以上傳",
84
85
  "titleMultiple": "在此點擊或拖曳檔案以上傳"
85
86
  },
86
87
  "empty": "無檔案",
87
88
  "error": {
89
+ "accept": "{files} 不是可接受的檔案類型({accept})。",
88
90
  "oversize": "{files} 超過 {size} 的大小限制。"
89
91
  },
90
92
  "hint": {
93
+ "accept": "接受:{types}。",
94
+ "acceptAudio": "音訊",
95
+ "acceptImage": "圖片",
96
+ "acceptVideo": "影片",
91
97
  "max": "最多可選擇 {max} 個檔案。",
92
98
  "maxSize": "每個檔案的最大大小:{size}。",
93
99
  "multiple": "可選擇多個檔案。",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymarbot/nuxt-layer-shadcn-ui",
3
- "version": "0.10.0",
3
+ "version": "0.10.1",
4
4
  "description": "Nuxt layer providing shadcn-vue based UI components",
5
5
  "type": "module",
6
6
  "main": "./nuxt.config.ts",
@@ -42,5 +42,5 @@
42
42
  "vue-i18n": "^11",
43
43
  "vue-router": "^4 || ^5"
44
44
  },
45
- "gitHead": "87dafc13dde0f3841ebfd7c4028b78499507c83d"
45
+ "gitHead": "d2dff840130e925b9459c2df9dd60b7b7b548bfb"
46
46
  }