elk/components/publish/PublishWidget.vue

210 lines
5.8 KiB
Vue
Raw Normal View History

2022-11-21 06:55:31 +00:00
<script setup lang="ts">
2022-11-24 11:35:26 +00:00
import type { CreateStatusParams, StatusVisibility } from 'masto'
import { fileOpen } from 'browser-fs-access'
import { useDropZone } from '@vueuse/core'
2022-11-21 06:55:31 +00:00
const {
draftKey,
placeholder = 'What is on your mind?',
inReplyToId,
expanded: _expanded = false,
2022-11-21 06:55:31 +00:00
} = defineProps<{
draftKey: string
placeholder?: string
inReplyToId?: string
expanded?: boolean
2022-11-21 06:55:31 +00:00
}>()
const expanded = $ref(_expanded)
2022-11-21 06:55:31 +00:00
let isSending = $ref(false)
2022-11-24 11:35:26 +00:00
let { draft } = $(useDraft(draftKey, inReplyToId))
2022-11-24 06:54:54 +00:00
2022-11-23 17:17:54 +00:00
const status = $computed(() => {
return {
2022-11-24 06:54:54 +00:00
...draft.params,
mediaIds: draft.attachments.map(a => a.id),
2022-11-23 17:17:54 +00:00
} as CreateStatusParams
})
2022-11-24 09:15:58 +00:00
const currentVisibility = $computed(() => {
2022-11-24 13:26:33 +00:00
return STATUS_VISIBILITIES.find(v => v.value === status.visibility) || STATUS_VISIBILITIES[0]
2022-11-24 09:15:58 +00:00
})
2022-11-23 17:17:54 +00:00
let isUploading = $ref<boolean>(false)
async function handlePaste(evt: ClipboardEvent) {
const files = evt.clipboardData?.files
2022-11-24 08:20:21 +00:00
if (!files || files.length === 0)
2022-11-23 17:17:54 +00:00
return
2022-11-24 04:05:13 +00:00
evt.preventDefault()
2022-11-23 17:17:54 +00:00
await uploadAttachments(Array.from(files))
}
async function pickAttachments() {
const files = await fileOpen([
{
description: 'Attachments',
multiple: true,
mimeTypes: ['image/*'],
extensions: ['.png', '.gif', '.jpeg', '.jpg', '.webp', '.avif', '.heic', '.heif'],
},
{
description: 'Attachments',
mimeTypes: ['video/*'],
extensions: ['.webm', '.mp4', '.m4v', '.mov', '.ogv', '.3gp'],
},
{
2022-11-24 04:05:13 +00:00
description: 'Attachments',
mimeTypes: ['audio/*'],
extensions: ['.mp3', '.ogg', '.oga', '.wav', '.flac', '.opus', '.aac', '.m4a', '.3gp', '.wma'],
},
])
2022-11-23 17:17:54 +00:00
await uploadAttachments(files)
}
async function uploadAttachments(files: File[]) {
isUploading = true
for (const file of files) {
const attachment = await masto.mediaAttachments.create({
file,
})
2022-11-24 06:54:54 +00:00
draft.attachments.push(attachment)
2022-11-23 17:17:54 +00:00
}
isUploading = false
}
2022-11-24 04:05:13 +00:00
function removeAttachment(index: number) {
2022-11-24 06:54:54 +00:00
draft.attachments.splice(index, 1)
2022-11-23 17:17:54 +00:00
}
2022-11-21 06:55:31 +00:00
2022-11-24 09:15:58 +00:00
function chooseVisibility(visibility: StatusVisibility) {
draft.params.visibility = visibility
}
2022-11-21 06:55:31 +00:00
async function publish() {
try {
isSending = true
2022-11-24 11:35:26 +00:00
if (!draft.editingStatus)
await masto.statuses.create(status)
else await masto.statuses.update(draft.editingStatus.id, status)
2022-11-24 14:32:20 +00:00
draft = getDefaultDraft(inReplyToId)
2022-11-24 11:35:26 +00:00
isPublishDialogOpen.value = false
2022-11-21 06:55:31 +00:00
}
finally {
isSending = false
}
}
const dropZoneRef = ref<HTMLDivElement>()
async function onDrop(files: File[] | null) {
if (files)
await uploadAttachments(files)
}
const { isOverDropZone } = useDropZone(dropZoneRef, onDrop)
2022-11-21 06:55:31 +00:00
onUnmounted(() => {
2022-11-24 06:54:54 +00:00
if (!draft.attachments.length && !draft.params.status) {
2022-11-21 06:55:31 +00:00
nextTick(() => {
2022-11-24 06:54:54 +00:00
delete currentUserDrafts.value[draftKey]
2022-11-21 06:55:31 +00:00
})
}
})
</script>
<template>
2022-11-24 14:32:20 +00:00
<div v-if="currentUser" flex="~ col gap-1">
2022-11-24 11:35:26 +00:00
<template v-if="draft.editingStatus">
<div flex="~ col gap-1">
<div text-gray self-center>
Editing
</div>
<StatusCard :status="draft.editingStatus" :actions="false" :hover="false" />
2022-11-24 07:53:27 +00:00
</div>
2022-11-24 11:35:26 +00:00
<div border="b dashed gray/40" />
</template>
2022-11-24 14:32:20 +00:00
2022-11-24 11:35:26 +00:00
<div p4 flex gap-4>
2022-11-24 15:48:52 +00:00
<NuxtLink w-12 h-12 :to="getAccountPath(currentUser.account)">
2022-11-24 15:19:18 +00:00
<AccountAvatar :account="currentUser.account" w-12 h-12 />
</NuxtLink>
2022-11-24 11:35:26 +00:00
<div
ref="dropZoneRef"
2022-11-24 15:19:18 +00:00
flex flex-col gap-3 flex-1
2022-11-25 09:31:32 +00:00
border="2 dashed transparent" p-1
:class="[isSending ? 'pointer-events-none' : '', isOverDropZone ? '!border-primary' : '']"
2022-11-24 11:35:26 +00:00
>
<textarea
v-model="draft.params.status"
:placeholder="placeholder"
h-80px
:class="expanded ? '!h-200px' : ''"
2022-11-24 11:35:26 +00:00
p2 border-rounded w-full bg-transparent
transition="height"
2022-11-24 11:35:26 +00:00
outline-none border="~ base"
@paste="handlePaste"
@focus="expanded = true"
@keydown.esc="expanded = false"
@keydown.ctrl.enter="publish"
@keydown.meta.enter="publish"
2022-11-24 11:35:26 +00:00
/>
2022-11-24 07:53:27 +00:00
2022-11-24 11:35:26 +00:00
<div flex="~ col gap-2" max-h-50vh overflow-auto>
<PublishAttachment
v-for="(att, idx) in draft.attachments" :key="att.id"
:attachment="att"
@remove="removeAttachment(idx)"
/>
</div>
<div v-if="isUploading" flex gap-2 justify-end items-center>
<div op50 i-ri:loader-2-fill animate-spin text-2xl />
Uploading...
</div>
<div flex="~ gap-2">
2022-11-24 15:48:52 +00:00
<CommonTooltip placement="bottom" content="Add images, a video or an audio file">
<button btn-action-icon @click="pickAttachments">
<div i-ri:upload-line />
</button>
</CommonTooltip>
2022-11-24 09:15:58 +00:00
2022-11-24 13:26:33 +00:00
<div flex-auto />
2022-11-24 11:35:26 +00:00
<CommonDropdown>
2022-11-24 13:26:33 +00:00
<button btn-action-icon w-12>
2022-11-24 11:35:26 +00:00
<div :class="currentVisibility.icon" />
2022-11-24 13:26:33 +00:00
<div i-ri:arrow-down-s-line text-sm op50 mr--1 />
2022-11-24 11:35:26 +00:00
</button>
<template #popper>
<CommonDropdownItem
v-for="visibility in STATUS_VISIBILITIES"
:key="visibility.value"
:icon="visibility.icon"
:checked="visibility.value === draft.params.visibility"
@click="chooseVisibility(visibility.value)"
>
{{ visibility.label }}
<template #description>
{{ visibility.description }}
</template>
</CommonDropdownItem>
</template>
</CommonDropdown>
<button
2022-11-24 13:26:33 +00:00
btn-solid rounded-full text-sm
2022-11-24 11:35:26 +00:00
:disabled="isUploading || (draft.attachments.length === 0 && !draft.params.status)"
@click="publish"
>
{{ !draft.editingStatus ? 'Publish!' : 'Save changes' }}
</button>
</div>
2022-11-24 07:53:27 +00:00
</div>
2022-11-21 06:55:31 +00:00
</div>
</div>
</template>