diff --git a/components/modal/ModalConfirm.vue b/components/modal/ModalConfirm.vue new file mode 100644 index 00000000..b0516bb9 --- /dev/null +++ b/components/modal/ModalConfirm.vue @@ -0,0 +1,28 @@ +<script setup lang="ts"> +import type { ConfirmDialogChoice, ConfirmDialogLabel } from '~/types' + +defineProps<ConfirmDialogLabel>() + +const emit = defineEmits<{ + (evt: 'choice', choice: ConfirmDialogChoice): void +}>() +</script> + +<template> + <div flex="~ col" gap-6> + <div font-bold text-lg text-center> + {{ title }} + </div> + <div v-if="description"> + {{ description }} + </div> + <div flex justify-end gap-2> + <button btn-text @click="emit('choice', 'cancel')"> + {{ cancel || $t('common.confirm_dialog.cancel') }} + </button> + <button btn-solid @click="emit('choice', 'confirm')"> + {{ confirm || $t('common.confirm_dialog.confirm') }} + </button> + </div> + </div> +</template> diff --git a/components/modal/ModalContainer.vue b/components/modal/ModalContainer.vue index 31ba7cb3..23c31c34 100644 --- a/components/modal/ModalContainer.vue +++ b/components/modal/ModalContainer.vue @@ -1,7 +1,9 @@ <script setup lang="ts"> import type { Status } from 'masto' +import type { ConfirmDialogChoice } from '~/types' import { isCommandPanelOpen, + isConfirmDialogOpen, isEditHistoryDialogOpen, isMediaPreviewOpen, isPreviewHelpOpen, @@ -36,6 +38,11 @@ const handlePublished = (status: Status) => { const handlePublishClose = () => { lastPublishDialogStatus.value = null } + +const handleConfirmChoice = (choice: ConfirmDialogChoice) => { + confirmDialogChoice.value = choice + isConfirmDialogOpen.value = false +} </script> <template> @@ -71,5 +78,8 @@ const handlePublishClose = () => { <ModalDialog v-model="isCommandPanelOpen" max-w-fit flex> <CommandPanel @close="closeCommandPanel()" /> </ModalDialog> + <ModalDialog v-model="isConfirmDialogOpen" py-4 px-8 max-w-125> + <ModalConfirm v-if="confirmDialogLabel" v-bind="confirmDialogLabel" @choice="handleConfirmChoice" /> + </ModalDialog> </template> </template> diff --git a/components/status/StatusActionsMore.vue b/components/status/StatusActionsMore.vue index fe183b84..be948f9e 100644 --- a/components/status/StatusActionsMore.vue +++ b/components/status/StatusActionsMore.vue @@ -22,6 +22,7 @@ const { const clipboard = useClipboard() const router = useRouter() const route = useRoute() +const { t } = useI18n() const isAuthor = $computed(() => status.account.id === currentUser.value?.account.id) @@ -60,13 +61,12 @@ const shareLink = async (status: Status) => { } const deleteStatus = async () => { - // TODO confirm to delete - if (process.dev) { - // eslint-disable-next-line no-alert - const result = confirm('[DEV] Are you sure you want to delete this post?') - if (!result) - return - } + if (await openConfirmDialog({ + title: t('menu.delete_confirm.title'), + confirm: t('menu.delete_confirm.confirm'), + cancel: t('menu.delete_confirm.cancel'), + }) !== 'confirm') + return removeCachedStatus(status.id) await masto.statuses.remove(status.id) diff --git a/composables/dialog.ts b/composables/dialog.ts index b7d07a98..361a0a56 100644 --- a/composables/dialog.ts +++ b/composables/dialog.ts @@ -1,7 +1,10 @@ import type { Attachment, Status, StatusEdit } from 'masto' -import type { Draft } from '~/types' +import type { ConfirmDialogChoice, ConfirmDialogLabel, Draft } from '~/types' import { STORAGE_KEY_FIRST_VISIT } from '~/constants' +export const confirmDialogChoice = ref<ConfirmDialogChoice>() +export const confirmDialogLabel = ref<ConfirmDialogLabel>() + export const mediaPreviewList = ref<Attachment[]>([]) export const mediaPreviewIndex = ref(0) @@ -18,6 +21,7 @@ export const isMediaPreviewOpen = ref(false) export const isEditHistoryDialogOpen = ref(false) export const isPreviewHelpOpen = ref(isFirstVisit.value) export const isCommandPanelOpen = ref(false) +export const isConfirmDialogOpen = ref(false) export const lastPublishDialogStatus = ref<Status | null>(null) @@ -25,6 +29,16 @@ export function openSigninDialog() { isSigninDialogOpen.value = true } +export async function openConfirmDialog(label: ConfirmDialogLabel | string): Promise<ConfirmDialogChoice> { + confirmDialogLabel.value = typeof label === 'string' ? { title: label } : label + confirmDialogChoice.value = undefined + isConfirmDialogOpen.value = true + + await until(isConfirmDialogOpen).toBe(false) + + return confirmDialogChoice.value! +} + export async function openPublishDialog(draftKey = 'dialog', draft?: Draft, overwrite = false): Promise<void> { dialogDraftKey.value = draftKey diff --git a/locales/en-US.json b/locales/en-US.json index edf496e5..78a9dde1 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -86,6 +86,11 @@ "toggle_zen_mode": "Toggle zen mode" }, "common": { + "confirm_dialog": { + "cancel": "No", + "confirm": "Yes", + "title": "Are you sure?" + }, "end_of_list": "End of the list", "error": "ERROR", "in": "in", @@ -123,6 +128,11 @@ "copy_link_to_post": "Copy link to this post", "delete": "Delete", "delete_and_redraft": "Delete & re-draft", + "delete_confirm": { + "cancel": "Cancel", + "confirm": "Delete", + "title": "Are you sure you want to delete this post?" + }, "direct_message_account": "Direct message {0}", "edit": "Edit", "mention_account": "Mention {0}", diff --git a/types/index.ts b/types/index.ts index 340b6c81..190862cf 100644 --- a/types/index.ts +++ b/types/index.ts @@ -65,6 +65,14 @@ export interface Draft { } export type DraftMap = Record<string, Draft> +export interface ConfirmDialogLabel { + title: string + description?: string + confirm?: string + cancel?: string +} +export type ConfirmDialogChoice = 'confirm' | 'cancel' + export interface BuildInfo { version: string commit: string