|
1 | 1 | <template> |
2 | | - <Teleport to="body"> |
3 | | - <Modal |
4 | | - ref="modalRef" |
5 | | - :beforeCloseFunction="()=>{modalStore.onAcceptFunction(false);modalStore.isOpened=false}" |
6 | | - backgroundCustomClasses="z-[998]" |
7 | | - modalCustomClasses="z-[999] flex items-center justify-center" |
8 | | - > |
9 | | - <div class="relative p-6 sm:w-[420px] rounded-[inherit] bg-lightAcceptModalBackground dark:bg-darkAcceptModalBackground" > |
10 | | - |
11 | | - <button type="button" @click="modalStore.togleModal()" class="absolute top-3 right-3 p-1.5 rounded-default text-lightAcceptModalCloseIcon hover:text-lightAcceptModalCloseIconHover hover:bg-lightAcceptModalCloseIconHoverBackground dark:text-darkAcceptModalCloseIcon dark:hover:text-darkAcceptModalCloseIconHover dark:hover:bg-darkAcceptModalCloseIconHoverBackground transition-colors" > |
12 | | - <IconX class="w-4 h-4" /> |
13 | | - </button> |
14 | | - |
15 | | - <div class="text-center flex flex-col"> |
16 | | - <div class="mx-auto flex items-center justify-center h-12 w-12 rounded-xl mb-4 relative" |
17 | | - :class="modalStore.modalContent.dangerous ? 'bg-lightDangerSoft dark:bg-darkDangerSoft' : 'bg-lightSecondaryDarken dark:bg-darkSecondaryLighten'"> |
18 | | - <IconClipboardList class="w-6 h-6" |
19 | | - :class="modalStore.modalContent.dangerous ? 'text-lightAcceptModalWarningIcon dark:text-darkAcceptModalWarningIcon' : 'text-lightButtonsBackground dark:text-darkButtonsBackground'" /> |
20 | | - <div class="absolute -bottom-1 -right-1 rounded-full w-[18px] h-[18px] flex items-center justify-center border-2 border-lightAcceptModalBackground dark:border-darkAcceptModalBackground" |
21 | | - :class="modalStore.modalContent.dangerous ? 'bg-lightAcceptModalConfirmButtonBackground dark:bg-darkAcceptModalConfirmButtonBackground' : 'bg-lightButtonsBackground dark:bg-darkButtonsBackground'"> |
22 | | - <span class="text-lightButtonsText dark:text-darkButtonsText text-[10px] font-medium">!</span> |
23 | | - </div> |
24 | | - </div> |
25 | | - |
26 | | - <div class="flex flex-col gap-3"> |
27 | | - <h3 v-if="modalStore?.modalContent?.title" class="text-lg font-semibold tracking-tight text-lightDialogHeaderText dark:text-darkDialogHeaderText"> |
28 | | - {{ modalStore.modalContent.title }} |
29 | | - </h3> |
30 | | - |
31 | | - <div class="text-sm text-lightAcceptModalText dark:text-darkAcceptModalText"> |
32 | | - <div v-if="modalStore?.modalContent?.contentHTML" v-html="modalStore.modalContent.contentHTML"></div> |
33 | | - <p v-else-if="modalStore?.modalContent?.content">{{ modalStore.modalContent.content }}</p> |
34 | | - </div> |
35 | | - </div> |
36 | | - |
37 | | - <hr class="border-t border-lightDialogBreakLine dark:border-darkDialogBreakLine my-5"> |
| 2 | + <Modal |
| 3 | + ref="modalRef" |
| 4 | + class="w-full sm:w-[400px]" |
| 5 | + :role="dangerous ? 'alertdialog' : 'dialog'" |
| 6 | + :aria-labelledby="titleId" |
| 7 | + :beforeCloseFunction="() => { modalStore.onAcceptFunction(false); modalStore.isOpened = false; }" |
| 8 | + backgroundCustomClasses="z-[998]" |
| 9 | + > |
| 10 | + <div class="flex flex-col gap-3 px-5 py-[18px]"> |
| 11 | + <div class="flex items-start gap-3"> |
| 12 | + <span |
| 13 | + v-if="dangerous" |
| 14 | + class="flex w-9 h-9 shrink-0 items-center justify-center rounded-lg bg-lightDangerSoft text-lightDanger dark:bg-darkDangerSoft dark:text-darkDanger" |
| 15 | + > |
| 16 | + <component :is="icon" class="w-5 h-5" aria-hidden="true" /> |
| 17 | + </span> |
| 18 | + <div class="flex-1 min-w-0 flex flex-col gap-1" :class="dangerous ? 'pt-1.5' : ''"> |
| 19 | + <h3 :id="titleId" class="text-base font-semibold tracking-[-0.01em] text-lightDialogHeaderText dark:text-darkDialogHeaderText"> |
| 20 | + {{ title }} |
| 21 | + </h3> |
| 22 | + <p v-if="subtitle" class="text-sm leading-5 text-lightDialogBodyText dark:text-darkDialogBodyText">{{ subtitle }}</p> |
| 23 | + </div> |
| 24 | + <Button |
| 25 | + v-if="!dangerous" |
| 26 | + type="button" |
| 27 | + variant="ghost" |
| 28 | + size="sm" |
| 29 | + iconOnly |
| 30 | + class="-mt-0.5 -me-1.5 text-lightDialogCloseButton hover:text-lightDialogCloseButtonHover hover:bg-lightDialogCloseButtonHoverBackground dark:text-darkDialogCloseButton dark:hover:text-darkDialogCloseButtonHover dark:hover:bg-darkDialogCloseButtonHoverBackground" |
| 31 | + :aria-label="t('Close Modal')" |
| 32 | + @click="answer(false)" |
| 33 | + > |
| 34 | + <IconX aria-hidden="true" /> |
| 35 | + </Button> |
| 36 | + </div> |
38 | 37 |
|
39 | | - <div class="flex justify-center gap-2 w-full"> |
40 | | - <Button @click="()=>{modalStore.onAcceptFunction(false);modalStore.togleModal()}" type="button" variant="secondary" class="flex-1"> |
41 | | - {{ modalStore?.modalContent?.cancelText }} |
42 | | - </Button> |
43 | | - |
44 | | - <Button |
45 | | - @click="()=>{ modalStore.onAcceptFunction(true);modalStore.togleModal()}" |
46 | | - type="button" |
47 | | - class="flex-1" |
48 | | - :variant="modalStore.modalContent.dangerous ? 'danger' : 'primary'"> |
49 | | - {{ modalStore?.modalContent?.acceptText }} |
50 | | - </Button> |
51 | | - </div> |
| 38 | + <div v-if="modalContent.contentHTML" class="text-sm text-lightDialogBodyText dark:text-darkDialogBodyText" v-html="modalContent.contentHTML"></div> |
52 | 39 |
|
53 | | - <div v-if="modalStore?.modalContent?.guardMessage" class="flex items-center justify-center mt-5 text-xs text-lightAcceptModalText dark:text-darkAcceptModalText gap-1.5 font-medium"> |
54 | | - <IconShieldCheck class="w-4 h-4" /> |
55 | | - <span> {{ modalStore?.modalContent?.guardMessage }}</span> |
56 | | - </div> |
| 40 | + <p v-if="modalContent.guardMessage" class="flex items-center gap-1.5 text-xs font-medium text-lightInputIconColor dark:text-darkInputIconColor"> |
| 41 | + <IconShieldCheck class="w-3.5 h-3.5 shrink-0" aria-hidden="true" /> |
| 42 | + {{ modalContent.guardMessage }} |
| 43 | + </p> |
| 44 | + </div> |
57 | 45 |
|
58 | | - </div> |
59 | | - </div> |
60 | | - </Modal> |
61 | | - </Teleport> |
| 46 | + <div :class="dialogFooterClasses"> |
| 47 | + <Button type="button" variant="secondary" @click="answer(false)">{{ modalContent.cancelText }}</Button> |
| 48 | + <Button type="button" :variant="dangerous ? 'danger' : 'primary'" @click="answer(true)">{{ modalContent.acceptText }}</Button> |
| 49 | + </div> |
| 50 | + </Modal> |
62 | 51 | </template> |
63 | 52 |
|
64 | 53 | <script setup lang="ts"> |
65 | | -import { watch, ref } from 'vue'; |
| 54 | +import { watch, ref, computed, useId, type Component } from 'vue'; |
| 55 | +import { storeToRefs } from 'pinia'; |
| 56 | +import { useI18n } from 'vue-i18n'; |
66 | 57 | import { useModalStore } from '@/stores/modal'; |
67 | 58 | import { Button, Modal } from '@/afcl'; |
68 | | -import { IconClipboardList, IconShieldCheck, IconX } from '@iconify-prerendered/vue-lucide'; |
69 | | -
|
| 59 | +import { dialogFooterClasses } from '@/afcl/dialogStyles'; |
| 60 | +import { IconShieldCheck, IconTriangleAlert, IconX } from '@iconify-prerendered/vue-lucide'; |
70 | 61 |
|
| 62 | +const { t } = useI18n(); |
71 | 63 | const modalRef = ref(); |
| 64 | +const titleId = useId(); |
72 | 65 | const modalStore = useModalStore(); |
| 66 | +const { modalContent } = storeToRefs(modalStore); |
73 | 67 |
|
74 | | -watch( () => modalStore.isOpened, (newVal) => { |
75 | | - if (newVal) { |
76 | | - open(); |
77 | | - } else { |
78 | | - close(); |
79 | | - } |
80 | | - } |
81 | | -); |
82 | | -
|
83 | | -
|
| 68 | +const dangerous = computed(() => modalContent.value.dangerous); |
| 69 | +const icon = computed(() => (modalContent.value.icon ?? IconTriangleAlert) as Component); |
| 70 | +// a call with only a message shows it as the title, a call with a title shows the message under it |
| 71 | +const title = computed(() => modalContent.value.title || modalContent.value.content); |
| 72 | +const subtitle = computed(() => modalContent.value.title ? modalContent.value.content : ''); |
84 | 73 |
|
85 | | -function open() { |
86 | | - modalRef.value.open(); |
87 | | -} |
88 | | -
|
89 | | -function close() { |
90 | | - modalRef.value.close(); |
| 74 | +function answer(accepted: boolean) { |
| 75 | + modalStore.onAcceptFunction(accepted); |
| 76 | + modalStore.togleModal(); |
91 | 77 | } |
92 | 78 |
|
| 79 | +watch(() => modalStore.isOpened, (opened) => { |
| 80 | + if (opened) { |
| 81 | + modalRef.value.open(); |
| 82 | + } else { |
| 83 | + modalRef.value.close(); |
| 84 | + } |
| 85 | +}); |
93 | 86 | </script> |
0 commit comments