AppAlertModal.vue 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. <template>
  2. <ClientOnly>
  3. <Teleport to="body">
  4. <div
  5. class="modal--dim"
  6. :class="{ active: modelValue }"
  7. @click.self="handleBackdrop"
  8. >
  9. <div class="alert--wrap" :class="[{ center, active: modelValue }]">
  10. <div
  11. v-if="iconType"
  12. :class="['error--ico', `error--ico--${iconType}`]"
  13. >{{ iconText }}</div>
  14. <div v-if="title" class="modal--tit">
  15. <h2>{{ title }}</h2>
  16. </div>
  17. <div v-if="message" class="modal--cont">
  18. <p v-html="formattedMessage"></p>
  19. </div>
  20. <div class="modal--btn">
  21. <button
  22. v-if="type === 'confirm'"
  23. type="button"
  24. class="cancel"
  25. @click="handleCancel"
  26. >{{ cancelText }}</button>
  27. <button type="button" @click="handleConfirm">{{ confirmText }}</button>
  28. </div>
  29. </div>
  30. </div>
  31. </Teleport>
  32. </ClientOnly>
  33. </template>
  34. <script setup>
  35. import { computed } from 'vue'
  36. const props = defineProps({
  37. modelValue: { type: Boolean, default: false },
  38. // 'alert'(확인만) | 'confirm'(취소/확인)
  39. type: { type: String, default: 'alert' },
  40. // 'error' | 'success' | 'info' | null
  41. iconType: { type: String, default: null },
  42. title: { type: String, default: '' },
  43. message: { type: String, default: '' },
  44. confirmText: { type: String, default: '확인' },
  45. cancelText: { type: String, default: '취소' },
  46. center: { type: Boolean, default: true },
  47. // 백드롭 클릭으로 닫기 허용 여부
  48. closeOnBackdrop: { type: Boolean, default: false },
  49. })
  50. const emit = defineEmits(['update:modelValue', 'confirm', 'cancel'])
  51. const iconText = computed(() => {
  52. if (props.iconType === 'error') return '!'
  53. if (props.iconType === 'success') return '✓'
  54. if (props.iconType === 'info') return 'i'
  55. return ''
  56. })
  57. const formattedMessage = computed(() =>
  58. (props.message || '').replace(/\n/g, '<br />')
  59. )
  60. const close = () => emit('update:modelValue', false)
  61. const handleConfirm = () => {
  62. emit('confirm')
  63. close()
  64. }
  65. const handleCancel = () => {
  66. emit('cancel')
  67. close()
  68. }
  69. const handleBackdrop = () => {
  70. if (props.closeOnBackdrop) close()
  71. }
  72. </script>