161 lines
4.5 KiB
Vue
161 lines
4.5 KiB
Vue
<script setup>
|
|
import AdminNavPrimaryBranch from './AdminNavPrimaryBranch.vue'
|
|
|
|
const props = defineProps({
|
|
/** buildNavigationEditorTree 결과 */
|
|
wraps: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
/** 들여쓰기 단계 */
|
|
depth: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
/** 루트면 `'root'`, 아니면 부모 항목 id */
|
|
parentKey: {
|
|
type: String,
|
|
default: 'root'
|
|
},
|
|
/** 드래그 중인 항목 id */
|
|
draggingId: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
/** 드롭 대상 위에 올린 항목 id */
|
|
dragOverId: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
})
|
|
|
|
const emit = defineEmits([
|
|
'drag-start',
|
|
'drag-over',
|
|
'drag-end',
|
|
'drop',
|
|
'add-child',
|
|
'remove'
|
|
])
|
|
|
|
/**
|
|
* 드래그 시작
|
|
* @param {DragEvent} event - 이벤트
|
|
* @param {string} itemId - 항목 id
|
|
* @returns {void}
|
|
*/
|
|
const onDragStart = (event, itemId) => {
|
|
if (!event.dataTransfer) {
|
|
return
|
|
}
|
|
emit('drag-start', { parentKey: props.parentKey, itemId })
|
|
event.dataTransfer.effectAllowed = 'move'
|
|
}
|
|
|
|
/**
|
|
* 드래그 오버
|
|
* @param {DragEvent} event - 이벤트
|
|
* @param {string} itemId - 항목 id
|
|
* @returns {void}
|
|
*/
|
|
const onDragOver = (event, itemId) => {
|
|
event.preventDefault()
|
|
emit('drag-over', itemId)
|
|
}
|
|
|
|
/**
|
|
* 드롭
|
|
* @param {DragEvent} event - 이벤트
|
|
* @param {string} itemId - 대상 id
|
|
* @returns {void}
|
|
*/
|
|
const onDrop = (event, itemId) => {
|
|
event.preventDefault()
|
|
emit('drop', { parentKey: props.parentKey, targetId: itemId })
|
|
}
|
|
|
|
/**
|
|
* 드래그 종료
|
|
* @returns {void}
|
|
*/
|
|
const onDragEnd = () => {
|
|
emit('drag-end')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<ul class="admin-nav-primary-branch space-y-2" :class="depth ? 'mt-1 border-l border-line pl-3' : ''">
|
|
<li
|
|
v-for="wrap in wraps"
|
|
:key="wrap.item.id"
|
|
class="admin-nav-primary-branch__row rounded border border-transparent bg-white px-2 py-2 transition-colors"
|
|
:class="dragOverId === wrap.item.id ? 'border-ink/20 bg-[#f5f5f2]' : draggingId === wrap.item.id ? 'opacity-60' : ''"
|
|
>
|
|
<div class="admin-nav-primary-branch__controls flex flex-wrap items-center gap-2" :style="{ paddingLeft: `${depth * 4}px` }">
|
|
<span
|
|
class="admin-nav-primary-branch__handle cursor-grab select-none text-muted active:cursor-grabbing"
|
|
draggable="true"
|
|
title="드래그하여 순서 변경"
|
|
@dragstart="onDragStart($event, wrap.item.id)"
|
|
@dragover="onDragOver($event, wrap.item.id)"
|
|
@drop="onDrop($event, wrap.item.id)"
|
|
@dragend="onDragEnd"
|
|
>
|
|
::
|
|
</span>
|
|
<label class="admin-nav-primary-branch__visible flex items-center gap-1 text-xs text-muted">
|
|
<input v-model="wrap.item.isVisible" class="h-4 w-4" type="checkbox">
|
|
표시
|
|
</label>
|
|
<label class="admin-nav-primary-branch__folder flex items-center gap-1 text-xs text-muted">
|
|
<input v-model="wrap.item.isFolder" class="h-4 w-4" type="checkbox">
|
|
폴더
|
|
</label>
|
|
<input
|
|
v-model="wrap.item.label"
|
|
class="admin-nav-primary-branch__label min-w-[120px] flex-1 rounded border border-line px-2 py-1.5 text-sm"
|
|
type="text"
|
|
placeholder="라벨"
|
|
required
|
|
>
|
|
<input
|
|
v-model="wrap.item.url"
|
|
class="admin-nav-primary-branch__url min-w-[160px] flex-1 rounded border border-line px-2 py-1.5 text-sm font-mono"
|
|
type="text"
|
|
placeholder="URL (# 또는 /경로)"
|
|
required
|
|
>
|
|
<button
|
|
class="admin-nav-primary-branch__add-child rounded border border-line px-2 py-1 text-xs font-semibold"
|
|
type="button"
|
|
@click="emit('add-child', wrap.item.id)"
|
|
>
|
|
하위
|
|
</button>
|
|
<button
|
|
class="admin-nav-primary-branch__remove rounded border border-red-200 px-2 py-1 text-xs font-semibold text-red-700"
|
|
type="button"
|
|
@click="emit('remove', wrap.item.id)"
|
|
>
|
|
삭제
|
|
</button>
|
|
</div>
|
|
<AdminNavPrimaryBranch
|
|
v-if="wrap.children.length"
|
|
class="admin-nav-primary-branch__children mt-2"
|
|
:wraps="wrap.children"
|
|
:depth="depth + 1"
|
|
:parent-key="String(wrap.item.id)"
|
|
:dragging-id="draggingId"
|
|
:drag-over-id="dragOverId"
|
|
@drag-start="emit('drag-start', $event)"
|
|
@drag-over="emit('drag-over', $event)"
|
|
@drag-end="emit('drag-end')"
|
|
@drop="emit('drop', $event)"
|
|
@add-child="emit('add-child', $event)"
|
|
@remove="emit('remove', $event)"
|
|
/>
|
|
</li>
|
|
</ul>
|
|
</template>
|