Skip to content

Commit defdb46

Browse files
committed
add file list, update file input
1 parent e673720 commit defdb46

2 files changed

Lines changed: 195 additions & 3 deletions

File tree

resources/js/components/forms/FFileInput.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,19 @@
2424
class="font-mono text-[10px]"
2525
>(.{{ localFile.extension }})</span>
2626
</div>
27-
<div class="flex justify-start space-x-2">
27+
<div class="flex justify-center space-x-2">
2828
<button
2929
class="font-semibold text-left focus:outline-none"
3030
@click="$vfm.show('file-modal', {id: localFile.id})"
3131
>
3232
<PenToSquareIcon class="w-4 h-4" />
3333
</button>
3434
<button
35-
class="font-semibold focus:outline-none"
35+
class="font-medium focus:outline-none text-xs leading-none"
3636
@click="clearFile"
3737
>
38-
<XMarkIcon class="w-4 h-4" />
38+
Rensa fil
39+
<!-- <XMarkIcon class="w-4 h-4" /> -->
3940
</button>
4041
</div>
4142
</div>
@@ -159,6 +160,7 @@ export default {
159160
}
160161
const { data } = await File.show(id, payload)
161162
this.localFile = data
163+
data._id = Math.random().toString(20).substring(2, 8)
162164
this.$emit('input', data)
163165
this.emitFileSelected()
164166
this.pickerOpen = false
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
<template>
2+
<div>
3+
<div class="flex justify-between mt-2 mb-4 text-sm font-semibold">
4+
<div class="text-xl font-light">
5+
<slot />
6+
</div>
7+
<button
8+
:disabled="addLocked"
9+
:class="{'cursor-not-allowed text-neutral-400': addLocked}"
10+
class="flex items-center text-sm font-semibold focus:outline-none"
11+
type="button"
12+
@click="addFile"
13+
>
14+
<span
15+
v-if="maxItems && maxItems <= files.length"
16+
class="mr-4 text-xs italic font-normal text-neutral-400"
17+
>Du har nått det maximala antalet filer </span>
18+
<PlusIcon class="w-5 h-5 mr-2 " />Lägg till fil
19+
</button>
20+
</div>
21+
<div v-if="noFiles">
22+
<UiDashedBox size="min-h-24">
23+
<template #header>
24+
<div class="text-base">
25+
Ingen fil har lagts till ännu
26+
</div>
27+
</template>
28+
<template #link>
29+
<div class="flex justify-center">
30+
<button
31+
v-if="noFiles"
32+
class="flex items-center text-sm font-semibold focus:outline-none"
33+
type="button"
34+
@click="addFile"
35+
>
36+
<PlusIcon class="w-5 h-5 mr-2 " />Lägg till fil
37+
</button>
38+
</div>
39+
</template>
40+
</UiDashedBox>
41+
</div>
42+
<Draggable
43+
v-model="files"
44+
handle=".handle"
45+
tag="div"
46+
v-bind="dragOptions"
47+
class="list-group border rounded"
48+
:group="{ name: 'files', pull: 'clone', put: ['files'] }"
49+
@start="drag = true"
50+
@end="emitChange"
51+
>
52+
<div
53+
v-for="(file, index) in files"
54+
:key="file._id"
55+
class="flex gap-x-4 items-center px-4 py-1.5 border-b last-of-type:border-b-0"
56+
>
57+
<div class="cursor-move">
58+
<GripVerticalIcon class="block w-4 h-4 text-gray-400 handle" />
59+
</div>
60+
<FFileInput
61+
v-model="files[index]"
62+
class="flex-1 col-span-12"
63+
:placeholder="placeholder"
64+
:pages="pages"
65+
:color="color"
66+
:arrow="arrow"
67+
/>
68+
<div class="flex items-end col-span-1 spliceFile">
69+
<button
70+
type="button"
71+
class="p-4 -m-4 transition-colors duration-200 transform focus:outline-none hover:text-red-600"
72+
@click="spliceFile(index)"
73+
>
74+
<MinusIcon
75+
class="w-6 h-6"
76+
thin
77+
/>
78+
</button>
79+
</div>
80+
</div>
81+
</Draggable>
82+
</div>
83+
</template>
84+
<script>
85+
import Draggable from 'vuedraggable'
86+
87+
export default {
88+
name: 'FFileList',
89+
components: {
90+
Draggable
91+
},
92+
props: {
93+
value: {
94+
type: Array,
95+
default: () => []
96+
},
97+
options: {
98+
required: false,
99+
type: Object,
100+
default: () => ({})
101+
},
102+
maxItems: {
103+
type: Number,
104+
required: false,
105+
default: null
106+
},
107+
placeholder: {
108+
type: String,
109+
required: false,
110+
default: ''
111+
},
112+
color: {
113+
type: Boolean,
114+
default: false,
115+
},
116+
arrow: {
117+
type: Boolean,
118+
default: false,
119+
}
120+
},
121+
data () {
122+
return {
123+
files: [],
124+
defaultOptions: {
125+
newTab: false
126+
},
127+
pages: []
128+
}
129+
},
130+
computed: {
131+
noFiles () {
132+
return this.files.length === 0
133+
},
134+
mergedOptions () {
135+
return {
136+
...this.defaultOptions,
137+
...this.options
138+
}
139+
},
140+
addLocked() {
141+
return this.maxItems && this.maxItems <= this.files.length
142+
},
143+
dragOptions () {
144+
return {
145+
animation: 200,
146+
group: 'description',
147+
disabled: false,
148+
ghostClass: 'ghost'
149+
}
150+
}
151+
},
152+
created () {
153+
if (!this.value) {
154+
this.$emit('input', this.files)
155+
}
156+
this.files = this.value
157+
// Ensure existing files have unique IDs
158+
this.files.forEach(file => {
159+
if (!file._id) {
160+
file._id = Math.random().toString(20).substring(2, 8)
161+
}
162+
})
163+
},
164+
methods: {
165+
emitChange() {
166+
167+
this.$emit('input', this.files)
168+
},
169+
addFile () {
170+
this.files.push({
171+
_id: Math.random().toString(20).substring(2, 8),
172+
type:'internal',
173+
title: '',
174+
url: '',
175+
newTab: false,
176+
file: {
177+
id: null
178+
}
179+
})
180+
this.$emit('input', this.files)
181+
182+
this.fetchPages()
183+
// this.fetchTree()
184+
},
185+
spliceFile (index) {
186+
this.files.splice(index, 1)
187+
}
188+
}
189+
}
190+
</script>

0 commit comments

Comments
 (0)