♻️ Interactive v2 #1
| @@ -28,6 +28,7 @@ | |||||||
|             label="Content" |             label="Content" | ||||||
|             hint="The content supports markdown syntax" |             hint="The content supports markdown syntax" | ||||||
|             v-model="data.content" |             v-model="data.content" | ||||||
|  |             @paste="pasteMedia" | ||||||
|           /> |           /> | ||||||
|  |  | ||||||
|           <v-expansion-panels> |           <v-expansion-panels> | ||||||
| @@ -73,9 +74,7 @@ | |||||||
|                 <div class="flex justify-between items-center"> |                 <div class="flex justify-between items-center"> | ||||||
|                   <div> |                   <div> | ||||||
|                     <p class="text-xs">This article attached</p> |                     <p class="text-xs">This article attached</p> | ||||||
|                     <p class="text-lg font-medium"> |                     <p class="text-lg font-medium">{{ data.attachments.length }} attachment(s)</p> | ||||||
|                       {{ data.attachments.length }} attachment(s) |  | ||||||
|                     </p> |  | ||||||
|                   </div> |                   </div> | ||||||
|                   <v-btn size="small" icon="mdi-camera-plus" variant="text" @click="dialogs.media = true" /> |                   <v-btn size="small" icon="mdi-camera-plus" variant="text" @click="dialogs.media = true" /> | ||||||
|                 </div> |                 </div> | ||||||
| @@ -88,7 +87,7 @@ | |||||||
|   </v-card> |   </v-card> | ||||||
|  |  | ||||||
|   <planned-publish v-model:show="dialogs.plan" v-model:value="data.publishedAt" /> |   <planned-publish v-model:show="dialogs.plan" v-model:value="data.publishedAt" /> | ||||||
|   <media v-model:show="dialogs.media" v-model:uploading="uploading" v-model:value="data.attachments" /> |   <media ref="media" v-model:show="dialogs.media" v-model:uploading="uploading" v-model:value="data.attachments" /> | ||||||
|  |  | ||||||
|   <v-snackbar v-model="success" :timeout="3000">Your article has been published.</v-snackbar> |   <v-snackbar v-model="success" :timeout="3000">Your article has been published.</v-snackbar> | ||||||
|   <v-snackbar v-model="uploading" :timeout="-1"> |   <v-snackbar v-model="uploading" :timeout="-1"> | ||||||
| @@ -158,6 +157,22 @@ async function postArticle(evt: SubmitEvent) { | |||||||
|   } |   } | ||||||
|   loading.value = false |   loading.value = false | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const media = ref<any>(null) | ||||||
|  |  | ||||||
|  | function pasteMedia(evt: ClipboardEvent) { | ||||||
|  |   const files = evt.clipboardData?.files | ||||||
|  |   if (files) { | ||||||
|  |     Array.from(files).forEach((item) => { | ||||||
|  |       media.value.upload(item).then((meta: any) => { | ||||||
|  |         if (meta) { | ||||||
|  |           data.content += `\n` | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }) | ||||||
|  |     evt.preventDefault() | ||||||
|  |   } | ||||||
|  | } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style scoped> | <style scoped> | ||||||
|   | |||||||
| @@ -117,3 +117,13 @@ async function postMoment(evt: SubmitEvent) { | |||||||
|   loading.value = false |   loading.value = false | ||||||
| } | } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
|  | <style> | ||||||
|  | .snackbar-progress { | ||||||
|  |   margin-left: -16px; | ||||||
|  |   margin-right: -16px; | ||||||
|  |   margin-bottom: -14px; | ||||||
|  |   margin-top: 12px; | ||||||
|  |   width: calc(100% + 64px); | ||||||
|  | } | ||||||
|  | </style> | ||||||
| @@ -22,9 +22,7 @@ | |||||||
|         <v-card variant="tonal"> |         <v-card variant="tonal"> | ||||||
|           <v-list> |           <v-list> | ||||||
|             <v-list-item v-for="item in props.value" :title="getFileName(item)"> |             <v-list-item v-for="item in props.value" :title="getFileName(item)"> | ||||||
|               <template #subtitle> |               <template #subtitle> {{ getFileType(item) }} · {{ formatBytes(item.filesize) }} </template> | ||||||
|                 {{ getFileType(item) }} · {{ formatBytes(item.filesize) }} |  | ||||||
|               </template> |  | ||||||
|               <template #append> |               <template #append> | ||||||
|                 <v-btn icon="mdi-delete" size="small" variant="text" color="error" /> |                 <v-btn icon="mdi-delete" size="small" variant="text" color="error" /> | ||||||
|               </template> |               </template> | ||||||
| @@ -68,16 +66,20 @@ async function upload(file?: any) { | |||||||
|     headers: { Authorization: `Bearer ${getAtk()}` }, |     headers: { Authorization: `Bearer ${getAtk()}` }, | ||||||
|     body: data |     body: data | ||||||
|   }) |   }) | ||||||
|  |   let meta: any; | ||||||
|   if (res.status !== 200) { |   if (res.status !== 200) { | ||||||
|     error.value = await res.text() |     error.value = await res.text() | ||||||
|   } else { |   } else { | ||||||
|     const data = await res.json() |     meta = await res.json() | ||||||
|     emits("update:value", props.value.concat([data.info])) |     emits("update:value", props.value.concat([meta.info])) | ||||||
|     picked.value = [] |     picked.value = [] | ||||||
|   } |   } | ||||||
|   emits("update:uploading", false) |   emits("update:uploading", false) | ||||||
|  |   return meta | ||||||
| } | } | ||||||
|  |  | ||||||
|  | defineExpose({ upload }) | ||||||
|  |  | ||||||
| function getFileName(item: any) { | function getFileName(item: any) { | ||||||
|   return item.filename.replace(/\.[^/.]+$/, "") |   return item.filename.replace(/\.[^/.]+$/, "") | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user