From 1234fb2dd1966e931d5913d60295fe2b3b4e6dc6 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Mon, 8 Apr 2024 11:53:26 +0200 Subject: [PATCH] feat: add threaded drafts & posts (#2715) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastian Di Luzio Co-authored-by: Emanuel Pina Co-authored-by: lazzzis Co-authored-by: Joaquín Sánchez Co-authored-by: TAKAHASHI Shuuji Co-authored-by: Francesco <129339155+katullo11@users.noreply.github.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: patak-dev --- components/modal/ModalContainer.vue | 2 +- components/publish/PublishThreadTools.vue | 45 ++ components/publish/PublishWidget.vue | 623 +++++++++--------- .../publish/PublishWidgetFull.client.vue | 27 +- components/publish/PublishWidgetList.vue | 49 ++ components/timeline/TimelineHome.vue | 3 +- composables/dialog.ts | 6 +- composables/masto/publish.ts | 55 +- composables/masto/statusDrafts.ts | 77 ++- composables/thread.ts | 94 +++ locales/de-DE.json | 4 + locales/en.json | 4 + pages/[[server]]/@[account]/[status].vue | 2 +- pages/compose.vue | 10 +- pages/intent/post.vue | 2 +- plugins/magic-keys.client.ts | 2 +- types/index.ts | 6 +- 17 files changed, 634 insertions(+), 377 deletions(-) create mode 100644 components/publish/PublishThreadTools.vue create mode 100644 components/publish/PublishWidgetList.vue create mode 100644 composables/thread.ts diff --git a/components/modal/ModalContainer.vue b/components/modal/ModalContainer.vue index c71eb497..1b94c4a7 100644 --- a/components/modal/ModalContainer.vue +++ b/components/modal/ModalContainer.vue @@ -67,7 +67,7 @@ function handleFavouritedBoostedByClose() { @close="handlePublishClose" > - +const props = defineProps<{ + draftKey: string + draftItemIndex: number +}>() + +const { threadIsActive, addThreadItem, threadItems, removeThreadItem } = useThreadComposer(props.draftKey) + +const isRemovableItem = computed(() => threadIsActive.value && props.draftItemIndex < threadItems.value.length - 1) + +function addOrRemoveItem() { + if (isRemovableItem.value) + removeThreadItem(props.draftItemIndex) + + else + addThreadItem() +} + +const { t } = useI18n() + +const label = computed(() => { + if (!isRemovableItem.value && props.draftItemIndex === 0) + return t('tooltip.start_thread') + + return isRemovableItem.value ? t('tooltip.remove_thread_item') : t('tooltip.add_thread_item') +}) + + + diff --git a/components/publish/PublishWidget.vue b/components/publish/PublishWidget.vue index 1280321d..70e45164 100644 --- a/components/publish/PublishWidget.vue +++ b/components/publish/PublishWidget.vue @@ -2,17 +2,19 @@ import { EditorContent } from '@tiptap/vue-3' import stringLength from 'string-length' import type { mastodon } from 'masto' -import type { Draft } from '~/types' +import type { DraftItem } from '~/types' const { draftKey, - initial = getDefaultDraft, + draftItemIndex, expanded = false, placeholder, dialogLabelledBy, + initial = getDefaultDraftItem, } = defineProps<{ - draftKey?: string - initial?: () => Draft + draftKey: string + draftItemIndex: number + initial?: () => DraftItem placeholder?: string inReplyToId?: string inReplyToVisibility?: mastodon.v1.StatusVisibility @@ -26,8 +28,17 @@ const emit = defineEmits<{ const { t } = useI18n() -const draftState = useDraft(draftKey, initial) -const { draft } = draftState +const { threadItems, threadIsActive, publishThread } = useThreadComposer(draftKey) + +const draft = computed({ + get: () => threadItems.value[draftItemIndex], + set: (updatedDraft: DraftItem) => { + threadItems.value[draftItemIndex] = updatedDraft + }, +}, +) + +const isFinalItemOfThread = computed(() => draftItemIndex === threadItems.value.length - 1) const { isExceedingAttachmentLimit, @@ -43,8 +54,8 @@ const { const { shouldExpanded, isExpanded, isSending, isPublishDisabled, publishDraft, failedMessages, preferredLanguage, publishSpoilerText } = usePublish( { - draftState, - ...{ expanded: toRef(() => expanded), isUploading, initialDraft: toRef(() => initial) }, + draftItem: draft, + ...{ expanded: toRef(() => expanded), isUploading, initialDraft: initial, isPartOfThread: false }, }, ) @@ -181,9 +192,13 @@ async function toggleSensitive() { } async function publish() { - const status = await publishDraft() - if (status) - emit('published', status) + const publishResult = await (threadIsActive.value ? publishThread() : publishDraft()) + if (publishResult) { + if (Array.isArray(publishResult)) + failedMessages.value = publishResult + else + emit('published', publishResult) + } } useWebShareTarget(async ({ data: { data, action } }: any) => { @@ -215,10 +230,6 @@ function stopQuestionMarkPropagation(e: KeyboardEvent) { if (e.key === '?') e.stopImmediatePropagation() } - -onDeactivated(() => { - clearEmptyDrafts() -}) -
- - - - -
- - - - -
- -
- - -
-
- - - - -
-
    -
  1. - {{ i + 1 }}. - {{ error }} -
  2. -
-
- -
- -
- -
-
-
-
- {{ $t('state.uploading') }} -
- -
-
- - - - -
-
- {{ $t('state.attachments_exceed_server_limit') }} -
-
    -
  1. - {{ error[1] }}: - {{ error[0] }} -
  2. -
-
- -
- +
+ + + +
+
-
-
-