diff --git a/components/admin/AdminMediaFolderPanel.vue b/components/admin/AdminMediaFolderPanel.vue index 672f012..57a203f 100644 --- a/components/admin/AdminMediaFolderPanel.vue +++ b/components/admin/AdminMediaFolderPanel.vue @@ -43,6 +43,14 @@ const props = defineProps({ deletingFolder: { type: String, default: '' + }, + draggingCount: { + type: Number, + default: 0 + }, + busy: { + type: Boolean, + default: false } }) @@ -53,6 +61,8 @@ const emit = defineEmits([ 'select-folder' ]) +const hoveredFolder = ref(null) + /** * 논리 폴더 경로가 썸네일 전용 루트인지 확인한다. * @param {string} folder - 폴더 경로 @@ -80,6 +90,54 @@ const getFolderName = (folder) => String(folder || '').split('/').filter(Boolean * @returns {number} 폴더 깊이 */ const getFolderDepth = (folder) => Math.max(String(folder || '').split('/').filter(Boolean).length - 1, 0) + +/** + * 내부 미디어 드래그만 폴더 이동 대상으로 허용한다. + * @param {DragEvent} event - 드래그 이벤트 + * @param {string} folder - 대상 폴더 + * @returns {void} + */ +const onFolderDragOver = (event, folder) => { + if (!props.draggingCount || props.busy || isThumbnailFolderPath(folder) || (props.deletingFolder && props.deletingFolder === folder)) { + return + } + event.preventDefault() + if (event.dataTransfer) { + event.dataTransfer.dropEffect = 'move' + } + hoveredFolder.value = folder +} + +/** + * 폴더 내부 요소 간 이동을 제외하고 드롭 강조를 해제한다. + * @param {DragEvent} event - 드래그 이탈 이벤트 + * @returns {void} + */ +const onFolderDragLeave = (event) => { + if (!event.currentTarget.contains(event.relatedTarget)) { + hoveredFolder.value = null + } +} + +/** + * 유효한 내부 드래그에 한해 폴더 이동을 요청한다. + * @param {DragEvent} event - 드롭 이벤트 + * @param {string} folder - 대상 폴더 + * @returns {void} + */ +const onFolderDrop = (event, folder) => { + event.preventDefault() + hoveredFolder.value = null + if (props.draggingCount && !props.busy && !isThumbnailFolderPath(folder) && props.deletingFolder !== folder) { + emit('drop-folder', folder) + } +} + +watch(() => props.draggingCount, (count) => { + if (!count) { + hoveredFolder.value = null + } +})