diff --git a/components/publish/PublishErrMessage.vue b/components/common/CommonErrorMessage.vue similarity index 77% rename from components/publish/PublishErrMessage.vue rename to components/common/CommonErrorMessage.vue index e9ec814d2..90ac77b63 100644 --- a/components/publish/PublishErrMessage.vue +++ b/components/common/CommonErrorMessage.vue @@ -1,22 +1,18 @@ diff --git a/components/list/ListEntry.vue b/components/list/ListEntry.vue index e36e7f56f..a508fd60e 100644 --- a/components/list/ListEntry.vue +++ b/components/list/ListEntry.vue @@ -19,24 +19,28 @@ const client = useMastoClient() let isEditing = $ref(false) let busy = $ref(false) let deleteBusy = $ref(false) +let actionError = $ref(undefined) const enableSaveButton = computed(() => list.title !== modelValue.value) const edit = ref() +const deleteBtn = ref() const input = ref() const prepareEdit = () => { isEditing = true + actionError = undefined nextTick(() => { - input.value.focus() + input.value?.focus() }) } -const cancelEdit = (updateTitle = true) => { +const cancelEdit = () => { isEditing = false - if (updateTitle) - modelValue.value = list.title + actionError = undefined + modelValue.value = list.title + nextTick(() => { - edit.value.focus() + edit.value?.focus() }) } async function finishEditing() { @@ -44,14 +48,22 @@ async function finishEditing() { return busy = true + actionError = undefined await nextTick() try { const updateList = await client.v1.lists.update(list.id, { title: modelValue.value, }) - cancelEdit(false) + cancelEdit() emit('listUpdated', updateList) } + catch (err) { + console.error(err) + actionError = (err as Error).message + nextTick(() => { + input.value?.focus() + }) + } finally { busy = false } @@ -61,6 +73,7 @@ async function removeList() { return deleteBusy = true + actionError = undefined await nextTick() const confirmDelete = await openConfirmDialog({ @@ -75,6 +88,13 @@ async function removeList() { await client.v1.lists.remove(list.id) emit('listRemoved', list.id) } + catch (err) { + console.error(err) + actionError = (err as Error).message + nextTick(() => { + deleteBtn.value?.focus() + }) + } finally { deleteBusy = false } @@ -83,11 +103,27 @@ async function removeList() { deleteBusy = false } } -onBeforeUnmount(() => cancelEdit(false)) + +function clearError() { + actionError = undefined + nextTick(() => { + if (isEditing) + input.value?.focus() + else + deleteBtn.value?.focus() + }) +} + +onDeactivated(cancelEdit) - + cancelEdit(false)) type="button" rounded-full text-sm p2 transition-colors hover:text-primary - @click="cancelEdit(true)" + @click="cancelEdit()" > @@ -114,7 +150,7 @@ onBeforeUnmount(() => cancelEdit(false)) pb="1px" flex-1 placeholder-text-secondary - @keydown.esc="cancelEdit(true)" + @keydown.esc="cancelEdit()" > @@ -151,6 +187,7 @@ onBeforeUnmount(() => cancelEdit(false)) cancelEdit(false)) + + + + + {{ $t(`list.${isEditing ? 'edit_error' : 'delete_error'}`) }} + + + + + + + + + + {{ $t('list.error_prefix') }} + {{ actionError }} + + + diff --git a/components/publish/PublishWidget.vue b/components/publish/PublishWidget.vue index 685cca879..6d2b3a226 100644 --- a/components/publish/PublishWidget.vue +++ b/components/publish/PublishWidget.vue @@ -164,8 +164,8 @@ defineExpose({ > - - + + {{ $t('state.publish_failed') }} @@ -178,14 +178,14 @@ defineExpose({ - + {{ i + 1 }}. {{ error }} - + {{ $t('state.uploading') }} - - + {{ $t('state.upload_failed') }} @@ -218,7 +218,7 @@ defineExpose({ - + {{ $t('state.attachments_exceed_server_limit') }} @@ -228,7 +228,7 @@ defineExpose({ {{ error[0] }} - + (undefined) let busy = $ref(false) const createText = ref('') const enableSubmit = computed(() => createText.value.length > 0) @@ -25,24 +27,42 @@ async function createList() { return busy = true + actionError = undefined await nextTick() try { const newEntry = await client.v1.lists.create({ title: createText.value, }) - paginatorRef.value.createEntry(newEntry) + paginatorRef.value?.createEntry(newEntry) createText.value = '' } + catch (err) { + console.error(err) + actionError = (err as Error).message + nextTick(() => { + inputRef.value?.focus() + }) + } finally { busy = false } } + +function clearError(focusBtn: boolean) { + actionError = undefined + focusBtn && nextTick(() => { + inputRef.value?.focus() + }) +} + function updateEntry(list: mastodon.v1.List) { - paginatorRef.value.updateEntry(list) + paginatorRef.value?.updateEntry(list) } function removeEntry(id: string) { - paginatorRef.value.removeEntry(id) + paginatorRef.value?.removeEntry(id) } + +onDeactivated(() => clearError(false)) @@ -67,6 +87,8 @@ function removeEntry(id: string) { border="t base" p-4 w-full flex="~ wrap" relative gap-3 + :aria-describedby="actionError ? 'create-list-error' : undefined" + :class="actionError ? 'border border-base border-rounded rounded-be-is-0 rounded-be-ie-0 border-b-unset border-$c-danger-active' : null" @submit.prevent="createList" > + + + + + {{ $t('list.error') }} + + + + + + + + + + {{ $t('list.error_prefix') }} + {{ actionError }} + + +
{{ $t(`list.${isEditing ? 'edit_error' : 'delete_error'}`) }}
{{ $t('state.publish_failed') }}
{{ $t('state.upload_failed') }}
{{ $t('list.error') }}